diff --git a/.github/ISSUE_TEMPLATE/bug_report_form.yml b/.github/ISSUE_TEMPLATE/bug_report_form.yml
new file mode 100644
index 0000000000000..f64b772437fc9
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report_form.yml
@@ -0,0 +1,65 @@
+name: Bug Report
+description: Create a report to help reproduce and fix the issue.
+body:
+ - type: markdown
+ attributes:
+ value: |
+ # **Please read the following guidelines. Follow all instructions or else your issue is subject to closure.**
+ ## If you use the "Report Issue" button in the top-right corner of the game, it will automatically fill in some of the information below.
+
+ If you are reporting an issue found in another branch or codebase, you _must_ link the branch or codebase repo in your issue report or it will be closed.
+ For branches, If you have not pushed your code up, please either reproduce it on master or push your code up before making an issue report.
+ For other codebases, if you do not have a public code repository you will be refused help unless you can completely reproduce the issue on our master branch.
+ - type: input
+ id: reporting-version
+ attributes:
+ label: "Client Version:"
+ description: |
+ The BYOND version you are using to report this issue. You can find this information in the bottom left corner of the "About BYOND" window in the BYOND client.
+ It is strongly recommended that you include this, especially for concerns on the visual aspects of the game.
+ placeholder: "xxx.xxxx"
+ validations:
+ required: false
+ - type: textarea
+ id: issue-summary
+ attributes:
+ label: "Issue Summary:"
+ description: |
+ Briefly explain your issue in a few plain sentences. You may copy and paste the issue title here if it is suitable.
+ placeholder: |
+ "When I do X, Y happens instead of Z."
+ "X on Y map has Z issue."
+ validations:
+ required: true
+ - type: input
+ id: round-id
+ attributes:
+ label: "Round ID:"
+ description: |
+ If you discovered this issue from playing tgstation hosted servers, the Round ID can be found in the Status panel or retrieved from https://statbus.space/
+ The Round ID lets us look up valuable information and logs for the round the bug happened. Leave this blank if there is no round ID.
+ placeholder: "XXXXXX"
+ validations:
+ required: false
+ - type: textarea
+ id: test-merges
+ attributes:
+ label: "Test Merge Information:"
+ description: |
+ If you're certain the issue is to be caused by a test merge [OOC Tab -> Show Server Revision], report it in the pull request's comment section rather than on the tracker.
+ If you're unsure you can refer to the issue number by prefixing said number with #. The issue number can be found beside the title after submission of this form.
+ validations:
+ required: false
+ - type: textarea
+ id: reproduction
+ attributes:
+ label: "Reproduction Steps:"
+ description: |
+ Describe the steps to reproduce the issue in detail. Include any relevant information, such as the map, round type, and any other factors that may be relevant.
+ If it is a runtime-related error, please include the runtime here as that is pertient information. Issues are not for oddities introduced by admin varedits, ensure these occur in normal circumstances.
+ placeholder: |
+ 1. Go to the X location
+ 2. Do Y action
+ 3. Observe Z result
+ validations:
+ required: true
diff --git a/.github/gbp.toml b/.github/gbp.toml
index fe086e79b55f9..382c65b308d6d 100644
--- a/.github/gbp.toml
+++ b/.github/gbp.toml
@@ -23,3 +23,4 @@ reset_label = "GBP: Reset"
"Sound" = 3
"Sprites" = 3
"Unit Tests" = 6
+"Wallening Revert Recovery" = 10
\ No newline at end of file
diff --git a/.github/workflows/update_tgs_dmapi.yml b/.github/workflows/update_tgs_dmapi.yml
index 8dfdee90e36a0..232c02c0ecbed 100644
--- a/.github/workflows/update_tgs_dmapi.yml
+++ b/.github/workflows/update_tgs_dmapi.yml
@@ -21,6 +21,7 @@ jobs:
- name: Apply DMAPI update
uses: tgstation/tgs-dmapi-updater@v2
+ id: dmapi-update
with:
header-path: 'code/__DEFINES/tgs.dm'
library-path: 'code/modules/tgs'
@@ -41,7 +42,7 @@ jobs:
source_branch: "tgs-dmapi-update"
destination_branch: "master"
pr_title: "Automatic TGS DMAPI Update"
- pr_body: "This pull request updates the TGS DMAPI to the latest version. Please note any changes that may be breaking or unimplemented in your codebase by checking what changes are in the definitions file: code/__DEFINES/tgs.dm before merging."
+ pr_body: "This pull request updates the TGS DMAPI to the latest version. Please note any changes that may be breaking or unimplemented in your codebase by checking what changes are in the definitions file: code/__DEFINES/tgs.dm before merging.\n\n${{ steps.dmapi-update.outputs.release-notes }}"
pr_label: "Tools"
pr_allow_empty: false
github_token: ${{ secrets.COMFY_ORANGE_PAT }}
diff --git a/README.md b/README.md
index c0c5fc1f89bbf..6fccae54e43c1 100644
--- a/README.md
+++ b/README.md
@@ -20,6 +20,8 @@ This is the codebase for the /tg/station flavoured fork of SpaceStation 13.
Space Station 13 is a paranoia-laden round-based roleplaying game set against the backdrop of a nonsensical, metal death trap masquerading as a space station, with charming spritework designed to represent the sci-fi setting and its dangerous undertones. Have fun, and survive!
+*All github inquiries (such as moderation actions) may be handled via the /tg/station discord [#coding-general](https://discord.com/channels/326822144233439242/326831214667235328). Simply ping the `@Maintainer` role, following the guide on asking questions located in the channel description, with your issue!*
+
## DOWNLOADING
[Downloading](.github/guides/DOWNLOADING.md)
diff --git a/_maps/RandomRuins/IceRuins/icemoon_surface_pizza.dmm b/_maps/RandomRuins/IceRuins/icemoon_surface_pizza.dmm
index 0e78558d6f38c..121f9e4ea45d4 100644
--- a/_maps/RandomRuins/IceRuins/icemoon_surface_pizza.dmm
+++ b/_maps/RandomRuins/IceRuins/icemoon_surface_pizza.dmm
@@ -300,7 +300,6 @@
/area/ruin/pizzeria)
"kr" = (
/obj/structure/table,
-/obj/item/trash/waffles,
/obj/effect/turf_decal/tile/blue/opposingcorners{
dir = 1
},
diff --git a/_maps/RandomRuins/IceRuins/icemoon_underground_comms_agent.dmm b/_maps/RandomRuins/IceRuins/icemoon_underground_comms_agent.dmm
index ff3417fefce6d..d5c344e9cd31a 100644
--- a/_maps/RandomRuins/IceRuins/icemoon_underground_comms_agent.dmm
+++ b/_maps/RandomRuins/IceRuins/icemoon_underground_comms_agent.dmm
@@ -451,12 +451,8 @@
/area/ruin/comms_agent)
"xq" = (
/obj/effect/decal/cleanable/dirt,
-/obj/item/radio/intercom{
- pixel_x = 31;
- syndie = 1;
- freerange = 1;
- name = "syndicate radio intercom";
- desc = "A custom-made Syndicate-issue intercom used to transmit on all Nanotrasen frequencies. Particularly expensive."
+/obj/item/radio/intercom/syndicate/freerange{
+ pixel_x = 31
},
/obj/structure/table/reinforced,
/obj/machinery/fax{
diff --git a/_maps/RandomRuins/LavaRuins/lavaland_biodome_beach.dmm b/_maps/RandomRuins/LavaRuins/lavaland_biodome_beach.dmm
index 82f4d3677800a..85b662d04aa95 100644
--- a/_maps/RandomRuins/LavaRuins/lavaland_biodome_beach.dmm
+++ b/_maps/RandomRuins/LavaRuins/lavaland_biodome_beach.dmm
@@ -406,6 +406,10 @@
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer4,
/turf/open/floor/plating,
/area/ruin/powered/beach)
+"mv" = (
+/obj/effect/spawner/message_in_a_bottle/low_prob,
+/turf/open/misc/beach/coast,
+/area/ruin/powered/beach)
"mw" = (
/obj/structure/flora/coconuts,
/turf/open/misc/beach/sand,
@@ -985,6 +989,7 @@
dir = 1
},
/obj/machinery/light/directional/south,
+/obj/effect/spawner/message_in_a_bottle/low_prob,
/turf/open/misc/beach/coast/corner{
dir = 8
},
@@ -1990,7 +1995,7 @@ bG
bL
VI
VI
-yT
+mv
pz
Eu
pz
diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_crashsite.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_crashsite.dmm
new file mode 100644
index 0000000000000..828e7b7f74352
--- /dev/null
+++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_crashsite.dmm
@@ -0,0 +1,908 @@
+//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE
+"a" = (
+/turf/open/misc/asteroid/basalt/lava_land_surface,
+/area/lavaland/surface)
+"b" = (
+/obj/machinery/door/airlock/titanium{
+ name = "Escape Pod Airlock"
+ },
+/turf/open/floor/mineral/titanium/blue,
+/area/ruin/unpowered)
+"c" = (
+/obj/item/gps/computer,
+/obj/structure/tubes,
+/turf/open/floor/pod/dark,
+/area/ruin/powered)
+"d" = (
+/obj/structure/tubes,
+/obj/structure/rack,
+/obj/item/survivalcapsule,
+/turf/open/floor/pod/dark,
+/area/ruin/powered)
+"e" = (
+/obj/structure/chair/comfy/shuttle{
+ dir = 4
+ },
+/turf/open/floor/mineral/titanium/blue,
+/area/ruin/unpowered)
+"f" = (
+/obj/structure/bed/pod{
+ dir = 1
+ },
+/obj/item/bedsheet/black{
+ dir = 4
+ },
+/turf/open/floor/pod/dark,
+/area/ruin/powered)
+"g" = (
+/obj/structure/rack,
+/obj/item/clothing/suit/space/orange,
+/obj/item/clothing/suit/space/orange,
+/obj/item/clothing/head/helmet/space/fragile,
+/obj/item/clothing/head/helmet/space/fragile,
+/turf/open/floor/pod/dark,
+/area/ruin/powered)
+"h" = (
+/obj/effect/decal/cleanable/rubble,
+/turf/open/misc/asteroid/basalt/lava_land_surface,
+/area/lavaland/surface)
+"i" = (
+/obj/effect/mob_spawn/corpse/goliath,
+/turf/open/misc/asteroid/basalt/lava_land_surface,
+/area/lavaland/surface)
+"j" = (
+/obj/structure/chair/comfy/shuttle{
+ dir = 4
+ },
+/obj/item/bitrunning_disk/item/pka_mods,
+/turf/open/floor/mineral/titanium/blue,
+/area/ruin/unpowered)
+"k" = (
+/obj/structure/girder,
+/turf/open/floor/plating/lavaland_atmos,
+/area/ruin/unpowered)
+"l" = (
+/turf/open/water/lavaland_atmos,
+/area/lavaland/surface)
+"m" = (
+/obj/machinery/door/airlock/survival_pod/glass,
+/turf/open/floor/pod/dark,
+/area/ruin/powered)
+"n" = (
+/turf/closed/wall/mineral/titanium{
+ initial_gas_mix = "LAVALAND_ATMOS"
+ },
+/area/ruin/unpowered)
+"o" = (
+/turf/closed/mineral/volcanic/lava_land_surface,
+/area/lavaland/surface)
+"p" = (
+/obj/structure/rack,
+/obj/item/storage/toolbox/emergency,
+/obj/item/storage/toolbox/emergency,
+/turf/open/floor/pod/dark,
+/area/ruin/powered)
+"q" = (
+/turf/closed/wall/mineral/titanium/interior,
+/area/ruin/unpowered)
+"r" = (
+/obj/machinery/door/airlock/titanium{
+ name = "Escape Pod Airlock"
+ },
+/turf/open/floor/mineral/titanium/blue/lavaland_atmos,
+/area/ruin/unpowered)
+"s" = (
+/turf/open/floor/pod/dark,
+/area/ruin/powered)
+"t" = (
+/obj/structure/flora/tree/stump,
+/turf/open/misc/asteroid/basalt/lava_land_surface,
+/area/lavaland/surface)
+"u" = (
+/obj/structure/bonfire/prelit,
+/turf/open/misc/asteroid/basalt/lava_land_surface,
+/area/lavaland/surface)
+"v" = (
+/obj/effect/decal/cleanable/rubble,
+/obj/item/stack/sheet/mineral/titanium,
+/obj/item/stack/sheet/mineral/titanium,
+/turf/open/misc/asteroid/basalt/lava_land_surface,
+/area/lavaland/surface)
+"w" = (
+/obj/effect/decal/cleanable/glass/titanium,
+/obj/item/stack/sheet/mineral/titanium,
+/obj/item/stack/sheet/mineral/titanium,
+/turf/open/floor/plating,
+/area/ruin/unpowered)
+"x" = (
+/obj/structure/chair/plastic{
+ dir = 8
+ },
+/turf/open/misc/ashplanet/wateryrock,
+/area/lavaland/surface)
+"y" = (
+/obj/structure/chair/comfy/shuttle{
+ dir = 1
+ },
+/obj/effect/mob_spawn/corpse/human/engineer,
+/turf/open/floor/mineral/titanium/blue/lavaland_atmos,
+/area/ruin/unpowered)
+"z" = (
+/obj/item/book/manual/fish_catalog,
+/turf/open/misc/ashplanet/wateryrock,
+/area/lavaland/surface)
+"B" = (
+/mob/living/basic/mining/goliath,
+/turf/open/misc/asteroid/basalt/lava_land_surface,
+/area/lavaland/surface)
+"D" = (
+/obj/item/gun/energy/recharge/kinetic_accelerator,
+/turf/open/misc/asteroid/basalt/lava_land_surface,
+/area/lavaland/surface)
+"E" = (
+/turf/open/misc/ashplanet/wateryrock,
+/area/lavaland/surface)
+"F" = (
+/obj/effect/mob_spawn/corpse/human/cargo_tech,
+/turf/open/misc/asteroid/basalt/lava_land_surface,
+/area/lavaland/surface)
+"G" = (
+/turf/template_noop,
+/area/template_noop)
+"H" = (
+/obj/structure/chair/comfy/shuttle{
+ dir = 4
+ },
+/obj/effect/mob_spawn/corpse/human/cook,
+/turf/open/floor/mineral/titanium/blue,
+/area/ruin/unpowered)
+"I" = (
+/obj/structure/chair/comfy/shuttle{
+ dir = 1
+ },
+/turf/open/floor/mineral/titanium/blue/lavaland_atmos,
+/area/ruin/unpowered)
+"J" = (
+/obj/machinery/smartfridge/survival_pod{
+ desc = "A heated storage unit. This one's seen better days.";
+ name = "dusty survival pod storage"
+ },
+/turf/open/floor/pod/dark,
+/area/ruin/powered)
+"K" = (
+/obj/structure/fans,
+/turf/open/floor/pod/dark,
+/area/ruin/powered)
+"L" = (
+/obj/item/storage/toolbox/fishing,
+/turf/open/misc/ashplanet/wateryrock,
+/area/lavaland/surface)
+"M" = (
+/obj/structure/rack,
+/obj/item/pickaxe/emergency,
+/obj/item/pickaxe/emergency,
+/obj/item/crowbar/large/emergency,
+/turf/open/floor/pod/dark,
+/area/ruin/powered)
+"N" = (
+/turf/closed/wall/mineral/titanium/survival/pod,
+/area/ruin/powered)
+"O" = (
+/obj/effect/spawner/structure/window/reinforced/shuttle,
+/turf/open/floor/plating,
+/area/ruin/unpowered)
+"P" = (
+/obj/effect/mob_spawn/corpse/human/miner,
+/turf/open/misc/asteroid/basalt/lava_land_surface,
+/area/lavaland/surface)
+"Q" = (
+/turf/closed/wall/mineral/titanium/nodiagonal,
+/area/ruin/unpowered)
+"R" = (
+/mob/living/basic/mining/goliath/ancient,
+/turf/open/misc/asteroid/basalt/lava_land_surface,
+/area/lavaland/surface)
+"S" = (
+/obj/structure/bed/pod,
+/obj/item/bedsheet/black,
+/turf/open/floor/pod/dark,
+/area/ruin/powered)
+"T" = (
+/obj/structure/tubes,
+/turf/open/floor/pod/dark,
+/area/ruin/powered)
+"U" = (
+/obj/item/bait_can/worm/premium,
+/turf/open/misc/ashplanet/wateryrock,
+/area/lavaland/surface)
+"V" = (
+/obj/structure/table/survival_pod,
+/obj/item/food/meat/steak/goliath,
+/turf/open/floor/pod/dark,
+/area/ruin/powered)
+"Y" = (
+/obj/machinery/power/shuttle_engine/propulsion/burst{
+ dir = 8
+ },
+/turf/closed/wall/mineral/titanium/interior,
+/area/ruin/unpowered)
+"Z" = (
+/obj/machinery/power/shuttle_engine/propulsion/burst,
+/turf/closed/wall/mineral/titanium/interior,
+/area/ruin/unpowered)
+
+(1,1,1) = {"
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+"}
+(2,1,1) = {"
+G
+G
+G
+G
+G
+G
+G
+o
+o
+G
+o
+o
+G
+o
+o
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+"}
+(3,1,1) = {"
+G
+G
+G
+G
+G
+G
+o
+o
+o
+o
+o
+o
+o
+o
+o
+o
+G
+o
+G
+G
+G
+G
+G
+G
+G
+"}
+(4,1,1) = {"
+G
+G
+G
+G
+G
+o
+o
+o
+o
+o
+o
+o
+o
+o
+o
+o
+o
+o
+o
+o
+G
+o
+G
+G
+G
+"}
+(5,1,1) = {"
+G
+G
+G
+G
+o
+o
+o
+o
+o
+E
+E
+E
+E
+E
+E
+o
+o
+o
+o
+o
+o
+o
+o
+G
+G
+"}
+(6,1,1) = {"
+G
+G
+G
+o
+o
+o
+o
+a
+a
+E
+l
+l
+l
+l
+E
+E
+F
+N
+N
+N
+N
+N
+o
+G
+G
+"}
+(7,1,1) = {"
+G
+G
+G
+o
+o
+a
+a
+a
+t
+E
+l
+l
+l
+l
+E
+E
+a
+N
+K
+s
+M
+N
+o
+G
+G
+"}
+(8,1,1) = {"
+G
+G
+G
+o
+o
+a
+a
+a
+a
+E
+E
+l
+l
+l
+E
+h
+a
+N
+J
+s
+p
+N
+o
+G
+G
+"}
+(9,1,1) = {"
+G
+G
+G
+o
+n
+q
+q
+Z
+a
+a
+E
+E
+l
+U
+E
+a
+a
+N
+V
+s
+S
+N
+o
+o
+G
+"}
+(10,1,1) = {"
+G
+G
+G
+o
+O
+y
+I
+r
+a
+a
+R
+z
+x
+L
+a
+a
+h
+N
+N
+m
+N
+N
+o
+G
+G
+"}
+(11,1,1) = {"
+G
+G
+G
+o
+n
+q
+k
+Z
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+a
+o
+o
+G
+"}
+(12,1,1) = {"
+G
+G
+G
+o
+o
+v
+a
+B
+a
+a
+i
+a
+a
+a
+a
+a
+a
+a
+B
+a
+a
+a
+G
+G
+G
+"}
+(13,1,1) = {"
+G
+G
+G
+G
+o
+o
+a
+a
+a
+a
+D
+a
+a
+a
+a
+u
+a
+a
+a
+a
+a
+a
+G
+G
+G
+"}
+(14,1,1) = {"
+G
+G
+G
+G
+o
+o
+Y
+b
+Y
+P
+a
+a
+a
+a
+a
+h
+a
+a
+a
+a
+a
+a
+G
+G
+G
+"}
+(15,1,1) = {"
+G
+G
+G
+o
+o
+o
+q
+e
+Q
+N
+N
+m
+N
+N
+t
+a
+a
+a
+a
+a
+a
+a
+G
+G
+G
+"}
+(16,1,1) = {"
+G
+G
+G
+o
+o
+o
+q
+j
+Q
+N
+K
+s
+f
+N
+a
+a
+a
+a
+a
+a
+a
+G
+G
+G
+G
+"}
+(17,1,1) = {"
+G
+G
+G
+o
+o
+o
+n
+o
+Q
+N
+J
+s
+g
+N
+a
+Y
+b
+Y
+a
+a
+a
+o
+o
+G
+G
+"}
+(18,1,1) = {"
+G
+G
+G
+G
+o
+o
+o
+o
+o
+N
+c
+T
+d
+N
+a
+q
+e
+q
+a
+a
+o
+o
+o
+G
+G
+"}
+(19,1,1) = {"
+G
+G
+G
+G
+G
+o
+o
+o
+o
+N
+N
+N
+N
+N
+o
+q
+H
+q
+a
+o
+o
+o
+o
+G
+G
+"}
+(20,1,1) = {"
+G
+G
+G
+G
+G
+o
+o
+o
+o
+o
+o
+o
+o
+o
+o
+q
+w
+o
+o
+o
+o
+G
+G
+G
+G
+"}
+(21,1,1) = {"
+G
+G
+G
+G
+G
+G
+G
+o
+o
+o
+o
+o
+o
+o
+o
+o
+o
+o
+o
+o
+G
+G
+G
+G
+G
+"}
+(22,1,1) = {"
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+o
+o
+o
+o
+o
+o
+o
+G
+G
+G
+G
+G
+G
+"}
+(23,1,1) = {"
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+"}
+(24,1,1) = {"
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+"}
+(25,1,1) = {"
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+G
+"}
diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_seed_vault.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_seed_vault.dmm
index c70a28308c3ec..41b4510ea3459 100644
--- a/_maps/RandomRuins/LavaRuins/lavaland_surface_seed_vault.dmm
+++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_seed_vault.dmm
@@ -338,7 +338,6 @@
/area/ruin/powered/seedvault)
"bc" = (
/obj/machinery/light/directional/west,
-/obj/machinery/hydroponics/constructable,
/obj/effect/decal/cleanable/dirt,
/obj/effect/turf_decal/trimline/green/line{
dir = 8
@@ -346,6 +345,7 @@
/obj/effect/turf_decal/trimline/green/line{
dir = 4
},
+/obj/machinery/hydroponics/constructable/fullupgrade,
/turf/open/floor/mineral/plastitanium,
/area/ruin/powered/seedvault)
"bd" = (
@@ -375,10 +375,10 @@
/turf/open/floor/mineral/plastitanium,
/area/ruin/powered/seedvault)
"bh" = (
-/obj/machinery/hydroponics/constructable,
/obj/effect/turf_decal/trimline/green/line{
dir = 6
},
+/obj/machinery/hydroponics/constructable/fullupgrade,
/turf/open/floor/mineral/plastitanium,
/area/ruin/powered/seedvault)
"bi" = (
@@ -395,10 +395,10 @@
/turf/open/floor/mineral/plastitanium,
/area/ruin/powered/seedvault)
"bj" = (
-/obj/machinery/hydroponics/constructable,
/obj/effect/turf_decal/trimline/green/line{
dir = 10
},
+/obj/machinery/hydroponics/constructable/fullupgrade,
/turf/open/floor/mineral/plastitanium,
/area/ruin/powered/seedvault)
"bk" = (
@@ -413,7 +413,6 @@
/obj/structure/disposalpipe/segment{
dir = 4
},
-/obj/machinery/hydroponics/constructable,
/obj/effect/decal/cleanable/dirt,
/obj/effect/turf_decal/trimline/green/line{
dir = 8
@@ -421,6 +420,7 @@
/obj/effect/turf_decal/trimline/green/line{
dir = 4
},
+/obj/machinery/hydroponics/constructable/fullupgrade,
/turf/open/floor/mineral/plastitanium,
/area/ruin/powered/seedvault)
"bm" = (
@@ -479,13 +479,13 @@
/area/ruin/powered/seedvault)
"bw" = (
/obj/machinery/light/directional/south,
-/obj/machinery/hydroponics/constructable,
/obj/effect/decal/cleanable/dirt,
/obj/effect/decal/cleanable/dirt,
/obj/effect/turf_decal/trimline/green/line{
dir = 1
},
/obj/effect/turf_decal/trimline/green/line,
+/obj/machinery/hydroponics/constructable/fullupgrade,
/turf/open/floor/mineral/plastitanium,
/area/ruin/powered/seedvault)
"bx" = (
@@ -511,17 +511,17 @@
/turf/closed/wall/r_wall,
/area/ruin/powered/seedvault)
"bB" = (
-/obj/machinery/hydroponics/constructable,
/obj/effect/turf_decal/trimline/green/line{
dir = 5
},
+/obj/machinery/hydroponics/constructable/fullupgrade,
/turf/open/floor/mineral/plastitanium,
/area/ruin/powered/seedvault)
"bC" = (
-/obj/machinery/hydroponics/constructable,
/obj/effect/turf_decal/trimline/green/line{
dir = 9
},
+/obj/machinery/hydroponics/constructable/fullupgrade,
/turf/open/floor/mineral/plastitanium,
/area/ruin/powered/seedvault)
"bD" = (
@@ -565,7 +565,6 @@
/turf/open/floor/iron/freezer,
/area/ruin/powered/seedvault)
"pZ" = (
-/obj/machinery/hydroponics/constructable,
/obj/effect/decal/cleanable/dirt,
/obj/effect/decal/cleanable/cobweb/cobweb2,
/obj/effect/turf_decal/trimline/green/line{
@@ -574,10 +573,10 @@
/obj/effect/turf_decal/trimline/green/line{
dir = 4
},
+/obj/machinery/hydroponics/constructable/fullupgrade,
/turf/open/floor/mineral/plastitanium,
/area/ruin/powered/seedvault)
"rF" = (
-/obj/machinery/hydroponics/constructable,
/obj/effect/decal/cleanable/dirt,
/obj/effect/turf_decal/trimline/green/line{
dir = 8
@@ -585,6 +584,7 @@
/obj/effect/turf_decal/trimline/green/line{
dir = 4
},
+/obj/machinery/hydroponics/constructable/fullupgrade,
/turf/open/floor/mineral/plastitanium,
/area/ruin/powered/seedvault)
"rX" = (
@@ -656,12 +656,12 @@
/turf/open/floor/iron/freezer,
/area/ruin/powered/seedvault)
"VF" = (
-/obj/machinery/hydroponics/constructable,
/obj/effect/decal/cleanable/dirt,
/obj/effect/turf_decal/trimline/green/line{
dir = 1
},
/obj/effect/turf_decal/trimline/green/line,
+/obj/machinery/hydroponics/constructable/fullupgrade,
/turf/open/floor/mineral/plastitanium,
/area/ruin/powered/seedvault)
diff --git a/_maps/RandomRuins/SpaceRuins/dangerous_research.dmm b/_maps/RandomRuins/SpaceRuins/dangerous_research.dmm
index a7eac1fe1a8b1..edd734ee6f586 100644
--- a/_maps/RandomRuins/SpaceRuins/dangerous_research.dmm
+++ b/_maps/RandomRuins/SpaceRuins/dangerous_research.dmm
@@ -1062,7 +1062,7 @@
/turf/open/floor/iron/dark,
/area/ruin/space/has_grav/dangerous_research/lab)
"oJ" = (
-/obj/structure/closet/crate/medical,
+/obj/structure/closet/crate/secure/interdyne,
/obj/item/stack/medical/suture/emergency,
/obj/item/stack/medical/gauze/twelve,
/obj/item/reagent_containers/hypospray/medipen/blood_loss,
@@ -2155,7 +2155,7 @@
/turf/open/floor/iron/dark,
/area/ruin/space/has_grav/dangerous_research/lab)
"BG" = (
-/obj/structure/closet/crate,
+/obj/structure/closet/crate/secure/interdyne,
/obj/item/stack/sheet/mineral/plasma/thirty,
/obj/item/stack/sheet/mineral/wood/fifty,
/obj/item/stack/sheet/iron/fifty,
@@ -3658,7 +3658,7 @@
/turf/open/floor/iron/dark,
/area/ruin/space/has_grav/dangerous_research)
"VQ" = (
-/obj/structure/closet/crate,
+/obj/structure/closet/crate/secure/interdyne,
/obj/item/reagent_containers/cup/glass/waterbottle/large,
/obj/item/reagent_containers/cup/glass/waterbottle/large,
/obj/item/reagent_containers/cup/glass/waterbottle/large,
diff --git a/_maps/RandomRuins/SpaceRuins/garbagetruck1.dmm b/_maps/RandomRuins/SpaceRuins/garbagetruck1.dmm
index a81508dbe1f40..6aca5d7938a01 100644
--- a/_maps/RandomRuins/SpaceRuins/garbagetruck1.dmm
+++ b/_maps/RandomRuins/SpaceRuins/garbagetruck1.dmm
@@ -491,9 +491,6 @@
/area/ruin/space/has_grav/garbagetruck/foodwaste)
"xf" = (
/obj/item/trash/tray,
-/obj/item/trash/waffles,
-/obj/item/trash/waffles,
-/obj/item/trash/waffles,
/obj/item/food/grown/mushroom/plumphelmet,
/obj/structure/closet/crate/trashcart,
/mob/living/basic/mouse/rat,
diff --git a/_maps/RandomRuins/SpaceRuins/infested_frigate.dmm b/_maps/RandomRuins/SpaceRuins/infested_frigate.dmm
index 21b981191aeb3..abccc6b550eb1 100644
--- a/_maps/RandomRuins/SpaceRuins/infested_frigate.dmm
+++ b/_maps/RandomRuins/SpaceRuins/infested_frigate.dmm
@@ -562,7 +562,7 @@
/obj/machinery/airalarm/directional/north,
/obj/effect/mapping_helpers/airalarm/all_access,
/obj/machinery/icecream_vat{
- desc = "Waffle co. actually ordered these guys to steal one of these just to be sure."
+ desc = "Waffle Corp. actually ordered these guys to steal one of these just to be sure."
},
/turf/open/floor/plating,
/area/ruin/space/has_grav/infested_frigate)
diff --git a/_maps/RandomZLevels/TheBeach.dmm b/_maps/RandomZLevels/TheBeach.dmm
index 64cdcbb6d362e..41fcd3280d490 100644
--- a/_maps/RandomZLevels/TheBeach.dmm
+++ b/_maps/RandomZLevels/TheBeach.dmm
@@ -102,6 +102,17 @@
"bi" = (
/turf/open/floor/iron/white/textured_large,
/area/awaymission/beach)
+"bo" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 9
+ },
+/obj/effect/turf_decal/tile/dark/half{
+ pixel_y = -1;
+ pixel_x = 5;
+ dir = 8
+ },
+/turf/open/water/beach,
+/area/awaymission/beach)
"bx" = (
/obj/effect/turf_decal/sand,
/obj/machinery/door/airlock/wood{
@@ -278,16 +289,6 @@
/obj/structure/musician/piano,
/turf/open/floor/wood,
/area/awaymission/beach)
-"dx" = (
-/obj/structure/sign/directions/dorms/directional/north{
- pixel_y = 35
- },
-/obj/structure/sign/directions/medical/directional/north{
- pixel_y = 29
- },
-/obj/machinery/computer/slot_machine,
-/turf/open/floor/wood/large,
-/area/awaymission/beach)
"dL" = (
/obj/machinery/door/airlock/public/glass{
name = "Locker Room"
@@ -505,6 +506,10 @@
},
/turf/closed/wall/mineral/wood,
/area/awaymission/beach)
+"gq" = (
+/obj/item/broken_bottle,
+/turf/open/misc/beach/sand,
+/area/awaymission/beach)
"gw" = (
/obj/item/stack/sheet/mineral/sandstone{
pixel_x = -8
@@ -894,17 +899,6 @@
/obj/structure/table/wood,
/turf/open/floor/wood/large,
/area/awaymission/beach)
-"lk" = (
-/obj/effect/turf_decal/siding/wood{
- dir = 9
- },
-/obj/effect/turf_decal/tile/dark/half{
- pixel_y = -1;
- pixel_x = 5;
- dir = 8
- },
-/turf/open/water/beach,
-/area/awaymission/beach)
"ll" = (
/obj/machinery/door/airlock/wood{
name = "Room 11";
@@ -1191,6 +1185,10 @@
},
/turf/open/misc/beach/sand,
/area/awaymission/beach)
+"pq" = (
+/obj/effect/spawner/random/trash/cigbutt,
+/turf/open/misc/beach/sand,
+/area/awaymission/beach)
"pr" = (
/obj/item/reagent_containers/cup/soda_cans/space_mountain_wind{
pixel_x = -17;
@@ -2573,13 +2571,6 @@
},
/turf/open/misc/beach/sand,
/area/awaymission/beach)
-"FJ" = (
-/obj/item/instrument/guitar{
- pixel_y = 4;
- pixel_x = -1
- },
-/turf/open/misc/beach/coast,
-/area/awaymission/beach)
"FK" = (
/obj/item/toy/seashell{
pixel_x = 12;
@@ -2856,6 +2847,17 @@
/obj/machinery/light/directional/west,
/turf/open/floor/wood/large,
/area/awaymission/beach)
+"Jv" = (
+/obj/item/paper/fluff/old_pirate_note{
+ pixel_x = -5;
+ pixel_y = -7
+ },
+/obj/item/pen/fountain{
+ pixel_y = -11;
+ pixel_x = -8
+ },
+/turf/open/misc/beach/sand,
+/area/awaymission/beach)
"JF" = (
/obj/structure/marker_beacon/burgundy,
/turf/open/water/beach,
@@ -2960,6 +2962,13 @@
},
/turf/open/misc/beach/sand,
/area/awaymission/beach)
+"KQ" = (
+/obj/item/instrument/guitar{
+ pixel_y = 4;
+ pixel_x = -1
+ },
+/turf/open/misc/beach/coast,
+/area/awaymission/beach)
"KV" = (
/obj/effect/decal/cleanable/dirt,
/obj/effect/decal/cleanable/dirt/dust,
@@ -3330,6 +3339,12 @@
},
/turf/open/misc/beach/sand,
/area/awaymission/beach)
+"Pb" = (
+/obj/item/fishing_rod,
+/obj/structure/closet/crate/trashcart,
+/obj/item/reagent_containers/cup/glass/bottle/rum/aged,
+/turf/open/misc/beach/sand,
+/area/awaymission/beach)
"Pe" = (
/turf/open/misc/beach/coast{
dir = 5
@@ -3378,6 +3393,11 @@
},
/turf/open/misc/beach/sand,
/area/awaymission/beach)
+"PU" = (
+/obj/effect/mob_spawn/corpse/human/old_pirate_captain,
+/obj/structure/bed/maint,
+/turf/open/misc/beach/sand,
+/area/awaymission/beach)
"Qe" = (
/obj/effect/turf_decal/sand,
/obj/machinery/door/airlock/wood{
@@ -3996,6 +4016,16 @@
"Zp" = (
/turf/open/floor/wood/large,
/area/awaymission/beach)
+"Zs" = (
+/obj/structure/sign/directions/dorms/directional/north{
+ pixel_y = 35
+ },
+/obj/structure/sign/directions/medical/directional/north{
+ pixel_y = 29
+ },
+/obj/machinery/computer/slot_machine,
+/turf/open/floor/wood/large,
+/area/awaymission/beach)
"Zt" = (
/obj/structure/table/bronze,
/obj/item/storage/toolbox/fishing{
@@ -7415,8 +7445,8 @@ XB
XB
Vf
YV
-VY
-VY
+Pb
+gq
hL
ni
XB
@@ -7672,8 +7702,8 @@ XB
XB
Vf
VY
-VY
-VY
+pq
+PU
Er
BK
XB
@@ -7929,7 +7959,7 @@ XB
XB
Vf
VY
-VY
+Jv
VY
VY
BK
@@ -8187,7 +8217,7 @@ XB
Vf
IZ
VY
-VY
+pq
VY
BK
XB
@@ -13210,7 +13240,7 @@ xv
xv
xv
xv
-dx
+Zs
Zp
Zp
mb
@@ -16284,7 +16314,7 @@ vx
Bq
Xd
Ej
-lk
+bo
LC
XB
XB
@@ -29420,7 +29450,7 @@ VY
VY
Rn
VY
-FJ
+KQ
xv
CG
Gh
diff --git a/_maps/RandomZLevels/snowdin.dmm b/_maps/RandomZLevels/snowdin.dmm
index 6f565143e790e..be1301a9fbabf 100644
--- a/_maps/RandomZLevels/snowdin.dmm
+++ b/_maps/RandomZLevels/snowdin.dmm
@@ -1909,11 +1909,6 @@
},
/turf/open/floor/iron/cafeteria,
/area/awaymission/snowdin/post/messhall)
-"ht" = (
-/obj/structure/table,
-/obj/item/trash/waffles,
-/turf/open/floor/iron/cafeteria,
-/area/awaymission/snowdin/post/messhall)
"hu" = (
/obj/structure/chair{
dir = 8
@@ -5245,7 +5240,7 @@
desc = "A console meant for calling and sending a transit ferry. It seems iced-over and non-functional.";
dir = 4;
icon_screen = null;
- name = "Shuttle Transist Console"
+ name = "Shuttle Transit Console"
},
/turf/open/floor/iron/dark/snowdin,
/area/awaymission/snowdin/outside)
@@ -5830,7 +5825,7 @@
desc = "A console meant for calling and sending a transit ferry. It seems iced-over and non-functional.";
dir = 1;
icon_screen = null;
- name = "Shuttle Transist Console"
+ name = "Shuttle Transit Console"
},
/turf/open/floor/mineral/titanium/blue,
/area/awaymission/snowdin/post/broken_shuttle)
@@ -25007,7 +25002,7 @@ Kd
ex
fJ
gA
-ht
+hq
hW
iH
jz
diff --git a/_maps/deathmatch/lattice_battles.dmm b/_maps/deathmatch/lattice_battles.dmm
new file mode 100644
index 0000000000000..eab56ca3064a0
--- /dev/null
+++ b/_maps/deathmatch/lattice_battles.dmm
@@ -0,0 +1,994 @@
+//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE
+"bm" = (
+/obj/structure/lattice/catwalk,
+/obj/structure/closet/crate/large/hats,
+/turf/open/chasm,
+/area/deathmatch/fullbright)
+"bz" = (
+/obj/structure/railing/unbreakable{
+ dir = 1
+ },
+/obj/item/clothing/head/cone,
+/obj/effect/playeronly_barrier,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch/fullbright)
+"cN" = (
+/obj/structure/railing/unbreakable{
+ dir = 8
+ },
+/obj/effect/playeronly_barrier,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch/fullbright)
+"df" = (
+/obj/structure/lattice/catwalk,
+/obj/effect/decal/cleanable/dirt/dust,
+/turf/open/chasm,
+/area/deathmatch/fullbright)
+"dM" = (
+/turf/open/chasm,
+/area/deathmatch/fullbright)
+"eK" = (
+/obj/structure/lattice/catwalk,
+/obj/effect/landmark/deathmatch_player_spawn,
+/obj/effect/decal/cleanable/dirt/dust,
+/turf/open/chasm,
+/area/deathmatch/fullbright)
+"gz" = (
+/obj/structure/flora/rock/pile/style_random,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch/fullbright)
+"gN" = (
+/turf/closed/mineral/random,
+/area/deathmatch/fullbright)
+"gW" = (
+/obj/structure/railing/unbreakable{
+ dir = 1
+ },
+/obj/structure/flora/lunar_plant/style_1,
+/obj/effect/playeronly_barrier,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch/fullbright)
+"ho" = (
+/obj/structure/flora/lunar_plant/style_1,
+/obj/effect/playeronly_barrier,
+/obj/structure/railing/unbreakable{
+ dir = 6
+ },
+/turf/open/misc/asteroid/moon,
+/area/deathmatch/fullbright)
+"hH" = (
+/obj/structure/railing/unbreakable{
+ dir = 5
+ },
+/obj/structure/flora/rock/pile/style_random,
+/obj/structure/flora/lunar_plant/style_3,
+/obj/effect/playeronly_barrier,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch/fullbright)
+"jb" = (
+/obj/structure/flora/rock/style_random,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch/fullbright)
+"lO" = (
+/obj/structure/railing/unbreakable{
+ dir = 9
+ },
+/obj/structure/flora/rock/pile/style_random,
+/obj/structure/flora/lunar_plant/style_3,
+/obj/effect/playeronly_barrier,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch/fullbright)
+"rE" = (
+/obj/structure/flora/rock/pile/style_random,
+/turf/closed/mineral/random,
+/area/deathmatch/fullbright)
+"sl" = (
+/mob/living/basic/spider/giant/hunter/away_caves,
+/obj/effect/decal/cleanable/cobweb/cobweb2,
+/obj/structure/spider/stickyweb,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch/fullbright)
+"sQ" = (
+/obj/structure/flora/lunar_plant/style_2,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch/fullbright)
+"tw" = (
+/obj/structure/railing/unbreakable{
+ dir = 4
+ },
+/obj/effect/playeronly_barrier,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch/fullbright)
+"tL" = (
+/obj/structure/railing/unbreakable,
+/obj/effect/playeronly_barrier,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch/fullbright)
+"uJ" = (
+/obj/structure/railing/unbreakable{
+ dir = 4
+ },
+/obj/item/clothing/head/cone,
+/obj/effect/playeronly_barrier,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch/fullbright)
+"uO" = (
+/obj/structure/lattice/catwalk,
+/obj/structure/closet/crate/critter,
+/mob/living/basic/mothroach,
+/mob/living/basic/mothroach,
+/mob/living/basic/mothroach,
+/turf/open/chasm,
+/area/deathmatch/fullbright)
+"vk" = (
+/obj/structure/lattice/catwalk,
+/turf/open/chasm,
+/area/deathmatch/fullbright)
+"vr" = (
+/obj/structure/flora/lunar_plant/style_2,
+/obj/structure/spider/stickyweb/very_sticky,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch/fullbright)
+"wb" = (
+/obj/structure/lattice/catwalk,
+/obj/effect/landmark/deathmatch_player_spawn,
+/turf/open/chasm,
+/area/deathmatch/fullbright)
+"yB" = (
+/obj/structure/railing/unbreakable{
+ dir = 8
+ },
+/obj/structure/flora/lunar_plant/style_1,
+/obj/effect/playeronly_barrier,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch/fullbright)
+"AS" = (
+/mob/living/basic/pet/cat/space,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch/fullbright)
+"BL" = (
+/obj/structure/railing/unbreakable{
+ dir = 1
+ },
+/obj/effect/playeronly_barrier,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch/fullbright)
+"Cf" = (
+/obj/structure/flora/rock/pile/style_random,
+/obj/structure/flora/lunar_plant/style_3,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch/fullbright)
+"CI" = (
+/mob/living/basic/pet/dog/corgi/puppy/void,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch/fullbright)
+"CP" = (
+/obj/structure/lattice/catwalk,
+/obj/item/clothing/head/cone,
+/turf/open/chasm,
+/area/deathmatch/fullbright)
+"Dk" = (
+/mob/living/basic/wumborian_fugu,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch/fullbright)
+"He" = (
+/turf/open/misc/asteroid/moon,
+/area/deathmatch/fullbright)
+"Ia" = (
+/obj/machinery/power/floodlight,
+/obj/structure/lattice/catwalk,
+/turf/open/chasm,
+/area/deathmatch/fullbright)
+"IT" = (
+/obj/structure/lattice/catwalk,
+/obj/effect/landmark/deathmatch_player_spawn,
+/obj/effect/decal/cleanable/rubble,
+/turf/open/chasm,
+/area/deathmatch/fullbright)
+"JE" = (
+/obj/structure/railing/unbreakable{
+ dir = 10
+ },
+/obj/structure/flora/lunar_plant/style_1,
+/obj/effect/playeronly_barrier,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch/fullbright)
+"KO" = (
+/obj/structure/closet/crate/cardboard,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch/fullbright)
+"LN" = (
+/obj/structure/railing/corner,
+/obj/effect/playeronly_barrier,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch/fullbright)
+"MF" = (
+/obj/structure/lattice,
+/turf/open/chasm,
+/area/deathmatch/fullbright)
+"MZ" = (
+/obj/item/clothing/head/cone,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch/fullbright)
+"Nf" = (
+/obj/effect/landmark/deathmatch_player_spawn,
+/obj/structure/lattice,
+/turf/open/chasm,
+/area/deathmatch/fullbright)
+"NA" = (
+/obj/structure/flora/lunar_plant/style_2,
+/obj/effect/playeronly_barrier,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch/fullbright)
+"NG" = (
+/obj/structure/lattice/catwalk,
+/obj/effect/decal/cleanable/dirt/dust,
+/obj/structure/closet/crate/cardboard,
+/obj/item/statuebust,
+/turf/open/chasm,
+/area/deathmatch/fullbright)
+"NI" = (
+/obj/structure/lattice/catwalk,
+/obj/effect/decal/cleanable/rubble,
+/turf/open/chasm,
+/area/deathmatch/fullbright)
+"NY" = (
+/obj/effect/playeronly_barrier,
+/obj/structure/railing/unbreakable,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch/fullbright)
+"OF" = (
+/obj/machinery/power/port_gen/pacman/pre_loaded,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch/fullbright)
+"St" = (
+/mob/living/basic/spider/giant/nurse/away_caves,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch/fullbright)
+"Sv" = (
+/obj/structure/lattice/catwalk,
+/obj/effect/decal/cleanable/dirt/dust,
+/obj/effect/decal/cleanable/rubble,
+/turf/open/chasm,
+/area/deathmatch/fullbright)
+"SL" = (
+/obj/structure/flora/rock/pile/style_random,
+/obj/structure/flora/lunar_plant/style_3,
+/obj/effect/playeronly_barrier,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch/fullbright)
+"Uy" = (
+/obj/item/clothing/head/cone,
+/obj/effect/playeronly_barrier,
+/obj/structure/railing/corner/unbreakable{
+ dir = 1
+ },
+/turf/open/misc/asteroid/moon,
+/area/deathmatch/fullbright)
+"UU" = (
+/obj/structure/railing{
+ dir = 9
+ },
+/obj/structure/flora/rock/style_random,
+/obj/effect/playeronly_barrier,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch/fullbright)
+"Xf" = (
+/obj/structure/flora/rock/pile/style_random,
+/obj/structure/spider/stickyweb,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch/fullbright)
+"Xk" = (
+/obj/structure/lattice/catwalk,
+/obj/machinery/power/floodlight,
+/turf/open/chasm,
+/area/deathmatch/fullbright)
+"Xo" = (
+/obj/structure/flora/rock/style_random,
+/obj/effect/playeronly_barrier,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch/fullbright)
+"Yu" = (
+/obj/structure/flora/rock/pile/style_random,
+/obj/structure/railing/unbreakable{
+ dir = 6
+ },
+/obj/structure/flora/lunar_plant/style_3,
+/obj/effect/playeronly_barrier,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch/fullbright)
+"YH" = (
+/obj/effect/playeronly_barrier,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch/fullbright)
+"YV" = (
+/obj/structure/lattice/catwalk,
+/obj/item/clothing/head/cone,
+/obj/effect/decal/cleanable/rubble,
+/turf/open/chasm,
+/area/deathmatch/fullbright)
+"Zp" = (
+/obj/effect/decal/cleanable/garbage,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch/fullbright)
+"ZH" = (
+/obj/structure/flora/rock/pile/style_random,
+/mob/living/basic/cow/moonicorn,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch/fullbright)
+
+(1,1,1) = {"
+rE
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+"}
+(2,1,1) = {"
+gN
+gN
+He
+He
+jb
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+"}
+(3,1,1) = {"
+gN
+He
+He
+Dk
+He
+KO
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+"}
+(4,1,1) = {"
+gN
+jb
+Cf
+He
+LN
+tw
+uJ
+tw
+tw
+Yu
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+"}
+(5,1,1) = {"
+gN
+gN
+OF
+Zp
+NY
+dM
+MF
+MF
+MF
+MF
+MF
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+MF
+gN
+gN
+gN
+gN
+gN
+"}
+(6,1,1) = {"
+gN
+gN
+gN
+MZ
+ho
+vk
+MF
+vk
+vk
+MF
+MF
+MF
+vk
+df
+vk
+df
+vk
+MF
+dM
+dM
+lO
+gN
+gN
+gN
+gN
+"}
+(7,1,1) = {"
+gN
+gN
+gN
+gN
+gN
+MF
+MF
+wb
+vk
+vk
+MF
+vk
+wb
+vk
+vk
+vk
+vk
+wb
+MF
+dM
+bz
+gN
+gN
+gN
+gN
+"}
+(8,1,1) = {"
+gN
+gN
+gN
+gN
+JE
+MF
+vk
+vk
+vk
+vk
+vk
+NI
+vk
+vk
+vk
+vk
+MF
+vk
+MF
+MF
+BL
+sQ
+gN
+gN
+gN
+"}
+(9,1,1) = {"
+gN
+gN
+sQ
+YH
+tL
+MF
+vk
+vk
+vk
+CP
+vk
+vk
+vk
+vk
+vk
+CP
+MF
+vk
+vk
+MF
+BL
+ZH
+gN
+gN
+gN
+"}
+(10,1,1) = {"
+gN
+gN
+gN
+AS
+tL
+MF
+vk
+MF
+MF
+vk
+df
+Sv
+vk
+MF
+vk
+df
+MF
+vk
+vk
+MF
+gW
+jb
+gN
+gN
+gN
+"}
+(11,1,1) = {"
+gN
+gN
+gN
+CI
+tL
+MF
+vk
+df
+MF
+MF
+vk
+vk
+MF
+MF
+vk
+df
+vk
+vk
+df
+vk
+hH
+gN
+gN
+gN
+gN
+"}
+(12,1,1) = {"
+gN
+gN
+gN
+jb
+tL
+MF
+vk
+vk
+vk
+vk
+vk
+vk
+vk
+vk
+vk
+vk
+vk
+vk
+df
+NG
+gN
+gN
+gN
+gN
+gN
+"}
+(13,1,1) = {"
+gN
+gN
+gN
+gN
+Yu
+MF
+MF
+eK
+vk
+vk
+vk
+vk
+wb
+CP
+vk
+vk
+vk
+wb
+vk
+Xk
+gN
+gN
+gN
+gN
+gN
+"}
+(14,1,1) = {"
+gN
+gN
+gN
+gN
+gN
+Ia
+MF
+vk
+vk
+vk
+vk
+vk
+vk
+vk
+vk
+NI
+vk
+vk
+vk
+gN
+gN
+gN
+gN
+gN
+gN
+"}
+(15,1,1) = {"
+gN
+gN
+gN
+gN
+gN
+gN
+bm
+df
+vk
+vk
+vk
+MF
+MF
+vk
+vk
+vk
+MF
+MF
+vk
+gN
+gN
+gN
+gN
+gN
+gN
+"}
+(16,1,1) = {"
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+MF
+MF
+vk
+vk
+MF
+vk
+vk
+vk
+df
+MF
+vk
+vk
+gN
+gN
+gN
+gN
+gN
+gN
+"}
+(17,1,1) = {"
+gN
+gN
+gN
+gN
+gN
+gN
+MF
+MF
+vk
+vk
+NI
+vk
+vk
+vk
+vk
+CP
+vk
+vk
+vk
+gN
+gN
+gN
+gN
+gN
+gN
+"}
+(18,1,1) = {"
+gN
+gN
+gN
+gN
+gN
+MF
+MF
+MF
+vk
+vk
+YV
+vk
+MF
+MF
+vk
+vk
+vk
+vk
+df
+gN
+gN
+gN
+gN
+gN
+gN
+"}
+(19,1,1) = {"
+gN
+gN
+gN
+gN
+SL
+dM
+MF
+Nf
+vk
+vk
+vk
+MF
+Nf
+MF
+MF
+vk
+vk
+IT
+vk
+uO
+gN
+gN
+gN
+gN
+gN
+"}
+(20,1,1) = {"
+gN
+gN
+gN
+gN
+dM
+dM
+dM
+MF
+MF
+vk
+MF
+MF
+MF
+MF
+MF
+MF
+vk
+vk
+MF
+MF
+UU
+gN
+gN
+gN
+gN
+"}
+(21,1,1) = {"
+gN
+gN
+gN
+SL
+dM
+dM
+dM
+dM
+uO
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+vk
+MF
+dM
+dM
+BL
+St
+Xf
+gN
+gN
+"}
+(22,1,1) = {"
+gN
+gN
+gN
+jb
+NA
+dM
+SL
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+lO
+yB
+cN
+Uy
+vr
+gN
+gN
+gN
+"}
+(23,1,1) = {"
+gN
+gN
+gN
+gN
+gz
+Xo
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+sl
+gz
+gN
+gN
+gN
+gN
+gN
+"}
+(24,1,1) = {"
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+"}
+(25,1,1) = {"
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+gN
+"}
diff --git a/_maps/deathmatch/ragin_mages.dmm b/_maps/deathmatch/ragin_mages.dmm
index 3dcdb966d1147..1a3d307181d08 100644
--- a/_maps/deathmatch/ragin_mages.dmm
+++ b/_maps/deathmatch/ragin_mages.dmm
@@ -8,7 +8,7 @@
dir = 4
},
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"aT" = (
/obj/item/cardboard_cutout/adaptive{
pixel_y = 14;
@@ -17,7 +17,7 @@
/obj/effect/decal/cleanable/cobweb,
/obj/effect/decal/cleanable/dirt/dust,
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"bb" = (
/obj/structure/chair/wood/wings{
dir = 8
@@ -28,15 +28,15 @@
set_luminosity = 4
},
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"bg" = (
/obj/effect/spawner/random/entertainment/arcade,
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"bv" = (
/obj/machinery/power/shuttle_engine/propulsion,
/turf/open/floor/plating/airless,
-/area/deathmatch/teleport)
+/area/deathmatch)
"co" = (
/obj/structure/table/reinforced,
/obj/item/paper_bin/carbon{
@@ -44,7 +44,7 @@
pixel_x = 7
},
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"ct" = (
/obj/structure/flora/bush/grassy/style_random,
/mob/living/basic/pet/gondola{
@@ -52,24 +52,24 @@
faction = list("gondola", "Wizard")
},
/turf/open/floor/grass,
-/area/deathmatch/teleport)
+/area/deathmatch)
"cU" = (
/obj/structure/chair/wood/wings{
dir = 1
},
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"dj" = (
/obj/machinery/door/airlock/wood,
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"ds" = (
/turf/open/floor/carpet/purple,
-/area/deathmatch/teleport)
+/area/deathmatch)
"ez" = (
/obj/structure/closet/crate,
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"fH" = (
/obj/effect/turf_decal/tile/bar/opposingcorners,
/obj/machinery/griddle,
@@ -82,19 +82,19 @@
pixel_x = 9
},
/turf/open/floor/iron,
-/area/deathmatch/teleport)
+/area/deathmatch)
"fI" = (
/turf/open/lava,
-/area/deathmatch/teleport)
+/area/deathmatch)
"gn" = (
/obj/effect/spawner/structure/window/reinforced,
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"gr" = (
/obj/effect/turf_decal/tile/bar/opposingcorners,
/obj/structure/chair/wood,
/turf/open/floor/iron,
-/area/deathmatch/teleport)
+/area/deathmatch)
"hg" = (
/obj/structure/railing/corner/end/flip{
dir = 8
@@ -104,14 +104,14 @@
dir = 8
},
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"hk" = (
/obj/item/kirbyplants/organic/plant10{
pixel_y = 21;
pixel_x = -7
},
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"hK" = (
/obj/effect/decal/cleanable/dirt/dust,
/obj/effect/light_emitter{
@@ -120,20 +120,20 @@
set_luminosity = 4
},
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"ig" = (
/obj/structure/table/wood,
/obj/item/stack/medical/bruise_pack{
pixel_x = -12
},
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"iz" = (
/obj/structure/chair/comfy/brown{
dir = 1
},
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"iL" = (
/obj/effect/light_emitter{
set_cap = 2;
@@ -141,7 +141,7 @@
set_luminosity = 4
},
/turf/open/floor/carpet/red,
-/area/deathmatch/teleport)
+/area/deathmatch)
"iQ" = (
/obj/structure/table,
/obj/structure/bedsheetbin{
@@ -149,42 +149,42 @@
pixel_x = 3
},
/turf/open/floor/plastic,
-/area/deathmatch/teleport)
+/area/deathmatch)
"iZ" = (
/obj/effect/turf_decal/tile/bar/opposingcorners,
/obj/structure/sink/directional/west,
/turf/open/floor/iron,
-/area/deathmatch/teleport)
+/area/deathmatch)
"jb" = (
/obj/machinery/door/airlock/wood,
/obj/structure/railing/corner/end/flip,
/obj/structure/railing/corner/end,
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"jg" = (
/obj/effect/turf_decal/tile/bar/opposingcorners,
/obj/effect/landmark/deathmatch_player_spawn,
/turf/open/floor/iron,
-/area/deathmatch/teleport)
+/area/deathmatch)
"jm" = (
/obj/effect/decal/cleanable/dirt/dust,
/obj/structure/mystery_box/wands,
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"js" = (
/obj/effect/turf_decal/tile/bar/opposingcorners,
/turf/open/floor/iron,
-/area/deathmatch/teleport)
+/area/deathmatch)
"jM" = (
/obj/structure/table/reinforced,
/obj/effect/decal/cleanable/dirt/dust,
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"jV" = (
/obj/effect/turf_decal/tile/bar/opposingcorners,
/obj/machinery/door/airlock/wood,
/turf/open/floor/iron,
-/area/deathmatch/teleport)
+/area/deathmatch)
"kl" = (
/obj/structure/flora/bush/grassy/style_random,
/obj/machinery/light/floor,
@@ -194,7 +194,7 @@
set_luminosity = 4
},
/turf/open/floor/grass,
-/area/deathmatch/teleport)
+/area/deathmatch)
"li" = (
/obj/structure/table,
/obj/item/extinguisher{
@@ -206,7 +206,7 @@
pixel_x = -6
},
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"lM" = (
/obj/structure/bed{
dir = 1
@@ -220,19 +220,19 @@
set_luminosity = 4
},
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"lO" = (
/obj/structure/closet/crate,
/obj/effect/decal/cleanable/dirt/dust,
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"mu" = (
/obj/effect/turf_decal/stripes,
/obj/structure/railing{
dir = 4
},
/turf/open/floor/iron,
-/area/deathmatch/teleport)
+/area/deathmatch)
"mV" = (
/obj/structure/railing{
dir = 4
@@ -242,40 +242,40 @@
},
/obj/structure/mystery_box/tdome,
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"nk" = (
/obj/item/gun/magic/wand/death,
/obj/structure/window/reinforced/plasma/spawner/directional/east,
/obj/structure/window/reinforced/plasma/spawner/directional/north,
/obj/structure/window/reinforced/plasma/spawner/directional/west,
/turf/open/floor/grass,
-/area/deathmatch/teleport)
+/area/deathmatch)
"nx" = (
/obj/effect/landmark/deathmatch_player_spawn,
/turf/open/floor/carpet/red,
-/area/deathmatch/teleport)
+/area/deathmatch)
"nQ" = (
/obj/machinery/door/airlock/wood,
/turf/open/floor/plastic,
-/area/deathmatch/teleport)
+/area/deathmatch)
"on" = (
/obj/structure/table/wood,
/turf/open/floor/carpet/red,
-/area/deathmatch/teleport)
+/area/deathmatch)
"oP" = (
/obj/structure/destructible/cult/item_dispenser/archives/library,
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"pe" = (
/obj/item/kirbyplants/organic/plant10{
pixel_y = 21;
pixel_x = -7
},
/turf/open/floor/carpet/red,
-/area/deathmatch/teleport)
+/area/deathmatch)
"ph" = (
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"pv" = (
/obj/effect/light_emitter{
set_cap = 2;
@@ -283,18 +283,18 @@
set_luminosity = 4
},
/turf/open/floor/iron,
-/area/deathmatch/teleport)
+/area/deathmatch)
"pL" = (
/obj/effect/turf_decal/stripes{
dir = 1
},
/obj/structure/mystery_box/wands,
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"pV" = (
/obj/structure/flora/bush/flowers_br/style_random,
/turf/open/floor/grass,
-/area/deathmatch/teleport)
+/area/deathmatch)
"qx" = (
/obj/effect/light_emitter{
set_cap = 2;
@@ -302,15 +302,15 @@
set_luminosity = 4
},
/turf/open/floor/carpet/purple,
-/area/deathmatch/teleport)
+/area/deathmatch)
"qY" = (
/obj/structure/closet/crate/bin,
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"rj" = (
/obj/machinery/door/window/right/directional/east,
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"rD" = (
/obj/structure/railing{
dir = 4
@@ -319,11 +319,11 @@
dir = 8
},
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"sf" = (
/obj/structure/mirror/directional/east,
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"tL" = (
/obj/structure/flora/bush/fullgrass/style_random,
/mob/living/simple_animal/hostile/ooze/gelatinous{
@@ -331,7 +331,7 @@
faction = list("slime", "Wizard")
},
/turf/open/floor/grass,
-/area/deathmatch/teleport)
+/area/deathmatch)
"ue" = (
/obj/effect/turf_decal/tile/bar/opposingcorners,
/obj/item/food/burger/yellow{
@@ -347,14 +347,14 @@
},
/obj/structure/table/reinforced,
/turf/open/floor/iron,
-/area/deathmatch/teleport)
+/area/deathmatch)
"ui" = (
/obj/effect/turf_decal/stripes,
/turf/open/floor/iron,
-/area/deathmatch/teleport)
+/area/deathmatch)
"uz" = (
/turf/open/floor/iron,
-/area/deathmatch/teleport)
+/area/deathmatch)
"uR" = (
/obj/item/clothing/shoes/sandal/magic{
pixel_y = 16
@@ -365,82 +365,82 @@
set_luminosity = 4
},
/turf/open/floor/plastic,
-/area/deathmatch/teleport)
+/area/deathmatch)
"vh" = (
/obj/structure/mystery_box/wands,
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"vv" = (
/obj/vehicle/ridden/scooter/skateboard{
dir = 4
},
/obj/effect/decal/cleanable/dirt/dust,
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"vR" = (
/obj/structure/bookcase/random,
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"wd" = (
/obj/effect/turf_decal/tile/bar/opposingcorners,
/obj/structure/mystery_box/wands,
/turf/open/floor/iron,
-/area/deathmatch/teleport)
+/area/deathmatch)
"wl" = (
/obj/item/kirbyplants/organic/plant10{
pixel_y = 1;
pixel_x = -6
},
/turf/open/floor/carpet/purple,
-/area/deathmatch/teleport)
+/area/deathmatch)
"wL" = (
/obj/effect/turf_decal/tile/bar/opposingcorners,
/obj/machinery/gibber/autogibber,
/turf/open/floor/iron,
-/area/deathmatch/teleport)
+/area/deathmatch)
"xk" = (
/obj/structure/sink/directional/south,
/obj/structure/mirror/directional/north{
pixel_y = 36
},
/turf/open/floor/plastic,
-/area/deathmatch/teleport)
+/area/deathmatch)
"xs" = (
/obj/structure/flora/bush/grassy/style_random,
/turf/open/floor/grass,
-/area/deathmatch/teleport)
+/area/deathmatch)
"yA" = (
/obj/structure/chair/wood/wings,
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"zN" = (
/obj/structure/mystery_box/wands,
/obj/structure/sign/poster/contraband/the_big_gas_giant_truth/directional/north,
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"zO" = (
/obj/structure/closet,
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"Au" = (
/obj/structure/railing{
dir = 4
},
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"AD" = (
/obj/structure/sign/departments/restroom/directional/west,
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"Bm" = (
/obj/effect/landmark/deathmatch_player_spawn,
/turf/open/floor/plastic,
-/area/deathmatch/teleport)
+/area/deathmatch)
"Cb" = (
/obj/effect/turf_decal/tile/bar/opposingcorners,
/obj/structure/table/wood,
/turf/open/floor/iron,
-/area/deathmatch/teleport)
+/area/deathmatch)
"Cj" = (
/obj/structure/table,
/obj/item/clothing/ears/earmuffs{
@@ -456,10 +456,10 @@
pixel_y = -10
},
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"Cq" = (
/turf/open/floor/carpet/red,
-/area/deathmatch/teleport)
+/area/deathmatch)
"CM" = (
/obj/structure/railing/corner,
/obj/structure/railing/corner{
@@ -477,7 +477,7 @@
set_luminosity = 4
},
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"DK" = (
/obj/structure/railing{
dir = 8
@@ -489,11 +489,11 @@
dir = 4
},
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"DW" = (
/obj/machinery/computer,
/turf/open/floor/carpet/red,
-/area/deathmatch/teleport)
+/area/deathmatch)
"Eh" = (
/obj/effect/light_emitter{
set_cap = 2;
@@ -501,64 +501,64 @@
set_luminosity = 4
},
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"Fb" = (
/obj/effect/turf_decal/stripes{
dir = 1
},
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"Fm" = (
/obj/structure/chair/comfy/black{
dir = 1
},
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"Fv" = (
/obj/structure/chair/wood/wings{
dir = 4
},
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"Fx" = (
/obj/item/target,
/obj/structure/sign/flag/nanotrasen/directional/north,
/turf/open/floor/iron,
-/area/deathmatch/teleport)
+/area/deathmatch)
"FL" = (
/turf/open/floor/plastic,
-/area/deathmatch/teleport)
+/area/deathmatch)
"Ge" = (
/obj/item/flashlight/flare{
pixel_x = -5;
pixel_y = -12
},
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"Gv" = (
/obj/item/kirbyplants/organic/plant10{
pixel_y = 2;
pixel_x = 5
},
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"GC" = (
/obj/effect/spawner/structure/window,
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"GZ" = (
/obj/structure/curtain,
/obj/machinery/shower/directional/north,
/obj/item/soap/syndie,
/turf/open/floor/noslip,
-/area/deathmatch/teleport)
+/area/deathmatch)
"Hf" = (
/obj/item/kirbyplants/organic/plant10{
pixel_y = 1;
pixel_x = -6
},
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"Hs" = (
/turf/template_noop,
/area/template_noop)
@@ -572,17 +572,17 @@
pixel_y = 4
},
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"HP" = (
/obj/structure/chair/comfy/black{
dir = 1
},
/turf/open/floor/carpet/red,
-/area/deathmatch/teleport)
+/area/deathmatch)
"HS" = (
/obj/structure/table/wood/fancy,
/turf/open/floor/plastic,
-/area/deathmatch/teleport)
+/area/deathmatch)
"IE" = (
/obj/structure/table/wood,
/obj/item/clothing/suit/wizrobe/black{
@@ -594,40 +594,40 @@
pixel_x = 6
},
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"IM" = (
/obj/item/kirbyplants/organic/plant10{
pixel_y = 2;
pixel_x = 5
},
/turf/open/floor/carpet/purple,
-/area/deathmatch/teleport)
+/area/deathmatch)
"Jm" = (
/turf/closed/wall/mineral/wood,
-/area/deathmatch/teleport)
+/area/deathmatch)
"Jo" = (
/obj/structure/toilet{
dir = 4
},
/turf/open/floor/plastic,
-/area/deathmatch/teleport)
+/area/deathmatch)
"Kr" = (
/obj/effect/landmark/deathmatch_player_spawn,
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"KW" = (
/obj/effect/decal/cleanable/dirt/dust,
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"Le" = (
/obj/structure/filingcabinet,
/obj/effect/decal/cleanable/dirt/dust,
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"Mg" = (
/obj/machinery/computer,
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"Nl" = (
/obj/machinery/power/shuttle_engine/heater{
resistance_flags = 3
@@ -636,21 +636,21 @@
resistance_flags = 3
},
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"Nm" = (
/obj/item/kirbyplants/organic/plant10{
pixel_y = 21;
pixel_x = 6
},
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"Nt" = (
/obj/item/target{
pixel_y = 11
},
/obj/effect/turf_decal/stripes,
/turf/open/floor/iron,
-/area/deathmatch/teleport)
+/area/deathmatch)
"NW" = (
/obj/structure/railing{
dir = 4
@@ -659,30 +659,30 @@
dir = 1
},
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"Ok" = (
/obj/machinery/vending/cigarette,
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"OD" = (
/obj/structure/filingcabinet,
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"OK" = (
/obj/item/kirbyplants/organic/plant10{
pixel_y = 21;
pixel_x = 6
},
/turf/open/floor/carpet/red,
-/area/deathmatch/teleport)
+/area/deathmatch)
"PD" = (
/obj/structure/table/wood,
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"Qj" = (
/obj/structure/dresser,
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"QH" = (
/obj/structure/table,
/obj/item/clothing/head/wizard{
@@ -690,19 +690,19 @@
pixel_x = 4
},
/turf/open/floor/plastic,
-/area/deathmatch/teleport)
+/area/deathmatch)
"QT" = (
/obj/structure/mystery_box/wands,
/turf/open/floor/plastic,
-/area/deathmatch/teleport)
+/area/deathmatch)
"RB" = (
/obj/machinery/vending/snack,
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"RI" = (
/obj/effect/decal/cleanable/cobweb,
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"RT" = (
/obj/machinery/power/shuttle_engine/heater{
resistance_flags = 3
@@ -711,14 +711,14 @@
resistance_flags = 3
},
/turf/open/lava,
-/area/deathmatch/teleport)
+/area/deathmatch)
"Sa" = (
/turf/open/floor/grass,
-/area/deathmatch/teleport)
+/area/deathmatch)
"SK" = (
/obj/structure/flora/bush/fullgrass/style_random,
/turf/open/floor/grass,
-/area/deathmatch/teleport)
+/area/deathmatch)
"Th" = (
/obj/effect/turf_decal/tile/bar/opposingcorners,
/obj/structure/table/reinforced,
@@ -736,15 +736,15 @@
set_luminosity = 4
},
/turf/open/floor/iron,
-/area/deathmatch/teleport)
+/area/deathmatch)
"Vk" = (
/obj/machinery/door/window/left/directional/east,
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"VM" = (
/obj/structure/table/wood/poker,
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"Wl" = (
/obj/structure/railing{
dir = 4
@@ -755,37 +755,37 @@
set_luminosity = 4
},
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"WX" = (
/obj/machinery/vending/magivend,
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"Xv" = (
/obj/structure/railing,
/obj/structure/railing{
dir = 1
},
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"YP" = (
/obj/structure/closet/crate/coffin,
/obj/effect/decal/cleanable/cobweb/cobweb2,
/obj/effect/decal/cleanable/dirt/dust,
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"YS" = (
/obj/effect/decal/cleanable/cobweb,
/obj/effect/decal/cleanable/dirt/dust,
/turf/open/floor/engine/cult,
-/area/deathmatch/teleport)
+/area/deathmatch)
"Zo" = (
/obj/structure/flora/bush/flowers_pp/style_random,
/turf/open/floor/grass,
-/area/deathmatch/teleport)
+/area/deathmatch)
"ZS" = (
/obj/structure/railing/corner/end/flip,
/turf/open/floor/iron,
-/area/deathmatch/teleport)
+/area/deathmatch)
(1,1,1) = {"
Hs
diff --git a/_maps/deathmatch/ragnarok.dmm b/_maps/deathmatch/ragnarok.dmm
new file mode 100644
index 0000000000000..328055398e71a
--- /dev/null
+++ b/_maps/deathmatch/ragnarok.dmm
@@ -0,0 +1,2160 @@
+//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE
+"aJ" = (
+/obj/item/wallframe/painting/eldritch/beauty,
+/turf/open/floor/plating/heretic_rust,
+/area/deathmatch)
+"aN" = (
+/obj/structure/flora/rock/pile/jungle/style_random,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch)
+"bb" = (
+/obj/structure/flora/coconuts,
+/turf/open/misc/dirt/jungle,
+/area/deathmatch)
+"bj" = (
+/obj/effect/turf_decal/siding/wood/corner,
+/obj/structure/bonfire/prelit,
+/turf/open/floor/wood/large,
+/area/deathmatch)
+"bn" = (
+/turf/closed/wall/mineral/bronze,
+/area/deathmatch)
+"bv" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 4
+ },
+/obj/effect/turf_decal/siding/wood,
+/turf/open/water/jungle,
+/area/deathmatch)
+"bI" = (
+/turf/open/misc/asteroid/moon,
+/area/deathmatch)
+"bO" = (
+/obj/structure/fluff/clockwork/alloy_shards/medium,
+/obj/effect/decal/cleanable/dirt/dust,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch)
+"bU" = (
+/turf/open/indestructible/plating,
+/area/deathmatch)
+"cb" = (
+/obj/effect/decal/cleanable/blood,
+/obj/effect/turf_decal/weather/dirt{
+ dir = 6
+ },
+/turf/open/floor/cult,
+/area/deathmatch)
+"cr" = (
+/obj/effect/decal/cleanable/blood/gibs,
+/turf/open/floor/cult,
+/area/deathmatch)
+"cs" = (
+/obj/structure/flora/grass/jungle/b/style_random,
+/obj/effect/turf_decal/weather/dirt{
+ dir = 5
+ },
+/turf/open/misc/dirt/jungle/wasteland,
+/area/deathmatch)
+"cH" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 8
+ },
+/turf/open/floor/cult,
+/area/deathmatch)
+"cR" = (
+/obj/effect/landmark/deathmatch_player_spawn,
+/obj/effect/turf_decal/weather/dirt,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch)
+"cT" = (
+/obj/effect/decal/cleanable/dirt,
+/turf/open/floor/wood/tile,
+/area/deathmatch)
+"dv" = (
+/obj/structure/fluff/clockwork/clockgolem_remains,
+/obj/effect/decal/cleanable/dirt/dust,
+/turf/open/floor/bronze,
+/area/deathmatch)
+"dI" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 6
+ },
+/turf/open/misc/dirt/jungle/wasteland,
+/area/deathmatch)
+"dS" = (
+/obj/structure/flora/rock/pile/jungle/style_random,
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"eB" = (
+/obj/effect/spawner/random/decoration/glowstick/on,
+/turf/open/misc/dirt/jungle,
+/area/deathmatch)
+"eG" = (
+/obj/effect/turf_decal/siding/wood,
+/obj/structure/flora/grass/jungle/b/style_random,
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"eL" = (
+/obj/effect/decal/remains/human,
+/turf/open/floor/plating/heretic_rust,
+/area/deathmatch)
+"eU" = (
+/obj/effect/decal/cleanable/dirt/dust,
+/obj/effect/decal/remains/human,
+/turf/open/floor/plating/heretic_rust,
+/area/deathmatch)
+"fc" = (
+/obj/effect/rune/wall,
+/obj/effect/turf_decal/weather/dirt{
+ dir = 10
+ },
+/obj/effect/turf_decal/weather/dirt{
+ dir = 1
+ },
+/turf/open/floor/cult,
+/area/deathmatch)
+"fl" = (
+/obj/structure/fake_stairs/wood,
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"ft" = (
+/obj/effect/turf_decal/siding/wood/end,
+/obj/effect/turf_decal/siding/wood{
+ dir = 1
+ },
+/turf/open/water/jungle,
+/area/deathmatch)
+"fO" = (
+/obj/effect/decal/cleanable/dirt/dust,
+/obj/effect/turf_decal/weather/dirt{
+ dir = 4
+ },
+/turf/open/floor/plating/heretic_rust,
+/area/deathmatch)
+"fW" = (
+/obj/structure/flora/rock/pile/style_random,
+/obj/structure/fluff/clockwork/alloy_shards/medium,
+/obj/effect/decal/cleanable/dirt/dust,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch)
+"gi" = (
+/obj/effect/turf_decal/siding/wood,
+/obj/structure/flora/bush/jungle/a/style_random,
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"gx" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 1
+ },
+/obj/structure/flora/coconuts,
+/turf/open/misc/dirt/jungle,
+/area/deathmatch)
+"gz" = (
+/obj/effect/decal/cleanable/dirt,
+/turf/open/floor/cult,
+/area/deathmatch)
+"gJ" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 1
+ },
+/obj/effect/turf_decal/siding/wood{
+ dir = 4
+ },
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"hg" = (
+/obj/effect/visible_heretic_influence,
+/obj/effect/turf_decal/weather/dirt{
+ dir = 4
+ },
+/turf/open/floor/plating/heretic_rust,
+/area/deathmatch)
+"hr" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 4
+ },
+/obj/structure/flora/grass/jungle/b/style_random,
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"hw" = (
+/obj/structure/flora/bush/jungle/b/style_random,
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"hV" = (
+/turf/open/chasm/jungle,
+/area/deathmatch)
+"hY" = (
+/mob/living/carbon/human/species/monkey,
+/obj/item/flashlight/flare/torch,
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"ih" = (
+/obj/effect/turf_decal/siding/wood/corner{
+ dir = 8
+ },
+/obj/structure/flora/bush/jungle/b/style_random,
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"ij" = (
+/obj/structure/flora/rock/pile/style_random,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch)
+"iq" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 4
+ },
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"iJ" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 9
+ },
+/turf/open/water/jungle,
+/area/deathmatch)
+"iO" = (
+/obj/structure/flora/bush/jungle/b/style_random,
+/obj/effect/decal/cleanable/cobweb/cobweb2,
+/turf/open/misc/dirt/jungle/dark,
+/area/deathmatch)
+"jb" = (
+/obj/effect/turf_decal/siding/wood/corner,
+/obj/effect/turf_decal/siding/wood{
+ dir = 1
+ },
+/obj/effect/turf_decal/weather/dirt{
+ dir = 6
+ },
+/turf/open/water/jungle,
+/area/deathmatch)
+"jv" = (
+/obj/structure/flora/grass/jungle/b/style_random,
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"jC" = (
+/obj/item/food/grown/banana,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch)
+"jI" = (
+/obj/effect/rune/wall,
+/obj/effect/turf_decal/weather/dirt{
+ dir = 6
+ },
+/turf/open/floor/cult,
+/area/deathmatch)
+"jL" = (
+/obj/structure/flora/rock/style_random,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch)
+"jP" = (
+/obj/effect/decal/cleanable/blood/innards,
+/turf/open/floor/cult,
+/area/deathmatch)
+"kc" = (
+/obj/structure/flora/grass/jungle/b/style_random,
+/obj/effect/turf_decal/weather/dirt{
+ dir = 4
+ },
+/turf/open/misc/dirt/jungle/wasteland,
+/area/deathmatch)
+"ku" = (
+/obj/structure/flora/tree/jungle/style_random,
+/obj/item/food/grown/banana/bunch,
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"lr" = (
+/obj/effect/turf_decal/siding/wood,
+/obj/structure/bonfire/prelit,
+/turf/open/floor/wood/large,
+/area/deathmatch)
+"lx" = (
+/obj/effect/turf_decal/siding/wood,
+/turf/open/misc/dirt/jungle,
+/area/deathmatch)
+"lC" = (
+/obj/effect/decal/cleanable/dirt,
+/obj/effect/turf_decal/weather/dirt{
+ dir = 10
+ },
+/turf/open/floor/cult,
+/area/deathmatch)
+"lK" = (
+/obj/structure/chair/wood/wings{
+ dir = 1
+ },
+/obj/effect/landmark/deathmatch_player_spawn,
+/turf/open/floor/wood/tile,
+/area/deathmatch)
+"lR" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 4
+ },
+/turf/open/floor/plating/heretic_rust,
+/area/deathmatch)
+"lX" = (
+/obj/effect/rune/blood_boil,
+/obj/effect/turf_decal/weather/dirt,
+/obj/effect/turf_decal/weather/dirt{
+ dir = 1
+ },
+/turf/open/floor/cult,
+/area/deathmatch)
+"mr" = (
+/obj/effect/decal/cleanable/dirt,
+/obj/effect/decal/cleanable/vomit,
+/turf/open/indestructible/plating,
+/area/deathmatch)
+"mD" = (
+/obj/effect/decal/cleanable/cobweb/cobweb2,
+/obj/effect/turf_decal/weather/dirt{
+ dir = 8
+ },
+/turf/open/floor/cult,
+/area/deathmatch)
+"nO" = (
+/obj/structure/flora/bush/jungle/c/style_random,
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"ou" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 1
+ },
+/obj/effect/turf_decal/weather/dirt{
+ dir = 8
+ },
+/turf/open/water/jungle,
+/area/deathmatch)
+"ox" = (
+/obj/effect/cosmic_rune,
+/turf/open/floor/plating/heretic_rust,
+/area/deathmatch)
+"oB" = (
+/turf/closed/wall/mineral/wood/nonmetal,
+/area/deathmatch)
+"oC" = (
+/obj/structure/flora/grass/jungle/b/style_random,
+/turf/open/misc/dirt/jungle/wasteland,
+/area/deathmatch)
+"oF" = (
+/obj/structure/flora/rock/pile/style_random,
+/obj/effect/decal/cleanable/rubble,
+/obj/effect/turf_decal/weather/dirt,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch)
+"oO" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 6
+ },
+/turf/open/water/jungle,
+/area/deathmatch)
+"pr" = (
+/obj/structure/flora/bush/jungle/a/style_random,
+/obj/effect/decal/cleanable/ants/fire,
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"px" = (
+/obj/effect/decal/cleanable/dirt/dust,
+/obj/effect/decal/cleanable/rubble,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch)
+"pz" = (
+/obj/effect/decal/cleanable/cobweb,
+/obj/effect/decal/cleanable/dirt,
+/obj/item/wallframe/painting/eldritch/vines,
+/turf/open/indestructible/plating,
+/area/deathmatch)
+"pF" = (
+/obj/effect/rune/blood_boil,
+/obj/effect/decal/cleanable/blood/tracks,
+/obj/effect/turf_decal/weather/dirt{
+ dir = 10
+ },
+/obj/effect/turf_decal/weather/dirt{
+ dir = 4
+ },
+/turf/open/floor/cult,
+/area/deathmatch)
+"qa" = (
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"qg" = (
+/turf/open/floor/wood/tile,
+/area/deathmatch)
+"qh" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 10
+ },
+/turf/open/water/jungle,
+/area/deathmatch)
+"qk" = (
+/obj/effect/decal/cleanable/blood/footprints,
+/obj/effect/turf_decal/weather/dirt,
+/obj/item/flashlight/flare/culttorch,
+/turf/open/floor/cult,
+/area/deathmatch)
+"qp" = (
+/obj/effect/turf_decal/siding/wood/corner{
+ dir = 4
+ },
+/obj/structure/flora/tree/jungle/small/style_random,
+/obj/structure/flora/coconuts,
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"qL" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 8
+ },
+/obj/effect/turf_decal/siding/wood/corner,
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"rc" = (
+/obj/structure/fluff/clockwork/alloy_shards,
+/obj/effect/decal/cleanable/dirt/dust,
+/turf/open/floor/bronze/flat,
+/area/deathmatch)
+"rh" = (
+/obj/structure/fluff/clockwork/alloy_shards/medium,
+/obj/effect/decal/cleanable/dirt/dust,
+/obj/effect/decal/cleanable/oil/slippery,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch)
+"rm" = (
+/obj/structure/flora/rock/pile/jungle/large/style_random,
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"rD" = (
+/obj/effect/turf_decal/siding/wood,
+/obj/effect/turf_decal/weather/dirt{
+ dir = 4
+ },
+/turf/open/water/jungle,
+/area/deathmatch)
+"rH" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 4
+ },
+/turf/open/misc/dirt/jungle,
+/area/deathmatch)
+"sa" = (
+/obj/structure/flora/rock/style_random,
+/obj/effect/decal/cleanable/cobweb,
+/obj/effect/decal/cleanable/rubble,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch)
+"sd" = (
+/obj/structure/table/bronze,
+/obj/item/toy/clockwork_watch,
+/obj/effect/decal/cleanable/dirt/dust,
+/turf/open/floor/bronze,
+/area/deathmatch)
+"sC" = (
+/obj/structure/flora/grass/jungle/b/style_random,
+/turf/open/misc/dirt/jungle,
+/area/deathmatch)
+"sE" = (
+/obj/effect/visible_heretic_influence,
+/obj/effect/decal/cleanable/dirt,
+/turf/open/indestructible/plating,
+/area/deathmatch)
+"sF" = (
+/obj/effect/decal/cleanable/blood/footprints,
+/turf/open/floor/cult,
+/area/deathmatch)
+"sJ" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 8
+ },
+/obj/effect/turf_decal/weather/dirt{
+ dir = 4
+ },
+/turf/open/floor/cult,
+/area/deathmatch)
+"tl" = (
+/obj/effect/decal/cleanable/dirt/dust,
+/turf/closed/wall/r_wall/heretic_rust,
+/area/deathmatch)
+"tm" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 4
+ },
+/turf/open/misc/dirt/jungle/wasteland,
+/area/deathmatch)
+"tE" = (
+/obj/effect/rune/malformed{
+ icon_state = "hierophant";
+ color = "#FFFF00"
+ },
+/obj/effect/landmark/deathmatch_player_spawn,
+/turf/open/floor/bronze/filled,
+/area/deathmatch)
+"uT" = (
+/obj/structure/table/bronze,
+/obj/item/clockwork_alloy,
+/obj/item/stack/sheet/bronze/thirty,
+/obj/effect/decal/cleanable/dirt/dust,
+/turf/open/floor/bronze,
+/area/deathmatch)
+"vI" = (
+/obj/structure/flora/tree/jungle/small/style_random,
+/obj/structure/flora/coconuts,
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"vR" = (
+/obj/structure/rack/skeletal,
+/obj/item/clothing/head/helmet/chaplain/cage{
+ pixel_y = 11;
+ pixel_x = -1
+ },
+/obj/effect/decal/cleanable/dirt/dust,
+/turf/open/floor/wood/tile,
+/area/deathmatch)
+"wf" = (
+/obj/structure/rack/skeletal,
+/obj/item/clothing/head/helmet/chaplain{
+ pixel_y = 9
+ },
+/turf/open/floor/wood/tile,
+/area/deathmatch)
+"wv" = (
+/obj/effect/turf_decal/siding/wood,
+/turf/open/floor/wood/large,
+/area/deathmatch)
+"wH" = (
+/obj/effect/turf_decal/siding/wood/corner,
+/turf/open/floor/wood/large,
+/area/deathmatch)
+"wP" = (
+/obj/structure/flora/rock/style_random,
+/obj/effect/turf_decal/weather/dirt{
+ dir = 8
+ },
+/turf/open/misc/asteroid/moon,
+/area/deathmatch)
+"wR" = (
+/obj/structure/flora/rock/pile/jungle/style_random,
+/turf/open/misc/dirt/jungle,
+/area/deathmatch)
+"xc" = (
+/obj/structure/flora/grass/jungle/a/style_random,
+/mob/living/carbon/human/species/monkey,
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"xx" = (
+/obj/effect/decal/cleanable/dirt,
+/obj/item/flashlight/flare/culttorch,
+/turf/open/floor/cult,
+/area/deathmatch)
+"xC" = (
+/obj/effect/rune/wall,
+/obj/effect/turf_decal/weather/dirt,
+/turf/open/floor/cult,
+/area/deathmatch)
+"ye" = (
+/obj/effect/decal/cleanable/blood/tracks,
+/turf/open/floor/cult,
+/area/deathmatch)
+"yv" = (
+/obj/effect/decal/cleanable/dirt,
+/obj/effect/turf_decal/weather/dirt{
+ dir = 6
+ },
+/turf/open/floor/cult,
+/area/deathmatch)
+"yY" = (
+/obj/effect/decal/cleanable/vomit,
+/obj/effect/spawner/random/decoration/glowstick/on,
+/turf/open/floor/plating/heretic_rust,
+/area/deathmatch)
+"zo" = (
+/obj/structure/flora/rock/pile/jungle/style_random,
+/obj/effect/landmark/deathmatch_player_spawn,
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"zX" = (
+/obj/structure/girder/bronze,
+/obj/effect/decal/cleanable/dirt/dust,
+/turf/open/floor/bronze/flat,
+/area/deathmatch)
+"Ab" = (
+/obj/effect/decal/cleanable/blood,
+/obj/effect/turf_decal/weather/dirt{
+ dir = 9
+ },
+/obj/effect/turf_decal/weather/dirt,
+/obj/item/flashlight/flare/culttorch,
+/turf/open/floor/cult,
+/area/deathmatch)
+"An" = (
+/obj/structure/fluff/clockwork/alloy_shards/large,
+/obj/effect/decal/cleanable/cobweb/cobweb2,
+/obj/effect/decal/cleanable/dirt/dust,
+/turf/open/floor/bronze,
+/area/deathmatch)
+"Ar" = (
+/obj/effect/decal/cleanable/blood,
+/obj/effect/turf_decal/weather/dirt{
+ dir = 5
+ },
+/turf/open/floor/cult,
+/area/deathmatch)
+"Av" = (
+/obj/structure/flora/rock/pile/style_random,
+/obj/effect/decal/cleanable/dirt/dust,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch)
+"AE" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 4
+ },
+/turf/open/floor/cult,
+/area/deathmatch)
+"AN" = (
+/obj/structure/sacrificealtar,
+/obj/item/knife/bloodletter{
+ name = "McGuffin";
+ desc = "An occult looking dagger that is cold to the touch. Somehow, the flawless orb on the pommel is made entirely of liquid blood. Honestly pretty disappointing as far as Mcguffins go."
+ },
+/turf/open/floor/wood/tile,
+/area/deathmatch)
+"AO" = (
+/obj/effect/decal/cleanable/ants,
+/turf/closed/wall/heretic_rust,
+/area/deathmatch)
+"Ba" = (
+/obj/structure/destructible/cult/pylon,
+/turf/open/floor/cult,
+/area/deathmatch)
+"Bd" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 6
+ },
+/turf/open/floor/plating/heretic_rust,
+/area/deathmatch)
+"Be" = (
+/obj/effect/decal/cleanable/dirt/dust,
+/turf/open/floor/plating/heretic_rust,
+/area/deathmatch)
+"Bi" = (
+/obj/item/food/grown/banana,
+/turf/open/floor/plating/heretic_rust,
+/area/deathmatch)
+"Bl" = (
+/obj/effect/landmark/deathmatch_player_spawn,
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"Bp" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 1
+ },
+/obj/effect/turf_decal/weather/dirt{
+ dir = 6
+ },
+/turf/open/water/jungle,
+/area/deathmatch)
+"CB" = (
+/obj/structure/destructible/eldritch_crucible,
+/obj/effect/decal/cleanable/dirt,
+/obj/effect/decal/cleanable/vomit,
+/obj/effect/heretic_rune/big,
+/turf/open/indestructible/plating,
+/area/deathmatch)
+"CE" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 4
+ },
+/obj/effect/turf_decal/weather/dirt{
+ dir = 8
+ },
+/turf/open/water/jungle,
+/area/deathmatch)
+"CR" = (
+/mob/living/carbon/human/species/monkey,
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"Dn" = (
+/obj/structure/girder/cult,
+/turf/open/floor/cult,
+/area/deathmatch)
+"Do" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 1
+ },
+/obj/effect/turf_decal/weather/dirt{
+ dir = 9
+ },
+/turf/open/water/jungle,
+/area/deathmatch)
+"Ds" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 8
+ },
+/obj/effect/turf_decal/siding/wood,
+/turf/open/water/jungle,
+/area/deathmatch)
+"Du" = (
+/obj/structure/flora/rock/pile/style_random,
+/obj/effect/turf_decal/weather/dirt{
+ dir = 9
+ },
+/obj/item/flashlight/flare/torch,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch)
+"DA" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 8
+ },
+/obj/effect/turf_decal/weather/dirt{
+ dir = 6
+ },
+/turf/open/water/jungle,
+/area/deathmatch)
+"EF" = (
+/obj/effect/decal/cleanable/dirt,
+/turf/open/indestructible/plating,
+/area/deathmatch)
+"Fj" = (
+/obj/effect/decal/cleanable/dirt/dust,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch)
+"Fn" = (
+/obj/item/food/grown/banana/bunch,
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"FK" = (
+/turf/open/misc/dirt/jungle,
+/area/deathmatch)
+"FO" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 4
+ },
+/obj/effect/turf_decal/siding/wood,
+/turf/open/floor/wood/large,
+/area/deathmatch)
+"FQ" = (
+/obj/effect/decal/cleanable/dirt,
+/obj/effect/decal/cleanable/ants,
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"FS" = (
+/obj/structure/fluff/clockwork/alloy_shards/medium_gearbit,
+/obj/effect/decal/cleanable/cobweb/cobweb2,
+/obj/effect/decal/cleanable/dirt/dust,
+/turf/open/floor/bronze,
+/area/deathmatch)
+"Ga" = (
+/obj/effect/landmark/deathmatch_player_spawn,
+/obj/effect/turf_decal/weather/dirt,
+/turf/open/misc/dirt/jungle/wasteland,
+/area/deathmatch)
+"GD" = (
+/obj/structure/flora/bush/jungle/a/style_random,
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"GE" = (
+/obj/effect/decal/cleanable/blood,
+/obj/effect/decal/cleanable/dirt,
+/obj/effect/turf_decal/weather/dirt{
+ dir = 4
+ },
+/obj/effect/turf_decal/weather/dirt{
+ dir = 6
+ },
+/turf/open/floor/cult,
+/area/deathmatch)
+"GO" = (
+/obj/item/food/grown/banana,
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"GS" = (
+/obj/structure/girder/bronze,
+/obj/effect/decal/cleanable/cobweb/cobweb2,
+/obj/effect/decal/cleanable/dirt/dust,
+/turf/open/floor/bronze/flat,
+/area/deathmatch)
+"HN" = (
+/obj/structure/flora/rock/pile/jungle/large/style_random,
+/obj/item/flashlight/flare/torch,
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"HS" = (
+/obj/effect/decal/cleanable/dirt/dust,
+/turf/open/floor/bronze/filled,
+/area/deathmatch)
+"HV" = (
+/obj/effect/rune/empower,
+/obj/effect/decal/cleanable/blood,
+/turf/open/floor/cult,
+/area/deathmatch)
+"Ic" = (
+/obj/effect/decal/cleanable/ants,
+/turf/open/misc/dirt/jungle,
+/area/deathmatch)
+"Ig" = (
+/turf/closed/indestructible/rock,
+/area/deathmatch)
+"Ik" = (
+/obj/structure/flora/bush/jungle/b/style_random,
+/obj/structure/flora/grass/jungle/b/style_random,
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"Io" = (
+/obj/structure/fluff/clockwork/blind_eye,
+/obj/effect/decal/cleanable/dirt/dust,
+/turf/open/floor/bronze/filled,
+/area/deathmatch)
+"IG" = (
+/obj/structure/flora/bush/jungle/b/style_random,
+/mob/living/carbon/human/species/monkey,
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"IM" = (
+/obj/effect/decal/cleanable/blood/footprints,
+/obj/effect/turf_decal/weather/dirt{
+ dir = 1
+ },
+/turf/open/floor/cult,
+/area/deathmatch)
+"Jf" = (
+/turf/open/misc/dirt/jungle/dark,
+/area/deathmatch)
+"JF" = (
+/obj/structure/flora/grass/jungle/a/style_random,
+/turf/open/misc/dirt/jungle/wasteland,
+/area/deathmatch)
+"JL" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 8
+ },
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"Kg" = (
+/turf/open/water/jungle,
+/area/deathmatch)
+"Kl" = (
+/obj/effect/spawner/structure/window/bronze,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch)
+"KL" = (
+/turf/open/floor/cult,
+/area/deathmatch)
+"KT" = (
+/obj/effect/turf_decal/siding/wood/corner{
+ dir = 1
+ },
+/turf/open/chasm/jungle,
+/area/deathmatch)
+"Lf" = (
+/obj/structure/fluff/clockwork/alloy_shards,
+/obj/effect/decal/cleanable/dirt/dust,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch)
+"LC" = (
+/obj/effect/decal/cleanable/blood/gibs/down,
+/turf/open/floor/cult,
+/area/deathmatch)
+"LU" = (
+/obj/structure/flora/grass/jungle/a/style_random,
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"My" = (
+/obj/structure/table/wood,
+/obj/item/food/grown/holymelon,
+/turf/open/floor/wood/tile,
+/area/deathmatch)
+"MM" = (
+/obj/effect/turf_decal/siding/wood/corner{
+ dir = 4
+ },
+/turf/open/chasm/jungle,
+/area/deathmatch)
+"Nf" = (
+/obj/structure/girder/cult,
+/turf/open/misc/dirt/jungle/dark,
+/area/deathmatch)
+"NQ" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 4
+ },
+/turf/open/water/jungle,
+/area/deathmatch)
+"NX" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 8
+ },
+/obj/effect/turf_decal/siding/wood{
+ dir = 1
+ },
+/turf/open/water/jungle,
+/area/deathmatch)
+"Or" = (
+/obj/structure/flora/tree/jungle/style_random,
+/obj/structure/flora/coconuts,
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"Ov" = (
+/obj/effect/turf_decal/siding/wood,
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"Pi" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 6
+ },
+/obj/effect/turf_decal/siding/wood,
+/turf/open/water/jungle,
+/area/deathmatch)
+"Px" = (
+/obj/structure/flora/tree/jungle/style_random,
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"PH" = (
+/obj/effect/visible_heretic_influence,
+/turf/open/misc/dirt/jungle,
+/area/deathmatch)
+"PI" = (
+/turf/open/floor/wood/large,
+/area/deathmatch)
+"PU" = (
+/obj/structure/flora/bush/jungle/c/style_random,
+/obj/structure/flora/rock/style_random,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch)
+"Qf" = (
+/turf/closed/wall/r_wall,
+/area/deathmatch)
+"QF" = (
+/obj/effect/visible_heretic_influence,
+/turf/open/misc/dirt/jungle/wasteland,
+/area/deathmatch)
+"QO" = (
+/obj/effect/forcefield/cult,
+/turf/open/misc/dirt/jungle/dark,
+/area/deathmatch)
+"QQ" = (
+/turf/closed/wall/r_wall/heretic_rust,
+/area/deathmatch)
+"Rj" = (
+/obj/structure/flora/rock/style_random,
+/obj/effect/turf_decal/weather/dirt,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch)
+"Rm" = (
+/obj/effect/forcefield/cult/permanent,
+/turf/open/misc/dirt/jungle/dark,
+/area/deathmatch)
+"RE" = (
+/obj/structure/bonfire/prelit,
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"RL" = (
+/obj/effect/turf_decal/siding/wood,
+/obj/structure/flora/rock/pile/jungle/style_random,
+/turf/open/misc/dirt/jungle,
+/area/deathmatch)
+"RW" = (
+/obj/effect/decal/cleanable/shreds,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch)
+"Sf" = (
+/obj/effect/rune/wall,
+/turf/open/misc/dirt/jungle/dark,
+/area/deathmatch)
+"Sh" = (
+/obj/effect/decal/cleanable/blood/gibs/up,
+/turf/open/floor/cult,
+/area/deathmatch)
+"Sp" = (
+/obj/structure/fluff/clockwork/alloy_shards/small,
+/obj/structure/fluff/clockwork/fallen_armor,
+/obj/effect/decal/cleanable/dirt/dust,
+/turf/open/floor/bronze,
+/area/deathmatch)
+"Sw" = (
+/turf/open/misc/dirt/jungle/wasteland,
+/area/deathmatch)
+"SC" = (
+/turf/closed/wall/heretic_rust,
+/area/deathmatch)
+"SE" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 5
+ },
+/turf/open/water/jungle,
+/area/deathmatch)
+"SW" = (
+/obj/effect/turf_decal/siding/wood/corner{
+ dir = 1
+ },
+/obj/structure/flora/grass/jungle/b/style_random,
+/obj/effect/turf_decal/siding/wood,
+/obj/effect/turf_decal/siding/wood{
+ dir = 4
+ },
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"Ti" = (
+/obj/effect/decal/cleanable/vomit,
+/obj/effect/turf_decal/weather/dirt{
+ dir = 4
+ },
+/turf/open/indestructible/plating,
+/area/deathmatch)
+"To" = (
+/obj/structure/flora/bush/jungle/c/style_random,
+/obj/structure/flora/grass/jungle/b/style_random,
+/obj/structure/flora/rock/pile/jungle/large/style_random,
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"TE" = (
+/obj/structure/flora/rock/pile/style_random,
+/obj/effect/landmark/deathmatch_player_spawn,
+/turf/open/misc/asteroid/moon,
+/area/deathmatch)
+"TN" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 8
+ },
+/turf/open/water/jungle,
+/area/deathmatch)
+"TX" = (
+/obj/structure/flora/grass/jungle/b/style_random,
+/obj/effect/decal/cleanable/ants/fire,
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"UI" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 9
+ },
+/turf/open/floor/cult,
+/area/deathmatch)
+"UM" = (
+/obj/structure/flora/bush/jungle/b/style_random,
+/obj/effect/turf_decal/siding/wood,
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"UQ" = (
+/obj/structure/rack/skeletal,
+/obj/item/clothing/head/helmet/chaplain/witchunter_hat{
+ pixel_y = 8;
+ pixel_x = -1
+ },
+/turf/open/floor/wood/tile,
+/area/deathmatch)
+"UX" = (
+/obj/effect/decal/cleanable/dirt/dust,
+/obj/effect/decal/cleanable/vomit,
+/turf/open/floor/plating/heretic_rust,
+/area/deathmatch)
+"UY" = (
+/turf/open/floor/plating/heretic_rust,
+/area/deathmatch)
+"Vm" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 1
+ },
+/obj/structure/flora/grass/jungle/b/style_random,
+/turf/open/misc/dirt/jungle,
+/area/deathmatch)
+"Vv" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 1
+ },
+/turf/open/water/jungle,
+/area/deathmatch)
+"VF" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 1
+ },
+/obj/effect/turf_decal/siding/wood{
+ dir = 4
+ },
+/obj/effect/turf_decal/siding/wood{
+ dir = 8
+ },
+/obj/structure/flora/bush/jungle/b/style_random,
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"VP" = (
+/obj/effect/spawner/random/decoration/glowstick/on,
+/turf/open/indestructible/plating,
+/area/deathmatch)
+"VY" = (
+/obj/structure/table/bronze,
+/obj/item/clothing/shoes/bronze,
+/obj/item/clothing/suit/costume/bronze,
+/obj/item/clothing/head/costume/bronze,
+/obj/effect/decal/cleanable/dirt/dust,
+/obj/item/flashlight/flare/torch,
+/turf/open/floor/bronze/flat,
+/area/deathmatch)
+"VZ" = (
+/obj/effect/turf_decal/siding/wood/corner,
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"Wm" = (
+/obj/structure/fluff/clockwork/alloy_shards/medium,
+/obj/effect/decal/cleanable/dirt/dust,
+/turf/open/floor/bronze,
+/area/deathmatch)
+"Wp" = (
+/obj/structure/flora/grass/jungle/b/style_random,
+/turf/open/misc/dirt/jungle/dark,
+/area/deathmatch)
+"Xa" = (
+/obj/structure/rack/skeletal,
+/obj/item/clothing/head/helmet/chaplain/ancient{
+ pixel_y = 6
+ },
+/turf/open/floor/wood/tile,
+/area/deathmatch)
+"XL" = (
+/obj/effect/decal/cleanable/dirt,
+/obj/item/wallframe/painting/eldritch/weeping,
+/turf/open/floor/plating/heretic_rust,
+/area/deathmatch)
+"XT" = (
+/turf/closed/wall/mineral/cult/artificer,
+/area/deathmatch)
+"Yn" = (
+/obj/effect/decal/cleanable/ants,
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"Ys" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 4
+ },
+/obj/structure/flora/rock/pile/jungle/style_random,
+/turf/open/misc/dirt/jungle,
+/area/deathmatch)
+"Yv" = (
+/obj/structure/flora/tree/jungle/small/style_random,
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"Yx" = (
+/obj/structure/flora/rock/pile/jungle/style_random,
+/obj/effect/turf_decal/siding/wood/corner{
+ dir = 4
+ },
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"YA" = (
+/obj/effect/decal/cleanable/blood/gibs/limb,
+/obj/effect/turf_decal/weather/dirt{
+ dir = 10
+ },
+/turf/open/floor/cult,
+/area/deathmatch)
+"YI" = (
+/obj/effect/turf_decal/weather/dirt{
+ dir = 4
+ },
+/turf/open/floor/wood/large,
+/area/deathmatch)
+"YN" = (
+/obj/structure/girder/cult,
+/obj/effect/turf_decal/weather/dirt{
+ dir = 6
+ },
+/turf/open/floor/cult,
+/area/deathmatch)
+"YY" = (
+/obj/structure/girder/cult,
+/obj/effect/turf_decal/weather/dirt{
+ dir = 9
+ },
+/turf/open/floor/cult,
+/area/deathmatch)
+"Zj" = (
+/obj/structure/flora/grass/jungle/b/style_random,
+/obj/effect/turf_decal/siding/wood,
+/obj/effect/turf_decal/siding/wood{
+ dir = 4
+ },
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"Zw" = (
+/obj/effect/decal/cleanable/dirt/dust,
+/turf/open/floor/wood/tile,
+/area/deathmatch)
+"ZJ" = (
+/obj/structure/destructible/cult/pants_altar,
+/obj/effect/rune/apocalypse{
+ req_cultists = 999
+ },
+/obj/item/knife/ritual,
+/turf/open/floor/cult,
+/area/deathmatch)
+"ZR" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 1
+ },
+/obj/effect/turf_decal/siding/wood{
+ dir = 8
+ },
+/obj/effect/turf_decal/siding/wood/corner,
+/turf/open/misc/grass/jungle,
+/area/deathmatch)
+"ZY" = (
+/obj/structure/bonfire/prelit,
+/turf/open/misc/dirt/jungle,
+/area/deathmatch)
+
+(1,1,1) = {"
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+"}
+(2,1,1) = {"
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+SC
+SC
+SC
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+"}
+(3,1,1) = {"
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+sa
+UY
+UY
+TE
+QQ
+QQ
+QQ
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+"}
+(4,1,1) = {"
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+bI
+qa
+Px
+qa
+dS
+bU
+UY
+UY
+bU
+QQ
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+"}
+(5,1,1) = {"
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+ij
+dS
+GO
+qa
+qa
+Sw
+oC
+EF
+Sw
+Sw
+Sw
+Px
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+"}
+(6,1,1) = {"
+Ig
+Ig
+Ig
+Ig
+Ig
+jL
+jv
+CR
+LU
+Yn
+Sw
+Sw
+yY
+aJ
+bU
+QQ
+QF
+Sw
+LU
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+"}
+(7,1,1) = {"
+Ig
+Ig
+Ig
+Ig
+jL
+ij
+qa
+hw
+qa
+Sw
+oC
+SC
+sE
+UY
+Be
+ox
+Qf
+Sw
+Sw
+IG
+ij
+jL
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+"}
+(8,1,1) = {"
+Ig
+Ig
+Ig
+Ig
+bI
+nO
+HN
+qa
+vI
+oC
+QQ
+QQ
+UY
+Be
+UY
+bU
+UX
+Bi
+oC
+LU
+LU
+dS
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+"}
+(9,1,1) = {"
+Ig
+Ig
+Ig
+ij
+qa
+qa
+LU
+qa
+Sw
+JF
+QQ
+pz
+UY
+CB
+eL
+Be
+XL
+VP
+AO
+tm
+qa
+vI
+pr
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+"}
+(10,1,1) = {"
+Ig
+Ig
+Ig
+aN
+qa
+qa
+Or
+Bl
+QF
+Qf
+tl
+UY
+eU
+UY
+UY
+UY
+SC
+kc
+Ga
+PH
+FK
+FK
+FK
+ZY
+Ig
+Ig
+Ig
+Ig
+Ig
+"}
+(11,1,1) = {"
+Ig
+Ig
+Ig
+GD
+qa
+LU
+Fn
+qa
+Sw
+Sw
+oC
+UY
+UY
+EF
+UY
+mr
+dI
+lx
+PI
+Vm
+iJ
+TN
+qh
+FK
+wR
+Ig
+Ig
+Ig
+Ig
+"}
+(12,1,1) = {"
+Ig
+Ig
+wR
+ZY
+Ic
+FK
+FK
+sC
+LU
+pr
+Sw
+Ti
+fO
+lR
+hg
+Bd
+FK
+lx
+PI
+NX
+NQ
+NQ
+NQ
+TN
+CE
+DA
+Ig
+Ig
+Ig
+"}
+(13,1,1) = {"
+Ig
+Ig
+iJ
+TN
+TN
+TN
+qh
+FK
+FK
+FK
+cs
+FK
+eB
+SC
+FK
+sC
+iJ
+Ds
+PI
+Bp
+FK
+FK
+wR
+SE
+FK
+sC
+Ig
+Ig
+Ig
+"}
+(14,1,1) = {"
+Ig
+Ig
+SE
+NQ
+NQ
+NQ
+Kg
+TN
+qh
+FK
+FK
+iJ
+qh
+RL
+PI
+Do
+Kg
+Pi
+PI
+gx
+FK
+qa
+FK
+FK
+FK
+Du
+Ig
+Ig
+Ig
+"}
+(15,1,1) = {"
+Ig
+Ig
+sC
+sC
+FK
+bb
+SE
+NQ
+bv
+PI
+ou
+NQ
+Kg
+Ds
+ft
+Vv
+oO
+FK
+ZY
+qa
+GD
+qa
+jv
+Yn
+GD
+RW
+jL
+Ig
+Ig
+"}
+(16,1,1) = {"
+Ig
+Ig
+wP
+GD
+qa
+Wp
+ZY
+FK
+RL
+PI
+Bp
+bb
+SE
+rD
+YI
+jb
+rH
+Ys
+iq
+iq
+hr
+qp
+GO
+hY
+qa
+ij
+Ig
+Ig
+Ig
+"}
+(17,1,1) = {"
+Ig
+Ig
+jC
+xc
+QO
+fc
+Nf
+Sf
+Rm
+yv
+Jf
+FK
+sC
+FK
+sC
+lx
+oB
+qg
+qg
+qg
+vR
+gJ
+qa
+rm
+jv
+nO
+Ig
+Ig
+Ig
+"}
+(18,1,1) = {"
+Ig
+Ig
+ij
+Px
+Nf
+lX
+Wp
+Jf
+Ab
+Sf
+Jf
+qa
+GD
+qa
+qa
+gi
+Xa
+cT
+My
+qg
+qg
+fl
+jv
+qa
+qa
+ku
+Ig
+Ig
+Ig
+"}
+(19,1,1) = {"
+Ig
+Ig
+PU
+cR
+Jf
+Ar
+cH
+cH
+KL
+YA
+QO
+Jf
+Yv
+qa
+RE
+Ov
+qg
+qg
+AN
+lK
+qg
+VF
+qa
+VZ
+iq
+Yx
+Ig
+Ig
+Ig
+"}
+(20,1,1) = {"
+Ig
+Ig
+Ig
+oF
+Nf
+Wp
+gz
+KL
+jP
+KL
+lC
+Sf
+Jf
+qa
+qa
+Ov
+wf
+qg
+My
+qg
+cT
+fl
+VZ
+Zj
+bj
+Ig
+Ig
+Ig
+Ig
+"}
+(21,1,1) = {"
+Ig
+Ig
+Ig
+Rj
+XT
+YY
+Sh
+ye
+ZJ
+ye
+LC
+pF
+XT
+qa
+FQ
+eG
+oB
+Zw
+qg
+qg
+UQ
+ZR
+Zj
+wH
+FO
+KT
+Ig
+Ig
+Ig
+"}
+(22,1,1) = {"
+Ig
+Ig
+XT
+KL
+sJ
+AE
+KL
+cr
+KL
+AE
+jI
+Nf
+Jf
+qa
+qa
+ih
+JL
+JL
+JL
+JL
+qL
+SW
+wH
+FO
+KT
+hV
+Ig
+Ig
+Ig
+"}
+(23,1,1) = {"
+Ig
+Ig
+XT
+GE
+ij
+Jf
+IM
+sF
+qk
+Nf
+Wp
+Jf
+jv
+hY
+qa
+qa
+qa
+qa
+qa
+qa
+Ov
+wH
+FO
+KT
+hV
+hV
+Ig
+Ig
+Ig
+"}
+(24,1,1) = {"
+Ig
+Ig
+Ig
+Wp
+Nf
+UI
+KL
+Ba
+xC
+Jf
+Jf
+qa
+qa
+jv
+To
+qa
+qa
+jv
+Or
+TX
+Ov
+wv
+KT
+hV
+hV
+Ig
+Ig
+Ig
+Ig
+"}
+(25,1,1) = {"
+Ig
+Ig
+XT
+mD
+KL
+HV
+gz
+KL
+YN
+Wp
+qa
+qa
+Yn
+qa
+qa
+qa
+jv
+qa
+dS
+qa
+UM
+lr
+MM
+hV
+Ig
+Ig
+Ig
+Ig
+Ig
+"}
+(26,1,1) = {"
+Ig
+Ig
+Ig
+XT
+xx
+KL
+Nf
+Sf
+Jf
+RE
+Px
+Ik
+GO
+qa
+nO
+jL
+Av
+bO
+rc
+bn
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+"}
+(27,1,1) = {"
+Ig
+Ig
+Ig
+Ig
+Dn
+cb
+Wp
+Jf
+qa
+jv
+qa
+qa
+qa
+jL
+bI
+Ig
+Lf
+px
+fW
+dv
+Sp
+zX
+bn
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+"}
+(28,1,1) = {"
+Ig
+Ig
+Ig
+Ig
+Ig
+iO
+jL
+ij
+zo
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+An
+HS
+Fj
+Fj
+rh
+sd
+Kl
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+"}
+(29,1,1) = {"
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+bn
+GS
+Wm
+tE
+Io
+uT
+Kl
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+"}
+(30,1,1) = {"
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Kl
+FS
+VY
+bn
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+"}
+(31,1,1) = {"
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+Ig
+"}
diff --git a/_maps/deathmatch/species_warfare.dmm b/_maps/deathmatch/species_warfare.dmm
new file mode 100644
index 0000000000000..e80485c2b5e5c
--- /dev/null
+++ b/_maps/deathmatch/species_warfare.dmm
@@ -0,0 +1,2461 @@
+//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE
+"aA" = (
+/obj/effect/turf_decal/tile/blue/half/contrasted{
+ dir = 4
+ },
+/obj/machinery/medical_kiosk,
+/obj/structure/sign/poster/official/moth_meth/directional/east,
+/turf/open/indestructible/white,
+/area/deathmatch)
+"aD" = (
+/obj/effect/turf_decal/tile/green/half/contrasted{
+ dir = 4
+ },
+/obj/effect/spawner/random/vending/colavend,
+/turf/open/indestructible,
+/area/deathmatch)
+"by" = (
+/mob/living/basic/mothroach,
+/turf/open/indestructible/white,
+/area/deathmatch)
+"bL" = (
+/obj/effect/turf_decal/tile/blue/half/contrasted{
+ dir = 1
+ },
+/obj/structure/table/glass,
+/obj/item/surgery_tray/full,
+/turf/open/indestructible/white,
+/area/deathmatch)
+"bX" = (
+/obj/effect/turf_decal/tile/dark_blue/full,
+/obj/structure/table/glass,
+/obj/item/storage/fancy/donut_box,
+/turf/open/indestructible/dark/smooth_large,
+/area/deathmatch)
+"cd" = (
+/obj/effect/turf_decal/tile/dark_blue/full,
+/obj/machinery/light/built/directional/south,
+/obj/machinery/computer{
+ dir = 4
+ },
+/turf/open/indestructible/dark/smooth_large,
+/area/deathmatch)
+"cl" = (
+/obj/effect/landmark/deathmatch_player_spawn,
+/obj/structure/bed,
+/obj/effect/spawner/random/bedsheet,
+/obj/machinery/light/small/blacklight/directional/north,
+/turf/open/floor/wood,
+/area/deathmatch)
+"cs" = (
+/obj/effect/turf_decal/tile/neutral/fourcorners,
+/obj/vehicle/sealed/mecha/ripley,
+/obj/item/mecha_parts/mecha_equipment/air_tank/full,
+/turf/open/floor/iron/dark,
+/area/deathmatch)
+"cy" = (
+/obj/effect/turf_decal/tile/blue/half/contrasted{
+ dir = 8
+ },
+/obj/machinery/cryo_cell,
+/turf/open/indestructible/white,
+/area/deathmatch)
+"dv" = (
+/obj/effect/turf_decal/tile/green/half/contrasted,
+/turf/open/indestructible,
+/area/deathmatch)
+"dA" = (
+/obj/effect/turf_decal/tile/blue/half/contrasted{
+ dir = 8
+ },
+/obj/machinery/atmospherics/components/unary/portables_connector/visible{
+ dir = 4
+ },
+/turf/open/indestructible/white,
+/area/deathmatch)
+"dB" = (
+/obj/effect/turf_decal/tile/yellow/fourcorners,
+/obj/machinery/portable_atmospherics/canister,
+/turf/open/indestructible,
+/area/deathmatch)
+"ee" = (
+/obj/effect/turf_decal/tile/green{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 1
+ },
+/turf/open/indestructible,
+/area/deathmatch)
+"em" = (
+/obj/effect/turf_decal/stripes/line{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/purple/half/contrasted{
+ dir = 8
+ },
+/turf/open/indestructible/white,
+/area/deathmatch)
+"es" = (
+/obj/effect/turf_decal/tile/blue/half/contrasted,
+/obj/machinery/stasis{
+ dir = 1
+ },
+/obj/effect/landmark/deathmatch_player_spawn,
+/obj/machinery/light/floor,
+/turf/open/indestructible/white,
+/area/deathmatch)
+"eE" = (
+/obj/effect/turf_decal/tile/yellow/half/contrasted,
+/obj/machinery/atmospherics/components/binary/crystallizer{
+ dir = 4
+ },
+/turf/open/indestructible,
+/area/deathmatch)
+"eO" = (
+/obj/effect/turf_decal/tile/dark_blue/anticorner/contrasted{
+ dir = 1
+ },
+/turf/open/indestructible,
+/area/deathmatch)
+"eW" = (
+/obj/effect/turf_decal/tile/dark_blue/anticorner/contrasted{
+ dir = 8
+ },
+/obj/structure/chair/office{
+ dir = 8
+ },
+/turf/open/indestructible/dark,
+/area/deathmatch)
+"fg" = (
+/obj/effect/turf_decal/tile/dark_blue/anticorner/contrasted,
+/turf/open/indestructible/dark,
+/area/deathmatch)
+"fm" = (
+/obj/item/pillow/random,
+/turf/open/floor/wood,
+/area/deathmatch)
+"fA" = (
+/obj/machinery/power/tracker,
+/obj/structure/cable,
+/turf/open/floor/plating/airless,
+/area/deathmatch)
+"fP" = (
+/obj/effect/turf_decal/tile/dark_blue/full,
+/obj/machinery/door/airlock/command/glass,
+/turf/open/indestructible/dark/smooth_large,
+/area/deathmatch)
+"fV" = (
+/obj/effect/turf_decal/tile/purple/full,
+/obj/machinery/door/airlock/science/glass,
+/turf/open/indestructible/white/smooth_large,
+/area/deathmatch)
+"gH" = (
+/mob/living/basic/pet/cat/feral,
+/obj/structure/bed,
+/obj/item/bedsheet/runtime,
+/obj/machinery/light/small/blacklight/directional/south,
+/turf/open/floor/wood,
+/area/deathmatch)
+"gI" = (
+/turf/open/indestructible/dark,
+/area/deathmatch)
+"gM" = (
+/obj/effect/spawner/random/structure/closet_private,
+/obj/effect/decal/cleanable/vomit,
+/turf/open/floor/wood,
+/area/deathmatch)
+"hk" = (
+/obj/effect/turf_decal/tile/green/full,
+/obj/machinery/door/airlock/glass,
+/turf/open/indestructible/large,
+/area/deathmatch)
+"ho" = (
+/obj/effect/turf_decal/tile/green/half/contrasted{
+ dir = 8
+ },
+/obj/effect/decal/cleanable/dirt/dust,
+/turf/open/indestructible,
+/area/deathmatch)
+"hA" = (
+/obj/effect/turf_decal/tile/yellow/anticorner/contrasted,
+/obj/machinery/atmospherics/pipe/smart/simple/green/visible{
+ dir = 9
+ },
+/turf/open/indestructible,
+/area/deathmatch)
+"hC" = (
+/obj/effect/turf_decal/tile/blue/anticorner/contrasted{
+ dir = 1
+ },
+/obj/structure/table/optable,
+/obj/effect/decal/cleanable/blood,
+/turf/open/indestructible/white,
+/area/deathmatch)
+"hG" = (
+/obj/effect/turf_decal/tile/neutral/fourcorners,
+/obj/effect/decal/cleanable/oil/slippery,
+/obj/item/mecha_parts/mecha_equipment/ripleyupgrade,
+/turf/open/floor/iron/dark,
+/area/deathmatch)
+"hR" = (
+/obj/structure/reagent_dispensers/watertank/high,
+/turf/open/indestructible/plating,
+/area/deathmatch)
+"is" = (
+/obj/item/grenade/spawnergrenade/cat,
+/turf/open/floor/wood,
+/area/deathmatch)
+"iu" = (
+/obj/effect/turf_decal/tile/blue/half/contrasted{
+ dir = 1
+ },
+/obj/machinery/sleeper/self_control,
+/turf/open/indestructible/white,
+/area/deathmatch)
+"ix" = (
+/obj/effect/turf_decal/tile/dark_blue{
+ dir = 4
+ },
+/turf/open/indestructible/dark,
+/area/deathmatch)
+"iK" = (
+/obj/effect/turf_decal/tile/dark_blue/half/contrasted{
+ dir = 1
+ },
+/turf/open/indestructible,
+/area/deathmatch)
+"iM" = (
+/obj/effect/turf_decal/tile/blue/half/contrasted,
+/obj/structure/table/glass,
+/obj/item/surgery_tray/full,
+/turf/open/indestructible/white,
+/area/deathmatch)
+"iV" = (
+/obj/item/card/id/advanced/engioutpost,
+/obj/effect/decal/remains/human/smokey,
+/turf/open/indestructible,
+/area/deathmatch)
+"jm" = (
+/obj/effect/turf_decal/tile/dark_blue/anticorner/contrasted{
+ dir = 4
+ },
+/obj/structure/closet/firecloset/full,
+/turf/open/indestructible/dark,
+/area/deathmatch)
+"jn" = (
+/obj/effect/landmark/deathmatch_player_spawn,
+/obj/machinery/light/floor,
+/turf/open/indestructible/dark,
+/area/deathmatch)
+"ju" = (
+/obj/effect/turf_decal/tile/dark_blue/anticorner/contrasted{
+ dir = 8
+ },
+/turf/open/indestructible/dark,
+/area/deathmatch)
+"jw" = (
+/turf/open/space/basic,
+/area/deathmatch)
+"jR" = (
+/obj/effect/turf_decal/tile/purple/half/contrasted{
+ dir = 4
+ },
+/obj/machinery/rnd/production/protolathe/offstation,
+/obj/machinery/light/directional/east,
+/turf/open/indestructible/white,
+/area/deathmatch)
+"ko" = (
+/obj/effect/turf_decal/tile/green/half/contrasted{
+ dir = 4
+ },
+/obj/structure/extinguisher_cabinet/directional/east,
+/obj/machinery/vending/cigarette/syndicate,
+/obj/machinery/light/directional/east,
+/turf/open/indestructible,
+/area/deathmatch)
+"kY" = (
+/obj/machinery/door/airlock{
+ id_tag = "Cabin2";
+ name = "Cabin 4"
+ },
+/turf/open/chasm{
+ icon_state = "wood";
+ icon = 'icons/turf/floors.dmi';
+ base_icon_state = "wood";
+ name = "Dorms 4"
+ },
+/area/deathmatch)
+"lF" = (
+/obj/effect/spawner/random/structure/closet_private,
+/turf/open/floor/wood,
+/area/deathmatch)
+"mn" = (
+/obj/effect/turf_decal/tile/dark_blue/anticorner/contrasted{
+ dir = 1
+ },
+/obj/structure/table/glass,
+/obj/machinery/computer/security/wooden_tv{
+ pixel_x = 1;
+ pixel_y = 6
+ },
+/turf/open/indestructible/dark,
+/area/deathmatch)
+"mo" = (
+/obj/effect/turf_decal/tile/yellow/full,
+/obj/structure/table/reinforced,
+/obj/machinery/door/window/right/directional/west,
+/turf/open/indestructible/large,
+/area/deathmatch)
+"mK" = (
+/obj/effect/turf_decal/tile/blue/anticorner/contrasted{
+ dir = 1
+ },
+/obj/structure/closet/emcloset,
+/turf/open/indestructible/white,
+/area/deathmatch)
+"mO" = (
+/obj/effect/turf_decal/tile/dark_blue/anticorner/contrasted{
+ dir = 4
+ },
+/obj/structure/chair/office{
+ dir = 1
+ },
+/turf/open/indestructible/dark,
+/area/deathmatch)
+"nb" = (
+/obj/effect/turf_decal/tile/dark_blue/half/contrasted{
+ dir = 8
+ },
+/turf/open/indestructible/dark/textured,
+/area/deathmatch)
+"nf" = (
+/obj/effect/turf_decal/tile/dark_blue/anticorner/contrasted{
+ dir = 1
+ },
+/obj/structure/table/glass,
+/obj/item/reagent_containers/cup/glass/bottle/champagne/cursed,
+/obj/item/food/donut/trumpet,
+/turf/open/indestructible/dark,
+/area/deathmatch)
+"nQ" = (
+/obj/effect/turf_decal/tile/dark_blue/anticorner/contrasted,
+/obj/structure/chair/office{
+ dir = 4
+ },
+/turf/open/indestructible/dark,
+/area/deathmatch)
+"nT" = (
+/obj/effect/turf_decal/tile/purple/anticorner/contrasted,
+/obj/structure/closet/firecloset/full,
+/turf/open/indestructible/white,
+/area/deathmatch)
+"oq" = (
+/obj/effect/turf_decal/tile/purple/half/contrasted{
+ dir = 1
+ },
+/obj/effect/decal/cleanable/greenglow,
+/turf/open/indestructible/white,
+/area/deathmatch)
+"oy" = (
+/obj/machinery/atmospherics/components/unary/portables_connector/visible,
+/turf/open/indestructible,
+/area/deathmatch)
+"oD" = (
+/obj/effect/turf_decal/tile/dark_blue/half/contrasted{
+ dir = 8
+ },
+/obj/machinery/light/small/blacklight/directional/west,
+/turf/open/indestructible/dark/textured,
+/area/deathmatch)
+"oN" = (
+/obj/effect/turf_decal/tile/yellow/half/contrasted{
+ dir = 4
+ },
+/obj/machinery/atmospherics/components/unary/portables_connector/visible,
+/turf/open/indestructible,
+/area/deathmatch)
+"pD" = (
+/obj/effect/turf_decal/tile/dark_blue/half/contrasted{
+ dir = 8
+ },
+/turf/open/indestructible,
+/area/deathmatch)
+"pH" = (
+/obj/structure/cable,
+/obj/structure/table/reinforced,
+/obj/item/fireaxe/metal_h2_axe,
+/turf/open/indestructible,
+/area/deathmatch)
+"pJ" = (
+/obj/effect/turf_decal/tile/green/half/contrasted{
+ dir = 8
+ },
+/obj/structure/extinguisher_cabinet/directional/west,
+/obj/machinery/light/directional/west,
+/turf/open/indestructible,
+/area/deathmatch)
+"pL" = (
+/mob/living/basic/lizard/wags_his_tail,
+/obj/effect/decal/cleanable/dirt,
+/turf/open/indestructible,
+/area/deathmatch)
+"qF" = (
+/obj/effect/turf_decal/tile/purple/half/contrasted,
+/turf/open/indestructible/white,
+/area/deathmatch)
+"qM" = (
+/obj/effect/turf_decal/tile/blue/half/contrasted{
+ dir = 4
+ },
+/turf/open/indestructible/white,
+/area/deathmatch)
+"qV" = (
+/obj/effect/turf_decal/tile/dark_blue/full,
+/obj/machinery/computer{
+ dir = 8
+ },
+/turf/open/indestructible/dark/smooth_large,
+/area/deathmatch)
+"rq" = (
+/obj/effect/turf_decal/tile/neutral/fourcorners,
+/obj/structure/table/reinforced,
+/obj/item/toy/plush/slimeplushie{
+ pixel_y = 10
+ },
+/obj/item/mecha_parts/mecha_equipment/weapon/energy/mecha_kineticgun,
+/turf/open/floor/iron/dark,
+/area/deathmatch)
+"ru" = (
+/obj/effect/turf_decal/tile/purple/anticorner/contrasted{
+ dir = 4
+ },
+/obj/machinery/rnd/production/circuit_imprinter/offstation,
+/obj/item/mecha_parts/mecha_equipment/wormhole_generator,
+/turf/open/indestructible/white,
+/area/deathmatch)
+"rO" = (
+/obj/structure/bed,
+/obj/effect/spawner/random/bedsheet,
+/obj/item/melee/supermatter_sword,
+/obj/machinery/light/small/blacklight/directional/south,
+/turf/open/floor/wood,
+/area/deathmatch)
+"rP" = (
+/obj/effect/turf_decal/tile/green/half/contrasted{
+ dir = 8
+ },
+/obj/structure/extinguisher_cabinet/directional/west,
+/obj/structure/table,
+/obj/item/restraints/legcuffs/beartrap{
+ pixel_x = -5;
+ pixel_y = 5
+ },
+/obj/item/restraints/legcuffs/beartrap{
+ pixel_x = 2
+ },
+/obj/item/key/janitor{
+ pixel_y = 10
+ },
+/turf/open/indestructible,
+/area/deathmatch)
+"rV" = (
+/obj/structure/lattice,
+/turf/open/space/basic,
+/area/deathmatch)
+"sn" = (
+/obj/effect/decal/cleanable/vomit,
+/turf/open/floor/wood,
+/area/deathmatch)
+"st" = (
+/obj/effect/turf_decal/tile/blue/half/contrasted{
+ dir = 8
+ },
+/obj/machinery/atmospherics/components/unary/thermomachine/freezer/on,
+/turf/open/indestructible/white,
+/area/deathmatch)
+"su" = (
+/obj/effect/turf_decal/tile/yellow/half/contrasted{
+ dir = 1
+ },
+/obj/structure/rack,
+/obj/item/storage/belt/utility/full{
+ pixel_y = 4
+ },
+/obj/item/storage/belt/utility/full,
+/turf/open/indestructible,
+/area/deathmatch)
+"sx" = (
+/obj/effect/turf_decal/tile/dark_blue/fourcorners,
+/obj/machinery/computer{
+ dir = 4
+ },
+/turf/open/indestructible/dark,
+/area/deathmatch)
+"sJ" = (
+/turf/open/floor/wood,
+/area/deathmatch)
+"sL" = (
+/obj/effect/turf_decal/tile/dark_blue/full,
+/obj/structure/table/glass,
+/obj/item/storage/medkit/regular,
+/turf/open/indestructible/dark/smooth_large,
+/area/deathmatch)
+"sW" = (
+/obj/effect/turf_decal/tile/dark_blue{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/blue{
+ dir = 8
+ },
+/turf/open/indestructible,
+/area/deathmatch)
+"tR" = (
+/obj/effect/turf_decal/tile/dark_blue/full,
+/obj/machinery/computer{
+ dir = 4
+ },
+/turf/open/indestructible/dark/smooth_large,
+/area/deathmatch)
+"uq" = (
+/obj/structure/table,
+/obj/effect/spawner/random/entertainment/dice,
+/turf/open/indestructible,
+/area/deathmatch)
+"uQ" = (
+/obj/effect/turf_decal/stripes/corner{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/purple{
+ dir = 8
+ },
+/turf/open/indestructible/white,
+/area/deathmatch)
+"uX" = (
+/obj/effect/turf_decal/tile/green/half/contrasted{
+ dir = 8
+ },
+/obj/effect/landmark/deathmatch_player_spawn,
+/turf/open/indestructible,
+/area/deathmatch)
+"vb" = (
+/obj/effect/turf_decal/tile/green/half/contrasted{
+ dir = 8
+ },
+/obj/item/kirbyplants/random,
+/turf/open/indestructible,
+/area/deathmatch)
+"vm" = (
+/obj/effect/turf_decal/tile/green/anticorner/contrasted{
+ dir = 8
+ },
+/turf/open/indestructible,
+/area/deathmatch)
+"vq" = (
+/obj/structure/cable,
+/turf/open/floor/iron/solarpanel/airless,
+/area/deathmatch)
+"vB" = (
+/obj/effect/turf_decal/tile/yellow/half/contrasted{
+ dir = 4
+ },
+/obj/effect/decal/cleanable/dirt/dust,
+/turf/open/indestructible,
+/area/deathmatch)
+"vI" = (
+/obj/effect/turf_decal/tile/green{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/purple,
+/turf/open/indestructible,
+/area/deathmatch)
+"vT" = (
+/obj/effect/turf_decal/tile/yellow/half/contrasted,
+/obj/machinery/atmospherics/components/unary/portables_connector/visible{
+ dir = 4
+ },
+/obj/machinery/light/built/directional/south,
+/turf/open/indestructible,
+/area/deathmatch)
+"wb" = (
+/obj/effect/turf_decal/tile/blue/half/contrasted{
+ dir = 1
+ },
+/obj/machinery/stasis{
+ dir = 1
+ },
+/obj/effect/landmark/deathmatch_player_spawn,
+/obj/machinery/light/floor,
+/turf/open/indestructible/white,
+/area/deathmatch)
+"wd" = (
+/obj/effect/turf_decal/tile/dark_blue/half/contrasted{
+ dir = 8
+ },
+/obj/structure/extinguisher_cabinet/directional/west,
+/turf/open/indestructible,
+/area/deathmatch)
+"wj" = (
+/obj/effect/turf_decal/tile/green/half/contrasted{
+ dir = 4
+ },
+/turf/open/indestructible,
+/area/deathmatch)
+"wA" = (
+/obj/structure/table/glass,
+/obj/item/storage/box/syringes,
+/obj/item/gun/syringe,
+/obj/item/reagent_containers/cup/bottle/morphine{
+ pixel_y = 17;
+ pixel_x = -7
+ },
+/obj/item/reagent_containers/cup/bottle/traitor{
+ pixel_y = 17;
+ pixel_x = 8
+ },
+/obj/item/toy/plush/moth{
+ name = "Mender Moff"
+ },
+/turf/open/indestructible/white,
+/area/deathmatch)
+"wG" = (
+/obj/effect/turf_decal/tile/blue/half/contrasted{
+ dir = 8
+ },
+/obj/structure/closet/firecloset/full,
+/turf/open/indestructible/white,
+/area/deathmatch)
+"wM" = (
+/obj/effect/turf_decal/tile/green/half/contrasted{
+ dir = 1
+ },
+/obj/machinery/vending/wardrobe/jani_wardrobe,
+/obj/effect/decal/cleanable/dirt,
+/obj/machinery/light/small/blacklight/directional/north,
+/turf/open/indestructible,
+/area/deathmatch)
+"xe" = (
+/obj/effect/turf_decal/tile/yellow/half/contrasted{
+ dir = 4
+ },
+/obj/item/kirbyplants/random,
+/turf/open/indestructible,
+/area/deathmatch)
+"xj" = (
+/obj/effect/decal/cleanable/blood/footprints,
+/turf/open/indestructible/white,
+/area/deathmatch)
+"xL" = (
+/obj/effect/spawner/structure/window/reinforced/indestructible,
+/turf/open/indestructible/large,
+/area/deathmatch)
+"xT" = (
+/obj/effect/turf_decal/tile/blue/half/contrasted,
+/obj/item/storage/medkit/brute{
+ pixel_x = -3;
+ pixel_y = -3
+ },
+/obj/item/storage/medkit/fire{
+ pixel_x = 3;
+ pixel_y = 3
+ },
+/obj/structure/cable,
+/obj/structure/table/glass,
+/turf/open/indestructible/white,
+/area/deathmatch)
+"yq" = (
+/obj/machinery/atmospherics/pipe/smart/manifold4w/cyan/visible,
+/turf/open/indestructible/white,
+/area/deathmatch)
+"yy" = (
+/obj/effect/turf_decal/tile/dark_blue/anticorner/contrasted{
+ dir = 4
+ },
+/obj/structure/table/glass,
+/obj/item/reagent_containers/cup/glass/bottle/champagne/cursed,
+/obj/item/food/donut/trumpet,
+/turf/open/indestructible/dark,
+/area/deathmatch)
+"yD" = (
+/obj/effect/turf_decal/tile/blue/half/contrasted{
+ dir = 4
+ },
+/obj/effect/decal/cleanable/blood,
+/obj/machinery/light/cold/dim/directional/east,
+/turf/open/indestructible/white,
+/area/deathmatch)
+"yU" = (
+/obj/effect/turf_decal/tile/green/anticorner/contrasted,
+/obj/effect/decal/cleanable/dirt,
+/turf/open/indestructible,
+/area/deathmatch)
+"zg" = (
+/obj/effect/turf_decal/tile/purple/half/contrasted,
+/obj/item/kirbyplants/random,
+/turf/open/indestructible,
+/area/deathmatch)
+"zs" = (
+/obj/effect/turf_decal/tile/blue/full,
+/turf/open/indestructible/white/smooth_large,
+/area/deathmatch)
+"zt" = (
+/obj/effect/turf_decal/tile/dark_blue/full,
+/obj/machinery/light/built/directional/south,
+/obj/machinery/computer{
+ dir = 8
+ },
+/turf/open/indestructible/dark/smooth_large,
+/area/deathmatch)
+"zw" = (
+/obj/effect/turf_decal/tile/green/anticorner/contrasted{
+ dir = 4
+ },
+/turf/open/indestructible,
+/area/deathmatch)
+"zx" = (
+/obj/item/stack/tile/iron/four{
+ pixel_y = 7;
+ pixel_x = 10
+ },
+/obj/structure/cable,
+/turf/open/indestructible/plating,
+/area/deathmatch)
+"zJ" = (
+/turf/closed/indestructible/reinforced,
+/area/deathmatch)
+"zK" = (
+/obj/effect/turf_decal/tile/dark_blue/half/contrasted,
+/turf/open/indestructible/dark,
+/area/deathmatch)
+"zZ" = (
+/obj/effect/turf_decal/tile/yellow,
+/obj/effect/turf_decal/tile/green{
+ dir = 4
+ },
+/obj/effect/spawner/random/vending/colavend,
+/turf/open/indestructible,
+/area/deathmatch)
+"Ac" = (
+/obj/effect/landmark/deathmatch_player_spawn,
+/obj/machinery/light/floor,
+/turf/open/indestructible,
+/area/deathmatch)
+"Ag" = (
+/obj/effect/turf_decal/stripes/line,
+/obj/effect/turf_decal/tile/purple/half/contrasted,
+/obj/effect/decal/cleanable/oil,
+/turf/open/indestructible/white,
+/area/deathmatch)
+"AE" = (
+/obj/effect/turf_decal/tile/yellow/full,
+/obj/machinery/door/airlock/engineering/glass,
+/turf/open/indestructible/large,
+/area/deathmatch)
+"AQ" = (
+/mob/living/basic/migo/hatsune,
+/obj/structure/bed,
+/obj/item/bedsheet/cult,
+/obj/machinery/light/small/blacklight/directional/south,
+/turf/open/floor/wood,
+/area/deathmatch)
+"AZ" = (
+/obj/effect/turf_decal/tile/blue/half/contrasted{
+ dir = 1
+ },
+/obj/item/storage/medkit/brute{
+ pixel_x = -3;
+ pixel_y = -3
+ },
+/obj/item/storage/medkit/fire{
+ pixel_x = 3;
+ pixel_y = 3
+ },
+/obj/structure/table/glass,
+/turf/open/indestructible/white,
+/area/deathmatch)
+"Bc" = (
+/obj/effect/turf_decal/tile/yellow/anticorner/contrasted{
+ dir = 4
+ },
+/obj/structure/closet/secure_closet/engineering_electrical,
+/obj/item/clothing/suit/armor/elder_atmosian,
+/obj/item/clothing/head/helmet/elder_atmosian,
+/turf/open/indestructible,
+/area/deathmatch)
+"Bh" = (
+/obj/effect/turf_decal/tile/blue/anticorner/contrasted,
+/obj/structure/table/glass,
+/obj/item/clothing/glasses/hud/health,
+/obj/item/clothing/glasses/hud/health{
+ pixel_y = 6
+ },
+/obj/machinery/light/cold/dim/directional/east,
+/turf/open/indestructible/white,
+/area/deathmatch)
+"Bu" = (
+/obj/effect/turf_decal/tile/yellow/half/contrasted,
+/obj/machinery/atmospherics/pipe/smart/manifold/green/visible,
+/turf/open/indestructible,
+/area/deathmatch)
+"BA" = (
+/obj/effect/turf_decal/tile/purple/half/contrasted{
+ dir = 1
+ },
+/obj/item/mecha_parts/mecha_equipment/drill/diamonddrill,
+/turf/open/indestructible/white,
+/area/deathmatch)
+"BH" = (
+/turf/open/chasm{
+ icon_state = "wood";
+ icon = 'icons/turf/floors.dmi';
+ base_icon_state = "wood";
+ name = "Dorms 4"
+ },
+/area/deathmatch)
+"BL" = (
+/obj/effect/turf_decal/tile/dark_blue/half/contrasted{
+ dir = 1
+ },
+/obj/structure/chair/office{
+ dir = 1
+ },
+/turf/open/indestructible/dark,
+/area/deathmatch)
+"BV" = (
+/obj/effect/decal/cleanable/garbage,
+/turf/open/indestructible,
+/area/deathmatch)
+"Dm" = (
+/obj/effect/turf_decal/tile/dark_blue/half/contrasted{
+ dir = 4
+ },
+/turf/open/indestructible/dark/textured,
+/area/deathmatch)
+"DN" = (
+/obj/effect/turf_decal/tile/yellow/half/contrasted{
+ dir = 4
+ },
+/obj/machinery/vending/engivend,
+/turf/open/indestructible,
+/area/deathmatch)
+"DV" = (
+/obj/effect/turf_decal/tile/dark_blue{
+ dir = 8
+ },
+/turf/open/indestructible/dark,
+/area/deathmatch)
+"DZ" = (
+/obj/effect/landmark/deathmatch_player_spawn,
+/obj/machinery/light/floor,
+/turf/open/floor/iron,
+/area/deathmatch)
+"El" = (
+/obj/effect/turf_decal/tile/yellow/half/contrasted{
+ dir = 4
+ },
+/obj/machinery/vending/wardrobe/engi_wardrobe,
+/obj/machinery/light/directional/east,
+/turf/open/indestructible,
+/area/deathmatch)
+"Es" = (
+/obj/effect/turf_decal/tile/yellow/half/contrasted{
+ dir = 1
+ },
+/obj/structure/extinguisher_cabinet/directional/north,
+/obj/structure/table/glass,
+/obj/item/gun/ballistic/rifle/rebarxbow/forced,
+/obj/item/ammo_casing/rebar,
+/obj/item/ammo_casing/rebar,
+/obj/item/ammo_casing/rebar,
+/obj/machinery/light/built/directional/north,
+/turf/open/indestructible,
+/area/deathmatch)
+"EC" = (
+/obj/effect/turf_decal/tile/yellow/half/contrasted,
+/obj/effect/decal/cleanable/ash/large,
+/turf/open/indestructible,
+/area/deathmatch)
+"EN" = (
+/obj/effect/turf_decal/tile/dark_blue{
+ dir = 1
+ },
+/turf/open/indestructible/dark,
+/area/deathmatch)
+"FY" = (
+/obj/effect/turf_decal/tile/blue/half/contrasted,
+/obj/machinery/sleeper/self_control{
+ dir = 1
+ },
+/turf/open/indestructible/white,
+/area/deathmatch)
+"Gl" = (
+/obj/structure/extinguisher_cabinet/directional/west,
+/obj/effect/turf_decal/tile/neutral/fourcorners,
+/obj/machinery/mecha_part_fabricator/maint,
+/turf/open/floor/iron/dark,
+/area/deathmatch)
+"Gm" = (
+/obj/effect/turf_decal/tile/dark_blue/anticorner/contrasted{
+ dir = 8
+ },
+/obj/structure/table/glass,
+/obj/machinery/recharger,
+/turf/open/indestructible/dark,
+/area/deathmatch)
+"Gp" = (
+/obj/effect/landmark/deathmatch_player_spawn,
+/obj/machinery/light/floor,
+/turf/open/indestructible/white,
+/area/deathmatch)
+"Gy" = (
+/obj/effect/turf_decal/tile/dark_blue/anticorner/contrasted{
+ dir = 1
+ },
+/obj/structure/chair/office{
+ dir = 1
+ },
+/turf/open/indestructible/dark,
+/area/deathmatch)
+"GA" = (
+/obj/effect/turf_decal/tile/yellow/half/contrasted{
+ dir = 4
+ },
+/turf/open/indestructible,
+/area/deathmatch)
+"GF" = (
+/obj/effect/turf_decal/tile/green/half/contrasted{
+ dir = 4
+ },
+/obj/structure/extinguisher_cabinet/directional/east,
+/obj/machinery/light/directional/east,
+/turf/open/indestructible,
+/area/deathmatch)
+"GY" = (
+/obj/effect/turf_decal/tile/yellow/half/contrasted{
+ dir = 4
+ },
+/obj/structure/reagent_dispensers/fueltank/large,
+/turf/open/indestructible,
+/area/deathmatch)
+"Hj" = (
+/obj/effect/turf_decal/tile/dark_blue/half/contrasted{
+ dir = 1
+ },
+/obj/structure/closet/firecloset/full,
+/turf/open/indestructible,
+/area/deathmatch)
+"Hy" = (
+/obj/effect/turf_decal/tile/blue/half/contrasted{
+ dir = 8
+ },
+/obj/machinery/cryo_cell{
+ dir = 1
+ },
+/turf/open/indestructible/white,
+/area/deathmatch)
+"Ia" = (
+/obj/effect/turf_decal/tile/green/half/contrasted{
+ dir = 1
+ },
+/turf/open/indestructible,
+/area/deathmatch)
+"Iq" = (
+/obj/effect/turf_decal/tile/dark_blue/full,
+/obj/structure/rack,
+/obj/item/gun/energy/e_gun/mini/practice_phaser,
+/obj/machinery/light/built/directional/north,
+/turf/open/indestructible/dark/smooth_large,
+/area/deathmatch)
+"Iu" = (
+/obj/effect/turf_decal/tile/purple/anticorner/contrasted{
+ dir = 1
+ },
+/obj/structure/table/reinforced,
+/obj/item/stack/sheet/iron/fifty,
+/obj/item/stack/sheet/glass/fifty,
+/obj/item/mecha_parts/mecha_equipment/weapon/energy/plasma,
+/turf/open/indestructible/white,
+/area/deathmatch)
+"Iz" = (
+/obj/effect/turf_decal/tile/yellow/half/contrasted{
+ dir = 4
+ },
+/obj/machinery/vending/tool,
+/turf/open/indestructible,
+/area/deathmatch)
+"IA" = (
+/obj/effect/spawner/random/structure/closet_private,
+/obj/item/toy/plush/awakenedplushie,
+/turf/open/floor/wood,
+/area/deathmatch)
+"IJ" = (
+/obj/effect/turf_decal/tile/yellow/half/contrasted{
+ dir = 1
+ },
+/obj/structure/closet/secure_closet/engineering_electrical,
+/turf/open/indestructible,
+/area/deathmatch)
+"IR" = (
+/obj/vehicle/ridden/janicart/upgraded,
+/obj/effect/decal/cleanable/dirt,
+/obj/item/stack/tile/iron/four{
+ pixel_y = 7;
+ pixel_x = 10
+ },
+/turf/open/indestructible/plating,
+/area/deathmatch)
+"JL" = (
+/obj/effect/turf_decal/tile/dark_blue/anticorner/contrasted,
+/obj/structure/table/glass,
+/obj/machinery/recharger,
+/turf/open/indestructible/dark,
+/area/deathmatch)
+"JS" = (
+/obj/effect/turf_decal/tile/purple{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/yellow,
+/turf/open/indestructible,
+/area/deathmatch)
+"JX" = (
+/obj/item/melee/chainofcommand/tailwhip/kitty,
+/turf/open/floor/wood,
+/area/deathmatch)
+"Ka" = (
+/obj/machinery/door/airlock{
+ id_tag = "Cabin7";
+ name = "Cabin 1"
+ },
+/turf/open/floor/wood,
+/area/deathmatch)
+"Kv" = (
+/obj/effect/turf_decal/stripes/line,
+/obj/effect/turf_decal/tile/purple/anticorner/contrasted{
+ dir = 8
+ },
+/obj/structure/mecha_wreckage/durand,
+/obj/item/mecha_parts/mecha_equipment/repair_droid,
+/turf/open/indestructible/white,
+/area/deathmatch)
+"Lk" = (
+/obj/effect/turf_decal/tile/green/anticorner/contrasted{
+ dir = 1
+ },
+/turf/open/indestructible,
+/area/deathmatch)
+"Lq" = (
+/obj/effect/turf_decal/tile/dark_blue/full,
+/obj/machinery/computer,
+/turf/open/indestructible/dark/smooth_large,
+/area/deathmatch)
+"Lr" = (
+/obj/effect/turf_decal/tile/green/anticorner/contrasted{
+ dir = 1
+ },
+/obj/structure/mop_bucket/janitorialcart,
+/obj/effect/decal/cleanable/dirt,
+/turf/open/indestructible,
+/area/deathmatch)
+"Lt" = (
+/obj/effect/turf_decal/tile/green/anticorner/contrasted,
+/turf/open/indestructible,
+/area/deathmatch)
+"LY" = (
+/obj/item/clothing/suit/pillow_suit,
+/obj/item/clothing/head/pillow_hood,
+/turf/open/floor/wood,
+/area/deathmatch)
+"Mi" = (
+/obj/structure/cable,
+/obj/structure/table/reinforced,
+/obj/effect/decal/cleanable/dirt/dust,
+/turf/open/indestructible,
+/area/deathmatch)
+"Mn" = (
+/turf/open/indestructible/white,
+/area/deathmatch)
+"ME" = (
+/obj/effect/turf_decal/tile/purple/half/contrasted{
+ dir = 1
+ },
+/obj/structure/table/reinforced,
+/obj/item/clothing/head/collectable/welding,
+/obj/item/sticker/syndicate/flash{
+ pixel_x = 3
+ },
+/obj/item/sticker/syndicate/flash{
+ pixel_x = -4
+ },
+/turf/open/indestructible/white,
+/area/deathmatch)
+"MG" = (
+/obj/effect/turf_decal/tile/blue/anticorner/contrasted{
+ dir = 4
+ },
+/obj/structure/table/glass,
+/obj/item/clothing/glasses/hud/health,
+/obj/item/clothing/glasses/hud/health{
+ pixel_y = 6
+ },
+/turf/open/indestructible/white,
+/area/deathmatch)
+"Nb" = (
+/obj/machinery/light/floor,
+/turf/open/indestructible/white,
+/area/deathmatch)
+"Ne" = (
+/obj/effect/turf_decal/tile/purple/full,
+/obj/effect/turf_decal/tile/purple/full,
+/obj/effect/turf_decal/tile/purple/full,
+/obj/effect/turf_decal/tile/purple/full,
+/obj/structure/table/reinforced/plasmarglass,
+/obj/machinery/door/window/right/directional/north,
+/turf/open/indestructible/white/smooth_large,
+/area/deathmatch)
+"Nr" = (
+/obj/machinery/vending/medical,
+/turf/open/indestructible/white,
+/area/deathmatch)
+"Ns" = (
+/obj/structure/table,
+/obj/item/reagent_containers/cup/bucket,
+/obj/item/mop,
+/turf/open/indestructible,
+/area/deathmatch)
+"Nv" = (
+/obj/effect/turf_decal/tile/dark_blue/half/contrasted{
+ dir = 4
+ },
+/obj/machinery/light/small/blacklight/directional/east,
+/turf/open/indestructible/dark/textured,
+/area/deathmatch)
+"ND" = (
+/obj/effect/turf_decal/tile/dark_blue/fourcorners,
+/obj/machinery/computer{
+ dir = 8
+ },
+/turf/open/indestructible/dark,
+/area/deathmatch)
+"Oa" = (
+/obj/effect/turf_decal/tile/yellow/anticorner/contrasted{
+ dir = 1
+ },
+/obj/structure/reagent_dispensers/fueltank,
+/turf/open/indestructible,
+/area/deathmatch)
+"Oo" = (
+/obj/effect/turf_decal/tile/dark_blue/half/contrasted{
+ dir = 1
+ },
+/turf/open/indestructible/dark,
+/area/deathmatch)
+"Os" = (
+/obj/effect/turf_decal/tile/yellow/anticorner/contrasted{
+ dir = 8
+ },
+/turf/open/indestructible,
+/area/deathmatch)
+"Ot" = (
+/obj/effect/turf_decal/tile/dark_blue,
+/turf/open/indestructible/dark,
+/area/deathmatch)
+"OF" = (
+/obj/effect/turf_decal/tile/dark_blue/full,
+/obj/structure/rack,
+/obj/item/cane,
+/obj/structure/fireaxecabinet/directional/south,
+/obj/machinery/light/built/directional/south,
+/turf/open/indestructible/dark/smooth_large,
+/area/deathmatch)
+"ON" = (
+/obj/effect/turf_decal/tile/blue/full,
+/obj/machinery/door/airlock/multi_tile/public/glass{
+ dir = 8
+ },
+/turf/open/indestructible/white/smooth_large,
+/area/deathmatch)
+"Ps" = (
+/obj/structure/table/reinforced,
+/turf/open/indestructible,
+/area/deathmatch)
+"Qo" = (
+/obj/effect/turf_decal/tile/purple/half/contrasted,
+/mob/living/basic/bot/medbot,
+/obj/item/mecha_parts/mecha_equipment/gravcatapult,
+/turf/open/indestructible/white,
+/area/deathmatch)
+"QM" = (
+/obj/effect/decal/cleanable/dirt/dust,
+/turf/open/indestructible,
+/area/deathmatch)
+"RX" = (
+/obj/structure/table,
+/obj/effect/decal/cleanable/dirt,
+/obj/item/grenade/chem_grenade/cleaner{
+ pixel_x = -1;
+ pixel_y = 3
+ },
+/obj/item/grenade/chem_grenade/cleaner{
+ pixel_x = -7;
+ pixel_y = 12
+ },
+/obj/item/grenade/chem_grenade/cleaner,
+/obj/item/toy/plush/lizard_plushie,
+/turf/open/indestructible/plating,
+/area/deathmatch)
+"RY" = (
+/obj/effect/turf_decal/stripes/line{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/purple/anticorner/contrasted{
+ dir = 8
+ },
+/obj/item/mecha_parts/mecha_equipment/extinguisher,
+/turf/open/indestructible/white,
+/area/deathmatch)
+"Sh" = (
+/obj/structure/lattice/catwalk,
+/obj/structure/cable,
+/turf/open/space/basic,
+/area/deathmatch)
+"Sm" = (
+/obj/structure/table/reinforced,
+/obj/item/grenade/gas_crystal/crystal_foam,
+/turf/open/indestructible,
+/area/deathmatch)
+"Sn" = (
+/obj/effect/turf_decal/tile/blue/anticorner/contrasted{
+ dir = 8
+ },
+/obj/structure/table/optable,
+/obj/item/reagent_containers/syringe/contraband/methamphetamine,
+/obj/effect/decal/cleanable/blood,
+/turf/open/indestructible/white,
+/area/deathmatch)
+"Sy" = (
+/obj/effect/turf_decal/tile/purple/half/contrasted{
+ dir = 1
+ },
+/obj/machinery/computer,
+/turf/open/indestructible/white,
+/area/deathmatch)
+"To" = (
+/obj/effect/turf_decal/tile/dark_blue/half/contrasted{
+ dir = 4
+ },
+/obj/structure/chair/office{
+ dir = 4
+ },
+/turf/open/indestructible/dark,
+/area/deathmatch)
+"TZ" = (
+/obj/structure/cable,
+/turf/open/floor/plating/airless,
+/area/deathmatch)
+"Uj" = (
+/obj/effect/turf_decal/tile/green/half/contrasted{
+ dir = 4
+ },
+/obj/item/kirbyplants/random,
+/turf/open/indestructible,
+/area/deathmatch)
+"Ur" = (
+/obj/machinery/washing_machine,
+/obj/effect/turf_decal/tile/blue/opposingcorners{
+ dir = 1
+ },
+/turf/open/floor/iron/cafeteria,
+/area/deathmatch)
+"UD" = (
+/obj/effect/turf_decal/tile/green,
+/obj/effect/turf_decal/tile/dark_blue/half/contrasted{
+ dir = 1
+ },
+/turf/open/indestructible,
+/area/deathmatch)
+"UH" = (
+/obj/structure/table,
+/obj/effect/spawner/random/entertainment/deck,
+/turf/open/indestructible,
+/area/deathmatch)
+"Vl" = (
+/turf/open/indestructible,
+/area/deathmatch)
+"Vp" = (
+/obj/effect/turf_decal/tile/dark_blue/half/contrasted,
+/obj/item/kirbyplants/photosynthetic,
+/turf/open/indestructible/dark,
+/area/deathmatch)
+"VE" = (
+/obj/effect/turf_decal/tile/green/half/contrasted{
+ dir = 4
+ },
+/obj/item/kirbyplants/random/dead,
+/obj/effect/decal/cleanable/vomit,
+/turf/open/indestructible,
+/area/deathmatch)
+"Wf" = (
+/obj/effect/turf_decal/tile/yellow/half/contrasted{
+ dir = 1
+ },
+/obj/structure/table/glass,
+/obj/item/storage/medkit/fire,
+/obj/item/toy/plush/plasmamanplushie,
+/turf/open/indestructible,
+/area/deathmatch)
+"Wy" = (
+/obj/machinery/vending/drugs,
+/turf/open/indestructible/white,
+/area/deathmatch)
+"WE" = (
+/obj/effect/turf_decal/tile/green/half/contrasted{
+ dir = 4
+ },
+/obj/effect/decal/cleanable/dirt/dust,
+/turf/open/indestructible,
+/area/deathmatch)
+"XZ" = (
+/obj/effect/turf_decal/tile/yellow/half/contrasted{
+ dir = 8
+ },
+/turf/open/indestructible,
+/area/deathmatch)
+"Yb" = (
+/obj/effect/turf_decal/tile/yellow/anticorner/contrasted,
+/obj/structure/closet/firecloset/full,
+/turf/open/indestructible,
+/area/deathmatch)
+"Yo" = (
+/mob/living/basic/cat_butcherer,
+/obj/structure/bed,
+/obj/item/bedsheet/runtime,
+/obj/machinery/light/small/blacklight/directional/north,
+/turf/open/floor/wood,
+/area/deathmatch)
+"Yr" = (
+/mob/living/basic/alien/maid,
+/obj/structure/bed,
+/obj/effect/spawner/random/bedsheet,
+/obj/effect/decal/cleanable/vomit,
+/obj/machinery/light/small/blacklight/directional/north,
+/turf/open/floor/wood,
+/area/deathmatch)
+"YJ" = (
+/obj/effect/turf_decal/tile/purple/half/contrasted{
+ dir = 4
+ },
+/obj/machinery/rnd/destructive_analyzer,
+/turf/open/indestructible/white,
+/area/deathmatch)
+"YQ" = (
+/obj/effect/turf_decal/tile/dark_blue/half/contrasted{
+ dir = 8
+ },
+/obj/structure/chair/office{
+ dir = 8
+ },
+/turf/open/indestructible/dark,
+/area/deathmatch)
+"Za" = (
+/obj/effect/spawner/structure/window/reinforced/indestructible,
+/turf/open/indestructible/plating,
+/area/deathmatch)
+"Zb" = (
+/obj/effect/turf_decal/tile/blue/half/contrasted{
+ dir = 8
+ },
+/turf/open/indestructible,
+/area/deathmatch)
+"ZO" = (
+/obj/effect/turf_decal/tile/green,
+/turf/open/indestructible,
+/area/deathmatch)
+
+(1,1,1) = {"
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+TZ
+rV
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+"}
+(2,1,1) = {"
+jw
+jw
+jw
+jw
+jw
+vq
+vq
+vq
+vq
+Sh
+vq
+vq
+vq
+vq
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+"}
+(3,1,1) = {"
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+rV
+Sh
+rV
+rV
+Za
+Za
+Za
+Za
+Za
+Za
+Za
+Za
+rV
+rV
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+"}
+(4,1,1) = {"
+jw
+jw
+jw
+jw
+jw
+vq
+vq
+vq
+vq
+Sh
+vq
+zJ
+zJ
+mK
+cy
+st
+dA
+Hy
+wG
+zJ
+zJ
+rV
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+"}
+(5,1,1) = {"
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+rV
+Sh
+rV
+Za
+hC
+Mn
+yq
+yq
+yq
+yq
+Mn
+Sn
+Za
+rV
+rV
+rV
+rV
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+"}
+(6,1,1) = {"
+jw
+jw
+jw
+jw
+jw
+jw
+vq
+vq
+vq
+Sh
+vq
+Za
+bL
+Mn
+Mn
+Mn
+wA
+xj
+xj
+iM
+zJ
+zJ
+zJ
+Za
+zJ
+zJ
+jw
+jw
+jw
+jw
+jw
+jw
+"}
+(7,1,1) = {"
+jw
+jw
+rV
+rV
+rV
+jw
+jw
+jw
+jw
+Sh
+jw
+Za
+wb
+Mn
+Mn
+by
+Nr
+by
+Mn
+es
+zJ
+Lr
+rP
+uX
+IR
+zJ
+rV
+jw
+jw
+jw
+jw
+jw
+"}
+(8,1,1) = {"
+jw
+rV
+zJ
+Za
+Za
+Za
+zJ
+rV
+jw
+Sh
+jw
+Za
+AZ
+Mn
+Mn
+Mn
+Wy
+Mn
+Mn
+xT
+zJ
+wM
+BV
+pL
+dv
+Za
+rV
+jw
+jw
+jw
+jw
+jw
+"}
+(9,1,1) = {"
+rV
+zJ
+zJ
+tR
+sx
+cd
+zJ
+zJ
+rV
+Sh
+jw
+Za
+iu
+Mn
+Mn
+Mn
+Nb
+Mn
+Mn
+FY
+zJ
+Ns
+ZO
+VE
+hR
+zJ
+rV
+rV
+jw
+jw
+jw
+jw
+"}
+(10,1,1) = {"
+rV
+zJ
+Lq
+Gy
+YQ
+eW
+sL
+zJ
+rV
+Sh
+rV
+Za
+MG
+yD
+qM
+qM
+aA
+qM
+qM
+Bh
+zJ
+RX
+yU
+zJ
+xL
+zJ
+zJ
+Za
+zJ
+jw
+jw
+jw
+"}
+(11,1,1) = {"
+rV
+Za
+nf
+gI
+jn
+gI
+Gm
+zJ
+zJ
+zJ
+zJ
+zJ
+zJ
+zJ
+zs
+ON
+zJ
+zs
+ON
+zJ
+zJ
+zJ
+hk
+Za
+Iu
+Kv
+Gl
+cs
+zJ
+jw
+jw
+jw
+"}
+(12,1,1) = {"
+jw
+Za
+jm
+ix
+gI
+gI
+zK
+fP
+nb
+fP
+eO
+wd
+pD
+pD
+sW
+Zb
+Zb
+Zb
+Zb
+ee
+pJ
+ho
+vm
+Za
+ME
+Ag
+rq
+hG
+zJ
+jw
+jw
+jw
+"}
+(13,1,1) = {"
+rV
+zJ
+Iq
+Oo
+gI
+Ot
+fg
+fP
+Nv
+fP
+iK
+QM
+Vl
+Vl
+Vl
+Vl
+Vl
+Vl
+Vl
+Vl
+Vl
+Vl
+vI
+Ne
+BA
+uQ
+em
+RY
+Za
+rV
+jw
+jw
+"}
+(14,1,1) = {"
+rV
+Za
+Lq
+BL
+gI
+Vp
+OF
+zJ
+zJ
+zJ
+Hj
+Vl
+Ac
+Vl
+Vl
+Vl
+Vl
+Vl
+Vl
+Ac
+Vl
+Vl
+zg
+Za
+Sy
+Mn
+Gp
+qF
+Za
+rV
+jw
+jw
+"}
+(15,1,1) = {"
+rV
+zJ
+Iq
+Oo
+gI
+DV
+ju
+fP
+oD
+fP
+iK
+Vl
+Vl
+Vl
+Vl
+Vl
+Vl
+Vl
+Vl
+Vl
+Vl
+Vl
+JS
+fV
+oq
+Mn
+Mn
+Qo
+Za
+rV
+jw
+jw
+"}
+(16,1,1) = {"
+jw
+Za
+mn
+EN
+gI
+gI
+zK
+fP
+Dm
+fP
+UD
+wj
+GF
+WE
+Uj
+aD
+ko
+zZ
+xe
+GA
+GA
+vB
+Yb
+Za
+ru
+jR
+YJ
+nT
+zJ
+rV
+rV
+jw
+"}
+(17,1,1) = {"
+rV
+Za
+yy
+gI
+jn
+gI
+JL
+zJ
+zJ
+zJ
+zJ
+hk
+zJ
+hk
+zJ
+zJ
+zJ
+zJ
+Za
+mo
+Za
+AE
+Za
+zJ
+zJ
+Za
+Za
+Za
+zJ
+zJ
+rV
+jw
+"}
+(18,1,1) = {"
+rV
+zJ
+Lq
+mO
+To
+nQ
+bX
+zJ
+cl
+sJ
+zJ
+Lk
+vb
+vm
+zJ
+sJ
+rO
+zJ
+Oa
+XZ
+XZ
+XZ
+XZ
+XZ
+Os
+dB
+dB
+dB
+dB
+zJ
+rV
+jw
+"}
+(19,1,1) = {"
+rV
+zJ
+zJ
+qV
+ND
+zt
+zJ
+zJ
+lF
+sJ
+Ka
+Ia
+Ac
+dv
+kY
+BH
+IA
+zJ
+Wf
+Vl
+Vl
+Vl
+Vl
+Vl
+EC
+dB
+dB
+dB
+dB
+zJ
+jw
+jw
+"}
+(20,1,1) = {"
+jw
+rV
+zJ
+Za
+Za
+Za
+zJ
+zJ
+zJ
+zJ
+zJ
+Ia
+Vl
+dv
+zJ
+zJ
+zJ
+zJ
+Es
+Vl
+Sm
+DZ
+Ps
+Vl
+vT
+zJ
+zJ
+zJ
+zJ
+zJ
+jw
+jw
+"}
+(21,1,1) = {"
+jw
+jw
+jw
+jw
+rV
+rV
+rV
+zJ
+Yo
+JX
+zJ
+Ia
+uq
+dv
+zJ
+sn
+AQ
+zJ
+su
+Vl
+pH
+zx
+Mi
+Vl
+eE
+zJ
+rV
+rV
+rV
+jw
+jw
+jw
+"}
+(22,1,1) = {"
+jw
+jw
+vq
+jw
+jw
+vq
+rV
+zJ
+gM
+sJ
+Ka
+Ia
+UH
+dv
+Ka
+sJ
+lF
+zJ
+IJ
+iV
+Vl
+Vl
+Vl
+oy
+Bu
+zJ
+rV
+rV
+jw
+jw
+jw
+jw
+"}
+(23,1,1) = {"
+jw
+jw
+vq
+rV
+rV
+vq
+jw
+zJ
+zJ
+zJ
+zJ
+Ia
+Vl
+dv
+zJ
+zJ
+zJ
+zJ
+Bc
+Iz
+DN
+El
+GY
+oN
+hA
+zJ
+rV
+jw
+jw
+jw
+jw
+jw
+"}
+(24,1,1) = {"
+jw
+fA
+Sh
+Sh
+Sh
+Sh
+Sh
+zJ
+Yr
+LY
+zJ
+Ia
+Ac
+dv
+zJ
+is
+gH
+zJ
+zJ
+Za
+Za
+zJ
+Za
+Za
+zJ
+zJ
+jw
+jw
+jw
+jw
+jw
+jw
+"}
+(25,1,1) = {"
+jw
+rV
+vq
+rV
+rV
+vq
+jw
+zJ
+lF
+fm
+Ka
+zw
+Ur
+Lt
+Ka
+sJ
+lF
+zJ
+rV
+rV
+jw
+Sh
+rV
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+"}
+(26,1,1) = {"
+jw
+jw
+vq
+jw
+jw
+vq
+rV
+zJ
+Za
+zJ
+zJ
+zJ
+Za
+zJ
+zJ
+zJ
+Za
+zJ
+rV
+vq
+vq
+Sh
+vq
+vq
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+"}
+(27,1,1) = {"
+jw
+jw
+jw
+jw
+jw
+jw
+rV
+rV
+rV
+rV
+rV
+jw
+jw
+jw
+jw
+rV
+rV
+rV
+rV
+jw
+rV
+Sh
+rV
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+"}
+(28,1,1) = {"
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+rV
+Sh
+rV
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+"}
+(29,1,1) = {"
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+vq
+vq
+Sh
+vq
+vq
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+"}
+(30,1,1) = {"
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+rV
+TZ
+rV
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+"}
+(31,1,1) = {"
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+rV
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+"}
+(32,1,1) = {"
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+jw
+"}
diff --git a/_maps/map_files/Birdshot/birdshot.dmm b/_maps/map_files/Birdshot/birdshot.dmm
index 00961dbd7f5d6..2087d98e0ee5f 100644
--- a/_maps/map_files/Birdshot/birdshot.dmm
+++ b/_maps/map_files/Birdshot/birdshot.dmm
@@ -41227,9 +41227,9 @@
/turf/open/floor/iron/dark/small,
/area/station/security/checkpoint/customs)
"ohN" = (
-/obj/item/kirbyplants/random,
/obj/item/radio/intercom/directional/north,
/obj/machinery/firealarm/directional/west,
+/obj/machinery/vending/cytopro,
/turf/open/floor/iron/white,
/area/station/science/cytology)
"oig" = (
@@ -52468,6 +52468,7 @@
/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{
dir = 8
},
+/obj/item/kirbyplants/random,
/turf/open/floor/iron/white,
/area/station/science/cytology)
"rYx" = (
@@ -53177,6 +53178,7 @@
name = "Detective Requests Console"
},
/obj/machinery/light/small/directional/west,
+/obj/structure/detectiveboard/directional/west,
/turf/open/floor/wood,
/area/station/security/detectives_office)
"smf" = (
diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm
index 8959abab5589d..39d7cd24bdd2e 100644
--- a/_maps/map_files/Deltastation/DeltaStation2.dmm
+++ b/_maps/map_files/Deltastation/DeltaStation2.dmm
@@ -24906,6 +24906,7 @@
/obj/effect/turf_decal/tile/purple/half/contrasted{
dir = 1
},
+/obj/machinery/vending/cytopro,
/turf/open/floor/iron,
/area/station/science/xenobiology)
"gfR" = (
diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm
index b88647d4934a0..a47e7176c77eb 100644
--- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm
+++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm
@@ -293,6 +293,7 @@
dir = 8
},
/obj/machinery/status_display/ai/directional/north,
+/obj/structure/closet/secure_closet/cytology,
/turf/open/floor/iron/smooth_large,
/area/station/science/cytology)
"afz" = (
@@ -5684,7 +5685,6 @@
dir = 4
},
/obj/effect/decal/cleanable/dirt,
-/obj/item/trash/waffles,
/turf/open/floor/plating,
/area/station/maintenance/port/aft)
"bGm" = (
@@ -69816,7 +69816,7 @@
/area/icemoon/underground/explored)
"uNH" = (
/obj/structure/railing,
-/obj/structure/closet/secure_closet/cytology,
+/obj/machinery/vending/cytopro,
/turf/open/floor/iron/smooth_large,
/area/station/science/cytology)
"uNV" = (
@@ -73744,6 +73744,7 @@
pixel_x = -5
},
/obj/structure/cable,
+/obj/structure/detectiveboard/directional/west,
/turf/open/floor/carpet,
/area/station/security/detectives_office)
"vZS" = (
diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm
index a719ae4c67114..a3b90c665b221 100644
--- a/_maps/map_files/MetaStation/MetaStation.dmm
+++ b/_maps/map_files/MetaStation/MetaStation.dmm
@@ -20128,7 +20128,6 @@
/area/station/cargo/sorting)
"hlj" = (
/obj/structure/table/wood,
-/obj/structure/secure_safe/directional/east,
/obj/machinery/computer/security/wooden_tv{
pixel_x = 3;
pixel_y = 2
@@ -20138,6 +20137,7 @@
name = "detective's office shutters control";
req_access = list("detective")
},
+/obj/structure/detectiveboard/directional/east,
/turf/open/floor/carpet,
/area/station/security/detectives_office)
"hlq" = (
@@ -26583,13 +26583,13 @@
/turf/open/floor/iron/dark,
/area/station/engineering/atmos)
"juH" = (
-/obj/item/kirbyplants/random,
/obj/machinery/firealarm/directional/west{
pixel_y = -9
},
/obj/effect/turf_decal/tile/purple/half/contrasted{
dir = 8
},
+/obj/machinery/vending/cytopro,
/turf/open/floor/iron/white,
/area/station/science/cytology)
"juJ" = (
@@ -50063,6 +50063,11 @@
},
/turf/open/floor/iron,
/area/station/engineering/break_room)
+"rJh" = (
+/obj/structure/window/reinforced/spawner/directional/north,
+/obj/structure/secure_safe/directional/west,
+/turf/open/floor/iron/grimy,
+/area/station/security/detectives_office)
"rJk" = (
/obj/machinery/door/airlock{
name = "Theater Backstage"
@@ -54523,6 +54528,7 @@
/obj/machinery/atmospherics/components/binary/pump{
dir = 4
},
+/obj/item/kirbyplants/random,
/turf/open/floor/iron/white,
/area/station/science/cytology)
"tmq" = (
@@ -99518,7 +99524,7 @@ sWV
sWV
sWV
qJb
-fEn
+rJh
hME
olw
olw
diff --git a/_maps/map_files/NorthStar/north_star.dmm b/_maps/map_files/NorthStar/north_star.dmm
index b4168c7d54d93..0d591a0ea0e1b 100644
--- a/_maps/map_files/NorthStar/north_star.dmm
+++ b/_maps/map_files/NorthStar/north_star.dmm
@@ -34444,6 +34444,7 @@
dir = 8
},
/obj/item/radio/intercom/directional/north,
+/obj/structure/detectiveboard/directional/east,
/turf/open/floor/carpet,
/area/station/security/detectives_office)
"iWW" = (
@@ -52447,6 +52448,7 @@
},
/obj/structure/cable,
/obj/machinery/power/apc/auto_name/directional/west,
+/obj/machinery/vending/cytopro,
/turf/open/floor/iron,
/area/station/science/cytology)
"nxm" = (
diff --git a/_maps/map_files/debug/runtimestation.dmm b/_maps/map_files/debug/runtimestation.dmm
index 6c38b33783521..dfab71ec7974e 100644
--- a/_maps/map_files/debug/runtimestation.dmm
+++ b/_maps/map_files/debug/runtimestation.dmm
@@ -10,16 +10,22 @@
/turf/open/space,
/area/space/nearstation)
"ad" = (
-/turf/closed/wall/r_wall,
-/area/station/maintenance/department/bridge)
+/obj/effect/turf_decal/stripes/line,
+/obj/structure/transit_tube/horizontal,
+/turf/open/floor/iron,
+/area/station/engineering/gravity_generator)
"ae" = (
/obj/structure/lattice,
/obj/structure/grille,
/turf/open/space,
/area/space/nearstation)
"af" = (
-/turf/open/floor/plating,
-/area/station/maintenance/department/bridge)
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
+/obj/structure/transit_tube/crossing/horizontal,
+/turf/open/floor/iron,
+/area/station/engineering/gravity_generator)
"ag" = (
/turf/closed/wall/r_wall,
/area/station/security/brig)
@@ -129,13 +135,7 @@
/turf/open/floor/iron,
/area/station/engineering/main)
"aX" = (
-/obj/machinery/door/airlock/engineering/glass{
- name = "Gravity Generator"
- },
-/obj/effect/mapping_helpers/airlock/cyclelink_helper{
- dir = 8
- },
-/turf/open/floor/iron/dark,
+/turf/open/floor/iron,
/area/station/engineering/gravity_generator)
"aY" = (
/obj/machinery/light/directional/east,
@@ -318,9 +318,9 @@
/turf/open/floor/iron,
/area/station/security/brig)
"bY" = (
-/obj/effect/spawner/structure/window/reinforced,
-/turf/open/floor/plating,
-/area/station/maintenance/department/bridge)
+/obj/machinery/light/floor,
+/turf/open/floor/iron,
+/area/station/engineering/gravity_generator)
"bZ" = (
/obj/effect/spawner/structure/window/reinforced,
/turf/open/floor/plating,
@@ -593,6 +593,13 @@
},
/turf/open/floor/iron,
/area/station/construction)
+"dN" = (
+/obj/machinery/navbeacon{
+ location = "1-Southwest";
+ codes_txt = "patrol;next_patrol=2-Northwest"
+ },
+/turf/open/floor/iron,
+/area/station/commons/storage/primary)
"dP" = (
/obj/effect/turf_decal/stripes/line{
dir = 1
@@ -1090,8 +1097,7 @@
/area/station/security/brig)
"gW" = (
/obj/effect/spawner/structure/window/reinforced,
-/obj/structure/sign/warning/radiation/rad_area/directional/north,
-/turf/open/floor/plating,
+/turf/closed/wall/r_wall,
/area/station/engineering/gravity_generator)
"hm" = (
/obj/machinery/airalarm/directional/west,
@@ -1116,6 +1122,13 @@
},
/turf/open/floor/iron,
/area/station/medical/chemistry)
+"hS" = (
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
+/obj/structure/transit_tube/station,
+/turf/open/floor/iron,
+/area/station/engineering/gravity_generator)
"ii" = (
/obj/effect/turf_decal/stripes/line{
dir = 4
@@ -1307,6 +1320,13 @@
},
/turf/open/floor/iron,
/area/station/cargo/storage)
+"pY" = (
+/obj/machinery/navbeacon{
+ codes_txt = "patrol;next_patrol=1-Southwest";
+ location = "4-Southeast"
+ },
+/turf/open/floor/iron,
+/area/station/commons/storage/primary)
"pZ" = (
/obj/machinery/light/directional/north,
/obj/machinery/camera/directional/north,
@@ -1327,6 +1347,13 @@
/obj/effect/turf_decal/stripes/full,
/turf/open/floor/iron/dark,
/area/station/cargo/storage)
+"qq" = (
+/obj/effect/turf_decal/stripes/line{
+ dir = 5
+ },
+/obj/structure/transit_tube/station/reverse,
+/turf/open/floor/iron,
+/area/station/engineering/gravity_generator)
"qv" = (
/obj/structure/cable,
/turf/open/floor/iron,
@@ -1351,6 +1378,14 @@
"qQ" = (
/turf/open/floor/engine,
/area/station/cargo/miningoffice)
+"qR" = (
+/obj/effect/landmark/start,
+/obj/machinery/navbeacon{
+ codes_txt = "delivery;dir=4";
+ location = "Center"
+ },
+/turf/open/floor/iron,
+/area/station/commons/storage/primary)
"rh" = (
/obj/machinery/door/airlock,
/obj/structure/cable,
@@ -1486,6 +1521,12 @@
/obj/machinery/door/airlock,
/turf/open/floor/plating,
/area/station/commons/storage/primary)
+"vw" = (
+/obj/machinery/door/airlock/engineering/glass{
+ name = "Gravity Generator"
+ },
+/turf/open/floor/iron,
+/area/station/engineering/gravity_generator)
"vy" = (
/obj/effect/turf_decal/stripes/corner{
dir = 4
@@ -1562,9 +1603,23 @@
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/turf/open/floor/iron,
/area/station/cargo/miningoffice)
+"wR" = (
+/obj/machinery/navbeacon{
+ codes_txt = "patrol;next_patrol=3-Northeast";
+ location = "2-Northwest"
+ },
+/turf/open/floor/iron,
+/area/station/commons/storage/primary)
"wU" = (
/turf/closed/wall/r_wall,
/area/station/science/explab)
+"xq" = (
+/obj/effect/turf_decal/stripes/line{
+ dir = 6
+ },
+/obj/structure/transit_tube/station/dispenser/reverse/flipped,
+/turf/open/floor/iron,
+/area/station/engineering/gravity_generator)
"xD" = (
/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4,
/obj/effect/turf_decal/tile/blue/half/contrasted,
@@ -2011,6 +2066,13 @@
/obj/effect/turf_decal/tile/neutral/fourcorners,
/turf/open/floor/iron/dark,
/area/station/engineering/gravity_generator)
+"JJ" = (
+/obj/machinery/navbeacon{
+ codes_txt = "patrol;next_patrol=4-Southeast";
+ location = "3-Northeast"
+ },
+/turf/open/floor/iron,
+/area/station/commons/storage/primary)
"JV" = (
/obj/machinery/camera/autoname/directional/east,
/obj/effect/turf_decal/stripes/line{
@@ -2040,9 +2102,17 @@
/turf/open/floor/plating,
/area/station/engineering/atmos)
"Lb" = (
-/obj/machinery/door/airlock,
-/turf/open/floor/plating,
-/area/station/medical/medbay)
+/obj/effect/turf_decal/stripes/line{
+ dir = 1
+ },
+/obj/structure/transit_tube/station/reverse/flipped{
+ dir = 1
+ },
+/obj/structure/transit_tube_pod{
+ dir = 4
+ },
+/turf/open/floor/iron,
+/area/station/engineering/gravity_generator)
"Lq" = (
/obj/effect/turf_decal/stripes/full,
/obj/machinery/door/airlock/external/glass/ruin{
@@ -2243,6 +2313,13 @@
},
/turf/open/floor/iron/white/corner,
/area/station/medical/medbay)
+"Qi" = (
+/obj/effect/turf_decal/stripes/line,
+/obj/structure/transit_tube/station/dispenser/reverse{
+ dir = 1
+ },
+/turf/open/floor/iron,
+/area/station/engineering/gravity_generator)
"Qu" = (
/obj/docking_port/stationary/mining_home{
dir = 8
@@ -2305,6 +2382,7 @@
dir = 5
},
/obj/structure/closet/radiation,
+/obj/structure/sign/warning/radiation/rad_area/directional/north,
/turf/open/floor/iron,
/area/station/engineering/gravity_generator)
"RD" = (
@@ -2382,9 +2460,6 @@
/obj/machinery/door/airlock/engineering/glass{
name = "Gravity Generator"
},
-/obj/effect/mapping_helpers/airlock/cyclelink_helper{
- dir = 4
- },
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/structure/cable,
/turf/open/floor/iron,
@@ -7355,14 +7430,14 @@ bE
cS
qv
dJ
+wR
dJ
dJ
dJ
dJ
dJ
dJ
-dJ
-dJ
+dN
dJ
dJ
cS
@@ -7520,8 +7595,8 @@ aa
aa
aa
aa
-ad
-ad
+ak
+ak
ak
ak
ak
@@ -7612,8 +7687,8 @@ aa
aa
aa
aa
-ad
-af
+aa
+aa
ak
Va
Bp
@@ -7704,13 +7779,13 @@ aa
aa
aa
aa
-bY
-af
+aa
+aa
ak
Rx
-bh
-bh
-bh
+aX
+aX
+aX
br
ak
bS
@@ -7726,7 +7801,7 @@ dt
dJ
dD
dJ
-dI
+qR
dJ
XZ
dJ
@@ -7796,14 +7871,14 @@ aa
aa
aa
aa
-ad
-af
+aa
+aa
ak
gW
-aI
+Lb
aX
-aI
-aI
+Qi
+ak
ak
Ly
EX
@@ -7888,14 +7963,14 @@ aa
aa
aa
aa
-ad
+aa
+aa
+aa
+aI
af
-ak
-av
-av
-av
-av
-av
+aX
+ad
+aI
by
by
ck
@@ -7980,14 +8055,14 @@ aa
aa
aa
aa
-ad
+aa
+aa
+aa
+aI
af
-ak
-av
-MN
-MN
-MN
-av
+aX
+ad
+aI
by
Ot
cl
@@ -8072,14 +8147,14 @@ aa
aa
aa
aa
-ad
+aa
+aa
+aa
+aI
af
-ak
-dT
-MN
-av
-Jp
-av
+aX
+ad
+aI
by
DD
cm
@@ -8091,14 +8166,14 @@ Sj
by
jk
dJ
-dJ
+JJ
dJ
dJ
yl
dJ
dJ
dJ
-dJ
+pY
dJ
dJ
cS
@@ -8164,14 +8239,14 @@ aa
aa
aa
aa
-ad
+aa
+aa
+aa
+aI
af
-ak
-av
-MN
-MN
-MN
-av
+aX
+ad
+aI
by
ER
cm
@@ -8256,14 +8331,14 @@ aa
aa
aa
aa
-ad
+aa
+aa
+aa
+aI
af
-ak
-av
-av
-aY
-av
-av
+bY
+ad
+aI
by
jZ
cm
@@ -8348,14 +8423,14 @@ aa
aa
aa
aa
-ad
+aa
+aa
+aa
+aI
af
-ak
-ak
-ak
-ak
-ak
-ak
+aX
+ad
+aI
by
er
cm
@@ -8440,15 +8515,15 @@ aa
aa
aa
aa
-ad
-af
-af
-af
-af
-af
-af
+aa
+aa
+aa
+aI
af
-Lb
+aX
+ad
+aI
+by
wk
PK
PK
@@ -8532,14 +8607,14 @@ aa
aa
aa
aa
+aa
+aa
+aa
+aI
+af
+aX
ad
-ad
-ad
-ad
-ad
-ad
-ad
-ad
+aI
by
by
by
@@ -8627,11 +8702,11 @@ aa
fg
fg
fg
-fg
-fg
-fg
-fg
-fg
+aI
+af
+aX
+ad
+aI
aa
aa
ck
@@ -8719,11 +8794,11 @@ aa
aa
aa
aa
-aa
-aa
-aa
-aa
-aa
+aI
+hS
+bY
+ad
+aI
aa
aa
ck
@@ -8811,11 +8886,11 @@ aa
aa
aa
aa
-aa
-aa
-aa
-aa
-aa
+aI
+af
+aX
+ad
+aI
aa
aa
by
@@ -8903,11 +8978,11 @@ aa
aa
aa
aa
-aa
-aa
-aa
-aa
-aa
+aI
+af
+aX
+ad
+aI
aa
aa
aa
@@ -8995,11 +9070,11 @@ aa
aa
aa
aa
-aa
-aa
-aa
-aa
-aa
+aI
+af
+aX
+ad
+aI
aa
aa
aa
@@ -9087,11 +9162,11 @@ aa
aa
aa
aa
-aa
-aa
-aa
-aa
-aa
+aI
+af
+aX
+ad
+aI
aa
aa
aa
@@ -9179,11 +9254,11 @@ aa
aa
aa
aa
-aa
-aa
-aa
-aa
-aa
+aI
+af
+bY
+ad
+aI
aa
aa
aa
@@ -9271,11 +9346,11 @@ aa
aa
aa
aa
-aa
-aa
-aa
-aa
-aa
+aI
+af
+aX
+ad
+aI
aa
aa
aa
@@ -9363,11 +9438,11 @@ aa
aa
aa
aa
-aa
-aa
-aa
-aa
-aa
+aI
+af
+aX
+ad
+aI
aa
aa
aa
@@ -9455,11 +9530,11 @@ aa
aa
aa
aa
-aa
-aa
-aa
-aa
-aa
+aI
+af
+aX
+ad
+aI
aa
aa
aa
@@ -9547,11 +9622,11 @@ aa
aa
aa
aa
-aa
-aa
-aa
-aa
-aa
+aI
+af
+aX
+ad
+aI
aa
aa
aa
@@ -9639,11 +9714,11 @@ aa
aa
aa
aa
-aa
-aa
-aa
-aa
-aa
+ak
+qq
+bh
+xq
+ak
aa
aa
aa
@@ -9730,13 +9805,13 @@ aa
aa
aa
aa
-aa
-aa
-aa
-aa
-aa
-aa
-aa
+ak
+ak
+aI
+vw
+aI
+ak
+ak
aa
aa
aa
@@ -9822,13 +9897,13 @@ aa
aa
aa
aa
-aa
-aa
-aa
-aa
-aa
-aa
-aa
+ak
+av
+av
+av
+av
+av
+ak
aa
aa
aa
@@ -9914,13 +9989,13 @@ aa
aa
aa
aa
-aa
-aa
-aa
-aa
-aa
-aa
-aa
+ak
+av
+MN
+MN
+MN
+av
+ak
aa
aa
aa
@@ -10006,13 +10081,13 @@ aa
aa
aa
aa
-aa
-aa
-aa
-aa
-aa
-aa
-aa
+ak
+dT
+MN
+av
+Jp
+av
+ak
aa
aa
aa
@@ -10098,13 +10173,13 @@ aa
aa
aa
aa
-aa
-aa
-aa
-aa
-aa
-aa
-aa
+ak
+av
+MN
+MN
+MN
+av
+ak
aa
aa
aa
@@ -10190,13 +10265,13 @@ aa
aa
aa
aa
-aa
-aa
-aa
-aa
-aa
-aa
-aa
+ak
+av
+av
+aY
+av
+av
+ak
aa
aa
aa
@@ -10282,13 +10357,13 @@ aa
aa
aa
aa
-aa
-aa
-aa
-aa
-aa
-aa
-aa
+ak
+ak
+ak
+ak
+ak
+ak
+ak
aa
aa
aa
diff --git a/_maps/map_files/generic/CentCom.dmm b/_maps/map_files/generic/CentCom.dmm
index c02c9c5518580..283ffc887bd84 100644
--- a/_maps/map_files/generic/CentCom.dmm
+++ b/_maps/map_files/generic/CentCom.dmm
@@ -196,13 +196,6 @@
/obj/effect/turf_decal/tile/neutral/fourcorners,
/turf/open/floor/iron/dark,
/area/centcom/central_command_areas/courtroom)
-"aV" = (
-/obj/structure/table/wood,
-/obj/item/clipboard,
-/obj/item/radio/headset/headset_cent,
-/obj/effect/turf_decal/tile/neutral/fourcorners,
-/turf/open/floor/iron/dark,
-/area/centcom/central_command_areas/briefing)
"aW" = (
/obj/effect/turf_decal/stripes/line{
dir = 6
@@ -712,10 +705,21 @@
},
/turf/open/floor/iron,
/area/centcom/central_command_areas/admin)
-"de" = (
-/obj/effect/landmark/start/new_player,
-/turf/closed/indestructible/start_area,
-/area/misc/start)
+"df" = (
+/obj/structure/table/wood,
+/obj/item/clipboard,
+/obj/item/folder/red,
+/obj/item/stamp/denied{
+ pixel_x = 6;
+ pixel_y = 6
+ },
+/obj/item/stamp{
+ pixel_x = 3;
+ pixel_y = 3
+ },
+/obj/item/stamp/centcom,
+/turf/open/floor/iron/grimy,
+/area/centcom/central_command_areas/admin)
"dh" = (
/obj/effect/turf_decal/tile/dark_blue/half/contrasted{
dir = 4
@@ -785,6 +789,20 @@
/obj/machinery/light/directional/south,
/turf/open/floor/iron/dark,
/area/centcom/central_command_areas/control)
+"ds" = (
+/obj/machinery/door/firedoor,
+/obj/machinery/door/airlock/centcom{
+ name = "CentCom Security"
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 8
+ },
+/obj/effect/mapping_helpers/airlock/cyclelink_helper{
+ dir = 4
+ },
+/obj/effect/mapping_helpers/airlock/access/all/admin/general,
+/turf/open/floor/iron,
+/area/centcom/central_command_areas/ferry)
"dv" = (
/obj/structure/railing/corner{
dir = 8
@@ -1111,6 +1129,13 @@
},
/turf/open/floor/iron,
/area/centcom/central_command_areas/ferry)
+"fb" = (
+/obj/machinery/flasher{
+ id = "tdomeflash";
+ name = "Thunderdome Flash"
+ },
+/turf/open/floor/circuit/green,
+/area/centcom/tdome/arena)
"fc" = (
/obj/effect/turf_decal/delivery,
/obj/effect/light_emitter/thunderdome,
@@ -1175,17 +1200,6 @@
/obj/effect/turf_decal/tile/neutral/fourcorners,
/turf/open/floor/iron,
/area/centcom/central_command_areas/ferry)
-"fy" = (
-/obj/structure/signpost/salvation{
- icon = 'icons/obj/structures.dmi';
- icon_state = "ladder10";
- invisibility = 100
- },
-/turf/open/misc/ashplanet/wateryrock{
- initial_gas_mix = "o2=22;n2=82;TEMP=293.15";
- planetary_atmos = 0
- },
-/area/awaymission/errorroom)
"fA" = (
/obj/machinery/vending/cola,
/obj/effect/turf_decal/delivery,
@@ -1283,9 +1297,6 @@
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/turf/open/floor/catwalk_floor,
/area/centcom/central_command_areas/evacuation/ship)
-"fX" = (
-/turf/closed/indestructible/start_area,
-/area/misc/start)
"fZ" = (
/obj/effect/landmark/ctf,
/turf/open/space/basic,
@@ -1322,11 +1333,6 @@
/obj/machinery/light/small/directional/south,
/turf/open/floor/iron,
/area/centcom/central_command_areas/prison)
-"gh" = (
-/turf/closed/indestructible/fakedoor{
- name = "Thunderdome Admin"
- },
-/area/centcom/tdome/administration)
"gi" = (
/obj/docking_port/stationary{
dir = 4;
@@ -1480,6 +1486,19 @@
},
/turf/open/floor/iron,
/area/centcom/central_command_areas/armory)
+"gY" = (
+/obj/machinery/door/firedoor,
+/obj/machinery/door/airlock/centcom{
+ name = "CentCom"
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 8
+ },
+/obj/effect/mapping_helpers/airlock/cyclelink_helper{
+ dir = 4
+ },
+/turf/open/floor/iron,
+/area/centcom/central_command_areas/control)
"gZ" = (
/obj/effect/turf_decal/tile/neutral{
dir = 4
@@ -1663,6 +1682,13 @@
/obj/item/soap/nanotrasen,
/turf/open/floor/iron/white,
/area/centcom/tdome/observation)
+"ig" = (
+/obj/structure/table/reinforced,
+/obj/effect/turf_decal/tile/neutral/fourcorners,
+/obj/item/taperecorder,
+/obj/item/book/manual/wiki/security_space_law,
+/turf/open/floor/iron/dark,
+/area/centcom/central_command_areas/ferry)
"ih" = (
/obj/structure/bookcase/random,
/obj/effect/turf_decal/tile/neutral/fourcorners,
@@ -1778,11 +1804,6 @@
/obj/machinery/status_display/evac/directional/north,
/turf/open/floor/iron,
/area/centcom/central_command_areas/prison)
-"iB" = (
-/turf/closed/indestructible/fakedoor{
- name = "CentCom Cell"
- },
-/area/centcom/central_command_areas/prison/cells)
"iC" = (
/obj/structure/table/wood,
/obj/machinery/chem_dispenser/drinks/beer{
@@ -2412,10 +2433,7 @@
"lb" = (
/obj/structure/table/wood,
/obj/machinery/door/window/left/directional/south,
-/obj/item/radio/intercom{
- desc = "Talk smack through this.";
- syndie = 1
- },
+/obj/item/radio/intercom/syndicate,
/turf/open/floor/iron/grimy,
/area/centcom/central_command_areas/courtroom)
"lc" = (
@@ -2428,10 +2446,7 @@
/area/centcom/central_command_areas/courtroom)
"ld" = (
/obj/structure/table/wood,
-/obj/item/radio/intercom{
- desc = "Talk smack through this.";
- syndie = 1
- },
+/obj/item/radio/intercom/syndicate,
/obj/machinery/door/window/brigdoor/right/directional/south{
name = "CentCom Stand";
req_access = list("cent_captain")
@@ -2600,10 +2615,8 @@
/obj/structure/chair{
dir = 8
},
-/obj/item/radio/intercom{
- desc = "Talk smack through this.";
- pixel_x = -32;
- syndie = 1
+/obj/item/radio/intercom/syndicate{
+ pixel_x = -32
},
/turf/open/floor/iron/grimy,
/area/centcom/central_command_areas/courtroom)
@@ -2669,10 +2682,7 @@
/area/centcom/central_command_areas/courtroom)
"mn" = (
/obj/structure/table/wood,
-/obj/item/radio/intercom{
- desc = "Talk smack through this.";
- syndie = 1
- },
+/obj/item/radio/intercom/syndicate,
/turf/open/floor/iron/grimy,
/area/centcom/central_command_areas/courtroom)
"mo" = (
@@ -2905,6 +2915,11 @@
},
/turf/open/floor/iron,
/area/centcom/central_command_areas/fore)
+"nz" = (
+/obj/structure/table/reinforced,
+/obj/machinery/fax/admin,
+/turf/open/floor/iron/grimy,
+/area/centcom/central_command_areas/briefing)
"nA" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden,
/obj/effect/turf_decal/tile/neutral/fourcorners,
@@ -3766,6 +3781,13 @@
/obj/effect/turf_decal/tile/dark_blue/fourcorners,
/turf/open/floor/iron,
/area/centcom/central_command_areas/evacuation)
+"rr" = (
+/obj/structure/table/wood,
+/obj/effect/turf_decal/tile/neutral/fourcorners,
+/obj/item/clipboard,
+/obj/item/radio/headset/headset_cent,
+/turf/open/floor/iron/dark,
+/area/centcom/central_command_areas/briefing)
"rs" = (
/obj/effect/landmark/prisonwarp,
/obj/effect/turf_decal/tile/neutral/fourcorners,
@@ -3811,6 +3833,10 @@
/obj/effect/turf_decal/siding/wood/corner,
/turf/open/floor/wood/tile,
/area/centcom/central_command_areas/evacuation/ship)
+"rA" = (
+/obj/effect/landmark/start/new_player,
+/turf/cordon,
+/area/misc/start)
"rB" = (
/obj/structure/table/reinforced,
/obj/item/storage/fancy/donut_box,
@@ -4370,20 +4396,6 @@
/obj/structure/sign/poster/contraband/syndicate_recruitment/directional/north,
/turf/open/indestructible/dark,
/area/centcom/central_command_areas/admin)
-"ub" = (
-/obj/machinery/door/firedoor,
-/obj/machinery/door/airlock/centcom{
- name = "CentCom"
- },
-/obj/effect/turf_decal/stripes/line{
- dir = 8
- },
-/obj/effect/mapping_helpers/airlock/cyclelink_helper{
- dir = 8
- },
-/obj/effect/mapping_helpers/airlock/access/all/admin/general,
-/turf/open/floor/iron,
-/area/centcom/central_command_areas/control)
"uc" = (
/obj/effect/turf_decal/tile/neutral/fourcorners,
/turf/open/floor/iron/dark,
@@ -4417,6 +4429,20 @@
/obj/structure/flora/bush/generic/style_random,
/turf/open/floor/grass,
/area/centcom/central_command_areas/prison)
+"uk" = (
+/obj/machinery/door/firedoor,
+/obj/machinery/door/airlock/centcom{
+ name = "CentCom"
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 8
+ },
+/obj/effect/mapping_helpers/airlock/cyclelink_helper{
+ dir = 8
+ },
+/obj/effect/mapping_helpers/airlock/access/all/admin/general,
+/turf/open/floor/iron,
+/area/centcom/central_command_areas/control)
"ul" = (
/obj/effect/turf_decal/tile/neutral/fourcorners,
/obj/effect/turf_decal/siding/yellow/corner{
@@ -4936,20 +4962,6 @@
},
/turf/open/floor/iron,
/area/centcom/central_command_areas/ferry)
-"wu" = (
-/obj/machinery/door/firedoor,
-/obj/machinery/door/airlock/centcom{
- name = "CentCom Security"
- },
-/obj/effect/turf_decal/stripes/line{
- dir = 8
- },
-/obj/effect/mapping_helpers/airlock/cyclelink_helper{
- dir = 4
- },
-/obj/effect/mapping_helpers/airlock/access/all/admin/general,
-/turf/open/floor/iron,
-/area/centcom/central_command_areas/ferry)
"wv" = (
/obj/machinery/door/poddoor/shutters{
id = "XCCFerry";
@@ -5026,19 +5038,6 @@
},
/turf/open/floor/iron,
/area/centcom/central_command_areas/control)
-"wJ" = (
-/obj/machinery/door/firedoor,
-/obj/machinery/door/airlock/centcom{
- name = "CentCom"
- },
-/obj/effect/turf_decal/stripes/line{
- dir = 8
- },
-/obj/effect/mapping_helpers/airlock/cyclelink_helper{
- dir = 8
- },
-/turf/open/floor/iron,
-/area/centcom/central_command_areas/evacuation)
"wK" = (
/obj/effect/turf_decal/stripes/line{
dir = 8
@@ -5461,6 +5460,21 @@
},
/turf/open/floor/iron,
/area/centcom/central_command_areas/supply)
+"yR" = (
+/obj/item/clipboard,
+/obj/item/folder/red,
+/obj/item/stamp/denied{
+ pixel_x = 6;
+ pixel_y = 6
+ },
+/obj/item/stamp{
+ pixel_x = 3;
+ pixel_y = 3
+ },
+/obj/structure/table/reinforced,
+/obj/item/stamp/centcom,
+/turf/open/floor/iron/grimy,
+/area/centcom/central_command_areas/briefing)
"yS" = (
/obj/structure/table/reinforced,
/obj/item/storage/box/emps,
@@ -5471,19 +5485,6 @@
},
/turf/open/floor/iron,
/area/centcom/central_command_areas/armory)
-"yU" = (
-/obj/machinery/door/firedoor,
-/obj/machinery/door/airlock/centcom{
- name = "CentCom"
- },
-/obj/effect/turf_decal/stripes/line{
- dir = 8
- },
-/obj/effect/mapping_helpers/airlock/cyclelink_helper{
- dir = 4
- },
-/turf/open/floor/iron,
-/area/centcom/central_command_areas/control)
"yV" = (
/obj/docking_port/stationary{
dir = 8;
@@ -5743,6 +5744,19 @@
},
/turf/open/floor/iron,
/area/centcom/central_command_areas/supplypod/loading/two)
+"zO" = (
+/obj/machinery/camera/directional/north{
+ c_tag = "Red Team";
+ network = list("thunder");
+ pixel_x = 11;
+ pixel_y = -9;
+ resistance_flags = 64
+ },
+/obj/effect/landmark/thunderdome/two,
+/obj/effect/turf_decal/tile/neutral/fourcorners,
+/obj/effect/light_emitter/thunderdome,
+/turf/open/floor/iron,
+/area/centcom/tdome/arena)
"zR" = (
/obj/structure/closet/secure_closet/personal,
/obj/effect/turf_decal/tile/neutral/fourcorners,
@@ -6629,19 +6643,6 @@
/obj/effect/light_emitter/thunderdome,
/turf/open/floor/iron,
/area/centcom/tdome/arena)
-"DT" = (
-/obj/machinery/camera/directional/north{
- c_tag = "Green Team";
- network = list("thunder");
- pixel_x = 12;
- pixel_y = -10;
- resistance_flags = 64
- },
-/obj/effect/landmark/thunderdome/one,
-/obj/effect/turf_decal/tile/neutral/fourcorners,
-/obj/effect/light_emitter/thunderdome,
-/turf/open/floor/iron,
-/area/centcom/tdome/arena)
"DU" = (
/obj/item/kirbyplants/organic/plant21,
/obj/effect/turf_decal/stripes/line,
@@ -6739,6 +6740,19 @@
/obj/effect/turf_decal/tile/neutral/fourcorners,
/turf/open/floor/iron/dark,
/area/centcom/central_command_areas/courtroom)
+"EA" = (
+/obj/machinery/door/firedoor,
+/obj/machinery/door/airlock/centcom{
+ name = "CentCom"
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 8
+ },
+/obj/effect/mapping_helpers/airlock/cyclelink_helper{
+ dir = 8
+ },
+/turf/open/floor/iron,
+/area/centcom/central_command_areas/evacuation)
"EB" = (
/obj/effect/turf_decal/siding/wideplating_new/dark{
dir = 8
@@ -6935,6 +6949,17 @@
/obj/effect/light_emitter/thunderdome,
/turf/open/floor/iron,
/area/centcom/tdome/arena)
+"FM" = (
+/obj/structure/signpost/salvation{
+ icon = 'icons/obj/structures.dmi';
+ icon_state = "ladder10";
+ invisibility = 100
+ },
+/turf/open/misc/ashplanet/wateryrock{
+ initial_gas_mix = "o2=22;n2=82;TEMP=293.15";
+ planetary_atmos = 0
+ },
+/area/awaymission/errorroom)
"FO" = (
/obj/structure/table/reinforced,
/obj/item/computer_disk/quartermaster,
@@ -6950,6 +6975,11 @@
/obj/effect/light_emitter/podbay,
/turf/open/floor/iron,
/area/centcom/central_command_areas/supplypod/pod_storage)
+"FU" = (
+/turf/closed/indestructible/fakedoor{
+ name = "Thunderdome Admin"
+ },
+/area/centcom/tdome/administration)
"FX" = (
/obj/machinery/computer/auxiliary_base/directional/north,
/obj/structure/table/reinforced,
@@ -6964,12 +6994,6 @@
},
/turf/open/floor/iron,
/area/centcom/tdome/observation)
-"Ga" = (
-/obj/structure/table/reinforced,
-/obj/effect/turf_decal/tile/neutral/fourcorners,
-/obj/machinery/fax,
-/turf/open/floor/iron/dark,
-/area/centcom/central_command_areas/ferry)
"Gb" = (
/obj/effect/light_emitter/thunderdome,
/turf/closed/indestructible/fakeglass,
@@ -7347,6 +7371,19 @@
},
/turf/open/floor/iron,
/area/centcom/central_command_areas/prison)
+"Im" = (
+/obj/machinery/door/firedoor,
+/obj/machinery/door/airlock/centcom{
+ name = "CentCom"
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 8
+ },
+/obj/effect/mapping_helpers/airlock/cyclelink_helper{
+ dir = 8
+ },
+/turf/open/floor/iron,
+/area/centcom/central_command_areas/control)
"Io" = (
/obj/docking_port/stationary{
dir = 8;
@@ -7390,6 +7427,11 @@
/obj/effect/turf_decal/tile/neutral/fourcorners,
/turf/open/floor/iron/dark,
/area/centcom/central_command_areas/control)
+"IF" = (
+/turf/closed/indestructible/fakedoor{
+ name = "CentCom Cell"
+ },
+/area/centcom/central_command_areas/prison/cells)
"IK" = (
/obj/structure/closet/secure_closet/ert_sec,
/obj/effect/turf_decal/stripes/line{
@@ -7428,13 +7470,6 @@
"Ji" = (
/turf/open/floor/circuit/green,
/area/centcom/tdome/arena)
-"Jj" = (
-/obj/machinery/flasher{
- id = "tdomeflash";
- name = "Thunderdome Flash"
- },
-/turf/open/floor/circuit/green,
-/area/centcom/tdome/arena)
"Jl" = (
/obj/item/kirbyplants/organic/plant21,
/obj/effect/turf_decal/tile/green/anticorner/contrasted,
@@ -7511,17 +7546,6 @@
},
/turf/open/floor/iron,
/area/centcom/tdome/observation)
-"Ke" = (
-/obj/item/clipboard,
-/obj/item/folder/red,
-/obj/item/stamp/denied{
- pixel_x = 3;
- pixel_y = 3
- },
-/obj/item/stamp,
-/obj/structure/table/reinforced,
-/turf/open/floor/iron/grimy,
-/area/centcom/central_command_areas/briefing)
"Kf" = (
/obj/machinery/door/airlock/centcom{
name = "Administrative Storage"
@@ -7544,6 +7568,20 @@
},
/turf/open/floor/iron/white,
/area/centcom/tdome/observation)
+"Kv" = (
+/obj/machinery/door/firedoor,
+/obj/machinery/door/airlock/centcom{
+ name = "CentCom Security"
+ },
+/obj/effect/turf_decal/stripes/line{
+ dir = 8
+ },
+/obj/effect/mapping_helpers/airlock/cyclelink_helper{
+ dir = 8
+ },
+/obj/effect/mapping_helpers/airlock/access/all/admin/general,
+/turf/open/floor/iron,
+/area/centcom/central_command_areas/ferry)
"KA" = (
/obj/effect/landmark/thunderdome/two,
/obj/effect/turf_decal/stripes/line{
@@ -7642,6 +7680,18 @@
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/iron/dark/textured_large,
/area/centcom/central_command_areas/evacuation/ship)
+"KW" = (
+/obj/machinery/keycard_auth/wall_mounted/directional/south,
+/obj/structure/table/reinforced,
+/obj/machinery/recharger,
+/obj/machinery/button/door/indestructible{
+ id = "XCCFerry";
+ name = "Hanger Bay Shutters";
+ pixel_y = -38
+ },
+/obj/effect/turf_decal/tile/neutral/fourcorners,
+/turf/open/floor/iron/dark,
+/area/centcom/central_command_areas/ferry)
"KZ" = (
/obj/effect/turf_decal/tile/neutral/fourcorners,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden{
@@ -8221,6 +8271,27 @@
/obj/machinery/light/directional/south,
/turf/open/floor/wood,
/area/centcom/central_command_areas/admin)
+"NN" = (
+/obj/machinery/keycard_auth/wall_mounted/directional/south,
+/obj/structure/table/reinforced,
+/obj/item/stack/package_wrap{
+ pixel_y = 11;
+ pixel_x = -16
+ },
+/obj/item/stack/cable_coil{
+ pixel_y = 4;
+ pixel_x = -10
+ },
+/obj/item/hand_labeler{
+ pixel_y = 1
+ },
+/obj/effect/turf_decal/tile/neutral/fourcorners,
+/obj/item/hand_labeler_refill{
+ pixel_x = 8;
+ pixel_y = 12
+ },
+/turf/open/floor/iron/dark,
+/area/centcom/central_command_areas/supply)
"NO" = (
/turf/open/floor/iron/dark,
/area/centcom/central_command_areas/supplypod)
@@ -8307,19 +8378,6 @@
/obj/machinery/light/floor,
/turf/open/floor/iron,
/area/centcom/central_command_areas/evacuation)
-"Oj" = (
-/obj/machinery/door/firedoor,
-/obj/machinery/door/airlock/centcom{
- name = "CentCom"
- },
-/obj/effect/turf_decal/stripes/line{
- dir = 8
- },
-/obj/effect/mapping_helpers/airlock/cyclelink_helper{
- dir = 8
- },
-/turf/open/floor/iron,
-/area/centcom/central_command_areas/control)
"Om" = (
/obj/structure/table/reinforced,
/obj/item/clipboard,
@@ -8776,19 +8834,6 @@
"PW" = (
/turf/open/floor/iron,
/area/centcom/central_command_areas/supplypod/loading/three)
-"PX" = (
-/obj/structure/table/reinforced,
-/obj/item/folder/red{
- pixel_x = -2;
- pixel_y = -2
- },
-/obj/item/folder/blue{
- pixel_x = 2;
- pixel_y = 2
- },
-/obj/item/lighter,
-/turf/open/floor/iron/grimy,
-/area/centcom/central_command_areas/briefing)
"PY" = (
/obj/structure/closet/crate/bin,
/obj/effect/turf_decal/tile/neutral/fourcorners,
@@ -9204,6 +9249,19 @@
/obj/effect/turf_decal/tile/neutral/fourcorners,
/turf/open/floor/iron/dark,
/area/centcom/central_command_areas/courtroom)
+"RQ" = (
+/obj/machinery/camera/directional/north{
+ c_tag = "Green Team";
+ network = list("thunder");
+ pixel_x = 12;
+ pixel_y = -10;
+ resistance_flags = 64
+ },
+/obj/effect/landmark/thunderdome/one,
+/obj/effect/turf_decal/tile/neutral/fourcorners,
+/obj/effect/light_emitter/thunderdome,
+/turf/open/floor/iron,
+/area/centcom/tdome/arena)
"RR" = (
/obj/machinery/light/directional/north,
/obj/effect/turf_decal/tile/neutral/fourcorners,
@@ -9568,6 +9626,9 @@
/obj/effect/turf_decal/tile/neutral/fourcorners,
/turf/open/floor/iron/dark,
/area/centcom/central_command_areas/briefing)
+"TJ" = (
+/turf/cordon,
+/area/misc/start)
"TK" = (
/obj/structure/cable,
/obj/effect/turf_decal/tile/neutral/fourcorners,
@@ -9580,27 +9641,6 @@
/obj/effect/light_emitter/thunderdome,
/turf/open/floor/iron,
/area/centcom/tdome/arena)
-"TO" = (
-/obj/machinery/keycard_auth/wall_mounted/directional/south,
-/obj/structure/table/reinforced,
-/obj/item/stack/package_wrap{
- pixel_y = 11;
- pixel_x = -16
- },
-/obj/item/stack/cable_coil{
- pixel_y = 4;
- pixel_x = -10
- },
-/obj/item/hand_labeler{
- pixel_y = 1
- },
-/obj/effect/turf_decal/tile/neutral/fourcorners,
-/obj/item/hand_labeler_refill{
- pixel_x = 8;
- pixel_y = 12
- },
-/turf/open/floor/iron/dark,
-/area/centcom/central_command_areas/supply)
"TS" = (
/obj/structure/table/wood,
/obj/item/dice/d20{
@@ -9772,19 +9812,6 @@
/obj/machinery/light/directional/west,
/turf/open/floor/iron/dark,
/area/centcom/tdome/observation)
-"UE" = (
-/obj/machinery/camera/directional/north{
- c_tag = "Red Team";
- network = list("thunder");
- pixel_x = 11;
- pixel_y = -9;
- resistance_flags = 64
- },
-/obj/effect/landmark/thunderdome/two,
-/obj/effect/turf_decal/tile/neutral/fourcorners,
-/obj/effect/light_emitter/thunderdome,
-/turf/open/floor/iron,
-/area/centcom/tdome/arena)
"UH" = (
/obj/machinery/light/directional/west,
/obj/structure/closet/secure_closet/personal,
@@ -10234,27 +10261,11 @@
/obj/machinery/computer/station_alert{
dir = 8
},
-/obj/item/radio/intercom{
- desc = "Talk smack through this.";
- pixel_x = 28;
- syndie = 1
+/obj/item/radio/intercom/syndicate{
+ pixel_x = 28
},
/turf/open/floor/iron/dark,
/area/centcom/central_command_areas/control)
-"WQ" = (
-/obj/machinery/door/firedoor,
-/obj/machinery/door/airlock/centcom{
- name = "CentCom Security"
- },
-/obj/effect/turf_decal/stripes/line{
- dir = 8
- },
-/obj/effect/mapping_helpers/airlock/cyclelink_helper{
- dir = 8
- },
-/obj/effect/mapping_helpers/airlock/access/all/admin/general,
-/turf/open/floor/iron,
-/area/centcom/central_command_areas/ferry)
"WR" = (
/turf/open/floor/iron/dark,
/area/centcom/central_command_areas/briefing)
@@ -10376,18 +10387,6 @@
"Xq" = (
/turf/open/floor/wood,
/area/centcom/central_command_areas/admin)
-"Xr" = (
-/obj/machinery/keycard_auth/wall_mounted/directional/south,
-/obj/structure/table/reinforced,
-/obj/machinery/recharger,
-/obj/machinery/button/door/indestructible{
- id = "XCCFerry";
- name = "Hanger Bay Shutters";
- pixel_y = -38
- },
-/obj/effect/turf_decal/tile/neutral/fourcorners,
-/turf/open/floor/iron/dark,
-/area/centcom/central_command_areas/ferry)
"Xs" = (
/obj/effect/turf_decal/tile/brown/anticorner/contrasted,
/turf/open/floor/iron,
@@ -10491,17 +10490,6 @@
/obj/effect/spawner/structure/window/reinforced,
/turf/open/floor/plating,
/area/centcom/central_command_areas/supplypod)
-"XV" = (
-/obj/structure/table/wood,
-/obj/item/clipboard,
-/obj/item/folder/red,
-/obj/item/stamp/denied{
- pixel_x = 3;
- pixel_y = 3
- },
-/obj/item/stamp,
-/turf/open/floor/iron/grimy,
-/area/centcom/central_command_areas/admin)
"Ya" = (
/turf/closed/indestructible/riveted,
/area/centcom/central_command_areas/armory)
@@ -10913,20 +10901,20 @@
/area/centcom/central_command_areas/supply)
(1,1,1) = {"
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
gu
aa
aa
@@ -11170,21 +11158,21 @@ aa
aa
"}
(2,1,1) = {"
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
aa
aa
aa
@@ -11427,21 +11415,21 @@ LV
aa
"}
(3,1,1) = {"
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
aa
aa
aa
@@ -11684,21 +11672,21 @@ LV
aa
"}
(4,1,1) = {"
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
aa
aa
aa
@@ -11941,21 +11929,21 @@ LV
aa
"}
(5,1,1) = {"
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
aa
aa
aa
@@ -12198,21 +12186,21 @@ LV
aa
"}
(6,1,1) = {"
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
aa
aa
aa
@@ -12455,21 +12443,21 @@ LV
aa
"}
(7,1,1) = {"
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
aa
aa
aa
@@ -12712,21 +12700,21 @@ LV
aa
"}
(8,1,1) = {"
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-de
-fX
-fX
-fX
-fX
-fX
-fX
-fX
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+rA
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
aa
aa
aa
@@ -12969,21 +12957,21 @@ LV
aa
"}
(9,1,1) = {"
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
aa
aa
aa
@@ -13220,27 +13208,27 @@ zi
ik
ik
ZE
-fy
+FM
LW
LV
aa
"}
(10,1,1) = {"
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
aa
aa
aa
@@ -13483,21 +13471,21 @@ LV
aa
"}
(11,1,1) = {"
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
aa
aa
aa
@@ -13740,21 +13728,21 @@ LV
aa
"}
(12,1,1) = {"
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
aa
aa
aa
@@ -13997,21 +13985,21 @@ LV
aa
"}
(13,1,1) = {"
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
aa
aa
aa
@@ -14254,21 +14242,21 @@ LV
aa
"}
(14,1,1) = {"
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
aa
aa
aa
@@ -14511,21 +14499,21 @@ LV
aa
"}
(15,1,1) = {"
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
aa
aa
aa
@@ -14768,21 +14756,21 @@ LV
aa
"}
(16,1,1) = {"
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
aa
aa
aa
@@ -15025,21 +15013,21 @@ LV
aa
"}
(17,1,1) = {"
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
-fX
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
+TJ
aa
aa
aa
@@ -45260,7 +45248,7 @@ aa
aa
aa
oe
-Ga
+ig
sq
to
ZN
@@ -45520,7 +45508,7 @@ mD
FX
sr
tp
-Xr
+KW
mD
aa
oe
@@ -47065,9 +47053,9 @@ tu
mD
mD
mD
-wu
+ds
xh
-wu
+ds
mD
gO
cn
@@ -47331,7 +47319,7 @@ WN
cb
Bu
tb
-aV
+rr
ho
gO
aa
@@ -47579,9 +47567,9 @@ dx
Hz
dd
mD
-WQ
+Kv
xh
-WQ
+Kv
mD
WO
eF
@@ -48099,8 +48087,8 @@ fa
mD
PU
eF
-PX
-Ke
+nz
+yR
eV
eF
xU
@@ -49110,7 +49098,7 @@ vo
fP
On
Zw
-XV
+df
hd
To
BT
@@ -49933,7 +49921,7 @@ Bp
Sz
Sz
uf
-gh
+FU
uf
aa
aa
@@ -50649,7 +50637,7 @@ iF
Pg
mH
nm
-TO
+NN
On
Ui
JC
@@ -51467,7 +51455,7 @@ BY
QC
bR
HK
-UE
+zO
HK
HK
pb
@@ -51948,9 +51936,9 @@ YU
YU
mD
mD
-wu
+ds
xh
-wu
+ds
mD
Ya
rY
@@ -52462,9 +52450,9 @@ iu
iu
io
io
-ub
+uk
mk
-ub
+uk
io
io
iu
@@ -54294,7 +54282,7 @@ Gb
Ef
NY
NY
-Jj
+fb
Jq
NY
NY
@@ -55770,22 +55758,22 @@ aa
aa
Jb
ir
-iB
+IF
YX
ir
-iB
+IF
Jb
ir
-iB
+IF
Jb
ir
-iB
+IF
Jb
ir
-iB
+IF
YX
ir
-iB
+IF
Jb
iH
il
@@ -56060,9 +56048,9 @@ Fq
UO
io
io
-yU
+gY
mk
-yU
+gY
io
io
iu
@@ -56574,9 +56562,9 @@ io
yj
io
io
-Oj
+Im
mk
-Oj
+Im
io
io
iu
@@ -57121,7 +57109,7 @@ Tf
QC
dj
Mf
-DT
+RQ
Mf
Mf
Zi
@@ -58340,22 +58328,22 @@ aa
aa
Jb
ir
-iB
+IF
YX
ir
-iB
+IF
Jb
ir
-iB
+IF
Jb
ir
-iB
+IF
Jb
ir
-iB
+IF
YX
ir
-iB
+IF
Jb
pc
Hv
@@ -58630,9 +58618,9 @@ cg
cg
cg
cg
-yU
+gY
GJ
-yU
+gY
cg
cg
cg
@@ -58671,7 +58659,7 @@ Bp
Sz
Sz
uf
-gh
+FU
uf
aa
aa
@@ -59144,9 +59132,9 @@ cg
cg
cg
cg
-wJ
+EA
GJ
-wJ
+EA
cg
cg
cg
diff --git a/_maps/map_files/tramstation/tramstation.dmm b/_maps/map_files/tramstation/tramstation.dmm
index 469e5ec80fb3d..bcf24651157e8 100644
--- a/_maps/map_files/tramstation/tramstation.dmm
+++ b/_maps/map_files/tramstation/tramstation.dmm
@@ -44474,8 +44474,8 @@
/turf/closed/wall/r_wall,
/area/station/engineering/supermatter)
"oMh" = (
-/obj/structure/secure_safe/directional/east,
/obj/machinery/airalarm/directional/north,
+/obj/structure/detectiveboard/directional/east,
/turf/open/floor/carpet,
/area/station/security/detectives_office)
"oMz" = (
@@ -47957,6 +47957,7 @@
/obj/effect/turf_decal/trimline/purple/filled/line{
dir = 4
},
+/obj/machinery/vending/cytopro,
/turf/open/floor/iron/white,
/area/station/science/xenobiology)
"pWC" = (
@@ -59837,6 +59838,7 @@
pixel_x = -23;
pixel_y = 8
},
+/obj/structure/secure_safe/directional/south,
/turf/open/floor/iron/grimy,
/area/station/security/detectives_office)
"udZ" = (
diff --git a/_maps/map_files/wawastation/wawastation.dmm b/_maps/map_files/wawastation/wawastation.dmm
index fa4ea9e4b3263..47ed0380935d8 100644
--- a/_maps/map_files/wawastation/wawastation.dmm
+++ b/_maps/map_files/wawastation/wawastation.dmm
@@ -8832,6 +8832,7 @@
"diI" = (
/obj/machinery/light/small/directional/north,
/obj/machinery/computer/security,
+/obj/structure/detectiveboard/directional/north,
/turf/open/floor/carpet,
/area/station/security/detectives_office)
"diM" = (
@@ -13766,7 +13767,6 @@
"eTu" = (
/obj/effect/turf_decal/tile/neutral,
/obj/structure/table,
-/obj/item/trash/waffles,
/turf/open/floor/iron,
/area/station/hallway/primary/central)
"eTZ" = (
@@ -21383,6 +21383,12 @@
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/plating,
/area/station/science/xenobiology)
+"hAS" = (
+/obj/machinery/hydroponics/soil,
+/obj/effect/decal/cleanable/dirt,
+/obj/item/cultivator/rake,
+/turf/open/floor/grass,
+/area/station/security/prison/garden)
"hAV" = (
/obj/structure/table/wood,
/obj/item/flashlight/flare/candle{
@@ -24736,6 +24742,7 @@
/obj/machinery/hydroponics/soil,
/obj/effect/decal/cleanable/dirt,
/obj/structure/cable,
+/obj/item/plant_analyzer,
/turf/open/floor/grass,
/area/station/security/prison/garden)
"iNv" = (
@@ -39062,6 +39069,7 @@
/area/station/command/bridge)
"nPw" = (
/obj/structure/water_source/puddle,
+/obj/item/reagent_containers/cup/watering_can,
/turf/open/floor/grass,
/area/station/security/prison/garden)
"nPM" = (
@@ -46382,6 +46390,10 @@
/obj/effect/decal/cleanable/dirt/dust,
/turf/open/floor/plating,
/area/station/maintenance/department/cargo)
+"qwB" = (
+/obj/item/shovel/spade,
+/turf/open/floor/grass,
+/area/station/security/prison/garden)
"qwG" = (
/obj/structure/cable,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
@@ -52520,6 +52532,7 @@
/area/station/engineering/atmos)
"syF" = (
/obj/effect/landmark/start/prisoner,
+/obj/item/plant_analyzer,
/turf/open/floor/grass,
/area/station/security/prison/garden)
"syL" = (
@@ -53709,6 +53722,12 @@
},
/turf/open/floor/iron,
/area/station/security/brig)
+"sUD" = (
+/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/obj/structure/cable,
+/turf/open/floor/catwalk_floor,
+/area/station/maintenance/central/lesser)
"sUI" = (
/obj/machinery/door/airlock{
name = "Kitchen Cold Room"
@@ -60664,6 +60683,7 @@
/turf/open/floor/iron,
/area/station/engineering/lobby)
"vqN" = (
+/obj/machinery/vending/cytopro,
/turf/open/floor/iron/dark/small,
/area/station/science/cytology)
"vqY" = (
@@ -82467,7 +82487,7 @@ dUc
xrb
xrb
nPw
-dEG
+qwB
iqf
cKn
pjt
@@ -82979,7 +82999,7 @@ cLf
dUc
cLf
xrb
-nEx
+hAS
syF
ckc
sqk
@@ -83750,7 +83770,7 @@ cLf
iUF
cLf
sNu
-nEx
+hAS
rXZ
vjm
hbw
@@ -93566,7 +93586,7 @@ dTU
pMD
acc
kYl
-jUd
+sUD
dGc
fDN
enu
diff --git a/_maps/shuttles/pirate_ex_interdyne.dmm b/_maps/shuttles/pirate_ex_interdyne.dmm
index dce984f19c993..4036972b7a87a 100644
--- a/_maps/shuttles/pirate_ex_interdyne.dmm
+++ b/_maps/shuttles/pirate_ex_interdyne.dmm
@@ -291,7 +291,7 @@
/area/shuttle/pirate)
"aS" = (
/obj/effect/turf_decal/tile/dark_blue/opposingcorners,
-/obj/structure/closet/crate/freezer/blood,
+/obj/structure/closet/crate/freezer/blood/interdyne,
/obj/machinery/light/small/blacklight/directional/south,
/obj/machinery/iv_drip,
/turf/open/floor/iron/dark,
diff --git a/_maps/templates/lazy_templates/ninja_den.dmm b/_maps/templates/lazy_templates/ninja_den.dmm
index 88f4bce19d45a..f538a4e509673 100644
--- a/_maps/templates/lazy_templates/ninja_den.dmm
+++ b/_maps/templates/lazy_templates/ninja_den.dmm
@@ -1567,7 +1567,6 @@
/turf/open/floor/wood/tile,
/area/centcom/central_command_areas/holding)
"JV" = (
-/obj/structure/closet/secure_closet/freezer/kitchen,
/obj/item/food/grown/rice,
/obj/item/food/grown/rice,
/obj/item/food/grown/rice,
@@ -1583,6 +1582,9 @@
/obj/item/food/grown/onion/red,
/obj/item/food/grown/onion/red,
/obj/item/food/grown/coffee,
+/obj/structure/closet/secure_closet/freezer/fridge/open{
+ name = "kitchen cabinet"
+ },
/turf/open/floor/carpet/black,
/area/centcom/central_command_areas/holding)
"Kb" = (
diff --git a/code/__DEFINES/DNA.dm b/code/__DEFINES/DNA.dm
index 4756b80f02737..bd1b7933e861a 100644
--- a/code/__DEFINES/DNA.dm
+++ b/code/__DEFINES/DNA.dm
@@ -16,8 +16,8 @@
#define MINOR_NEGATIVE 4
-//Mutation classes. Normal being on them, extra being additional mutations with instability and other being stuff you dont want people to fuck with like wizard mutate
-/// A mutation that can be activated and deactived by completing a sequence
+//Mutation classes. Normal being on them, extra being additional mutations with instability and other being stuff you don't want people to fuck with like wizard mutate
+/// A mutation that can be activated and deactivated by completing a sequence
#define MUT_NORMAL 1
/// A mutation that is in the mutations tab, and can be given and taken away through though the DNA console. Has a 0 before its name in the mutation section of the dna console
#define MUT_EXTRA 2
diff --git a/code/__DEFINES/MC.dm b/code/__DEFINES/MC.dm
index 8a658f3913d7d..2de9e7140ad26 100644
--- a/code/__DEFINES/MC.dm
+++ b/code/__DEFINES/MC.dm
@@ -19,7 +19,7 @@
///creates a running average of "things elapsed" per time period when you need to count via a smaller time period.
///eg you want an average number of things happening per second but you measure the event every tick (50 milliseconds).
-///make sure both time intervals are in the same units. doesnt work if current_duration > total_duration or if total_duration == 0
+///make sure both time intervals are in the same units. doesn't work if current_duration > total_duration or if total_duration == 0
#define MC_AVG_OVER_TIME(average, current, total_duration, current_duration) ((((total_duration) - (current_duration)) / (total_duration)) * (average) + (current))
#define MC_AVG_MINUTES(average, current, current_duration) (MC_AVG_OVER_TIME(average, current, 1 MINUTES, current_duration))
@@ -32,7 +32,7 @@
#define STOP_PROCESSING(Processor, Datum) Datum.datum_flags &= ~DF_ISPROCESSING;Processor.processing -= Datum;Processor.currentrun -= Datum
/// Returns true if the MC is initialized and running.
-/// Optional argument init_stage controls what stage the mc must have initializted to count as initialized. Defaults to INITSTAGE_MAX if not specified.
+/// Optional argument init_stage controls what stage the mc must have initialized to count as initialized. Defaults to INITSTAGE_MAX if not specified.
#define MC_RUNNING(INIT_STAGE...) (Master && Master.processing > 0 && Master.current_runlevel && Master.init_stage_completed == (max(min(INITSTAGE_MAX, ##INIT_STAGE), 1)))
#define MC_LOOP_RTN_NEWSTAGES 1
@@ -133,3 +133,11 @@
}\
/datum/controller/subsystem/verb_manager/##X/fire() {..() /*just so it shows up on the profiler*/} \
/datum/controller/subsystem/verb_manager/##X
+
+#define AI_CONTROLLER_SUBSYSTEM_DEF(X) GLOBAL_REAL(SS##X, /datum/controller/subsystem/ai_controllers/##X);\
+/datum/controller/subsystem/ai_controllers/##X/New(){\
+ NEW_SS_GLOBAL(SS##X);\
+ PreInit();\
+}\
+/datum/controller/subsystem/ai_controllers/##X/fire() {..() /*just so it shows up on the profiler*/} \
+/datum/controller/subsystem/ai_controllers/##X
diff --git a/code/__DEFINES/_flags.dm b/code/__DEFINES/_flags.dm
index cbc17654078bf..687f5365f6d4a 100644
--- a/code/__DEFINES/_flags.dm
+++ b/code/__DEFINES/_flags.dm
@@ -25,7 +25,7 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204
#define NO_SCREENTIPS_1 (1<<2)
/// Prevent clicking things below it on the same turf eg. doors/ fulltile windows
#define PREVENT_CLICK_UNDER_1 (1<<3)
-///specifies that this atom is a hologram that isnt real
+///specifies that this atom is a hologram that isn't real
#define HOLOGRAM_1 (1<<4)
///Whether /atom/Initialize() has already run for the object
#define INITIALIZED_1 (1<<5)
@@ -52,7 +52,7 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204
/// Whether or not this atom is storing contents for a disassociated storage object
#define HAS_DISASSOCIATED_STORAGE_1 (1<<16)
/// If this atom has experienced a decal element "init finished" sourced appearance update
-/// We use this to ensure stacked decals don't double up appearance updates for no rasin
+/// We use this to ensure stacked decals don't double up appearance updates for no reason
/// Flag as an optimization, don't make this a trait without profiling
/// Yes I know this is a stupid flag, no you can't take him from me
#define DECAL_INIT_UPDATE_EXPERIENCED_1 (1<<17)
@@ -81,9 +81,9 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204
#define RICOCHET_HARD (1<<1)
//TURF FLAGS
-/// If a turf cant be jaunted through.
+/// If a turf can't be jaunted through.
#define NOJAUNT (1<<0)
-/// If a turf is an usused reservation turf awaiting assignment
+/// If a turf is an unused reservation turf awaiting assignment
#define UNUSED_RESERVATION_TURF (1<<1)
/// If a turf is a reserved turf
#define RESERVATION_TURF (1<<2)
@@ -281,8 +281,8 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204
#define RELIGION_TOOL_SACRIFICE (1<<1)
#define RELIGION_TOOL_SECTSELECT (1<<2)
-// ---- Skillchip incompatability flags ---- //
-// These flags control which skill chips are compatible with eachother.
+// ---- Skillchip incompatibility flags ---- //
+// These flags control which skill chips are compatible with each other.
// By default, skillchips are incompatible with themselves and multiple of the same istype() cannot be implanted together. Set this flag to disable that check.
#define SKILLCHIP_ALLOWS_MULTIPLE (1<<0)
// This skillchip is incompatible with other skillchips from the incompatible_category list.
diff --git a/code/__DEFINES/access.dm b/code/__DEFINES/access.dm
index 325116eb5b869..7d0f804dc5028 100644
--- a/code/__DEFINES/access.dm
+++ b/code/__DEFINES/access.dm
@@ -326,7 +326,6 @@
ACCESS_PHARMACY, \
ACCESS_PLUMBING, \
ACCESS_PSYCHOLOGY, \
- ACCESS_QM, \
ACCESS_RESEARCH, \
ACCESS_ROBOTICS, \
ACCESS_SCIENCE, \
diff --git a/code/__DEFINES/achievements.dm b/code/__DEFINES/achievements.dm
index 0253df0b57a4d..4f1cf4b746ac6 100644
--- a/code/__DEFINES/achievements.dm
+++ b/code/__DEFINES/achievements.dm
@@ -57,6 +57,7 @@
#define MEDAL_DEBT_EXTINGUISHED "Debt Extinguished"
#define MEDAL_SISYPHUS "Sisyphus"
#define MEDAL_ARCHMAGE "Archmage"
+#define MEDAL_CIGARETTES "Cigarettes"
#define MEDAL_THEORETICAL_LIMITS "All Within Theoretical Limits"
//Skill medal hub IDs
diff --git a/code/__DEFINES/admin.dm b/code/__DEFINES/admin.dm
index 66f34f5f57b37..74c9120d804d4 100644
--- a/code/__DEFINES/admin.dm
+++ b/code/__DEFINES/admin.dm
@@ -73,8 +73,8 @@
#define ADMIN_LUAVIEW_CHUNK(state, log_index) "(VIEW CODE)"
/// Displays "(SHOW)" in the chat, when clicked it tries to show atom(paper). First you need to set the request_state variable to TRUE for the paper.
#define ADMIN_SHOW_PAPER(atom) "(SHOW)"
-/// Displays "(PRINT)" in the chat, when clicked it will try to print the atom(paper) on the CentCom fax machine.
-#define ADMIN_PRINT_FAX(atom, fax_name) "(PRINT)"
+/// Displays "(PRINT)" in the chat, when clicked it will try to print the atom(paper) on the CentCom/Syndicate fax machine.
+#define ADMIN_PRINT_FAX(atom, sender, destination) "(PRINT)"
/// Displays "(PLAY)" in the chat, when clicked it tries to play internet sounds from the request.
#define ADMIN_PLAY_INTERNET(text, credit) "(PLAY)"
/// Displays "(SEE Z-LEVEL LAYOUT)" in the chat, when clicked it shows the z-level layouts for the current world state.
diff --git a/code/__DEFINES/admin_verb.dm b/code/__DEFINES/admin_verb.dm
index 04806e098b2c4..71e0475e5c39c 100644
--- a/code/__DEFINES/admin_verb.dm
+++ b/code/__DEFINES/admin_verb.dm
@@ -81,7 +81,7 @@ _ADMIN_VERB(verb_path_name, verb_permissions, verb_name, verb_desc, verb_categor
#define ADMIN_CATEGORY_FUN "Admin.Fun"
#define ADMIN_CATEGORY_GAME "Admin.Game"
-// Special categories that are seperated
+// Special categories that are separated
#define ADMIN_CATEGORY_DEBUG "Debug"
#define ADMIN_CATEGORY_SERVER "Server"
#define ADMIN_CATEGORY_OBJECT "Object"
diff --git a/code/__DEFINES/ai/ai.dm b/code/__DEFINES/ai/ai.dm
index 37ee5c077e2a5..73a8f2d1900bd 100644
--- a/code/__DEFINES/ai/ai.dm
+++ b/code/__DEFINES/ai/ai.dm
@@ -68,7 +68,7 @@
///macro for whether it's appropriate to resist right now, used by resist subtree
#define SHOULD_RESIST(source) (source.on_fire || source.buckled || HAS_TRAIT(source, TRAIT_RESTRAINED) || (source.pulledby && source.pulledby.grab_state > GRAB_PASSIVE))
///macro for whether the pawn can act, used generally to prevent some horrifying ai disasters
-#define IS_DEAD_OR_INCAP(source) (source.incapacitated() || source.stat)
+#define IS_DEAD_OR_INCAP(source) (source.incapacitated || source.stat)
GLOBAL_LIST_INIT(all_radial_directions, list(
"NORTH" = image(icon = 'icons/testing/turf_analysis.dmi', icon_state = "red_arrow", dir = NORTH),
diff --git a/code/__DEFINES/ai/ai_blackboard.dm b/code/__DEFINES/ai/ai_blackboard.dm
index 4374288b07c5b..0c682f7d411a8 100644
--- a/code/__DEFINES/ai/ai_blackboard.dm
+++ b/code/__DEFINES/ai/ai_blackboard.dm
@@ -8,7 +8,7 @@
#define BB_FOOD_TARGET "bb_food_target"
///How close a mob must be for us to select it as a target, if that is less than how far we can maintain it as a target
#define BB_AGGRO_RANGE "BB_aggro_range"
-///are we hungry? determined by the udder compnent
+///are we hungry? determined by the udder component
#define BB_CHECK_HUNGRY "BB_check_hungry"
///are we ready to breed?
#define BB_BREED_READY "BB_breed_ready"
@@ -47,7 +47,7 @@
///bane ai used by example script
#define BB_BANE_BATMAN "BB_bane_batman"
-//yep thats it
+//yep that's it
///Hunting BB keys
#define BB_CURRENT_HUNTING_TARGET "BB_current_hunting_target"
@@ -133,6 +133,9 @@
///Range for a MOD AI controller.
#define MOD_AI_RANGE 200
+///Only target mobs with these traits
+#define BB_TARGET_ONLY_WITH_TRAITS "BB_target_only_with_traits"
+
///should we skip the faction check for the targeting strategy?
#define BB_ALWAYS_IGNORE_FACTION "BB_always_ignore_factions"
///are we in some kind of temporary state of ignoring factions when targeting? can result in volatile results if multiple behaviours touch this
diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm
index f94871d10ccfa..159f1da9b45ff 100644
--- a/code/__DEFINES/antagonists.dm
+++ b/code/__DEFINES/antagonists.dm
@@ -165,7 +165,7 @@ GLOBAL_LIST_INIT(syndicate_employers, list(
"Waffle Corporation Terrorist",
"Waffle Corporation",
))
-///employers that are from nanotrasen
+///employers that are from Nanotrasen
GLOBAL_LIST_INIT(nanotrasen_employers, list(
"Champions of Evil",
"Corporate Climber",
@@ -217,22 +217,28 @@ GLOBAL_LIST_INIT(ai_employers, list(
/// Checks if the given mob is a traitor
#define IS_TRAITOR(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/traitor))
+/**
+ * Cult checks
+ */
+
/// Checks if the given mob is a blood cultist
-#define IS_CULTIST(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/cult))
+#define IS_CULTIST(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/cult) || HAS_TRAIT(mob, TRAIT_ACT_AS_CULTIST))
+
+/// Checks if the given mob is a blood cultist and is guaranteed to return the datum if possible - will cause issues with above trait
+#define GET_CULTIST(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/cult))
/// Checks if the mob is a sentient or non-sentient cultist
#define IS_CULTIST_OR_CULTIST_MOB(mob) ((IS_CULTIST(mob)) || (mob.faction.Find(FACTION_CULT)))
-/// Checks if the given mob is a changeling
-#define IS_CHANGELING(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/changeling))
-
-/// Checks if the given mob is a nuclear operative
-#define IS_NUKE_OP(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/nukeop))
-//Tells whether or not someone is a space ninja
-#define IS_SPACE_NINJA(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/ninja))
+/**
+ * Heretic checks
+ */
/// Checks if the given mob is a heretic.
-#define IS_HERETIC(mob) (mob.mind?.has_antag_datum(/datum/antagonist/heretic))
+#define IS_HERETIC(mob) (mob.mind?.has_antag_datum(/datum/antagonist/heretic) || HAS_TRAIT(mob, TRAIT_ACT_AS_HERETIC))
+/// Checks if the given mob is a heretic and is guaranteed to return the datum if possible - will cause issues with above trait
+#define GET_HERETIC(mob) (mob.mind?.has_antag_datum(/datum/antagonist/heretic))
+
/// Check if the given mob is a heretic monster.
#define IS_HERETIC_MONSTER(mob) (mob.mind?.has_antag_datum(/datum/antagonist/heretic_monster))
/// Check if the given mob is a lunatic
@@ -242,6 +248,19 @@ GLOBAL_LIST_INIT(ai_employers, list(
/// CHecks if the given mob is in the mansus realm
#define IS_IN_MANSUS(mob) (istype(get_area(mob), /area/centcom/heretic_sacrifice))
+/**
+ * Etc.
+ */
+
+/// Checks if the given mob is a changeling
+#define IS_CHANGELING(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/changeling))
+
+/// Checks if the given mob is a nuclear operative
+#define IS_NUKE_OP(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/nukeop))
+
+//Tells whether or not someone is a space ninja
+#define IS_SPACE_NINJA(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/ninja))
+
/// Checks if the given mob is a wizard
#define IS_WIZARD(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/wizard))
diff --git a/code/__DEFINES/atmospherics/atmos_helpers.dm b/code/__DEFINES/atmospherics/atmos_helpers.dm
index ca32e4859809b..d5bcbf51471c4 100644
--- a/code/__DEFINES/atmospherics/atmos_helpers.dm
+++ b/code/__DEFINES/atmospherics/atmos_helpers.dm
@@ -82,7 +82,7 @@ GLOBAL_LIST_INIT(atmos_adjacent_savings, list(0,0))
turf.archived_cycle = SSair.times_fired;\
turf.temperature_archived = turf.temperature;
-/* Fetch the energy transferred when two gas mixtures's temperature equalize.
+/* Fetch the energy transferred when two gas mixtures' temperature equalize.
*
* To equalize two gas mixtures, we simply pool the energy and divide it by the pooled heat capacity.
* T' = (W1+W2) / (C1+C2)
@@ -107,7 +107,7 @@ GLOBAL_LIST_INIT(atmos_adjacent_savings, list(0,0))
* Not immediately obvious, but saves us operation time.
*
* We put a lot of parentheses here because the numbers get really really big.
- * By prioritizing the division we try to tone the number down so we dont get overflows.
+ * By prioritizing the division we try to tone the number down so we don't get overflows.
*
* Arguments:
* * temperature_delta: T2 - T1. [/datum/gas_mixture/var/temperature]
diff --git a/code/__DEFINES/bodyparts.dm b/code/__DEFINES/bodyparts.dm
index 8afda278a418b..18d0a3c7cb87c 100644
--- a/code/__DEFINES/bodyparts.dm
+++ b/code/__DEFINES/bodyparts.dm
@@ -16,7 +16,7 @@
#define LIMB_MAX_HP_ALIEN_CORE 500 //Used by xenomorph chests and heads
/// Limb Body Damage Coefficient
-/// A mutiplication of the burn and brute damage that the limb's stored damage contributes to its attached mob's overall wellbeing.
+/// A multiplication of the burn and brute damage that the limb's stored damage contributes to its attached mob's overall wellbeing.
/// For instance, if a limb has 50 damage, and has a coefficient of 50%, the human is considered to have suffered 25 damage to their total health.
#define LIMB_BODY_DAMAGE_COEFFICIENT_ADVANCED 0.5 //Used by advanced robotic limbs.
diff --git a/code/__DEFINES/cameranets.dm b/code/__DEFINES/cameranets.dm
index 935e015e0cda0..3cd0d30660d3b 100644
--- a/code/__DEFINES/cameranets.dm
+++ b/code/__DEFINES/cameranets.dm
@@ -30,6 +30,7 @@
#define CAMERA_NETWORK_CARGO "cargo"
#define CAMERANET_NETWORK_ABDUCTOR "abductor"
#define OPERATIVE_CAMERA_NET "operative"
+#define CAMERANET_NETWORK_CURATOR "curator"
// Ruins/Away missiosn/Misc camera nets
#define CAMERANET_NETWORK_MOON19_XENO "mo19x"
diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm
index 4c7a9c169623b..60cd3a7b018b7 100644
--- a/code/__DEFINES/combat.dm
+++ b/code/__DEFINES/combat.dm
@@ -13,14 +13,14 @@
#define OXY "oxygen"
/// Exhaustion and nonlethal damage.
#define STAMINA "stamina"
-/// Brain damage. Should probably be decomissioned and replaced with proper organ damage.
+/// Brain damage. Should probably be decommissioned and replaced with proper organ damage.
#define BRAIN "brain"
//Damage flag defines //
/// Involves corrosive substances.
#define ACID "acid"
-/// Involved in checking wheter a disease can infect or spread. Also involved in xeno neurotoxin.
+/// Involved in checking whether a disease can infect or spread. Also involved in xeno neurotoxin.
#define BIO "bio"
/// Involves a shockwave, usually from an explosion.
#define BOMB "bomb"
@@ -36,7 +36,7 @@
#define LASER "laser"
/// Involves a melee attack or a thrown object.
#define MELEE "melee"
-/// Involved in checking the likelyhood of applying a wound to a mob.
+/// Involved in checking the likelihood of applying a wound to a mob.
#define WOUND "wound"
#define ARMOR_ALL "all_damage_types"
diff --git a/code/__DEFINES/construction/material.dm b/code/__DEFINES/construction/material.dm
index 445b4e0dc88e4..57d55ab804281 100644
--- a/code/__DEFINES/construction/material.dm
+++ b/code/__DEFINES/construction/material.dm
@@ -1,4 +1,4 @@
-//Defines for amount of material retrived from sheets & other items
+//Defines for amount of material retrieved from sheets & other items
/// The amount of materials you get from a sheet of mineral like iron/diamond/glass etc. 100 Units.
#define SHEET_MATERIAL_AMOUNT 100
/// The amount of materials you get from half a sheet. Used in standard object quantities. 50 units.
diff --git a/code/__DEFINES/construction/rcd.dm b/code/__DEFINES/construction/rcd.dm
index 95c5ab8005323..a8d98215af1dc 100644
--- a/code/__DEFINES/construction/rcd.dm
+++ b/code/__DEFINES/construction/rcd.dm
@@ -7,7 +7,7 @@
#define RCD_WINDOWGRILLE (1 << 1)
/// Windoors & Airlocks
#define RCD_AIRLOCK (1 << 2)
- /// Literarly anything that is spawned on top of a turf such as tables, machines etc
+ /// Literally anything that is spawned on top of a turf such as tables, machines etc
#define RCD_STRUCTURE (1 << 3)
/// For wallmounts like air alarms, fire alarms & apc
#define RCD_WALLFRAME (1 << 4)
diff --git a/code/__DEFINES/crushing.dm b/code/__DEFINES/crushing.dm
index 1261b98e730e8..62705e0e3b871 100644
--- a/code/__DEFINES/crushing.dm
+++ b/code/__DEFINES/crushing.dm
@@ -8,7 +8,7 @@
#define SUCCESSFULLY_FELL_OVER (1<<2)
#define CRUSH_CRIT_SHATTER_LEGS "crush_crit_shatter_legs"
-#define CRUSH_CRIT_PARAPALEGIC "crush_crit_parapalegic"
+#define CRUSH_CRIT_PARAPLEGIC "crush_crit_paraplegic"
#define CRUSH_CRIT_SQUISH_LIMB "crush_crit_pin"
#define CRUSH_CRIT_HEADGIB "crush_crit_headgib"
#define VENDOR_CRUSH_CRIT_PIN "vendor_crush_crit_pin"
diff --git a/code/__DEFINES/database.dm b/code/__DEFINES/database.dm
index 3d20b3b9a3cdc..22351b5052d74 100644
--- a/code/__DEFINES/database.dm
+++ b/code/__DEFINES/database.dm
@@ -4,3 +4,6 @@
#define DB_QUERY_FINISHED 1
/// When there was a problem with the execution of a query.
#define DB_QUERY_BROKEN 2
+
+///The probability of non-maploaded photos and papers being saved as bottle messages at the end of the round.
+#define MESSAGE_BOTTLE_CHANCE 0.2
diff --git a/code/__DEFINES/dcs/flags.dm b/code/__DEFINES/dcs/flags.dm
index 9b181e226a9c8..950a37d3c43c8 100644
--- a/code/__DEFINES/dcs/flags.dm
+++ b/code/__DEFINES/dcs/flags.dm
@@ -30,7 +30,7 @@
#define ELEMENT_DONT_SORT_LIST_ARGS (1<<3)
/**
* Elements with this flag will be ignored by the dcs_check_list_arguments test.
- * A good example is connect_loc, for which it's pratically undoable unless we force every signal proc to have a different name.
+ * A good example is connect_loc, for which it's practically undoable unless we force every signal proc to have a different name.
*/
#define ELEMENT_NO_LIST_UNIT_TEST (1<<4)
diff --git a/code/__DEFINES/dcs/helpers.dm b/code/__DEFINES/dcs/helpers.dm
index df6acffd761a8..01abfac80d4d5 100644
--- a/code/__DEFINES/dcs/helpers.dm
+++ b/code/__DEFINES/dcs/helpers.dm
@@ -1,5 +1,5 @@
/// Used to trigger signals and call procs registered for that signal
-/// The datum hosting the signal is automaticaly added as the first argument
+/// The datum hosting the signal is automatically added as the first argument
/// Returns a bitfield gathered from all registered procs
/// Arguments given here are packaged in a list and given to _SendSignal
#define SEND_SIGNAL(target, sigtype, arguments...) ( !target._listen_lookup?[sigtype] ? NONE : target._SendSignal(sigtype, list(target, ##arguments)) )
diff --git a/code/__DEFINES/dcs/signals/signals_action.dm b/code/__DEFINES/dcs/signals/signals_action.dm
index 2226e34bcccbd..c6e042a0581d5 100644
--- a/code/__DEFINES/dcs/signals/signals_action.dm
+++ b/code/__DEFINES/dcs/signals/signals_action.dm
@@ -2,7 +2,7 @@
///from base of datum/action/proc/Trigger(): (datum/action)
#define COMSIG_ACTION_TRIGGER "action_trigger"
- // Return to block the trigger from occuring
+ // Return to block the trigger from occurring
#define COMPONENT_ACTION_BLOCK_TRIGGER (1<<0)
/// From /datum/action/Grant(): (mob/grant_to)
#define COMSIG_ACTION_GRANTED "action_grant"
diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm
index d75d8bacec73a..24d7cd0b1701a 100644
--- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm
+++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm
@@ -74,7 +74,7 @@
#define COMSIG_MOVABLE_DISPOSING "movable_disposing"
// called when movable is expelled from a disposal pipe, bin or outlet on obj/pipe_eject: (direction)
#define COMSIG_MOVABLE_PIPE_EJECTING "movable_pipe_ejecting"
-///called when the movable sucessfully has its anchored var changed, from base atom/movable/set_anchored(): (value)
+///called when the movable successfully has its anchored var changed, from base atom/movable/set_anchored(): (value)
#define COMSIG_MOVABLE_SET_ANCHORED "movable_set_anchored"
///from base of atom/movable/setGrabState(): (newstate)
#define COMSIG_MOVABLE_SET_GRAB_STATE "living_set_grab_state"
@@ -119,6 +119,9 @@
/// From base of area/Exited(): (area/left, direction)
#define COMSIG_MOVABLE_EXITED_AREA "movable_exited_area"
+///from base of /atom/movable/point_at: (atom/A, obj/effect/temp_visual/point/point)
+#define COMSIG_MOVABLE_POINTED "movable_pointed"
+
/// Sent to movables when they are being stolen by a spy: (mob/living/spy, datum/spy_bounty/bounty)
#define COMSIG_MOVABLE_SPY_STEALING "movable_spy_stealing"
/// Called when something is pushed by a living mob bumping it: (mob/living/pusher, push force)
diff --git a/code/__DEFINES/dcs/signals/signals_fish.dm b/code/__DEFINES/dcs/signals/signals_fish.dm
index 2fbf99446ab94..8af3b8dfca79c 100644
--- a/code/__DEFINES/dcs/signals/signals_fish.dm
+++ b/code/__DEFINES/dcs/signals/signals_fish.dm
@@ -17,6 +17,12 @@
#define COMSIG_FISH_EATEN_BY_OTHER_FISH "fish_eaten_by_other_fish"
///From /obj/item/fish/feed: (fed_reagents, fed_reagent_type)
#define COMSIG_FISH_FED "fish_on_fed"
+///from /obj/item/fish/pet_fish
+#define COMSIG_FISH_PETTED "fish_petted"
+///From /obj/item/fish/update_size_and_weight: (new_size, new_weight)
+#define COMSIG_FISH_UPDATE_SIZE_AND_WEIGHT "fish_update_size_and_weight"
+///From /obj/item/fish/update_fish_force: (weight_rank, bonus_malus)
+#define COMSIG_FISH_FORCE_UPDATED "fish_force_updated"
/// Fishing challenge completed
#define COMSIG_FISHING_CHALLENGE_COMPLETED "fishing_completed"
diff --git a/code/__DEFINES/dcs/signals/signals_food.dm b/code/__DEFINES/dcs/signals/signals_food.dm
index 36a8b7b3392cf..113826a448630 100644
--- a/code/__DEFINES/dcs/signals/signals_food.dm
+++ b/code/__DEFINES/dcs/signals/signals_food.dm
@@ -16,6 +16,9 @@
/// called when an edible ingredient is added: (datum/component/edible/ingredient)
#define COMSIG_FOOD_INGREDIENT_ADDED "edible_ingredient_added"
+/// from base of /datum/component/edible/get_recipe_complexity(): (list/extra_complexity)
+#define COMSIG_FOOD_GET_EXTRA_COMPLEXITY "food_get_extra_complexity"
+
// Deep frying foods
/// An item becomes fried - From /datum/element/fried_item/Attach: (fry_time)
#define COMSIG_ITEM_FRIED "item_fried"
@@ -31,6 +34,8 @@
#define COMPONENT_MICROWAVE_BAD_RECIPE (1<<1)
///called on item when created through microwaving (): (obj/machinery/microwave/M, cooking_efficiency)
#define COMSIG_ITEM_MICROWAVE_COOKED "microwave_cooked"
+///called on the ingredient through microwawing: (result)
+#define COMSIG_ITEM_MICROWAVE_COOKED_FROM "item_microwave_cooked_from"
// Grilling foods (griddle, grill, and bonfire)
///Called when an object is placed onto a griddle
@@ -46,6 +51,9 @@
///Called when an object is turned into another item through grilling ontop of a griddle
#define COMSIG_ITEM_GRILLED "item_grill_completed"
+///Called when the object is grilled by the grill (not to be confused by the griddle, but oh gee the two should be merged in one)
+#define COMSIG_ITEM_BARBEQUE_GRILLED "item_barbeque_grilled"
+
// Baking foods (oven)
//Called when an object is inserted into an oven (atom/oven, mob/baker)
#define COMSIG_ITEM_OVEN_PLACED_IN "item_placed_in_oven"
diff --git a/code/__DEFINES/dcs/signals/signals_global.dm b/code/__DEFINES/dcs/signals/signals_global.dm
index 5e9011f5f4075..bda49bb4b4ae6 100644
--- a/code/__DEFINES/dcs/signals/signals_global.dm
+++ b/code/__DEFINES/dcs/signals/signals_global.dm
@@ -57,7 +57,7 @@
#define COMSIG_GLOB_NEW_MACHINE "!new_machine"
/// a client (re)connected, after all /client/New() checks have passed : (client/connected_client)
#define COMSIG_GLOB_CLIENT_CONNECT "!client_connect"
-/// a weather event of some kind occured
+/// a weather event of some kind occurred
#define COMSIG_WEATHER_TELEGRAPH(event_type) "!weather_telegraph [event_type]"
#define COMSIG_WEATHER_START(event_type) "!weather_start [event_type]"
#define COMSIG_WEATHER_WINDDOWN(event_type) "!weather_winddown [event_type]"
diff --git a/code/__DEFINES/dcs/signals/signals_mind.dm b/code/__DEFINES/dcs/signals/signals_mind.dm
index 72f43f518ebcd..e9a62a26102cf 100644
--- a/code/__DEFINES/dcs/signals/signals_mind.dm
+++ b/code/__DEFINES/dcs/signals/signals_mind.dm
@@ -6,3 +6,6 @@
/// Called on the mind when an antagonist is being removed, after the antagonist list has updated (datum/antagonist/antagonist)
#define COMSIG_ANTAGONIST_REMOVED "antagonist_removed"
+
+/// Called on the mob when losing an antagonist datum (datum/antagonist/antagonist)
+#define COMSIG_MOB_ANTAGONIST_REMOVED "mob_antagonist_removed"
diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_ai.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_ai.dm
index 026247acf57ab..16f7e00e78a19 100644
--- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_ai.dm
+++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_ai.dm
@@ -9,3 +9,5 @@
///Signal sent when a bot is reset
#define COMSIG_BOT_RESET "bot_reset"
+///Sent off /mob/living/basic/bot/proc/set_mode_flags() : (new_flags)
+#define COMSIG_BOT_MODE_FLAGS_SET "bot_mode_flags_set"
diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm
index 051953bd7e508..56d5ddf452471 100644
--- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm
+++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm
@@ -3,14 +3,14 @@
/// Stops the rest of the help
#define COMPONENT_BLOCK_HELP_ACT (1<<0)
-///Called from /mob/living/carbon/help_shake_act, before any hugs have ocurred. (mob/living/helper)
+///Called from /mob/living/carbon/help_shake_act, before any hugs have occurred. (mob/living/helper)
#define COMSIG_CARBON_PRE_MISC_HELP "carbon_pre_misc_help"
- /// Stops the rest of help act (hugging, etc) from occuring
+ /// Stops the rest of help act (hugging, etc) from occurring
#define COMPONENT_BLOCK_MISC_HELP (1<<0)
-///Called from /mob/living/carbon/help_shake_act on the person being helped, after any hugs have ocurred. (mob/living/helper)
+///Called from /mob/living/carbon/help_shake_act on the person being helped, after any hugs have occurred. (mob/living/helper)
#define COMSIG_CARBON_HELP_ACT "carbon_help"
-///Called from /mob/living/carbon/help_shake_act on the helper, after any hugs have ocurred. (mob/living/helped)
+///Called from /mob/living/carbon/help_shake_act on the helper, after any hugs have occurred. (mob/living/helped)
#define COMSIG_CARBON_HELPED "carbon_helped_someone"
///When a carbon slips. Called on /turf/open/handle_slip()
@@ -95,11 +95,11 @@
#define COMPONENT_OVERRIDE_HEALTH_HUD (1<<0)
///Called when a carbon updates their sanity (source = carbon)
#define COMSIG_CARBON_SANITY_UPDATE "carbon_sanity_update"
-///Called when a carbon attempts to breath, before the breath has actually occured
+///Called when a carbon attempts to breath, before the breath has actually occurred
#define COMSIG_CARBON_ATTEMPT_BREATHE "carbon_attempt_breathe"
// Prevents the breath
#define COMSIG_CARBON_BLOCK_BREATH (1 << 0)
-///Called when a carbon breathes, before the breath has actually occured
+///Called when a carbon breathes, before the breath has actually occurred
#define COMSIG_CARBON_PRE_BREATHE "carbon_pre_breathe"
///Called when a carbon updates their mood
#define COMSIG_CARBON_MOOD_UPDATE "carbon_mood_update"
@@ -133,6 +133,10 @@
#define VISIBLE_NAME_FACE 1
//Index for the name of the id
#define VISIBLE_NAME_ID 2
+ //Index for whether their name is being overridden instead of obfuscated
+ #define VISIBLE_NAME_FORCED 3
+///from /mob/living/carbon/human/get_id_name; only returns if the mob has TRAIT_UNKNOWN and it's being overridden: (identity)
+#define COMSIG_HUMAN_GET_FORCED_NAME "human_get_forced_name"
// Mob transformation signals
///Called when a human turns into a monkey, from /mob/living/carbon/proc/finish_monkeyize()
@@ -155,10 +159,10 @@
#define HANDLE_BLOOD_HANDLED (1<<0)
/// Return to skip default nutrition -> blood conversion
#define HANDLE_BLOOD_NO_NUTRITION_DRAIN (1<<1)
- /// Return to skip oxyloss and similar effecst from blood level
+ /// Return to skip oxyloss and similar effects from blood level
#define HANDLE_BLOOD_NO_OXYLOSS (1<<2)
-/// from /datum/status_effect/limp/proc/check_step(mob/whocares, OldLoc, Dir, forced) iodk where it shuld go
+/// from /datum/status_effect/limp/proc/check_step(mob/whocares, OldLoc, Dir, forced) iodk where it should go
#define COMSIG_CARBON_LIMPING "mob_limp_check"
#define COMPONENT_CANCEL_LIMP (1<<0)
diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm
index dfbfe68ad52cd..85e6a62d46c18 100644
--- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm
+++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm
@@ -50,7 +50,7 @@
#define COMSIG_MOB_CLIENT_BLOCK_PRE_MOVE COMPONENT_MOVABLE_BLOCK_PRE_MOVE
/// The argument of move_args which corresponds to the loc we're moving to
#define MOVE_ARG_NEW_LOC 1
- /// The arugment of move_args which dictates our movement direction
+ /// The argument of move_args which dictates our movement direction
#define MOVE_ARG_DIRECTION 2
/// From base of /client/Move(): (direction, old_dir)
#define COMSIG_MOB_CLIENT_MOVED "mob_client_moved"
@@ -72,7 +72,7 @@
#define COMSIG_MOB_MIND_TRANSFERRED_INTO "mob_mind_transferred_into"
///from mind/transfer_from. Sent to the mob the mind is being transferred out of.
#define COMSIG_MOB_MIND_TRANSFERRED_OUT_OF "mob_mind_transferred_out_of"
-/// From /mob/proc/ghostize() Called when a mob sucessfully ghosts
+/// From /mob/proc/ghostize() Called when a mob successfully ghosts
#define COMSIG_MOB_GHOSTIZED "mob_ghostized"
///from base of obj/allowed(mob/M): (/obj) returns ACCESS_ALLOWED if mob has id access to the obj
@@ -138,6 +138,7 @@
#define SPEECH_FILTERPROOF 8
#define SPEECH_RANGE 9
#define SPEECH_SAYMODE 10
+ #define SPEECH_MODS 11
///from /mob/say_dead(): (mob/speaker, message)
#define COMSIG_MOB_DEADSAY "mob_deadsay"
@@ -150,8 +151,6 @@
/// from base of mob/swap_hand(): ()
/// Performed after the hands are swapped.
#define COMSIG_MOB_SWAP_HANDS "mob_swap_hands"
-///from base of /mob/verb/pointed: (atom/A)
-#define COMSIG_MOB_POINTED "mob_pointed"
///Mob is trying to open the wires of a target [/atom], from /datum/wires/interactable(): (atom/target)
#define COMSIG_TRY_WIRES_INTERACT "try_wires_interact"
#define COMPONENT_CANT_INTERACT_WIRES (1<<0)
@@ -248,3 +247,6 @@
/// from /mob/proc/key_down(): (key, client/client, full_key)
#define COMSIG_MOB_KEYDOWN "mob_key_down"
+
+/// from /mob/update_incapacitated(): (old_incap, new_incap)
+#define COMSIG_MOB_INCAPACITATE_CHANGED "mob_incapacitated"
diff --git a/code/__DEFINES/dcs/signals/signals_object.dm b/code/__DEFINES/dcs/signals/signals_object.dm
index 45b671141a380..797256017d456 100644
--- a/code/__DEFINES/dcs/signals/signals_object.dm
+++ b/code/__DEFINES/dcs/signals/signals_object.dm
@@ -153,12 +153,12 @@
/// Sebt from obj/item/ui_action_click(): (mob/user, datum/action)
#define COMSIG_ITEM_UI_ACTION_CLICK "item_action_click"
- /// Return to prevent the default behavior (attack_selfing) from ocurring.
+ /// Return to prevent the default behavior (attack_selfing) from occurring.
#define COMPONENT_ACTION_HANDLED (1<<0)
/// Sent from obj/item/item_action_slot_check(): (mob/user, datum/action, slot)
#define COMSIG_ITEM_UI_ACTION_SLOT_CHECKED "item_action_slot_checked"
- /// Return to prevent the default behavior (attack_selfing) from ocurring.
+ /// Return to prevent the default behavior (attack_selfing) from occurring.
#define COMPONENT_ITEM_ACTION_SLOT_INVALID (1<<0)
///from base of mob/living/carbon/attacked_by(): (mob/living/carbon/target, mob/living/user, hit_zone)
@@ -530,6 +530,9 @@
/// from /datum/component/dart_insert/on_reskin()
#define COMSIG_DART_INSERT_PARENT_RESKINNED "dart_insert_parent_reskinned"
+/// from /datum/element/undertile/hide()
+#define COMSIG_UNDERTILE_UPDATED "undertile_updated"
+
/// Sent from /obj/item/update_weight_class(). (old_w_class, new_w_class)
#define COMSIG_ITEM_WEIGHT_CLASS_CHANGED "item_weight_class_changed"
/// Sent from /obj/item/update_weight_class(), to its loc. (obj/item/changed_item, old_w_class, new_w_class)
diff --git a/code/__DEFINES/dcs/signals/signals_reagent.dm b/code/__DEFINES/dcs/signals/signals_reagent.dm
index 5bb2c89d4ef33..367ec946361d0 100644
--- a/code/__DEFINES/dcs/signals/signals_reagent.dm
+++ b/code/__DEFINES/dcs/signals/signals_reagent.dm
@@ -53,8 +53,6 @@
#define COMSIG_REAGENTS_EXPOSE_MOB "reagents_expose_mob"
///from base of [/turf/proc/expose_reagents]: (/turf, /list, methods, volume_modifier, show_message)
#define COMSIG_REAGENTS_EXPOSE_TURF "reagents_expose_turf"
-///from base of [/datum/component/personal_crafting/proc/del_reqs]: ()
-#define COMSIG_REAGENTS_CRAFTING_PING "reagents_crafting_ping"
/// sent when reagents are transfered from a cup, to something refillable (atom/transfer_to)
#define COMSIG_REAGENTS_CUP_TRANSFER_TO "reagents_cup_transfer_to"
/// sent when reagents are transfered from some reagent container, to a cup (atom/transfer_from)
diff --git a/code/__DEFINES/dcs/signals/signals_spell.dm b/code/__DEFINES/dcs/signals/signals_spell.dm
index d9ef98527e25c..8d02affded85a 100644
--- a/code/__DEFINES/dcs/signals/signals_spell.dm
+++ b/code/__DEFINES/dcs/signals/signals_spell.dm
@@ -113,7 +113,7 @@
// Charge
/// Sent from /datum/action/cooldown/spell/charge/cast(), to the item in hand being charged: (datum/action/cooldown/spell/spell, mob/user)
#define COMSIG_ITEM_MAGICALLY_CHARGED "item_magic_charged"
- /// Return if an item was successfuly recharged
+ /// Return if an item was successful recharged
#define COMPONENT_ITEM_CHARGED (1 << 0)
/// Return if the item had a negative side effect occur while recharging
#define COMPONENT_ITEM_BURNT_OUT (1 << 1)
diff --git a/code/__DEFINES/dcs/signals/signals_tools.dm b/code/__DEFINES/dcs/signals/signals_tools.dm
index 562aa29d595c0..110db1ed89c16 100644
--- a/code/__DEFINES/dcs/signals/signals_tools.dm
+++ b/code/__DEFINES/dcs/signals/signals_tools.dm
@@ -1,6 +1,6 @@
// Notifies tools that something is happening.
-// Sucessful actions against an atom.
+// Successful actions against an atom.
///Called from /atom/proc/tool_act (atom)
#define COMSIG_TOOL_ATOM_ACTED_PRIMARY(tooltype) "tool_atom_acted_[tooltype]"
///Called from /atom/proc/tool_act (atom)
diff --git a/code/__DEFINES/events.dm b/code/__DEFINES/events.dm
index 2b1755b22c4b4..7045d8f0c65f7 100644
--- a/code/__DEFINES/events.dm
+++ b/code/__DEFINES/events.dm
@@ -22,7 +22,7 @@
#define EVENT_CATEGORY_FRIENDLY "Friendly"
///Events that affect the body and mind
#define EVENT_CATEGORY_HEALTH "Health"
-///Events reserved for special occassions
+///Events reserved for special occasions
#define EVENT_CATEGORY_HOLIDAY "Holiday"
///Events with enemy groups with a more complex plan
#define EVENT_CATEGORY_INVASION "Invasion"
diff --git a/code/__DEFINES/fish.dm b/code/__DEFINES/fish.dm
index 3671ff3d8cdc6..d6bcc2ec796e5 100644
--- a/code/__DEFINES/fish.dm
+++ b/code/__DEFINES/fish.dm
@@ -1,5 +1,7 @@
/// Use in fish tables to denote miss chance.
#define FISHING_DUD "dud"
+///Used in the the hydro tray fishing spot to define a random seed reward
+#define FISHING_RANDOM_SEED "Random seed"
// Baseline fishing difficulty levels
#define FISHING_DEFAULT_DIFFICULTY 15
@@ -14,11 +16,6 @@
#define FISH_TRAIT_MINOR_DIFFICULTY_BOOST 5
-// These define how the fish will behave in the minigame
-#define FISH_AI_DUMB "dumb"
-#define FISH_AI_ZIPPY "zippy"
-#define FISH_AI_SLOW "slow"
-
///Slot defines for the fishing rod and its equipment
#define ROD_SLOT_BAIT "bait"
#define ROD_SLOT_LINE "line"
@@ -89,7 +86,12 @@
#define FISH_ICON_GEM "gem"
#define FISH_ICON_CRAB "crab"
#define FISH_ICON_JELLYFISH "jellyfish"
+#define FISH_ICON_BOTTLE "bottle"
#define FISH_ICON_BONE "bone"
+#define FISH_ICON_ELECTRIC "electric"
+#define FISH_ICON_WEAPON "weapon"
+#define FISH_ICON_CRITTER "critter"
+#define FISH_ICON_SEED "seed"
#define AQUARIUM_ANIMATION_FISH_SWIM "fish"
#define AQUARIUM_ANIMATION_FISH_DEAD "dead"
@@ -110,8 +112,11 @@
///Fish size thresholds for w_class.
#define FISH_SIZE_TINY_MAX 30
#define FISH_SIZE_SMALL_MAX 50
-#define FISH_SIZE_NORMAL_MAX 90
-#define FISH_SIZE_BULKY_MAX 130
+#define FISH_SIZE_NORMAL_MAX 80
+#define FISH_SIZE_BULKY_MAX 120
+///size threshold for requiring two-handed carry
+#define FISH_SIZE_TWO_HANDS_REQUIRED 135
+#define FISH_SIZE_HUGE_MAX 165
///The coefficient for maximum weight/size divergence relative to the averages.
#define MAX_FISH_DEVIATION_COEFF 2.5
@@ -121,6 +126,15 @@
///The number of fillets is multiplied by the fish' size and divided by this.
#define FISH_FILLET_NUMBER_SIZE_DIVISOR 30
+///The slowdown of the fish when carried begins at this value
+#define FISH_WEIGHT_SLOWDOWN 2100
+///The value of the slowdown equals to the weight divided by this (and then at the power of a sub-1 exponent)
+#define FISH_WEIGHT_SLOWDOWN_DIVISOR 500
+///The sub-one exponent that results in the final slowdown of the fish item
+#define FISH_WEIGHT_SLOWDOWN_EXPONENT 0.54
+///Used to calculate the force of the fish by comparing (1 + log(weight/this_define)) and the w_class of the item.
+#define FISH_WEIGHT_FORCE_DIVISOR 250
+
///The breeding timeout for newly instantiated fish is multiplied by this.
#define NEW_FISH_BREEDING_TIMEOUT_MULT 2
///The last feeding timestamp of newly instantiated fish is multiplied by this: ergo, they spawn 50% hungry.
@@ -164,3 +178,7 @@
//Fish breeding stops if fish count exceeds this.
#define AQUARIUM_MAX_BREEDING_POPULATION 20
+
+//Minigame defines
+/// The height of the minigame slider. Not in pixels, but minigame units.
+#define FISHING_MINIGAME_AREA 1000
diff --git a/code/__DEFINES/food.dm b/code/__DEFINES/food.dm
index 3787aeb4df7b9..c9b7cb43cf0d9 100644
--- a/code/__DEFINES/food.dm
+++ b/code/__DEFINES/food.dm
@@ -139,7 +139,7 @@ GLOBAL_LIST_INIT(food_quality_events, list(
FOOD_QUALITY_TOP = /datum/mood_event/food/top,
))
-/// Crafted food buffs grouped by crafting_complexity
+/// Weighted lists of crafted food buffs randomly given according to crafting_complexity unless the food has a specific buff
GLOBAL_LIST_INIT(food_buffs, list(
FOOD_COMPLEXITY_1 = list(
/datum/status_effect/food/haste = 1,
@@ -152,11 +152,9 @@ GLOBAL_LIST_INIT(food_buffs, list(
),
FOOD_COMPLEXITY_4 = list(
/datum/status_effect/food/haste = 1,
- /datum/status_effect/food/trait/shockimmune = 1,
),
FOOD_COMPLEXITY_5 = list(
/datum/status_effect/food/haste = 1,
- /datum/status_effect/food/trait/shockimmune = 2,
),
))
diff --git a/code/__DEFINES/icon_smoothing.dm b/code/__DEFINES/icon_smoothing.dm
index a853fde0c5dee..5fce59b17fb72 100644
--- a/code/__DEFINES/icon_smoothing.dm
+++ b/code/__DEFINES/icon_smoothing.dm
@@ -206,6 +206,8 @@ DEFINE_BITFIELD(smoothing_junction, list(
#define SMOOTH_GROUP_SPIDER_WEB_WALL_TOUGH S_OBJ(73) // /obj/structure/spider/stickyweb/sealed/thick
#define SMOOTH_GROUP_SPIDER_WEB_WALL_MIRROR S_OBJ(74) // /obj/structure/spider/stickyweb/sealed/reflector
+#define SMOOTH_GROUP_GRAV_FIELD S_OBJ(69)
+
/// Performs the work to set smoothing_groups and canSmoothWith.
/// An inlined function used in both turf/Initialize and atom/Initialize.
#define SETUP_SMOOTHING(...) \
diff --git a/code/__DEFINES/inventory.dm b/code/__DEFINES/inventory.dm
index 63054e533b1bf..c58f12bf5c957 100644
--- a/code/__DEFINES/inventory.dm
+++ b/code/__DEFINES/inventory.dm
@@ -63,6 +63,8 @@
#define ITEM_SLOT_HANDCUFFED (1<<18)
/// Legcuff slot (bolas, beartraps)
#define ITEM_SLOT_LEGCUFFED (1<<19)
+/// Inside of a character's BELT.........
+#define ITEM_SLOT_BELTPACK (1<<20)
/// Total amount of slots
#define SLOTS_AMT 20 // Keep this up to date!
@@ -148,12 +150,18 @@ DEFINE_BITFIELD(no_equip_flags, list(
#define DIGITIGRADE_STYLE 2
//Flags (actual flags, fucker ^) for /obj/item/var/supports_variations_flags
-///No alternative sprites based on bodytype
+/// No alternative sprites or handling based on bodytype
#define CLOTHING_NO_VARIATION (1<<0)
-///Has a sprite for digitigrade legs specifically.
+/// Has a sprite for digitigrade legs specifically.
#define CLOTHING_DIGITIGRADE_VARIATION (1<<1)
-///The sprite works fine for digitigrade legs as-is.
+/// The sprite works fine for digitigrade legs as-is.
#define CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON (1<<2)
+/// Auto-generates the leg portion of the sprite with GAGS
+/// Suggested that you set [/obj/item/var/digitigrade_greyscale_config_worn] when using this flag
+#define CLOTHING_DIGITIGRADE_MASK (1<<3)
+
+/// All variation flags which render "correctly" on a digitigrade leg setup
+#define DIGITIGRADE_VARIATIONS (CLOTHING_DIGITIGRADE_VARIATION|CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON|CLOTHING_DIGITIGRADE_MASK)
//flags for covering body parts
#define GLASSESCOVERSEYES (1<<0)
diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm
index 0d9d28d4d858a..8846672efe1b7 100644
--- a/code/__DEFINES/is_helpers.dm
+++ b/code/__DEFINES/is_helpers.dm
@@ -69,6 +69,8 @@ GLOBAL_LIST_INIT(turfs_openspace, typecacheof(list(
#define isplatingturf(A) (istype(A, /turf/open/floor/plating))
+#define iscatwalkturf(A) (istype(A, /turf/open/floor/catwalk_floor))
+
#define isasteroidturf(A) (istype(A, /turf/open/misc/asteroid))
#define istransparentturf(A) (HAS_TRAIT(A, TURF_Z_TRANSPARENT_TRAIT))
@@ -137,19 +139,15 @@ GLOBAL_LIST_INIT(turfs_pass_meteor, typecacheof(list(
//Silicon mobs
#define issilicon(A) (istype(A, /mob/living/silicon))
-///Define on whether A has access to Silicon stuff either through being a silicon, admin ghost or is a non-silicon holding the Silicon remote.
-///This can only be used for instances where you are not specifically looking for silicon, but access.
-#define HAS_SILICON_ACCESS(A) (istype(A, /mob/living/silicon) || isAdminGhostAI(A) || A.has_unlimited_silicon_privilege || istype(A.get_active_held_item(), /obj/item/machine_remote))
-
#define isAI(A) (istype(A, /mob/living/silicon/ai))
-///Define on whether A has access to AI stuff either through being a AI, admin ghost, or is a non-silicon holding the Silicon remote
-///This can only be used for instances where you are not specifically looking for silicon, but access.
-#define HAS_AI_ACCESS(A) (istype(A, /mob/living/silicon/ai) || isAdminGhostAI(A) || istype(A.get_active_held_item(), /obj/item/machine_remote))
-
#define iscyborg(A) (istype(A, /mob/living/silicon/robot))
-
#define ispAI(A) (istype(A, /mob/living/silicon/pai))
+///This is used to see if you have Silicon access. This includes things like Admins, Drones, Bots, and Human wands.
+#define HAS_SILICON_ACCESS(possible_silicon) (HAS_TRAIT(possible_silicon, TRAIT_SILICON_ACCESS) || isAdminGhostAI(possible_silicon))
+///This is used to see if you have the access of an AI. This doesn't mean you are an AI, just have the same access as one.
+#define HAS_AI_ACCESS(possible_ai) (HAS_TRAIT(possible_ai, TRAIT_AI_ACCESS) || isAdminGhostAI(possible_ai))
+
// basic mobs
#define isbasicmob(A) (istype(A, /mob/living/basic))
diff --git a/code/__DEFINES/language.dm b/code/__DEFINES/language.dm
index cd6ee5ec0c9bd..d530185c14288 100644
--- a/code/__DEFINES/language.dm
+++ b/code/__DEFINES/language.dm
@@ -27,6 +27,7 @@
#define LANGUAGE_GLAND "gland"
#define LANGUAGE_HAT "hat"
#define LANGUAGE_QUIRK "quirk"
+#define LANGUAGE_DRINK "drink"
#define LANGUAGE_MALF "malf"
#define LANGUAGE_PIRATE "pirate"
#define LANGUAGE_MASTER "master"
diff --git a/code/__DEFINES/layers.dm b/code/__DEFINES/layers.dm
index 55272920fdd5a..d5c17a877a4b6 100644
--- a/code/__DEFINES/layers.dm
+++ b/code/__DEFINES/layers.dm
@@ -145,9 +145,9 @@
#define WIRE_LAYER (9 + TOPDOWN_LAYER)
#define GLASS_FLOOR_LAYER (10 + TOPDOWN_LAYER)
#define TRAM_RAIL_LAYER (11 + TOPDOWN_LAYER)
+#define ABOVE_OPEN_TURF_LAYER (12 + TOPDOWN_LAYER)
///catwalk overlay of /turf/open/floor/plating/catwalk_floor
-#define CATWALK_LAYER (12 + TOPDOWN_LAYER)
-#define ABOVE_OPEN_TURF_LAYER (13 + TOPDOWN_LAYER)
+#define CATWALK_LAYER (13 + TOPDOWN_LAYER)
//WALL_PLANE layers
#define BELOW_CLOSED_TURF_LAYER 2.053
@@ -253,7 +253,7 @@
//---------- EMISSIVES -------------
//Layering order of these is not particularly meaningful.
-//Important part is the seperation of the planes for control via plane_master
+//Important part is the separation of the planes for control via plane_master
/// The layer you should use if you _really_ don't want an emissive overlay to be blocked.
#define EMISSIVE_LAYER_UNBLOCKABLE 9999
diff --git a/code/__DEFINES/lighting.dm b/code/__DEFINES/lighting.dm
index 2c3c1c34f0836..a59d1b2c14449 100644
--- a/code/__DEFINES/lighting.dm
+++ b/code/__DEFINES/lighting.dm
@@ -77,21 +77,21 @@
#define _EMISSIVE_COLOR(val) list(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, val,val,val,0)
/// The color matrix applied to all emissive overlays. Should be solely dependent on alpha and not have RGB overlap with [EM_BLOCK_COLOR].
#define EMISSIVE_COLOR _EMISSIVE_COLOR(1)
-/// A globaly cached version of [EMISSIVE_COLOR] for quick access.
+/// A globally cached version of [EMISSIVE_COLOR] for quick access.
GLOBAL_LIST_INIT(emissive_color, EMISSIVE_COLOR)
#define _EM_BLOCK_COLOR(val) list(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,val, 0,0,0,0)
/// The color matrix applied to all emissive blockers. Should be solely dependent on alpha and not have RGB overlap with [EMISSIVE_COLOR].
#define EM_BLOCK_COLOR _EM_BLOCK_COLOR(1)
-/// A globaly cached version of [EM_BLOCK_COLOR] for quick access.
+/// A globally cached version of [EM_BLOCK_COLOR] for quick access.
GLOBAL_LIST_INIT(em_block_color, EM_BLOCK_COLOR)
/// A set of appearance flags applied to all emissive and emissive blocker overlays.
-/// KEEP_APART to prevent parent hooking, KEEP_TOGETHER for children, and we reset the color and alpha of our parent so nothing gets overriden
+/// KEEP_APART to prevent parent hooking, KEEP_TOGETHER for children, and we reset the color and alpha of our parent so nothing gets overridden
#define EMISSIVE_APPEARANCE_FLAGS (KEEP_APART|KEEP_TOGETHER|RESET_COLOR|RESET_ALPHA)
-/// The color matrix used to mask out emissive blockers on the emissive plane. Alpha should default to zero, be solely dependent on the RGB value of [EMISSIVE_COLOR], and be independant of the RGB value of [EM_BLOCK_COLOR].
+/// The color matrix used to mask out emissive blockers on the emissive plane. Alpha should default to zero, be solely dependent on the RGB value of [EMISSIVE_COLOR], and be independent of the RGB value of [EM_BLOCK_COLOR].
#define EM_MASK_MATRIX list(0,0,0,1/3, 0,0,0,1/3, 0,0,0,1/3, 0,0,0,0, 1,1,1,0)
-/// A globaly cached version of [EM_MASK_MATRIX] for quick access.
+/// A globally cached version of [EM_MASK_MATRIX] for quick access.
GLOBAL_LIST_INIT(em_mask_matrix, EM_MASK_MATRIX)
/// Parse the hexadecimal color into lumcounts of each perspective.
diff --git a/code/__DEFINES/living.dm b/code/__DEFINES/living.dm
index 63993f4bc620b..340bf3608bb5d 100644
--- a/code/__DEFINES/living.dm
+++ b/code/__DEFINES/living.dm
@@ -4,3 +4,6 @@
/// Always does *deathgasp when they die
/// If unset mobs will only deathgasp if supplied a death sound or custom death message
#define ALWAYS_DEATHGASP (1<<1)
+
+/// Getter for a mob/living's lying angle, otherwise protected
+#define GET_LYING_ANGLE(mob) (UNLINT(mob.lying_angle))
diff --git a/code/__DEFINES/machines.dm b/code/__DEFINES/machines.dm
index d7245d8b6f362..9d2cf451c62e1 100644
--- a/code/__DEFINES/machines.dm
+++ b/code/__DEFINES/machines.dm
@@ -52,7 +52,7 @@
#define BYPASS_DOOR_CHECKS 2
//used in design to specify which machine can build it
-//Note: More than one of these can be added to a design but imprinter and lathe designs are incompatable.
+//Note: More than one of these can be added to a design but imprinter and lathe designs are incompatible.
#define IMPRINTER (1<<0) //For circuits. Uses glass/chemicals.
#define PROTOLATHE (1<<1) //New stuff. Uses various minerals
#define AUTOLATHE (1<<2) //Prints basic designs without research
diff --git a/code/__DEFINES/market.dm b/code/__DEFINES/market.dm
index f0a19ad056d9a..e0bd457835208 100644
--- a/code/__DEFINES/market.dm
+++ b/code/__DEFINES/market.dm
@@ -10,3 +10,5 @@
// Sends a supply pod to the buyer's location, showy.
#define SHIPPING_METHOD_SUPPLYPOD "Supply Pod"
+/// The percentage on gains that's removed when selling an item through the blackmarket with the LTSRBT
+#define MARKET_WITHHOLDING_TAX 0.15
diff --git a/code/__DEFINES/melee.dm b/code/__DEFINES/melee.dm
index 8b3a422fc0b25..1880c75c97b8d 100644
--- a/code/__DEFINES/melee.dm
+++ b/code/__DEFINES/melee.dm
@@ -1,8 +1,9 @@
//Martial arts defines
#define MARTIALART_BOXING "boxing"
-#define MARTIALART_EVIL_BOXING "evil boxing"
#define MARTIALART_CQC "CQC"
+#define MARTIALART_EVIL_BOXING "evil boxing"
+#define MARTIALART_HUNTER_BOXING "hunter boxing"
#define MARTIALART_KRAVMAGA "krav maga"
#define MARTIALART_MUSHPUNCH "mushroom punch"
#define MARTIALART_PLASMAFIST "plasma fist"
diff --git a/code/__DEFINES/mobfactions.dm b/code/__DEFINES/mobfactions.dm
index aea143dad253c..cb934a28f5c5a 100644
--- a/code/__DEFINES/mobfactions.dm
+++ b/code/__DEFINES/mobfactions.dm
@@ -33,13 +33,13 @@
#define FACTION_HELL "hell"
/// Hivebots
#define FACTION_HIVEBOT "hivebot"
-/// Illusionary creaturs
+/// Illusionary creatures
#define FACTION_ILLUSION "illusion"
/// Creatures of the never finished jungle planet, and gorillas
#define FACTION_JUNGLE "jungle"
/// Small lizards
#define FACTION_LIZARD "lizard"
-/// Maint creatures have mutual respect for eachother.
+/// Maint creatures have mutual respect for each other.
#define FACTION_MAINT_CREATURES "maint_creatures"
/// Animated objects and statues
#define FACTION_MIMIC "mimic"
diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm
index b722c1a96155b..0de4d7e6ab763 100644
--- a/code/__DEFINES/mobs.dm
+++ b/code/__DEFINES/mobs.dm
@@ -152,7 +152,10 @@
///The species is forced to have digitigrade legs in generation.
#define DIGITIGRADE_FORCED 2
-///Digitigrade's prefs, used in features for legs if you're meant to be a Digitigrade.
+// Preferences for leg types
+/// Legs that are normal
+#define NORMAL_LEGS "Normal Legs"
+/// Digitgrade legs that are like bended and uhhh no shoes
#define DIGITIGRADE_LEGS "Digitigrade Legs"
// Health/damage defines
@@ -305,7 +308,7 @@
#define BRUTE_DAMAGE_REQUIRED_TO_STOP_CRYSTALIZATION 30
-#define CRYSTALIZE_STAGE_ENGULFING 100 //Cant use second defines
+#define CRYSTALIZE_STAGE_ENGULFING 100 //Can't use second defines
#define CRYSTALIZE_STAGE_ENCROACHING 300 //In switches
#define CRYSTALIZE_STAGE_SMALL 600 //Because they're not static
@@ -508,7 +511,7 @@
#define WABBAJACK_HUMAN "humanoid"
#define WABBAJACK_ANIMAL "animal"
-// Reasons a defibrilation might fail
+// Reasons a defibrillation might fail
#define DEFIB_POSSIBLE (1<<0)
#define DEFIB_FAIL_SUICIDE (1<<1)
#define DEFIB_FAIL_HUSK (1<<2)
@@ -713,7 +716,7 @@ GLOBAL_LIST_INIT(human_heights_to_offsets, list(
/// Glasses layer
#define GLASSES_LAYER 17
/// Belt layer
-#define BELT_LAYER 16 //Possible make this an overlay of somethign required to wear a belt?
+#define BELT_LAYER 16 //Possible make this an overlay of something required to wear a belt?
/// Suit storage layer (tucking a gun or baton underneath your armor)
#define SUIT_STORE_LAYER 15
/// Neck layer (for wearing capes and bedsheets)
@@ -844,7 +847,7 @@ GLOBAL_LIST_INIT(layers_to_offset, list(
#define NEED_VENTCRAWL (1<<8)
/// Skips adjacency checks
#define BYPASS_ADJACENCY (1<<9)
-/// Skips reccursive loc checks
+/// Skips recursive loc checks
#define NOT_INSIDE_TARGET (1<<10)
/// Checks for base adjacency, but silences the error
#define SILENT_ADJACENCY (1<<11)
@@ -878,6 +881,8 @@ GLOBAL_LIST_INIT(layers_to_offset, list(
/// Possible value of [/atom/movable/buckle_lying]. If set to a different (positive-or-zero) value than this, the buckling thing will force a lying angle on the buckled.
#define NO_BUCKLE_LYING -1
+/// Possible value of [/atom/movable/buckle_dir]. If set to a different (positive-or-zero) value than this, the buckling thing will force a dir on the buckled.
+#define BUCKLE_MATCH_DIR -1
// Flags for fully_heal().
@@ -974,6 +979,8 @@ GLOBAL_LIST_INIT(layers_to_offset, list(
/// The duration of the flip emote animation
#define FLIP_EMOTE_DURATION 0.7 SECONDS
+///The duration of a taunt emote, so how long they can deflect projectiles
+#define TAUNT_EMOTE_DURATION 0.9 SECONDS
// Sprites for photocopying butts
#define BUTT_SPRITE_HUMAN_MALE "human_male"
diff --git a/code/__DEFINES/mod.dm b/code/__DEFINES/mod.dm
index 8257e1969bedb..1a4bed1ca9922 100644
--- a/code/__DEFINES/mod.dm
+++ b/code/__DEFINES/mod.dm
@@ -5,7 +5,7 @@
#define DEFAULT_CHARGE_DRAIN (0.005 * STANDARD_CELL_CHARGE) // A standard cell lasts 200 seconds with this on active power usage, while a high power one lasts 2,000 seconds.
/// Default time for a part of the suit to seal.
-#define MOD_ACTIVATION_STEP_TIME (2 SECONDS)
+#define MOD_ACTIVATION_STEP_TIME (1 SECONDS)
/// Passive module, just acts when put in naturally.
#define MODULE_PASSIVE 0
diff --git a/code/__DEFINES/paper.dm b/code/__DEFINES/paper.dm
index 0d70a2f3ca40d..9cede4214bd93 100644
--- a/code/__DEFINES/paper.dm
+++ b/code/__DEFINES/paper.dm
@@ -18,3 +18,29 @@
#define BARCODE_SCANNER_INVENTORY "inventory"
#define IS_WRITING_UTENSIL(thing) (thing?.get_writing_implement_details()?["interaction_mode"] == MODE_WRITING)
+
+/**
+ * key defines used when converting a paper to and fro' a data/json list. It's really important that they stay the same
+ * lest we break persistence.
+ */
+#define LIST_PAPER_COLOR "paper_color"
+#define LIST_PAPER_NAME "paper_name"
+
+#define LIST_PAPER_RAW_TEXT_INPUT "raw_text_input"
+#define LIST_PAPER_RAW_FIELD_INPUT "raw_field_input"
+#define LIST_PAPER_RAW_STAMP_INPUT "raw_stamp_input"
+
+#define LIST_PAPER_RAW_TEXT "raw_text"
+#define LIST_PAPER_FONT "font"
+#define LIST_PAPER_FIELD_COLOR "color"
+#define LIST_PAPER_BOLD "bold"
+#define LIST_PAPER_ADVANCED_HTML "advanced_html"
+
+#define LIST_PAPER_FIELD_INDEX "field_index"
+#define LIST_PAPER_FIELD_DATA "field_data"
+#define LIST_PAPER_IS_SIGNATURE "is_signature"
+
+#define LIST_PAPER_CLASS "class"
+#define LIST_PAPER_STAMP_X "x"
+#define LIST_PAPER_STAMP_Y "y"
+#define LIST_PAPER_ROTATION "rotation"
diff --git a/code/__DEFINES/radio.dm b/code/__DEFINES/radio.dm
index 686c42e07d075..44e4417a20996 100644
--- a/code/__DEFINES/radio.dm
+++ b/code/__DEFINES/radio.dm
@@ -37,6 +37,10 @@
#define RADIO_KEY_AI_PRIVATE "o"
#define RADIO_TOKEN_AI_PRIVATE ":o"
+#define RADIO_CHANNEL_ENTERTAINMENT "Entertainment"
+#define RADIO_KEY_ENTERTAINMENT "p"
+#define RADIO_TOKEN_ENTERTAINMENT ":p"
+
#define RADIO_CHANNEL_SYNDICATE "Syndicate"
#define RADIO_KEY_SYNDICATE "t"
@@ -73,6 +77,7 @@
#define FREQ_MEDICAL 1355 // Medical comms frequency, soft blue
#define FREQ_ENGINEERING 1357 // Engineering comms frequency, orange
#define FREQ_SECURITY 1359 // Security comms frequency, red
+#define FREQ_ENTERTAINMENT 1415 // Used by entertainment monitors, cyan
#define FREQ_HOLOGRID_SOLUTION 1433
#define FREQ_STATUS_DISPLAYS 1435
@@ -130,3 +135,10 @@
#define RADIO_FREQENCY_LOCKED 1
/// Radio frequency is locked and unchangeable, but can be unlocked by an emag
#define RADIO_FREQENCY_EMAGGABLE_LOCK 2
+
+///Bitflag for if a headset can use the syndicate radio channel
+#define RADIO_SPECIAL_SYNDIE (1<<0)
+///Bitflag for if a headset can use the centcom radio channel
+#define RADIO_SPECIAL_CENTCOM (1<<1)
+///Bitflag for if a headset can use the binary radio channel
+#define RADIO_SPECIAL_BINARY (1<<2)
diff --git a/code/__DEFINES/reactions.dm b/code/__DEFINES/reactions.dm
index 98f8d4a18278d..a8c111c516476 100644
--- a/code/__DEFINES/reactions.dm
+++ b/code/__DEFINES/reactions.dm
@@ -89,7 +89,7 @@
#define FREON_MAXIMUM_BURN_TEMPERATURE 283
///Minimum temperature allowed for the burn to go at max speed, we would have negative pressure otherwise
#define FREON_LOWER_TEMPERATURE 60
-///Terminal temperature after wich we stop the reaction
+///Terminal temperature after which we stop the reaction
#define FREON_TERMINAL_TEMPERATURE 20
/// Multiplier for freonfire with O2 moles * FREON_OXYGEN_FULLBURN for the maximum fuel consumption
#define FREON_OXYGEN_FULLBURN 10
diff --git a/code/__DEFINES/research/anomalies.dm b/code/__DEFINES/research/anomalies.dm
index 93f1bc924c288..e04aead3464bc 100644
--- a/code/__DEFINES/research/anomalies.dm
+++ b/code/__DEFINES/research/anomalies.dm
@@ -2,7 +2,7 @@
#define MAX_CORES_BLUESPACE 3
#define MAX_CORES_GRAVITATIONAL 6
#define MAX_CORES_FLUX 8
-#define MAX_CORES_VORTEX 1
+#define MAX_CORES_VORTEX 3
#define MAX_CORES_PYRO 8
#define MAX_CORES_HALLUCINATION 8
#define MAX_CORES_BIOSCRAMBLER 8
diff --git a/code/__DEFINES/research/techweb_nodes.dm b/code/__DEFINES/research/techweb_nodes.dm
index 3c730e02169fa..f27225f1fedee 100644
--- a/code/__DEFINES/research/techweb_nodes.dm
+++ b/code/__DEFINES/research/techweb_nodes.dm
@@ -14,7 +14,7 @@
#define TECHWEB_NODE_BEAM_WEAPONS "beam_weapons"
#define TECHWEB_NODE_BIO_SCAN "bio_scan"
#define TECHWEB_NODE_BITRUNNING "bitrunning"
-#define TECHWEB_NODE_BLUESPACE "bluespace"
+#define TECHWEB_NODE_MECH_EQUIP_BLUESPACE "mech_equip_bluespace"
#define TECHWEB_NODE_BLUESPACE_THEORY "bluespace_theory"
#define TECHWEB_NODE_BLUESPACE_TRAVEL "bluespace_travel"
#define TECHWEB_NODE_BORG_ENGI "borg_engi"
diff --git a/code/__DEFINES/shuttles.dm b/code/__DEFINES/shuttles.dm
index 6f15ea6521638..759121e3b8dd8 100644
--- a/code/__DEFINES/shuttles.dm
+++ b/code/__DEFINES/shuttles.dm
@@ -36,7 +36,7 @@
/// These shuttles leave when the main emergency shuttle does but don't dock anywhere (to save space), so this counts as "escaped".
#define ENDGAME_TRANSIT 3
-//positive value = cannot puchase
+//positive value = cannot purchase
#define SHUTTLEPURCHASE_PURCHASABLE 0 //station can buy a shuttle
#define SHUTTLEPURCHASE_PURCHASED 1 //station has already bought a shuttle, so cannot
#define SHUTTLEPURCHASE_FORCED 2 //station was given a new shuttle through events or other shenanigans
diff --git a/code/__DEFINES/sight.dm b/code/__DEFINES/sight.dm
index 645e009413593..5a3e0d17ef348 100644
--- a/code/__DEFINES/sight.dm
+++ b/code/__DEFINES/sight.dm
@@ -71,7 +71,7 @@
//------------------------
// INVISIBILITY SOURCE IDS
// Though don't feel the need to add one here if you have a simple effect that
-// gets added and/or removed in only one place near eachother in the code.
+// gets added and/or removed in only one place near each other in the code.
#define INVISIBILITY_SOURCE_INVISIMIN "invisimin"
#define INVISIBILITY_SOURCE_STEALTHMODE "stealthmode"
diff --git a/code/__DEFINES/sound.dm b/code/__DEFINES/sound.dm
index 0034ce1c38e6f..168e4f9d85dfe 100644
--- a/code/__DEFINES/sound.dm
+++ b/code/__DEFINES/sound.dm
@@ -180,3 +180,11 @@ GLOBAL_LIST_INIT(announcer_keys, list(
#define SFX_PORTAL_CLOSE "portal_closed"
#define SFX_PORTAL_CREATED "portal_created"
#define SFX_SCREECH "screech"
+#define SFX_TOOL_SWITCH "tool_switch"
+#define SFX_KEYBOARD_CLICKS "keyboard_clicks"
+#define SFX_STONE_DROP "stone_drop"
+#define SFX_STONE_PICKUP "stone_pickup"
+#define SFX_MUFFLED_SPEECH "muffspeech"
+#define SFX_DEFAULT_FISH_SLAP "default_fish_slap"
+#define SFX_ALT_FISH_SLAP "alt_fish_slap"
+#define SFX_FISH_PICKUP "fish_pickup"
diff --git a/code/__DEFINES/span.dm b/code/__DEFINES/span.dm
index fadd00053156d..259a13e1e9afe 100644
--- a/code/__DEFINES/span.dm
+++ b/code/__DEFINES/span.dm
@@ -48,6 +48,7 @@
#define span_drone(str) ("" + str + "")
#define span_engradio(str) ("" + str + "")
#define span_extremelybig(str) ("" + str + "")
+#define span_enteradio(str) ("" + str + "")
#define span_game_say(str) ("" + str + "")
#define span_ghostalert(str) ("" + str + "")
#define span_green(str) ("" + str + "")
diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm
index 8ada83a2109cb..ead7764d60523 100644
--- a/code/__DEFINES/status_effects.dm
+++ b/code/__DEFINES/status_effects.dm
@@ -24,12 +24,18 @@
#define CURSE_GRASPING (1<<3)
//Incapacitated status effect flags
-/// If the incapacitated status effect will ignore a mob in restraints (handcuffs)
-#define IGNORE_RESTRAINTS (1<<0)
-/// If the incapacitated status effect will ignore a mob in stasis (stasis beds)
-#define IGNORE_STASIS (1<<1)
-/// If the incapacitated status effect will ignore a mob being agressively grabbed
-#define IGNORE_GRAB (1<<2)
+/// If the mob is normal incapacitated. Should never need this, just avoids issues if we ever overexpand this
+#define TRADITIONAL_INCAPACITATED (1<<0)
+/// If the incapacitated status effect is being caused by restraints (handcuffs)
+#define INCAPABLE_RESTRAINTS (1<<1)
+/// If the incapacitated status effect is being caused by stasis (stasis beds)
+#define INCAPABLE_STASIS (1<<2)
+/// If the incapacitated status effect is being caused by being agressively grabbed
+#define INCAPABLE_GRAB (1<<3)
+
+/// Checks to see if a mob would be incapacitated even while ignoring some types
+/// Does this by inverting the passed in flags and seeing if we're still incapacitated
+#define INCAPACITATED_IGNORING(mob, flags) (mob.incapacitated & ~(flags))
/// Maxamounts of fire stacks a mob can get
#define MAX_FIRE_STACKS 20
diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm
index e24ea5e862e4d..60db08791205a 100644
--- a/code/__DEFINES/subsystems.dm
+++ b/code/__DEFINES/subsystems.dm
@@ -39,7 +39,7 @@
* Timing should be based on how timing progresses on clients, not the server.
*
* Tracking this is more expensive,
- * should only be used in conjuction with things that have to progress client side, such as
+ * should only be used in conjunction with things that have to progress client side, such as
* animate() or sound()
*/
#define TIMER_CLIENT_TIME (1<<2)
@@ -81,15 +81,15 @@
///Nothing happens
#define INITIALIZE_HINT_NORMAL 0
/**
- * call LateInitialize at the end of all atom Initalization
+ * call LateInitialize at the end of all atom Initialization
*
* The item will be added to the late_loaders list, this is iterated over after
- * initalization of subsystems is complete and calls LateInitalize on the atom
+ * initialization of subsystems is complete and calls LateInitalize on the atom
* see [this file for the LateIntialize proc](atom.html#proc/LateInitialize)
*/
#define INITIALIZE_HINT_LATELOAD 1
-///Call qdel on the atom after intialization
+///Call qdel on the atom after initialization
#define INITIALIZE_HINT_QDEL 2
///type and all subtypes should always immediately call Initialize in New()
@@ -106,23 +106,23 @@
//! ### SS initialization hints
/**
- * Negative values incidate a failure or warning of some kind, positive are good.
- * 0 and 1 are unused so that TRUE and FALSE are guarenteed to be invalid values.
+ * Negative values indicate a failure or warning of some kind, positive are good.
+ * 0 and 1 are unused so that TRUE and FALSE are guaranteed to be invalid values.
*/
/// Subsystem failed to initialize entirely. Print a warning, log, and disable firing.
#define SS_INIT_FAILURE -2
-/// The default return value which must be overriden. Will succeed with a warning.
+/// The default return value which must be overridden. Will succeed with a warning.
#define SS_INIT_NONE -1
-/// Subsystem initialized sucessfully.
+/// Subsystem initialized successfully.
#define SS_INIT_SUCCESS 2
/// If your system doesn't need to be initialized (by being disabled or something)
#define SS_INIT_NO_NEED 3
-/// Succesfully initialized, BUT do not announce it to players (generally to hide game mechanics it would otherwise spoil)
+/// Successfully initialized, BUT do not announce it to players (generally to hide game mechanics it would otherwise spoil)
#define SS_INIT_NO_MESSAGE 4
//! ### SS initialization load orders
@@ -137,7 +137,7 @@
#define INIT_ORDER_BLACKBOX 94
#define INIT_ORDER_SERVER_MAINT 93
#define INIT_ORDER_INPUT 85
-#define INIT_ORDER_ADMIN_VERBS 84 // needs to be pretty high, admins cant do much without it
+#define INIT_ORDER_ADMIN_VERBS 84 // needs to be pretty high, admins can't do much without it
#define INIT_ORDER_SOUNDS 83
#define INIT_ORDER_INSTRUMENTS 82
#define INIT_ORDER_GREYSCALE 81
@@ -157,6 +157,7 @@
#define INIT_ORDER_TCG 55
#define INIT_ORDER_AUTOMAPPER 51 // BANDASTATION EDIT ADDITION
#define INIT_ORDER_MAPPING 50
+#define INIT_ORDER_AI_IDLE_CONTROLLERS 50
#define INIT_ORDER_EARLY_ASSETS 48
#define INIT_ORDER_RESEARCH 47
#define INIT_ORDER_TIMETRACK 46
@@ -193,7 +194,7 @@
// Subsystem fire priority, from lowest to highest priority
// If the subsystem isn't listed here it's either DEFAULT or PROCESS (if it's a processing subsystem child)
-
+#define FIRE_PRIORITY_IDLE_NPC 5
#define FIRE_PRIORITY_PING 10
#define FIRE_PRIORITY_SERVER_MAINT 10
#define FIRE_PRIORITY_RESEARCH 10
diff --git a/code/__DEFINES/text.dm b/code/__DEFINES/text.dm
index 8b0fda53cd79e..3b5cb5d795011 100644
--- a/code/__DEFINES/text.dm
+++ b/code/__DEFINES/text.dm
@@ -112,3 +112,7 @@
#define SPLASH_FILE "splashes.json"
///File location for mother hallucination lines
#define MOTHER_FILE "mother.json"
+
+#define ALPHABET list("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z")
+#define VOWELS list("a", "e", "i", "o", "u")
+#define CONSONANTS (ALPHABET - VOWELS)
diff --git a/code/__DEFINES/tgs.dm b/code/__DEFINES/tgs.dm
index 17464b44dae81..4766b3dfe661e 100644
--- a/code/__DEFINES/tgs.dm
+++ b/code/__DEFINES/tgs.dm
@@ -1,18 +1,19 @@
// tgstation-server DMAPI
+// The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in IETF RFC 2119.
-#define TGS_DMAPI_VERSION "7.1.3"
+#define TGS_DMAPI_VERSION "7.2.1"
// All functions and datums outside this document are subject to change with any version and should not be relied on.
// CONFIGURATION
-/// Create this define if you want to do TGS configuration outside of this file.
+/// Consumers SHOULD create this define if you want to do TGS configuration outside of this file.
#ifndef TGS_EXTERNAL_CONFIGURATION
-// Comment this out once you've filled in the below.
+// Consumers MUST comment this out once you've filled in the below and are not using [TGS_EXTERNAL_CONFIGURATION].
#error TGS API unconfigured
-// Uncomment this if you wish to allow the game to interact with TGS 3..
+// Consumers MUST uncomment this if you wish to allow the game to interact with TGS version 3.
// This will raise the minimum required security level of your game to TGS_SECURITY_TRUSTED due to it utilizing call()().
//#define TGS_V3_API
@@ -52,7 +53,7 @@
#ifndef TGS_FILE2TEXT_NATIVE
#ifdef file2text
-#error Your codebase is re-defining the BYOND proc file2text. The DMAPI requires the native version to read the result of world.Export(). You can fix this by adding "#define TGS_FILE2TEXT_NATIVE file2text" before your override of file2text to allow the DMAPI to use the native version. This will only be used for world.Export(), not regular file accesses
+#error Your codebase is re-defining the BYOND proc file2text. The DMAPI requires the native version to read the result of world.Export(). You SHOULD fix this by adding "#define TGS_FILE2TEXT_NATIVE file2text" before your override of file2text to allow the DMAPI to use the native version. This will only be used for world.Export(), not regular file accesses
#endif
#define TGS_FILE2TEXT_NATIVE file2text
#endif
@@ -152,16 +153,17 @@
//REQUIRED HOOKS
/**
- * Call this somewhere in [/world/proc/New] that is always run. This function may sleep!
+ * Consumers MUST call this somewhere in [/world/proc/New] that is always run. This function may sleep!
*
* * event_handler - Optional user defined [/datum/tgs_event_handler].
* * minimum_required_security_level: The minimum required security level to run the game in which the DMAPI is integrated. Can be one of [TGS_SECURITY_ULTRASAFE], [TGS_SECURITY_SAFE], or [TGS_SECURITY_TRUSTED].
+ * * http_handler - Optional user defined [/datum/tgs_http_handler].
*/
-/world/proc/TgsNew(datum/tgs_event_handler/event_handler, minimum_required_security_level = TGS_SECURITY_ULTRASAFE)
+/world/proc/TgsNew(datum/tgs_event_handler/event_handler, minimum_required_security_level = TGS_SECURITY_ULTRASAFE, datum/tgs_http_handler/http_handler)
return
/**
- * Call this when your initializations are complete and your game is ready to play before any player interactions happen.
+ * Consumers MUST call this when world initializations are complete and the game is ready to play before any player interactions happen.
*
* This may use [/world/var/sleep_offline] to make this happen so ensure no changes are made to it while this call is running.
* Afterwards, consider explicitly setting it to what you want to avoid this BYOND bug: http://www.byond.com/forum/post/2575184
@@ -170,12 +172,10 @@
/world/proc/TgsInitializationComplete()
return
-/// Put this at the start of [/world/proc/Topic].
+/// Consumers MUST run this macro at the start of [/world/proc/Topic].
#define TGS_TOPIC var/tgs_topic_return = TgsTopic(args[1]); if(tgs_topic_return) return tgs_topic_return
-/**
- * Call this as late as possible in [world/proc/Reboot] (BEFORE ..()).
- */
+/// Consumers MUST call this as late as possible in [world/proc/Reboot] (BEFORE ..()).
/world/proc/TgsReboot()
return
@@ -269,7 +269,7 @@
/// The [/datum/tgs_chat_channel] the user was from.
var/datum/tgs_chat_channel/channel
-/// User definable handler for TGS events.
+/// User definable handler for TGS events This abstract version SHOULD be overridden to be used.
/datum/tgs_event_handler
/// If the handler receieves [TGS_EVENT_HEALTH_CHECK] events.
var/receive_health_checks = FALSE
@@ -283,7 +283,41 @@
set waitfor = FALSE
return
-/// User definable chat command.
+/// User definable handler for HTTP calls. This abstract version MUST be overridden to be used.
+/datum/tgs_http_handler
+
+/**
+ * User definable callback for executing HTTP GET requests.
+ * MUST perform BYOND sleeps while the request is in flight.
+ * MUST return a [/datum/tgs_http_result].
+ * SHOULD log its own errors
+ *
+ * url - The full URL to execute the GET request for including query parameters.
+ */
+/datum/tgs_http_handler/proc/PerformGet(url)
+ CRASH("[type]/PerformGet not implemented!")
+
+/// Result of a [/datum/tgs_http_handler] call. MUST NOT be overridden.
+/datum/tgs_http_result
+ /// HTTP response as text
+ var/response_text
+ /// Boolean request success flag. Set for any 2XX response code.
+ var/success
+
+/**
+ * Create a [/datum/tgs_http_result].
+ *
+ * * response_text - HTTP response as text. Must be provided in New().
+ * * success - Boolean request success flag. Set for any 2XX response code. Must be provided in New().
+ */
+/datum/tgs_http_result/New(response_text, success)
+ if(response_text && !istext(response_text))
+ CRASH("response_text was not text!")
+
+ src.response_text = response_text
+ src.success = success
+
+/// User definable chat command. This abstract version MUST be overridden to be used.
/datum/tgs_chat_command
/// The string to trigger this command on a chat bot. e.g `@bot name ...` or `!tgs name ...`.
var/name = ""
@@ -296,21 +330,27 @@
/**
* Process command activation. Should return a [/datum/tgs_message_content] to respond to the issuer with.
+ * MUST be implemented
*
- * sender - The [/datum/tgs_chat_user] who issued the command.
- * params - The trimmed string following the command `/datum/tgs_chat_command/var/name].
+ * * sender - The [/datum/tgs_chat_user] who issued the command.
+ * * params - The trimmed string following the command `/datum/tgs_chat_command/var/name].
*/
/datum/tgs_chat_command/proc/Run(datum/tgs_chat_user/sender, params)
CRASH("[type] has no implementation for Run()")
-/// User definable chat message.
+/// User definable chat message. MUST NOT be overridden.
/datum/tgs_message_content
- /// The tring content of the message. Must be provided in New().
+ /// The string content of the message. Must be provided in New().
var/text
/// The [/datum/tgs_chat_embed] to embed in the message. Not supported on all chat providers.
var/datum/tgs_chat_embed/structure/embed
+/**
+ * Create a [/datum/tgs_message_content].
+ *
+ * * text - The string content of the message.
+ */
/datum/tgs_message_content/New(text)
..()
if(!istext(text))
@@ -319,7 +359,7 @@
src.text = text
-/// User definable chat embed. Currently mirrors Discord chat embeds. See https://discord.com/developers/docs/resources/channel#embed-object-embed-structure for details.
+/// User definable chat embed. Currently mirrors Discord chat embeds. See https://discord.com/developers/docs/resources/message#embed-object for details.
/datum/tgs_chat_embed/structure
var/title
var/description
@@ -331,13 +371,13 @@
/// Colour must be #AARRGGBB or #RRGGBB hex string.
var/colour
- /// See https://discord.com/developers/docs/resources/channel#embed-object-embed-image-structure for details.
+ /// See https://discord.com/developers/docs/resources/message#embed-object-embed-image-structure for details.
var/datum/tgs_chat_embed/media/image
- /// See https://discord.com/developers/docs/resources/channel#embed-object-embed-thumbnail-structure for details.
+ /// See https://discord.com/developers/docs/resources/message#embed-object-embed-thumbnail-structure for details.
var/datum/tgs_chat_embed/media/thumbnail
- /// See https://discord.com/developers/docs/resources/channel#embed-object-embed-image-structure for details.
+ /// See https://discord.com/developers/docs/resources/message#embed-object-embed-video-structure for details.
var/datum/tgs_chat_embed/media/video
var/datum/tgs_chat_embed/footer/footer
@@ -346,7 +386,7 @@
var/list/datum/tgs_chat_embed/field/fields
-/// Common datum for similar discord embed medias.
+/// Common datum for similar Discord embed medias.
/datum/tgs_chat_embed/media
/// Must be set in New().
var/url
@@ -354,6 +394,7 @@
var/height
var/proxy_url
+/// Create a [/datum/tgs_chat_embed].
/datum/tgs_chat_embed/media/New(url)
..()
if(!istext(url))
@@ -361,13 +402,14 @@
src.url = url
-/// See https://discord.com/developers/docs/resources/channel#embed-object-embed-footer-structure for details.
+/// See https://discord.com/developers/docs/resources/message#embed-object-embed-footer-structure for details.
/datum/tgs_chat_embed/footer
/// Must be set in New().
var/text
var/icon_url
var/proxy_icon_url
+/// Create a [/datum/tgs_chat_embed/footer].
/datum/tgs_chat_embed/footer/New(text)
..()
if(!istext(text))
@@ -375,16 +417,17 @@
src.text = text
-/// See https://discord.com/developers/docs/resources/channel#embed-object-embed-provider-structure for details.
+/// See https://discord.com/developers/docs/resources/message#embed-object-embed-provider-structure for details.
/datum/tgs_chat_embed/provider
var/name
var/url
-/// See https://discord.com/developers/docs/resources/channel#embed-object-embed-author-structure for details. Must have name set in New().
+/// See https://discord.com/developers/docs/resources/message#embed-object-embed-author-structure for details. Must have name set in New().
/datum/tgs_chat_embed/provider/author
var/icon_url
var/proxy_icon_url
+/// Create a [/datum/tgs_chat_embed/footer].
/datum/tgs_chat_embed/provider/author/New(name)
..()
if(!istext(name))
@@ -392,12 +435,15 @@
src.name = name
-/// See https://discord.com/developers/docs/resources/channel#embed-object-embed-field-structure for details. Must have name and value set in New().
+/// See https://discord.com/developers/docs/resources/message#embed-object-embed-field-structure for details.
/datum/tgs_chat_embed/field
+ /// Must be set in New().
var/name
+ /// Must be set in New().
var/value
var/is_inline
+/// Create a [/datum/tgs_chat_embed/field].
/datum/tgs_chat_embed/field/New(name, value)
..()
if(!istext(name))
diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm
index 294d32ddc3b0f..11b1e0d2b3127 100644
--- a/code/__DEFINES/traits/declarations.dm
+++ b/code/__DEFINES/traits/declarations.dm
@@ -24,7 +24,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_PULL_BLOCKED "pullblocked"
/// Abstract condition that prevents movement if being pulled and might be resisted against. Handcuffs and straight jackets, basically.
#define TRAIT_RESTRAINED "restrained"
-/// Apply this to make a mob not dense, and remove it when you want it to no longer make them undense, other sorces of undesity will still apply. Always define a unique source when adding a new instance of this!
+/// Apply this to make a mob not dense, and remove it when you want it to no longer make them undense, other sources of undesity will still apply. Always define a unique source when adding a new instance of this!
#define TRAIT_UNDENSE "undense"
/// Expands our FOV by 30 degrees if restricted
#define TRAIT_EXPANDED_FOV "expanded_fov"
@@ -50,7 +50,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_DEAF "deaf"
#define TRAIT_FAT "fat"
#define TRAIT_HUSK "husk"
-///Blacklisted from being revived via defibrilator
+///Blacklisted from being revived via defibrillator
#define TRAIT_DEFIB_BLACKLISTED "defib_blacklisted"
#define TRAIT_BADDNA "baddna"
#define TRAIT_CLUMSY "clumsy"
@@ -149,8 +149,6 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_MUTANT_COLORS "mutcolors"
/// Species with this trait have mutant colors that cannot be chosen by the player, nor altered ingame by external means
#define TRAIT_FIXED_MUTANT_COLORS "fixed_mutcolors"
-/// Species with this trait have a haircolor that cannot be chosen by the player, nor altered ingame by external means
-#define TRAIT_FIXED_HAIRCOLOR "fixed_haircolor"
/// Humans with this trait won't get bloody hands, nor bloody feet
#define TRAIT_NO_BLOOD_OVERLAY "no_blood_overlay"
/// Humans with this trait cannot have underwear
@@ -171,7 +169,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_NO_ZOMBIFY "no_zombify"
/// Carbons with this trait can't have their DNA copied by diseases nor changelings
#define TRAIT_NO_DNA_COPY "no_dna_copy"
-/// Carbons with this trait cant have their dna scrambled by genetics or a disease retrovirus.
+/// Carbons with this trait can't have their DNA scrambled by genetics or a disease retrovirus.
#define TRAIT_NO_DNA_SCRAMBLE "no_dna_scramble"
/// Carbons with this trait can eat blood to regenerate their own blood volume, instead of injecting it
#define TRAIT_DRINKS_BLOOD "drinks_blood"
@@ -227,10 +225,16 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_EXAMINE_FISHING_SPOT "examine_fishing_spot"
///lobstrosities and carps will prioritize/flee from those that have this trait (given by the skill-locked hat)
#define TRAIT_SCARY_FISHERMAN "scary_fisherman"
+///This trait lets you get the size and weight of the fish by examining them
+#define TRAIT_EXAMINE_FISH "examine_fish"
+///This trait lets you roughly know if the fish is dead, starving, drowning or sick by examining them
+#define TRAIT_EXAMINE_DEEPER_FISH "examine_deeper_fish"
///Trait given to turfs or objects that can be fished from
#define TRAIT_FISHING_SPOT "fishing_spot"
///Trait given to mobs that can fish without a rod
#define TRAIT_PROFOUND_FISHER "profound_fisher"
+/// If an atom has this trait, then you can toss a bottle with a message in it.
+#define TRAIT_MESSAGE_IN_A_BOTTLE_LOCATION "message_in_a_bottle_location"
/// This trait lets you evaluate someone's fitness level against your own
#define TRAIT_EXAMINE_FITNESS "reveal_power_level"
/// These mobs have particularly hygienic tongues
@@ -251,7 +255,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
/// Stop the mob from sliding around from being slipped, but not the slip part.
/// DOES NOT include ice slips.
#define TRAIT_NO_SLIP_SLIDE "noslip_slide"
-/// Stops all slipping and sliding from ocurring
+/// Stops all slipping and sliding from occurring
#define TRAIT_NO_SLIP_ALL "noslip_all"
/// Unlinks gliding from movement speed, meaning that there will be a delay between movements rather than a single move movement between tiles
@@ -263,7 +267,10 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_NODEATH "nodeath"
#define TRAIT_NOHARDCRIT "nohardcrit"
#define TRAIT_NOSOFTCRIT "nosoftcrit"
+/// Makes someone show up as mindshielded on sechuds. Does NOT actually make them unconvertable - See TRAIT_UNCONVERTABLE for that
#define TRAIT_MINDSHIELD "mindshield"
+/// Makes it impossible for someone to be converted by cult/revs/etc.
+#define TRAIT_UNCONVERTABLE "unconvertable"
#define TRAIT_DISSECTED "dissected"
#define TRAIT_SURGICALLY_ANALYZED "surgically_analyzed"
/// Lets the user succumb even if they got NODEATH
@@ -357,16 +364,14 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_GUNFLIP "gunflip"
/// Increases chance of getting special traumas, makes them harder to cure
#define TRAIT_SPECIAL_TRAUMA_BOOST "special_trauma_boost"
-/// Doubles the duration and cooldown of a flip
-#define TRAIT_SLOW_FLIP "slow_flip"
#define TRAIT_SPACEWALK "spacewalk"
-/// Sanity trait to keep track of when we're in hyperspace and add the appropriate element if we werent
+/// Sanity trait to keep track of when we're in hyperspace and add the appropriate element if we weren't
#define TRAIT_HYPERSPACED "hyperspaced"
///Gives the movable free hyperspace movement without being pulled during shuttle transit
#define TRAIT_FREE_HYPERSPACE_MOVEMENT "free_hyperspace_movement"
///Lets the movable move freely in the soft-cordon area of transit space, which would otherwise teleport them away just before they got to see the true cordon
#define TRAIT_FREE_HYPERSPACE_SOFTCORDON_MOVEMENT "free_hyperspace_softcordon_movement"
-///Deletes the object upon being dumped into space, usually from exiting hyperspace. Useful if you're spawning in a lot of stuff for hyperspace events that dont need to flood the entire game
+///Deletes the object upon being dumped into space, usually from exiting hyperspace. Useful if you're spawning in a lot of stuff for hyperspace events that don't need to flood the entire game
#define TRAIT_DEL_ON_SPACE_DUMP "del_on_hyperspace_leave"
/// We can walk up or around cliffs, or at least we don't fall off of it
#define TRAIT_CLIFF_WALKER "cliff_walker"
@@ -419,6 +424,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_ANTENNAE "antennae"
/// Blowing kisses actually does damage to the victim
#define TRAIT_KISS_OF_DEATH "kiss_of_death"
+/// Syndie kisses can apply burn damage
+#define TRAIT_SYNDIE_KISS "syndie_kiss"
/// Used to activate french kissing
#define TRAIT_GARLIC_BREATH "kiss_of_garlic_death"
/// Addictions don't tick down, basically they're permanently addicted
@@ -431,7 +438,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_BLOODSHOT_EYES "bloodshot_eyes"
/// This mob should never close UI even if it doesn't have a client
#define TRAIT_PRESERVE_UI_WITHOUT_CLIENT "preserve_ui_without_client"
-/// This mob overrides certian SSlag_switch measures with this special trait
+/// This mob overrides certain SSlag_switch measures with this special trait
#define TRAIT_BYPASS_MEASURES "bypass_lagswitch_measures"
/// Someone can safely be attacked with honorbound with ONLY a combat mode check, the trait is assuring holding a weapon and hitting won't hurt them..
#define TRAIT_ALLOWED_HONORBOUND_ATTACK "allowed_honorbound_attack"
@@ -527,9 +534,6 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
/// Mobs with this trait cannot be hit by projectiles, meaning the projectiles will just go through.
#define TRAIT_UNHITTABLE_BY_PROJECTILES "unhittable_by_projectiles"
-/// Projectile with this trait will always hit the defined zone of a struck living mob.
-#define TRAIT_ALWAYS_HIT_ZONE "always_hit_zone"
-
/// Mobs with this trait do care about a few grisly things, such as digging up graves. They also really do not like bringing people back to life or tending wounds, but love autopsies and amputations.
#define TRAIT_MORBID "morbid"
@@ -574,6 +578,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
/// Trait that determines vulnerability to being stunned from a shove
#define TRAIT_STUN_ON_NEXT_SHOVE "stun on next shove"
+/// Trait that determines whether our mob gains more strength from drinking during a fist fight
+#define TRAIT_DRUNKEN_BRAWLER "drunken brawler"
+
// METABOLISMS
// Various jobs on the station have historically had better reactions
// to various drinks and foodstuffs. Security liking donuts is a classic
@@ -667,6 +674,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
/// This movable atom has the explosive block element
#define TRAIT_BLOCKING_EXPLOSIVES "blocking_explosives"
+///This mob is currently blocking a projectile.
+#define TRAIT_BLOCKING_PROJECTILES "blocking_projectiles"
///Lava will be safe to cross while it has this trait.
#define TRAIT_LAVA_STOPPED "lava_stopped"
///Chasms will be safe to cross while they've this trait.
@@ -733,16 +742,18 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_FOOD_SILVER "food_silver"
/// If this item's been made by a chef instead of being map-spawned or admin-spawned or such
#define TRAIT_FOOD_CHEF_MADE "food_made_by_chef"
+/// This atom has a quality_food_ingredient element attached
+#define TRAIT_QUALITY_FOOD_INGREDIENT "quality_food_ingredient"
/// The items needs two hands to be carried
#define TRAIT_NEEDS_TWO_HANDS "needstwohands"
/// Can't be catched when thrown
#define TRAIT_UNCATCHABLE "uncatchable"
-/// Fish in this won't die
-#define TRAIT_FISH_SAFE_STORAGE "fish_case"
/// Stuff that can go inside fish cases
#define TRAIT_FISH_CASE_COMPATIBILE "fish_case_compatibile"
/// If the item can be used as a bit.
#define TRAIT_FISHING_BAIT "fishing_bait"
+/// This bait will kill any fish that doesn't have it on its favorite_bait list
+#define TRAIT_POISONOUS_BAIT "poisonous_bait"
/// The quality of the bait. It influences odds of catching fish
#define TRAIT_BASIC_QUALITY_BAIT "baic_quality_bait"
#define TRAIT_GOOD_QUALITY_BAIT "good_quality_bait"
@@ -928,6 +939,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_MECHA_CREATED_NORMALLY "trait_mecha_created_normally"
///fish traits
+#define TRAIT_FISH_STASIS "fish_stasis"
+#define TRAIT_FISH_FLOPPING "fish_flopping"
#define TRAIT_RESIST_EMULSIFY "resist_emulsify"
#define TRAIT_FISH_SELF_REPRODUCE "fish_self_reproduce"
#define TRAIT_FISH_NO_MATING "fish_no_mating"
@@ -942,6 +955,10 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_FISH_FROM_CASE "fish_from_case"
///Fish will also occasionally fire weak tesla zaps
#define TRAIT_FISH_ELECTROGENESIS "fish_electrogenesis"
+///Offsprings from this fish will never be of its same type (unless it's self-reproducing).
+#define TRAIT_FISH_RECESSIVE "fish_recessive"
+///This fish comes equipped with a stinger (increased damage and potentially venomous if also toxic)
+#define TRAIT_FISH_STINGER "fish_stinger"
/// Trait given to angelic constructs to let them purge cult runes
#define TRAIT_ANGELIC "angelic"
@@ -1039,6 +1056,13 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
/// things with this trait are treated as having no access in /atom/movable/proc/check_access(obj/item)
#define TRAIT_ALWAYS_NO_ACCESS "alwaysnoaccess"
+///The entity has Silicon 'access', so is either a silicon, has an access wand, or is an admin ghost AI.
+///This is put on the mob, it is used on the client for Admins but they are the exception as they use `isAdminGhostAI`.
+#define TRAIT_SILICON_ACCESS "silicon_access_trait"
+///The entity has AI 'access', so is either an AI, has an access wand, or is an admin ghost AI. Used to block off regular Silicons from things.
+///This is put on the mob, it is used on the client for Admins but they are the exception as they use `isAdminGhostAI`.
+#define TRAIT_AI_ACCESS "ai_access_trait"
+
///Used by wearable_client_colour to determine whether the mob wants to have the colours of the screen affected by worn items (some still do regardless).
#define TRAIT_SEE_WORN_COLOURS "see_worn_colour"
@@ -1084,14 +1108,16 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
/// Currently fishing
#define TRAIT_GONE_FISHING "fishing"
+/// Currently fishing, and it's the active minigame phase
+#define TRAIT_ACTIVELY_FISHING "actively_fishing"
-/// Makes a species be better/worse at tackling depending on their wing's status
+/// Makes a character be better/worse at tackling depending on their wing's status
#define TRAIT_TACKLING_WINGED_ATTACKER "tacking_winged_attacker"
-/// Makes a species be frail and more likely to roll bad results if they hit a wall
+/// Makes a character be frail and more likely to roll bad results if they hit a wall
#define TRAIT_TACKLING_FRAIL_ATTACKER "tackling_frail_attacker"
-/// Makes a species be better/worse at defending against tackling depending on their tail's status
+/// Makes a character be better/worse at defending against tackling depending on their tail's status
#define TRAIT_TACKLING_TAILED_DEFENDER "tackling_tailed_defender"
/// Is runechat for this atom/movable currently disabled, regardless of prefs or anything?
@@ -1189,6 +1215,12 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
/// Trait given to anything linked to, not necessarily allied to, the mansus
#define TRAIT_MANSUS_TOUCHED "mansus_touched"
+
+// These traits are used in IS_X() as an OR, and is utilized for pseudoantags (such as deathmatch or domains) so they don't need to actually get antag status.
+// To specifically and only get the antag datum, GET_X() exists now.
+#define TRAIT_ACT_AS_CULTIST "act_as_cultist"
+#define TRAIT_ACT_AS_HERETIC "act_as_heretic"
+
/// Appiled when wizard buy (/datum/spellbook_entry/perks/spalls_lottery) perk.
/// Give 50/25% chance not spend a spellbook charge on 1/2 cost spell.
/// Appiled it wizard can't refund any spells.
diff --git a/code/__DEFINES/traits/sources.dm b/code/__DEFINES/traits/sources.dm
index f11cc50dbbd58..ecdbdd15e3591 100644
--- a/code/__DEFINES/traits/sources.dm
+++ b/code/__DEFINES/traits/sources.dm
@@ -36,6 +36,8 @@
#define VENDING_MACHINE_TRAIT "vending_machine"
+///A trait given by a held item
+#define HELD_ITEM_TRAIT "held-item-trait"
#define ABSTRACT_ITEM_TRAIT "abstract-item"
/// A trait given by any status effect
#define STATUS_EFFECT_TRAIT "status-effect"
@@ -45,7 +47,8 @@
/// Trait given by an Action datum
#define ACTION_TRAIT "action"
-
+///A trait given by someone blocking.
+#define BLOCKING_TRAIT "blocking"
#define CLOTHING_TRAIT "clothing"
#define HELMET_TRAIT "helmet"
/// inherited from the mask
diff --git a/code/__HELPERS/_dreamluau.dm b/code/__HELPERS/_dreamluau.dm
index 196774d6a88e8..1e1e315a2aebd 100644
--- a/code/__HELPERS/_dreamluau.dm
+++ b/code/__HELPERS/_dreamluau.dm
@@ -1,8 +1,12 @@
/* This comment bypasses grep checks */ /var/__dreamluau
-#define DREAMLUAU (world.system_type == MS_WINDOWS ? "dreamluau.dll" : (__dreamluau || (__dreamluau = __detect_auxtools("dreamluau"))))
+/* This comment also bypasses grep checks */ /var/__dreamluau_exists
-#define DREAMLUAU_CALL(func) call_ext(DREAMLUAU, "byond:[#func]")
+#define DREAMLUAU_EXISTS (__dreamluau_exists ||= fexists(DREAMLUAU))
+
+#define DREAMLUAU (world.system_type == MS_WINDOWS ? "dreamluau.dll" : (__dreamluau ||= __detect_auxtools("dreamluau")))
+
+#define DREAMLUAU_CALL(func) (!DREAMLUAU_EXISTS) ? null : call_ext(DREAMLUAU, "byond:[#func]")
/**
* All of the following functions will return a string if the underlying rust code returns an error or a wrapped panic.
diff --git a/code/__HELPERS/_planes.dm b/code/__HELPERS/_planes.dm
index 779319114076f..87e9ff2d1ce69 100644
--- a/code/__HELPERS/_planes.dm
+++ b/code/__HELPERS/_planes.dm
@@ -29,8 +29,8 @@
// Now for the more niche things
-/// Takes an object, new plane, and multipler, and offsets the plane
-/// This is for cases where you have a multipler precalculated, and just want to use it
+/// Takes an object, new plane, and multiplier, and offsets the plane
+/// This is for cases where you have a multiplier precalculated, and just want to use it
/// Often an optimization, sometimes a necessity
#define SET_PLANE_W_SCALAR(thing, new_value, multiplier) (thing.plane = GET_NEW_PLANE(new_value, multiplier))
diff --git a/code/__HELPERS/atmospherics.dm b/code/__HELPERS/atmospherics.dm
index 2a59cf60b403f..9ebafd5fbb528 100644
--- a/code/__HELPERS/atmospherics.dm
+++ b/code/__HELPERS/atmospherics.dm
@@ -105,13 +105,13 @@ GLOBAL_LIST_EMPTY(gas_handbook)
factor_info["factor_name"] = factor
factor_info["factor_type"] = "misc"
if(factor == "Temperature" || factor == "Pressure")
- factor_info["tooltip"] = "Reaction is influenced by the [LOWER_TEXT(factor)] of the place where the reaction is occuring."
+ factor_info["tooltip"] = "Reaction is influenced by the [LOWER_TEXT(factor)] of the place where the reaction is occurring."
else if(factor == "Energy")
factor_info["tooltip"] = "Energy released by the reaction, may or may not result in linear temperature change depending on a slew of other factors."
else if(factor == "Radiation")
factor_info["tooltip"] = "This reaction emits dangerous radiation! Take precautions."
else if (factor == "Location")
- factor_info["tooltip"] = "This reaction has special behaviour when occuring in specific locations."
+ factor_info["tooltip"] = "This reaction has special behaviour when occurring in specific locations."
else if(factor == "Hot Ice")
factor_info["tooltip"] = "Hot ice are solidified stacks of plasma. Ignition of one will result in a raging fire."
reaction_info["factors"] += list(factor_info)
@@ -138,13 +138,13 @@ GLOBAL_LIST_EMPTY(gas_handbook)
factor_info["factor_name"] = factor
factor_info["factor_type"] = "misc"
if(factor == "Temperature" || factor == "Pressure")
- factor_info["tooltip"] = "Reaction is influenced by the [LOWER_TEXT(factor)] of the place where the reaction is occuring."
+ factor_info["tooltip"] = "Reaction is influenced by the [LOWER_TEXT(factor)] of the place where the reaction is occurring."
else if(factor == "Energy")
factor_info["tooltip"] = "Energy released by the reaction, may or may not result in linear temperature change depending on a slew of other factors."
else if(factor == "Radiation")
factor_info["tooltip"] = "This reaction emits dangerous radiation! Take precautions."
else if (factor == "Location")
- factor_info["tooltip"] = "This reaction has special behaviour when occuring in specific locations."
+ factor_info["tooltip"] = "This reaction has special behaviour when occurring in specific locations."
reaction_info["factors"] += list(factor_info)
GLOB.reaction_handbook += list(reaction_info)
qdel(reaction)
diff --git a/code/__HELPERS/construction.dm b/code/__HELPERS/construction.dm
index f7b0ece13f894..166a009f06661 100644
--- a/code/__HELPERS/construction.dm
+++ b/code/__HELPERS/construction.dm
@@ -61,7 +61,7 @@
. = new target.type(target.drop_location(), amount, FALSE, target.mats_per_unit)
/**
- * divides a list of materials uniformly among all contents of the target_object reccursively
+ * divides a list of materials uniformly among all contents of the target_object recursively
* Used to set materials of printed items with their design cost by taking into consideration their already existing materials
* e.g. if 12 iron is to be divided uniformly among 2 objects A, B who's current iron contents are 3 & 7
* Then first we normalize those values i.e. find their weights to decide who gets an higher share of iron
@@ -81,7 +81,7 @@
target_object.set_custom_materials(custom_materials, multiplier)
return
- //Step 1: Get reccursive contents of all objects, only filter obj cause that what's material container accepts
+ //Step 1: Get recursive contents of all objects, only filter obj cause that what's material container accepts
var/list/reccursive_contents = target_object.get_all_contents_type(/obj/item)
//Step 2: find the sum of each material type per object and record their amounts into an 2D list
diff --git a/code/__HELPERS/duplicating.dm b/code/__HELPERS/duplicating.dm
index 225dca91fb5b1..f0f3f9a9fce97 100644
--- a/code/__HELPERS/duplicating.dm
+++ b/code/__HELPERS/duplicating.dm
@@ -15,8 +15,6 @@ GLOBAL_LIST_INIT(duplicate_forbidden_vars, list(
"contents",
"cooldowns",
"_datum_components",
- "external_organs",
- "external_organs_slot",
"group",
"hand_bodyparts",
"held_items",
diff --git a/code/__HELPERS/heap.dm b/code/__HELPERS/heap.dm
index eeabfa6a20b4e..ede4c39f95040 100644
--- a/code/__HELPERS/heap.dm
+++ b/code/__HELPERS/heap.dm
@@ -26,7 +26,7 @@
swim(length(L))
//removes and returns the first element of the heap
-//(i.e the max or the min dependant on the comparison function)
+//(i.e the max or the min dependent on the comparison function)
/datum/heap/proc/pop()
if(!length(L))
return 0
diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm
index 8d8727a90b052..127ae5387e1b0 100644
--- a/code/__HELPERS/icons.dm
+++ b/code/__HELPERS/icons.dm
@@ -272,7 +272,7 @@ world
Blend(mask_icon, ICON_ADD)
/// Converts an rgb color into a list storing hsva
-/// Exists because it's useful to have a guarenteed alpha value
+/// Exists because it's useful to have a guaranteed alpha value
/proc/rgb2hsv(rgb)
var/list/hsv = rgb2num(rgb, COLORSPACE_HSV)
if(length(hsv) < 4)
@@ -815,11 +815,11 @@ GLOBAL_LIST_EMPTY(friendly_animal_types)
/// generates a filename for a given asset.
/// like generate_asset_name(), except returns the rsc reference and the rsc file hash as well as the asset name (sans extension)
-/// used so that certain asset files dont have to be hashed twice
+/// used so that certain asset files don't have to be hashed twice
/proc/generate_and_hash_rsc_file(file, dmi_file_path)
var/rsc_ref = fcopy_rsc(file)
var/hash
- //if we have a valid dmi file path we can trust md5'ing the rsc file because we know it doesnt have the bug described in http://www.byond.com/forum/post/2611357
+ //if we have a valid dmi file path we can trust md5'ing the rsc file because we know it doesn't have the bug described in http://www.byond.com/forum/post/2611357
if(dmi_file_path)
hash = md5(rsc_ref)
else //otherwise, we need to do the expensive fcopy() workaround
@@ -845,7 +845,7 @@ GLOBAL_LIST_EMPTY(friendly_animal_types)
fdel(savefile_path)
return new /savefile(savefile_path)
catch(var/exception/error)
- // if we failed to create a dummy once, try again; maybe someone slept somewhere they shouldnt have
+ // if we failed to create a dummy once, try again; maybe someone slept somewhere they shouldn't have
if(from_failure) // this *is* the retry, something fucked up
CRASH("get_dummy_savefile failed to create a dummy savefile: '[error]'")
return get_dummy_savefile(from_failure = TRUE)
@@ -890,18 +890,18 @@ GLOBAL_LIST_EMPTY(friendly_animal_types)
var/atom/atom_icon = icon
icon = atom_icon.icon
//atom icons compiled in from 'icons/path/to/dmi_file.dmi' are weird and not really icon objects that you generate with icon().
- //if theyre unchanged dmi's then they're stringifiable to "icons/path/to/dmi_file.dmi"
+ //if they're unchanged dmi's then they're stringifiable to "icons/path/to/dmi_file.dmi"
if(isicon(icon) && isfile(icon))
- //icons compiled in from 'icons/path/to/dmi_file.dmi' at compile time are weird and arent really /icon objects,
- ///but they pass both isicon() and isfile() checks. theyre the easiest case since stringifying them gives us the path we want
+ //icons compiled in from 'icons/path/to/dmi_file.dmi' at compile time are weird and aren't really /icon objects,
+ ///but they pass both isicon() and isfile() checks. they're the easiest case since stringifying them gives us the path we want
var/icon_ref = text_ref(icon)
var/locate_icon_string = "[locate(icon_ref)]"
icon_path = locate_icon_string
else if(isicon(icon) && "[icon]" == "/icon")
- // icon objects generated from icon() at runtime are icons, but they ARENT files themselves, they represent icon files.
+ // icon objects generated from icon() at runtime are icons, but they AREN'T files themselves, they represent icon files.
// if the files they represent are compile time dmi files in the rsc, then
// the rsc reference returned by fcopy_rsc() will be stringifiable to "icons/path/to/dmi_file.dmi"
var/rsc_ref = fcopy_rsc(icon)
@@ -960,7 +960,7 @@ GLOBAL_LIST_EMPTY(friendly_animal_types)
if(!length(targets))
return
- //check if the given object is associated with a dmi file in the icons folder. if it is then we dont need to do a lot of work
+ //check if the given object is associated with a dmi file in the icons folder. if it is then we don't need to do a lot of work
//for asset generation to get around byond limitations
var/icon_path = get_icon_dmi_path(thing)
@@ -1004,7 +1004,7 @@ GLOBAL_LIST_EMPTY(friendly_animal_types)
var/list/name_and_ref = generate_and_hash_rsc_file(icon2collapse, icon_path)//pretend that tuples exist
- var/rsc_ref = name_and_ref[1] //weird object thats not even readable to the debugger, represents a reference to the icons rsc entry
+ var/rsc_ref = name_and_ref[1] //weird object that's not even readable to the debugger, represents a reference to the icons rsc entry
var/file_hash = name_and_ref[2]
key = "[name_and_ref[3]].png"
@@ -1239,6 +1239,8 @@ GLOBAL_LIST_EMPTY(transformation_animation_objects)
var/mutable_appearance/alert_overlay = new(source)
alert_overlay.pixel_x = 0
alert_overlay.pixel_y = 0
+ alert_overlay.pixel_z = 0
+ alert_overlay.pixel_w = 0
var/scale = 1
var/list/icon_dimensions = get_icon_dimensions(source.icon)
diff --git a/code/__HELPERS/levels.dm b/code/__HELPERS/levels.dm
index 096655ad748bd..ca2cd3c5db3a3 100644
--- a/code/__HELPERS/levels.dm
+++ b/code/__HELPERS/levels.dm
@@ -56,5 +56,5 @@
// Syndicate recon outpost is on some moon or something
return TRUE
- // Finally, more specific checks are ran for edge cases, such as lazyily loaded map templates or away missions. Not perfect.
+ // Finally, more specific checks are ran for edge cases, such as lazily loaded map templates or away missions. Not perfect.
return istype(what_turf) && what_turf.planetary_atmos && what_turf.has_gravity()
diff --git a/code/__HELPERS/logging/mob.dm b/code/__HELPERS/logging/mob.dm
index 7b4b0ac070586..b6bebf74f689b 100644
--- a/code/__HELPERS/logging/mob.dm
+++ b/code/__HELPERS/logging/mob.dm
@@ -1,5 +1,5 @@
/**
- * Logs a mesage to the mob_tags log, including the mobs tag
+ * Logs a message to the mob_tags log, including the mobs tag
* Arguments:
* * text - text to log.
*/
diff --git a/code/__HELPERS/maths.dm b/code/__HELPERS/maths.dm
index 0271b2e4601cc..5a55fd46fd296 100644
--- a/code/__HELPERS/maths.dm
+++ b/code/__HELPERS/maths.dm
@@ -60,7 +60,7 @@
var/y_distance_sign = SIGN(y_distance)
var/x = abs_x_distance >> 1 //Counters for steps taken, setting to distance/2
- var/y = abs_y_distance >> 1 //Bit-shifting makes me l33t. It also makes get_line() unnessecarrily fast.
+ var/y = abs_y_distance >> 1 //Bit-shifting makes me l33t. It also makes get_line() unnecessarily fast.
if(abs_x_distance >= abs_y_distance) //x distance is greater than y
for(var/distance_counter in 0 to (abs_x_distance - 1))//It'll take abs_x_distance steps to get there
@@ -86,7 +86,7 @@
/**
* Get a list of turfs in a perimeter given the `center_atom` and `radius`.
- * Automatically rounds down decimals and does not accept values less than positive 1 as they dont play well with it.
+ * Automatically rounds down decimals and does not accept values less than positive 1 as they don't play well with it.
* Is efficient on large circles but ugly on small ones
* Uses [Jesko`s method to the midpoint circle Algorithm](https://en.wikipedia.org/wiki/Midpoint_circle_algorithm).
*/
diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm
index ba1f7fc4e1d15..7c8e84e226d23 100644
--- a/code/__HELPERS/mobs.dm
+++ b/code/__HELPERS/mobs.dm
@@ -542,8 +542,8 @@ GLOBAL_LIST_INIT(skin_tone_names, list(
* When passed the difference between two temperatures returns the amount of change to temperature to apply.
* The change rate should be kept at a low value tween 0.16 and 0.02 for optimal results.
* vars:
- * * temp_diff (required) The differance between two temperatures
- * * change_rate (optional)(Default: 0.06) The rate of range multiplyer
+ * * temp_diff (required) The difference between two temperatures
+ * * change_rate (optional)(Default: 0.06) The rate of range multiplier
*/
/proc/get_temp_change_amount(temp_diff, change_rate = 0.06)
if(temp_diff < 0)
@@ -693,6 +693,8 @@ GLOBAL_LIST_INIT(skin_tone_names, list(
slot_strings += "dextrous storage"
if(slot_flags & ITEM_SLOT_BACKPACK)
slot_strings += "backpack"
+ if(slot_flags & ITEM_SLOT_BELTPACK)
+ slot_strings += "belt" // ?
return slot_strings
///Returns the direction that the initiator and the target are facing
diff --git a/code/__HELPERS/paths/path.dm b/code/__HELPERS/paths/path.dm
index 189120b76c3bc..9530a5452351a 100644
--- a/code/__HELPERS/paths/path.dm
+++ b/code/__HELPERS/paths/path.dm
@@ -16,7 +16,7 @@
*/
/proc/get_path_to(atom/movable/caller, atom/end, max_distance = 30, mintargetdist, access=list(), simulated_only = TRUE, turf/exclude, skip_first=TRUE, diagonal_handling=DIAGONAL_REMOVE_CLUNKY)
var/list/hand_around = list()
- // We're guarenteed that list will be the first list in pathfinding_finished's argset because of how callback handles the arguments list
+ // We're guaranteed that list will be the first list in pathfinding_finished's argset because of how callback handles the arguments list
var/datum/callback/await = list(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(pathfinding_finished), hand_around))
if(!SSpathfinder.pathfind(caller, end, max_distance, mintargetdist, access, simulated_only, exclude, skip_first, diagonal_handling, await))
return list()
@@ -49,7 +49,7 @@
*/
/proc/get_swarm_path_to(atom/movable/caller, atom/end, max_distance = 30, mintargetdist, age = MAP_REUSE_INSTANT, access = list(), simulated_only = TRUE, turf/exclude, skip_first=TRUE)
var/list/hand_around = list()
- // We're guarenteed that list will be the first list in pathfinding_finished's argset because of how callback handles the arguments list
+ // We're guaranteed that list will be the first list in pathfinding_finished's argset because of how callback handles the arguments list
var/datum/callback/await = list(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(pathfinding_finished), hand_around))
if(!SSpathfinder.swarmed_pathfind(caller, end, max_distance, mintargetdist, age, access, simulated_only, exclude, skip_first, await))
return list()
@@ -62,7 +62,7 @@
/proc/get_sssp(atom/movable/caller, max_distance = 30, access = list(), simulated_only = TRUE, turf/exclude)
var/list/hand_around = list()
- // We're guarenteed that list will be the first list in pathfinding_finished's argset because of how callback handles the arguments list
+ // We're guaranteed that list will be the first list in pathfinding_finished's argset because of how callback handles the arguments list
var/datum/callback/await = list(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(pathfinding_finished), hand_around))
if(!SSpathfinder.build_map(caller, get_turf(caller), max_distance, access, simulated_only, exclude, await))
return null
@@ -335,7 +335,7 @@
src.has_gravity = construct_from.has_gravity()
if(ismob(construct_from))
var/mob/living/mob_construct = construct_from
- src.incapacitated = mob_construct.incapacitated()
+ src.incapacitated = mob_construct.incapacitated
if(mob_construct.buckled)
src.buckled_info = new(mob_construct.buckled, access, no_id, call_depth + 1)
if(isobserver(construct_from))
diff --git a/code/__HELPERS/paths/sssp.dm b/code/__HELPERS/paths/sssp.dm
index f735c66469487..21e520ea0164c 100644
--- a/code/__HELPERS/paths/sssp.dm
+++ b/code/__HELPERS/paths/sssp.dm
@@ -130,7 +130,7 @@
/// Returns a new /datum/pathfind/sssp based off our settings
/// Will have an invalid source mob, no max distance, and no ending callback
/datum/path_map/proc/settings_to_path()
- // Default creation to not set any vars incidentially
+ // Default creation to not set any vars incidentally
var/static/mob/jeremy = new()
var/datum/pathfind/sssp/based_on_what = new()
based_on_what.setup(pass_info, null, INFINITY, pass_space, avoid)
@@ -155,7 +155,7 @@
working_index -= 1
var/list/hand_around = list()
- // We're guarenteed that hand_around will be the first list in pathfinding_finished's argset because of how callback handles the arguments list
+ // We're guaranteed that hand_around will be the first list in pathfinding_finished's argset because of how callback handles the arguments list
var/datum/callback/await = CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(pathfinding_finished), hand_around)
// We're gonna build a pathfind datum from our settings and set it running
diff --git a/code/__HELPERS/reagents.dm b/code/__HELPERS/reagents.dm
index cb87e21cefa54..51ff7df475ee1 100644
--- a/code/__HELPERS/reagents.dm
+++ b/code/__HELPERS/reagents.dm
@@ -180,14 +180,23 @@
else
return null
-///Returns a random reagent object minus blacklisted reagents
-/proc/get_random_reagent_id()
- var/static/list/random_reagents = list()
- if(!random_reagents.len)
+///Returns a random reagent object, with the option to blacklist reagents.
+/proc/get_random_reagent_id(list/blacklist)
+ var/static/list/reagent_static_list = list() //This is static, and will be used by default if a blacklist is not passed.
+ var/list/reagent_list_to_process
+ if(blacklist) //If we do have a blacklist, we recompile a new list with the excluded reagents not present and pick from there.
+ reagent_list_to_process = list()
+ else
+ reagent_list_to_process = reagent_static_list
+
+ if(!reagent_list_to_process.len)
for(var/datum/reagent/reagent_path as anything in subtypesof(/datum/reagent))
+ if(is_path_in_list(reagent_path, blacklist))
+ continue
if(initial(reagent_path.chemical_flags) & REAGENT_CAN_BE_SYNTHESIZED)
- random_reagents += reagent_path
- var/picked_reagent = pick(random_reagents)
+ reagent_list_to_process += reagent_path
+
+ var/picked_reagent = pick(reagent_list_to_process)
return picked_reagent
///Returns a random reagent consumable ethanol object minus blacklisted reagents
diff --git a/code/__HELPERS/roundend.dm b/code/__HELPERS/roundend.dm
index ed8d882393b5c..71e80014bb54a 100644
--- a/code/__HELPERS/roundend.dm
+++ b/code/__HELPERS/roundend.dm
@@ -192,7 +192,7 @@ GLOBAL_LIST_INIT(achievements_unlocked, list())
if(human_mob.mind && (length(human_mob.mind.antag_datums) > 0))
for(var/datum/antagonist/antag_datums as anything in human_mob.mind.antag_datums)
- if(!antag_datums.hardcore_random_bonus) //dont give bonusses to dumb stuff like revs or hypnos
+ if(!antag_datums.hardcore_random_bonus) //don't give bonuses to dumb stuff like revs or hypnos
continue
if(initial(antag_datums.can_assign_self_objectives) && !antag_datums.can_assign_self_objectives)
continue // You don't get a prize if you picked your own objective, you can't fail those
diff --git a/code/__HELPERS/sorts/sort_instance.dm b/code/__HELPERS/sorts/sort_instance.dm
index bd1bbe0582a28..eaae55c18d399 100644
--- a/code/__HELPERS/sorts/sort_instance.dm
+++ b/code/__HELPERS/sorts/sort_instance.dm
@@ -392,7 +392,7 @@ GLOBAL_DATUM_INIT(sortInstance, /datum/sort_instance, new())
var/count1 = 0 //# of times in a row that first run won
var/count2 = 0 // " " " " " " second run won
- //do the straightfoward thin until one run starts winning consistently
+ //do the straightforward thin until one run starts winning consistently
do
//ASSERT(len1 > 1 && len2 > 0)
@@ -417,7 +417,7 @@ GLOBAL_DATUM_INIT(sortInstance, /datum/sort_instance, new())
while((count1 | count2) < minGallop)
- //one run is winning consistently so galloping may provide huge benifits
+ //one run is winning consistently so galloping may provide huge benefits
//so try galloping, until such time as the run is no longer consistently winning
do
//ASSERT(len1 > 1 && len2 > 0)
@@ -493,7 +493,7 @@ GLOBAL_DATUM_INIT(sortInstance, /datum/sort_instance, new())
var/count1 = 0 //# of times in a row that first run won
var/count2 = 0 // " " " " " " second run won
- //do the straightfoward thing until one run starts winning consistently
+ //do the straightforward thing until one run starts winning consistently
do
//ASSERT(len1 > 0 && len2 > 1)
if(call(cmp)(fetchElement(L,cursor2), fetchElement(L,cursor1)) < 0)
@@ -516,7 +516,7 @@ GLOBAL_DATUM_INIT(sortInstance, /datum/sort_instance, new())
break outer
while((count1 | count2) < minGallop)
- //one run is winning consistently so galloping may provide huge benifits
+ //one run is winning consistently so galloping may provide huge benefits
//so try galloping, until such time as the run is no longer consistently winning
do
//ASSERT(len1 > 0 && len2 > 1)
diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm
index feea67939f836..ee9e734428487 100644
--- a/code/__HELPERS/text.dm
+++ b/code/__HELPERS/text.dm
@@ -71,7 +71,7 @@
return t
t = matchMiddle.group[1]
- // Replace any non-space whitespace characters with spaces, and also multiple occurences with just one space
+ // Replace any non-space whitespace characters with spaces, and also multiple occurrences with just one space
var/static/regex/matchSpacing = new(@"\s+", "g")
t = replacetext(t, matchSpacing, " ")
@@ -153,7 +153,7 @@
/**
* Filters out undesirable characters from names.
*
- * * strict - return null immidiately instead of filtering out
+ * * strict - return null immediately instead of filtering out
* * allow_numbers - allows numbers and common special characters - used for silicon/other weird things names
* * cap_after_symbols - words like Bob's will be capitalized to Bob'S by default. False is good for titles.
*/
@@ -169,7 +169,7 @@
var/char = ""
// This is a sanity short circuit, if the users name is three times the maximum allowable length of name
- // We bail out on trying to process the name at all, as it could be a bug or malicious input and we dont
+ // We bail out on trying to process the name at all, as it could be a bug or malicious input and we don't
// Want to iterate all of it.
if(t_len > 3 * MAX_NAME_LEN)
return
@@ -1142,8 +1142,8 @@ GLOBAL_LIST_INIT(binary, list("0","1"))
return word
var/first_letter = copytext(word, 1, 2)
var/first_two_letters = copytext(word, 1, 3)
- var/first_word_is_vowel = (first_letter in list("a", "e", "i", "o", "u"))
- var/second_word_is_vowel = (copytext(word, 2, 3) in list("a", "e", "i", "o", "u"))
+ var/first_word_is_vowel = (first_letter in VOWELS)
+ var/second_word_is_vowel = (copytext(word, 2, 3) in VOWELS)
//If a word starts with a vowel add the word "way" at the end of the word.
if(first_word_is_vowel)
return word + pick("yay", "way", "hay") //in cultures around the world it's different, so heck lets have fun and make it random. should still be readable
diff --git a/code/__HELPERS/turfs.dm b/code/__HELPERS/turfs.dm
index 93da26ef292f8..c4867ba999373 100644
--- a/code/__HELPERS/turfs.dm
+++ b/code/__HELPERS/turfs.dm
@@ -76,7 +76,7 @@ Turf and target are separate in case you want to teleport some distance from a t
//destination_list = new()
/*This will draw a block around the target turf, given what the error is.
Specifying the values above will basically draw a different sort of block.
- If the values are the same, it will be a square. If they are different, it will be a rectengle.
+ If the values are the same, it will be a square. If they are different, it will be a rectangle.
In either case, it will center based on offset. Offset is position from center.
Offset always calculates in relation to direction faced. In other words, depending on the direction of the teleport,
the offset should remain positioned in relation to destination.*/
@@ -206,7 +206,7 @@ Turf and target are separate in case you want to teleport some distance from a t
* NOTE: if your atom has non-standard bounds then this proc
* will handle it, but:
* if the bounds are even, then there are an even amount of "middle" turfs, the one to the EAST, NORTH, or BOTH is picked
- * this may seem bad, but you're atleast as close to the center of the atom as possible, better than byond's default loc being all the way off)
+ * this may seem bad, but you're at least as close to the center of the atom as possible, better than byond's default loc being all the way off)
* if the bounds are odd, the true middle turf of the atom is returned
**/
/proc/get_turf_pixel(atom/checked_atom)
diff --git a/code/__HELPERS/visual_effects.dm b/code/__HELPERS/visual_effects.dm
index d219d11e1ce82..2b845c2131b00 100644
--- a/code/__HELPERS/visual_effects.dm
+++ b/code/__HELPERS/visual_effects.dm
@@ -44,9 +44,9 @@
speed /= segments
if(parallel)
- animate(src, transform = matrices[1], time = speed, loops , flags = ANIMATION_PARALLEL)
+ animate(src, transform = matrices[1], time = speed, loop = loops, flags = ANIMATION_PARALLEL)
else
- animate(src, transform = matrices[1], time = speed, loops)
+ animate(src, transform = matrices[1], time = speed, loop = loops)
for(var/i in 2 to segments) //2 because 1 is covered above
animate(transform = matrices[i], time = speed)
//doesn't have an object argument because this is "Stacking" with the animate call above
diff --git a/code/_compile_options.dm b/code/_compile_options.dm
index 5186860f53bfd..c42754644bb1a 100644
--- a/code/_compile_options.dm
+++ b/code/_compile_options.dm
@@ -19,7 +19,7 @@
/// We'll use another define to convert uses of the proc over. That'll be all
// #define APPEARANCE_SUCCESS_TRACKING
-///Used to find the sources of harddels, quite laggy, don't be surpised if it freezes your client for a good while
+///Used to find the sources of harddels, quite laggy, don't be surprised if it freezes your client for a good while
//#define REFERENCE_TRACKING
#ifdef REFERENCE_TRACKING
@@ -83,7 +83,8 @@
// If this is uncommented, we do a single run though of the game setup and tear down process with unit tests in between
// #define UNIT_TESTS
-// If this is uncommented, will attempt to load and initialize prof.dll/libprof.so.
+// If this is uncommented, will attempt to load and initialize prof.dll/libprof.so by default.
+// Even if it's not defined, you can pass "tracy" via -params in order to try to load it.
// We do not ship byond-tracy. Build it yourself here: https://github.com/mafemergency/byond-tracy/
// #define USE_BYOND_TRACY
diff --git a/code/_globalvars/admin.dm b/code/_globalvars/admin.dm
index 96f07e3cca870..e14a56c16814c 100644
--- a/code/_globalvars/admin.dm
+++ b/code/_globalvars/admin.dm
@@ -76,6 +76,7 @@ GLOBAL_LIST_INIT(spanname_to_formatting, list(
"Drone Radio" = "drone",
"Engineering Radio" = "engradio",
"Extremely Big" = "extremelybig",
+ "Entertainment Radio" = "enteradio",
"Game Say" = "game say",
"Ghost Alert" = "ghostalert",
"Green" = "green",
diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm
index 27c0d27ec2e92..8db59bccc3532 100644
--- a/code/_globalvars/bitfields.dm
+++ b/code/_globalvars/bitfields.dm
@@ -442,6 +442,7 @@ DEFINE_BITFIELD(supports_variations_flags, list(
"CLOTHING_NO_VARIATION" = CLOTHING_NO_VARIATION,
"CLOTHING_DIGITIGRADE_VARIATION" = CLOTHING_DIGITIGRADE_VARIATION,
"CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON" = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON,
+ "CLOTHING_DIGITIGRADE_MASK" = CLOTHING_DIGITIGRADE_MASK,
))
DEFINE_BITFIELD(flora_flags, list(
diff --git a/code/_globalvars/lists/basic_ai.dm b/code/_globalvars/lists/basic_ai.dm
new file mode 100644
index 0000000000000..8d79c9bfafeaf
--- /dev/null
+++ b/code/_globalvars/lists/basic_ai.dm
@@ -0,0 +1,12 @@
+///all basic ai subtrees
+GLOBAL_LIST_EMPTY(ai_subtrees)
+
+///basic ai controllers based on status
+GLOBAL_LIST_INIT(ai_controllers_by_status, list(
+ AI_STATUS_ON = list(),
+ AI_STATUS_OFF = list(),
+ AI_STATUS_IDLE = list(),
+))
+
+///basic ai controllers based on their z level
+GLOBAL_LIST_EMPTY(ai_controllers_by_zlevel)
diff --git a/code/_globalvars/lists/flavor_misc.dm b/code/_globalvars/lists/flavor_misc.dm
index faaabd77ba134..82cc3f1cf10b3 100644
--- a/code/_globalvars/lists/flavor_misc.dm
+++ b/code/_globalvars/lists/flavor_misc.dm
@@ -265,3 +265,5 @@ GLOBAL_LIST_INIT(status_display_state_pictures, list(
"blank",
"shuttle",
))
+
+GLOBAL_LIST_INIT(fishing_tips, world.file2list("strings/fishing_tips.txt"))
diff --git a/code/_globalvars/lists/maintenance_loot.dm b/code/_globalvars/lists/maintenance_loot.dm
index e44516d2f2873..fe28ec63969ba 100644
--- a/code/_globalvars/lists/maintenance_loot.dm
+++ b/code/_globalvars/lists/maintenance_loot.dm
@@ -151,6 +151,7 @@ GLOBAL_LIST_INIT(common_loot, list( //common: basic items
/obj/item/stack/spacecash/c10 = 1,
/obj/item/stack/sticky_tape = 1,
/obj/item/tank/internals/emergency_oxygen = 1,
+ /obj/item/paper/paperslip/fishing_tip = 1,
//light sources
/obj/effect/spawner/random/decoration/glowstick = 1,
diff --git a/code/_globalvars/lists/quirks.dm b/code/_globalvars/lists/quirks.dm
index 22ef830ea773d..896504beb7b2a 100644
--- a/code/_globalvars/lists/quirks.dm
+++ b/code/_globalvars/lists/quirks.dm
@@ -92,3 +92,9 @@ GLOBAL_LIST_INIT(organ_choice, list(
"Liver" = ORGAN_SLOT_LIVER,
"Stomach" = ORGAN_SLOT_STOMACH,
))
+
+///Paraplegic Quirk
+GLOBAL_LIST_INIT(paraplegic_choice, list(
+ "Default" = FALSE,
+ "Amputee" = TRUE,
+))
diff --git a/code/_globalvars/lists/reagents.dm b/code/_globalvars/lists/reagents.dm
index 685eda9357610..dc18f9814c63f 100644
--- a/code/_globalvars/lists/reagents.dm
+++ b/code/_globalvars/lists/reagents.dm
@@ -49,7 +49,7 @@ GLOBAL_LIST_INIT(chemical_reagents_list, init_chemical_reagent_list())
GLOBAL_LIST(chemical_reactions_results_lookup_list)
/// list of all reagents that are parent types used to define a bunch of children - but aren't used themselves as anything.
GLOBAL_LIST(fake_reagent_blacklist)
-/// Turfs metalgen cant touch
+/// Turfs metalgen can't touch
GLOBAL_LIST_INIT(blacklisted_metalgen_types, typecacheof(list(
/turf/closed/indestructible, //indestructible turfs should be indestructible, metalgen transmutation to plasma allows them to be destroyed
/turf/open/indestructible
@@ -176,7 +176,7 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagentlist())
/proc/build_name2reagentlist()
. = list()
- //build map with keys stored seperatly
+ //build map with keys stored separately
var/list/name_to_reagent = list()
var/list/only_names = list()
for (var/datum/reagent/reagent as anything in GLOB.chemical_reagents_list)
diff --git a/code/_globalvars/lists/typecache.dm b/code/_globalvars/lists/typecache.dm
index 805cea677a092..b1460165564e6 100644
--- a/code/_globalvars/lists/typecache.dm
+++ b/code/_globalvars/lists/typecache.dm
@@ -1,5 +1,5 @@
//please store common type caches here.
-//type caches should only be stored here if used in mutiple places or likely to be used in mutiple places.
+//type caches should only be stored here if used in multiple places or likely to be used in multiple places.
//Note: typecache can only replace istype if you know for sure the thing is at least a datum.
diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm
index dcda2365c4b0f..8a3697eaa4b56 100644
--- a/code/_globalvars/traits/_traits.dm
+++ b/code/_globalvars/traits/_traits.dm
@@ -19,9 +19,11 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_DRYABLE" = TRAIT_DRYABLE,
"TRAIT_FOOD_CHEF_MADE" = TRAIT_FOOD_CHEF_MADE,
"TRAIT_FOOD_FRIED" = TRAIT_FOOD_FRIED,
+ "TRAIT_QUALITY_FOOD_INGREDIENT" = TRAIT_QUALITY_FOOD_INGREDIENT,
"TRAIT_FOOD_SILVER" = TRAIT_FOOD_SILVER,
"TRAIT_KEEP_TOGETHER" = TRAIT_KEEP_TOGETHER,
"TRAIT_LIGHTING_DEBUGGED" = TRAIT_LIGHTING_DEBUGGED,
+ "TRAIT_MESSAGE_IN_A_BOTTLE_LOCATION" = TRAIT_MESSAGE_IN_A_BOTTLE_LOCATION,
"TRAIT_RECENTLY_COINED" = TRAIT_RECENTLY_COINED,
"TRAIT_RUSTY" = TRAIT_RUSTY,
"TRAIT_SPINNING" = TRAIT_SPINNING,
@@ -37,7 +39,6 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_CASTABLE_LOC" = TRAIT_CASTABLE_LOC,
"TRAIT_DEL_ON_SPACE_DUMP" = TRAIT_DEL_ON_SPACE_DUMP,
"TRAIT_FISH_CASE_COMPATIBILE" = TRAIT_FISH_CASE_COMPATIBILE,
- "TRAIT_FISH_SAFE_STORAGE" = TRAIT_FISH_SAFE_STORAGE,
"TRAIT_FROZEN" = TRAIT_FROZEN,
"TRAIT_HAS_LABEL" = TRAIT_HAS_LABEL,
"TRAIT_HEARING_SENSITIVE" = TRAIT_HEARING_SENSITIVE,
@@ -117,8 +118,12 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_CONTRABAND" = TRAIT_CONTRABAND,
),
/mob = list(
+ "TRAIT_AI_ACCESS" = TRAIT_AI_ACCESS,
"TRAIT_ABDUCTOR_SCIENTIST_TRAINING" = TRAIT_ABDUCTOR_SCIENTIST_TRAINING,
"TRAIT_ABDUCTOR_TRAINING" = TRAIT_ABDUCTOR_TRAINING,
+ "TRAIT_ACT_AS_CULTIST" = TRAIT_ACT_AS_CULTIST,
+ "TRAIT_ACT_AS_HERETIC" = TRAIT_ACT_AS_HERETIC,
+ "TRAIT_ACTIVELY_FISHING" = TRAIT_ACTIVELY_FISHING,
"TRAIT_ADAMANTINE_EXTRACT_ARMOR" = TRAIT_ADAMANTINE_EXTRACT_ARMOR,
"TRAIT_ADVANCEDTOOLUSER" = TRAIT_ADVANCEDTOOLUSER,
"TRAIT_AGENDER" = TRAIT_AGENDER,
@@ -148,6 +153,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_BIRTHDAY_BOY" = TRAIT_BIRTHDAY_BOY,
"TRAIT_BLOB_ALLY" = TRAIT_BLOB_ALLY,
"TRAIT_BLOCK_SHUTTLE_MOVEMENT" = TRAIT_BLOCK_SHUTTLE_MOVEMENT,
+ "TRAIT_BLOCKING_PROJECTILES" = TRAIT_BLOCKING_PROJECTILES,
"TRAIT_BLOOD_CLANS" = TRAIT_BLOOD_CLANS,
"TRAIT_BLOODSHOT_EYES" = TRAIT_BLOODSHOT_EYES,
"TRAIT_BLOODY_MESS" = TRAIT_BLOODY_MESS,
@@ -204,6 +210,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_DOUBLE_TAP" = TRAIT_DOUBLE_TAP,
"TRAIT_DREAMING" = TRAIT_DREAMING,
"TRAIT_DRINKS_BLOOD" = TRAIT_DRINKS_BLOOD,
+ "TRAIT_DRUNKEN_BRAWLER" = TRAIT_DRUNKEN_BRAWLER,
"TRAIT_DUMB" = TRAIT_DUMB,
"TRAIT_DWARF" = TRAIT_DWARF,
"TRAIT_EASILY_WOUNDED" = TRAIT_EASILY_WOUNDED,
@@ -216,6 +223,8 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_EMOTEMUTE" = TRAIT_EMOTEMUTE,
"TRAIT_EMPATH" = TRAIT_EMPATH,
"TRAIT_ENTRAILS_READER" = TRAIT_ENTRAILS_READER,
+ "TRAIT_EXAMINE_DEEPER_FISH" = TRAIT_EXAMINE_DEEPER_FISH,
+ "TRAIT_EXAMINE_FISH" = TRAIT_EXAMINE_FISH,
"TRAIT_EXAMINE_FISHING_SPOT" = TRAIT_EXAMINE_FISHING_SPOT,
"TRAIT_EXAMINE_FITNESS" = TRAIT_EXAMINE_FITNESS,
"TRAIT_EXPANDED_FOV" = TRAIT_EXPANDED_FOV,
@@ -230,7 +239,6 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_FENCE_CLIMBER" = TRAIT_FENCE_CLIMBER,
"TRAIT_FINGERPRINT_PASSTHROUGH" = TRAIT_FINGERPRINT_PASSTHROUGH,
"TRAIT_FIST_MINING" = TRAIT_FIST_MINING,
- "TRAIT_FIXED_HAIRCOLOR" = TRAIT_FIXED_HAIRCOLOR,
"TRAIT_FIXED_MUTANT_COLORS" = TRAIT_FIXED_MUTANT_COLORS,
"TRAIT_FLESH_DESIRE" = TRAIT_FLESH_DESIRE,
"TRAIT_FLOORED" = TRAIT_FLOORED,
@@ -288,6 +296,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_IWASBATONED" = TRAIT_IWASBATONED,
"TRAIT_JOLLY" = TRAIT_JOLLY,
"TRAIT_KISS_OF_DEATH" = TRAIT_KISS_OF_DEATH,
+ "TRAIT_SYNDIE_KISS" = TRAIT_SYNDIE_KISS,
"TRAIT_KNOCKEDOUT" = TRAIT_KNOCKEDOUT,
"TRAIT_KNOW_ENGI_WIRES" = TRAIT_KNOW_ENGI_WIRES,
"TRAIT_KNOW_ROBO_WIRES" = TRAIT_KNOW_ROBO_WIRES,
@@ -442,11 +451,11 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_SHOCKIMMUNE" = TRAIT_SHOCKIMMUNE,
"TRAIT_SIGN_LANG" = TRAIT_SIGN_LANG,
"TRAIT_SILENT_FOOTSTEPS" = TRAIT_SILENT_FOOTSTEPS,
+ "TRAIT_SILICON_ACCESS" = TRAIT_SILICON_ACCESS,
"TRAIT_SILICON_EMOTES_ALLOWED" = TRAIT_SILICON_EMOTES_ALLOWED,
"TRAIT_SIXTHSENSE" = TRAIT_SIXTHSENSE,
"TRAIT_SKITTISH" = TRAIT_SKITTISH,
"TRAIT_SLEEPIMMUNE" = TRAIT_SLEEPIMMUNE,
- "TRAIT_SLOW_FLIP" = TRAIT_SLOW_FLIP,
"TRAIT_SMOKER" = TRAIT_SMOKER,
"TRAIT_SNEAK" = TRAIT_SNEAK,
"TRAIT_SNOB" = TRAIT_SNOB,
@@ -500,6 +509,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_TUMOR_SUPPRESSION" = TRAIT_TUMOR_SUPPRESSED,
"TRAIT_UI_BLOCKED" = TRAIT_UI_BLOCKED,
"TRAIT_UNBREAKABLE" = TRAIT_UNBREAKABLE,
+ "TRAIT_UNCONVERTABLE" = TRAIT_UNCONVERTABLE,
"TRAIT_UNDENSE" = TRAIT_UNDENSE,
"TRAIT_UNDERWATER_BASKETWEAVING_KNOWLEDGE" = TRAIT_UNDERWATER_BASKETWEAVING_KNOWLEDGE,
"TRAIT_UNHUSKABLE" = TRAIT_UNHUSKABLE,
@@ -559,6 +569,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_NODROP" = TRAIT_NODROP,
"TRAIT_OMNI_BAIT" = TRAIT_OMNI_BAIT,
"TRAIT_PLANT_WILDMUTATE" = TRAIT_PLANT_WILDMUTATE,
+ "TRAIT_POISONOUS_BAIT" = TRAIT_POISONOUS_BAIT,
"TRAIT_T_RAY_VISIBLE" = TRAIT_T_RAY_VISIBLE,
"TRAIT_TRANSFORM_ACTIVE" = TRAIT_TRANSFORM_ACTIVE,
"TRAIT_UNCATCHABLE" = TRAIT_UNCATCHABLE,
@@ -589,13 +600,17 @@ GLOBAL_LIST_INIT(traits_by_type, list(
/obj/item/fish = list(
"TRAIT_FISH_AMPHIBIOUS" = TRAIT_FISH_AMPHIBIOUS,
"TRAIT_FISH_CROSSBREEDER" = TRAIT_FISH_CROSSBREEDER,
+ "TRAIT_FISH_ELECTROGENESIS" = TRAIT_FISH_ELECTROGENESIS,
"TRAIT_FISH_FED_LUBE" = TRAIT_FISH_FED_LUBE,
+ "TRAIT_FISH_FLOPPING" = TRAIT_FISH_FLOPPING,
"TRAIT_FISH_FROM_CASE" = TRAIT_FISH_FROM_CASE,
"TRAIT_FISH_NO_HUNGER" = TRAIT_FISH_NO_HUNGER,
"TRAIT_FISH_NO_MATING" = TRAIT_FISH_NO_MATING,
+ "TRAIT_FISH_RECESSIVE" = TRAIT_FISH_RECESSIVE,
"TRAIT_FISH_SELF_REPRODUCE" = TRAIT_FISH_SELF_REPRODUCE,
+ "TRAIT_FISH_STASIS" = TRAIT_FISH_STASIS,
+ "TRAIT_FISH_STINGER" = TRAIT_FISH_STINGER,
"TRAIT_FISH_TOXIN_IMMUNE" = TRAIT_FISH_TOXIN_IMMUNE,
- "TRAIT_FISH_ELECTROGENESIS" = TRAIT_FISH_ELECTROGENESIS,
"TRAIT_RESIST_EMULSIFY" = TRAIT_RESIST_EMULSIFY,
"TRAIT_YUCKY_FISH" = TRAIT_YUCKY_FISH,
),
@@ -632,9 +647,6 @@ GLOBAL_LIST_INIT(traits_by_type, list(
/obj/machinery/modular_computer = list(
"TRAIT_MODPC_INTERACTING_WITH_FRAME" = TRAIT_MODPC_INTERACTING_WITH_FRAME,
),
- /obj/projectile = list(
- "TRAIT_ALWAYS_HIT_ZONE" = TRAIT_ALWAYS_HIT_ZONE,
- ),
/obj/structure = list(
"TRAIT_RADSTORM_IMMUNE" = TRAIT_RADSTORM_IMMUNE,
),
diff --git a/code/_globalvars/traits/admin_tooling.dm b/code/_globalvars/traits/admin_tooling.dm
index 98c3fd6ab1fca..afb8709109832 100644
--- a/code/_globalvars/traits/admin_tooling.dm
+++ b/code/_globalvars/traits/admin_tooling.dm
@@ -26,6 +26,8 @@ GLOBAL_LIST_INIT(admin_visible_traits, list(
/mob = list(
"TRAIT_ABDUCTOR_SCIENTIST_TRAINING" = TRAIT_ABDUCTOR_SCIENTIST_TRAINING,
"TRAIT_ABDUCTOR_TRAINING" = TRAIT_ABDUCTOR_TRAINING,
+ "TRAIT_ACT_AS_CULTIST" = TRAIT_ACT_AS_CULTIST,
+ "TRAIT_ACT_AS_HERETIC" = TRAIT_ACT_AS_HERETIC,
"TRAIT_ADVANCEDTOOLUSER" = TRAIT_ADVANCEDTOOLUSER,
"TRAIT_AGENDER" = TRAIT_AGENDER,
"TRAIT_AGEUSIA" = TRAIT_AGEUSIA,
@@ -101,7 +103,6 @@ GLOBAL_LIST_INIT(admin_visible_traits, list(
"TRAIT_FEARLESS" = TRAIT_FEARLESS,
"TRAIT_FENCE_CLIMBER" = TRAIT_FENCE_CLIMBER,
"TRAIT_FIST_MINING" = TRAIT_FIST_MINING,
- "TRAIT_FIXED_HAIRCOLOR" = TRAIT_FIXED_HAIRCOLOR,
"TRAIT_FIXED_MUTANT_COLORS" = TRAIT_FIXED_MUTANT_COLORS,
"TRAIT_FLESH_DESIRE" = TRAIT_FLESH_DESIRE,
"TRAIT_FLOORED" = TRAIT_FLOORED,
@@ -259,7 +260,6 @@ GLOBAL_LIST_INIT(admin_visible_traits, list(
"TRAIT_SIXTHSENSE" = TRAIT_SIXTHSENSE,
"TRAIT_SKITTISH" = TRAIT_SKITTISH,
"TRAIT_SLEEPIMMUNE" = TRAIT_SLEEPIMMUNE,
- "TRAIT_SLOW_FLIP" = TRAIT_SLOW_FLIP,
"TRAIT_SMOKER" = TRAIT_SMOKER,
"TRAIT_SNOB" = TRAIT_SNOB,
"TRAIT_SOFTSPOKEN" = TRAIT_SOFTSPOKEN,
@@ -289,6 +289,7 @@ GLOBAL_LIST_INIT(admin_visible_traits, list(
"TRAIT_TRAIT_MEDIBOTCOMINGTHROUGH" = TRAIT_MEDIBOTCOMINGTHROUGH,
"TRAIT_TUMOR_SUPPRESSION" = TRAIT_TUMOR_SUPPRESSED,
"TRAIT_UI_BLOCKED" = TRAIT_UI_BLOCKED,
+ "TRAIT_UNCONVERTABLE" = TRAIT_UNCONVERTABLE,
"TRAIT_UNDENSE" = TRAIT_UNDENSE,
"TRAIT_UNDERWATER_BASKETWEAVING_KNOWLEDGE" = TRAIT_UNDERWATER_BASKETWEAVING_KNOWLEDGE,
"TRAIT_UNHUSKABLE" = TRAIT_UNHUSKABLE,
@@ -333,13 +334,19 @@ GLOBAL_LIST_INIT(admin_visible_traits, list(
"TRAIT_MAGNETIC_ID_CARD" = TRAIT_MAGNETIC_ID_CARD,
),
/obj/item/fish = list(
+ "TRAIT_FISH_AMPHIBIOUS" = TRAIT_FISH_AMPHIBIOUS,
"TRAIT_FISH_CROSSBREEDER" = TRAIT_FISH_CROSSBREEDER,
+ "TRAIT_FISH_ELECTROGENESIS" = TRAIT_FISH_ELECTROGENESIS,
"TRAIT_FISH_FED_LUBE" = TRAIT_FISH_FED_LUBE,
+ "TRAIT_FISH_FROM_CASE" = TRAIT_FISH_FROM_CASE,
"TRAIT_FISH_NO_HUNGER" = TRAIT_FISH_NO_HUNGER,
"TRAIT_FISH_NO_MATING" = TRAIT_FISH_NO_MATING,
+ "TRAIT_FISH_RECESSIVE" = TRAIT_FISH_RECESSIVE,
"TRAIT_FISH_SELF_REPRODUCE" = TRAIT_FISH_SELF_REPRODUCE,
+ "TRAIT_FISH_STASIS" = TRAIT_FISH_STASIS,
+ "TRAIT_FISH_STINGER" = TRAIT_FISH_STINGER,
"TRAIT_FISH_TOXIN_IMMUNE" = TRAIT_FISH_TOXIN_IMMUNE,
- "TRAIT_RESIST_EMULSIFY" = TRAIT_RESIST_EMULSIFY,
+ "TRAIT_RESIST_EMULSIFY" = TRAIT_RESIST_EMULSIFY,
"TRAIT_YUCKY_FISH" = TRAIT_YUCKY_FISH,
),
/obj/item/organ/internal/liver = list(
diff --git a/code/_onclick/adjacent.dm b/code/_onclick/adjacent.dm
index ab5b3f4aad974..a4a8ae1cdc41a 100644
--- a/code/_onclick/adjacent.dm
+++ b/code/_onclick/adjacent.dm
@@ -68,6 +68,8 @@
/atom/movable/Adjacent(atom/neighbor, atom/target, atom/movable/mover)
if(neighbor == loc)
return TRUE
+ if(neighbor?.loc == src)
+ return TRUE
var/turf/T = loc
if(!istype(T))
return FALSE
@@ -79,6 +81,8 @@
/obj/item/Adjacent(atom/neighbor, atom/target, atom/movable/mover, recurse = 1)
if(neighbor == loc)
return TRUE
+ if(neighbor?.loc == src)
+ return TRUE
if(isitem(loc))
if(recurse > 0)
return loc.Adjacent(neighbor, target, mover, recurse - 1)
diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm
index ec76dee9c8e22..200f56bed971c 100644
--- a/code/_onclick/ai.dm
+++ b/code/_onclick/ai.dm
@@ -7,7 +7,7 @@
Note that AI have no need for the adjacency proc, and so this proc is a lot cleaner.
*/
/mob/living/silicon/ai/DblClickOn(atom/A, params)
- if(control_disabled || incapacitated())
+ if(control_disabled || incapacitated)
return
if(ismob(A))
@@ -39,7 +39,7 @@
if(check_click_intercept(params,A))
return
- if(control_disabled || incapacitated())
+ if(control_disabled || incapacitated)
return
var/turf/pixel_turf = get_turf_pixel(A)
diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm
index 1d7e07f7b9912..0c441ba928ee4 100644
--- a/code/_onclick/click.dm
+++ b/code/_onclick/click.dm
@@ -101,7 +101,7 @@
CtrlClickOn(A)
return
- if(incapacitated(IGNORE_RESTRAINTS|IGNORE_STASIS))
+ if(INCAPACITATED_IGNORING(src, INCAPABLE_RESTRAINTS|INCAPABLE_STASIS))
return
face_atom(A)
diff --git a/code/_onclick/cyborg.dm b/code/_onclick/cyborg.dm
index a2dda93f4011f..60640d01d5a1f 100644
--- a/code/_onclick/cyborg.dm
+++ b/code/_onclick/cyborg.dm
@@ -58,7 +58,7 @@
return
if(W)
- if(incapacitated())
+ if(incapacitated)
return
//while buckled, you can still connect to and control things like doors, but you can't use your modules
diff --git a/code/_onclick/hud/ai.dm b/code/_onclick/hud/ai.dm
index 84efaf77c5dc9..aaad7457f6d3c 100644
--- a/code/_onclick/hud/ai.dm
+++ b/code/_onclick/hud/ai.dm
@@ -2,7 +2,7 @@
icon = 'icons/hud/screen_ai.dmi'
/atom/movable/screen/ai/Click()
- if(isobserver(usr) || usr.incapacitated())
+ if(isobserver(usr) || usr.incapacitated)
return TRUE
/atom/movable/screen/ai/aicore
diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm
index 1b1314bbcd5e5..73497bf418ff1 100644
--- a/code/_onclick/hud/hud.dm
+++ b/code/_onclick/hud/hud.dm
@@ -584,7 +584,7 @@ GLOBAL_LIST_INIT(available_ui_styles, list(
listed_actions.check_against_view()
palette_actions.check_against_view()
for(var/atom/movable/screen/movable/action_button/floating_button as anything in floating_actions)
- var/list/current_offsets = screen_loc_to_offset(floating_button.screen_loc)
+ var/list/current_offsets = screen_loc_to_offset(floating_button.screen_loc, our_view)
// We set the view arg here, so the output will be properly hemm'd in by our new view
floating_button.screen_loc = offset_to_screen_loc(current_offsets[1], current_offsets[2], view = our_view)
diff --git a/code/_onclick/hud/map_view.dm b/code/_onclick/hud/map_view.dm
index bc304f20f8a15..06a4197fe45eb 100644
--- a/code/_onclick/hud/map_view.dm
+++ b/code/_onclick/hud/map_view.dm
@@ -16,10 +16,7 @@ INITIALIZE_IMMEDIATE(/atom/movable/screen/map_view)
/atom/movable/screen/map_view/Destroy()
for(var/datum/weakref/client_ref in viewers_to_huds)
- var/client/our_client = client_ref.resolve()
- if(!our_client)
- continue
- hide_from(our_client.mob)
+ hide_from_client(client_ref.resolve())
return ..()
@@ -55,12 +52,18 @@ INITIALIZE_IMMEDIATE(/atom/movable/screen/map_view)
return pop_planes
/atom/movable/screen/map_view/proc/hide_from(mob/hide_from)
- hide_from?.canon_client.clear_map(assigned_map)
- var/client_ref = WEAKREF(hide_from?.canon_client)
+ hide_from_client(hide_from?.canon_client)
+/atom/movable/screen/map_view/proc/hide_from_client(client/hide_from)
+ if(!hide_from)
+ return
+ hide_from.clear_map(assigned_map)
+
+ var/datum/weakref/client_ref = WEAKREF(hide_from)
// Make sure we clear the *right* hud
var/datum/weakref/hud_ref = viewers_to_huds[client_ref]
viewers_to_huds -= client_ref
+
var/datum/hud/clear_from = hud_ref?.resolve()
if(!clear_from)
return
diff --git a/code/_onclick/hud/parallax/parallax.dm b/code/_onclick/hud/parallax/parallax.dm
index 0a3732e134fc4..135c3f0caef6e 100644
--- a/code/_onclick/hud/parallax/parallax.dm
+++ b/code/_onclick/hud/parallax/parallax.dm
@@ -273,7 +273,7 @@ INITIALIZE_IMMEDIATE(/atom/movable/screen/parallax_layer)
/atom/movable/screen/parallax_layer/Initialize(mapload, datum/hud/hud_owner, template = FALSE)
. = ..()
- // Parallax layers are independant of hud, they care about client
+ // Parallax layers are independent of hud, they care about client
// Not doing this will just create a bunch of hard deletes
set_new_hud(hud_owner = null)
@@ -335,7 +335,7 @@ INITIALIZE_IMMEDIATE(/atom/movable/screen/parallax_layer)
/atom/movable/screen/parallax_layer/planet
icon_state = "planet"
blend_mode = BLEND_OVERLAY
- absolute = TRUE //Status of seperation
+ absolute = TRUE //Status of separation
speed = 3
layer = 30
diff --git a/code/_onclick/hud/rendering/_render_readme.md b/code/_onclick/hud/rendering/_render_readme.md
index 2c5e9875801b6..493b9c68491ee 100644
--- a/code/_onclick/hud/rendering/_render_readme.md
+++ b/code/_onclick/hud/rendering/_render_readme.md
@@ -8,11 +8,11 @@
## Byond internal functionality
This part of the guide will assume that you have read the byond reference entry for rendering at www.byond.com/docs/ref//#/{notes}/renderer
-When you create an atom, this will always create an internal byond structure called an "appearance". This appearance you will likely be familiar with, as it is exposed through the /atom/var/appearance var. This appearance var holds data on how to render the object, ie what icon/icon_state/color etc it is using. Note that appearance vars will always copy, and do not hold a reference. When you update a var, for example lets pretend we add a filter, the appearance will be updated to include the filter. Note that, however, vis_contents objets are uniquely excluded from appearances. Then, when the filter is updated, the appearance will be recreated, and the atom marked as "dirty". After it has been updated, the SendMaps() function (sometimes also called maptick), which is a internal byond function that iterates over all objects in a clients view and in the clients.mob.contents, checks for "dirty" atoms, then resends any "dirty" appearances to clients as needed and unmarks them as dirty. This function is notoriosly slow, but we can see its tick usage through the world.map_cpu var. We can also avoid more complex checks checking whether an object is visible on a clients screen by using the TILE_BOUND appearance flag.
+When you create an atom, this will always create an internal byond structure called an "appearance". This appearance you will likely be familiar with, as it is exposed through the /atom/var/appearance var. This appearance var holds data on how to render the object, ie what icon/icon_state/color etc it is using. Note that appearance vars will always copy, and do not hold a reference. When you update a var, for example lets pretend we add a filter, the appearance will be updated to include the filter. Note that, however, vis_contents objets are uniquely excluded from appearances. Then, when the filter is updated, the appearance will be recreated, and the atom marked as "dirty". After it has been updated, the SendMaps() function (sometimes also called maptick), which is a internal byond function that iterates over all objects in a clients view and in the clients.mob.contents, checks for "dirty" atoms, then resends any "dirty" appearances to clients as needed and unmarks them as dirty. This function is notoriously slow, but we can see its tick usage through the world.map_cpu var. We can also avoid more complex checks checking whether an object is visible on a clients screen by using the TILE_BOUND appearance flag.
-Finally, we arrive at clientside behavior, where we have two main clientside functions: GetMapIcons, and Render. GetMapIcons is repsonsible for actual rendering calculations on the clientside, such as "Group Icons and Set bounds", which performs clientside calculations for transform matrixes. Note that particles here are handled in a separate thread and are not diplayed in the clientside profiler. Render handles the actual drawing of the screen.
+Finally, we arrive at clientside behavior, where we have two main clientside functions: GetMapIcons, and Render. GetMapIcons is responsible for actual rendering calculations on the clientside, such as "Group Icons and Set bounds", which performs clientside calculations for transform matrixes. Note that particles here are handled in a separate thread and are not displayed in the clientside profiler. Render handles the actual drawing of the screen.
-For debugging rendering issues its reccomended you do two things:
+For debugging rendering issues its recommended you do two things:
A) Talk to someone who has inside knowledge(like lummox) about it, most of this is undocumented and bugs often
B) Use the undocumented debug printer which reads of data on icons rendering, this is very dense but can be useful in some cases. To use: Right click top tab -> Options & Messages -> Client -> Command -> Enter ".debug profile mapicons" and press Enter -> go to your Byond directory and find BYOND/cfg/mapicons.json . Yes this is one giant one-line json.
@@ -22,9 +22,9 @@ The following is an incomplete list of pitfalls that come from byond snowflake t
1. Transforms are very slow on clientside. This is not usually noticable, but if you start using large amounts of them it will grind you to a halt quickly, regardless of whether its on overlays or objs
2. The darkness plane. This is unused, as it doesn't work with our rendering format, so this section is purely academic. The darkness plane has specific variables it needs to render correctly, and these can be found in the plane masters file. it is composed internally of two parts, a black mask over the clients screen, and a non rendering mask that blocks all luminosity=0 turfs and their contents from rendering if the SEE_BLACKNESS flag is set properly. The blocker will always block rendering but the mask can be layered under other objects.
3. render_target/source. Render_target/source will only copy certain rendering instructions, and these are only defined as "etc." in the byond reference. Known non copied appearance vars include: blend_mode, plane, layer, vis_contents, mouse_opacity...
-4. Large icons on the screen that peek over the edge will instead of only rendering partly like you would expect will instead stretch the screen while not adgusting the render buffer, which means that you can actively see as tiles and map objects are rendered. You can use this for an easy "offscreen" UI.
+4. Large icons on the screen that peek over the edge will instead of only rendering partly like you would expect will instead stretch the screen while not adjusting the render buffer, which means that you can actively see as tiles and map objects are rendered. You can use this for an easy "offscreen" UI.
5. Numerically large filters on objects of any size will torpedo performance, even though large objects with small filters will perform massively better. (ie blur(size=20) BAD)
-6. Texture Atlas: the texture atlas byond uses to render icons is very susceptible to corruption and can regularily replace icons with other icons or just not render at all. This can be exasperated by alt tabbing or pausing the dreamseeker process.
+6. Texture Atlas: the texture atlas byond uses to render icons is very susceptible to corruption and can regularly replace icons with other icons or just not render at all. This can be exasperated by alt tabbing or pausing the dreamseeker process.
7. The renderer is awful code and lummox said he will try changing a large part of it for 515 so keep an eye on that
8. Byond uses DirectX 9 (Lummox said he wants to update to DirectX 11)
9. Particles are just fancy overlays and are not independent of their owner
@@ -32,7 +32,7 @@ The following is an incomplete list of pitfalls that come from byond snowflake t
11. Displacement filter: The byond "displacement filter" does not, as the name would make you expect, use displacement maps, but instead uses normal maps.
## The rendering solution
-One of the main issues with making pretty effects is how objects can only render to one plane, and how filters can only be applied to single objects. Quite simply it means we cant apply effects to multiple planes at once, and an effect to one plane only by treating it as a single unit:
+One of the main issues with making pretty effects is how objects can only render to one plane, and how filters can only be applied to single objects. Quite simply it means we can't apply effects to multiple planes at once, and an effect to one plane only by treating it as a single unit:
![](https://raw.githubusercontent.com/tgstation/documentation-assets/main/rendering/renderpipe_old.png)
@@ -50,8 +50,8 @@ Through these this allows us to treat planes as single objects, and lets us dist
## Render plates
-The rendering system uses two objects to unify planes: render_relay and render_plates. Render relays use render_target/source and the relay_render_to_plane proc to replicate the plane master on the render relay. This render relay is then rendered onto a render_plate, which is a plane master that renders the render_relays onto itself. This plate can then be hierachically rendered with the same process until it reaches the master render_plate, which is the plate that will actually render to the player. These plates naturally in the byond style have quirks. For example, rendering to two plates will double any effects such as color or filters, and as such you need to carefully manage how you render them. Keep in mind as well that when sorting the layers for rendering on a plane that they should not be negative, this is handled automatically in relay_render_to_plane. When debugging note that mouse_opacity can act bizzarly with this method, such as only allowing you to click things that are layered over objects on a certain plane but auomatically setting the mouse_opacity should be handling this. Note that if you decide to manipulate a plane with internal byond objects that you will have to manually extrapolate the vars that are set if you want to render them to another plane (See blackness plane for example), and that this is not documented anywhere.
+The rendering system uses two objects to unify planes: render_relay and render_plates. Render relays use render_target/source and the relay_render_to_plane proc to replicate the plane master on the render relay. This render relay is then rendered onto a render_plate, which is a plane master that renders the render_relays onto itself. This plate can then be hierarchically rendered with the same process until it reaches the master render_plate, which is the plate that will actually render to the player. These plates naturally in the byond style have quirks. For example, rendering to two plates will double any effects such as color or filters, and as such you need to carefully manage how you render them. Keep in mind as well that when sorting the layers for rendering on a plane that they should not be negative, this is handled automatically in relay_render_to_plane. When debugging note that mouse_opacity can act bizarrely with this method, such as only allowing you to click things that are layered over objects on a certain plane but automatically setting the mouse_opacity should be handling this. Note that if you decide to manipulate a plane with internal byond objects that you will have to manually extrapolate the vars that are set if you want to render them to another plane (See blackness plane for example), and that this is not documented anywhere.
-Goodluck and godspeed with coding
+Good luck and godspeed with coding
- Just another contributor
diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm
index d0f6426254936..cb06e00d116ef 100644
--- a/code/_onclick/hud/screen_objects.dm
+++ b/code/_onclick/hud/screen_objects.dm
@@ -110,7 +110,7 @@
if(world.time <= usr.next_move)
return 1
- if(usr.incapacitated())
+ if(usr.incapacitated)
return 1
if(ismob(usr))
@@ -143,7 +143,7 @@
screen_loc = ui_building
/atom/movable/screen/area_creator/Click()
- if(usr.incapacitated() || (isobserver(usr) && !isAdminGhostAI(usr)))
+ if(usr.incapacitated || (isobserver(usr) && !isAdminGhostAI(usr)))
return TRUE
var/area/A = get_area(usr)
if(!A.outdoors)
@@ -204,7 +204,7 @@
if(world.time <= usr.next_move)
return TRUE
- if(usr.incapacitated(IGNORE_STASIS))
+ if(INCAPACITATED_IGNORING(usr, INCAPABLE_STASIS))
return TRUE
if(ismecha(usr.loc)) // stops inventory actions in a mech
return TRUE
@@ -294,7 +294,7 @@
return TRUE
if(world.time <= user.next_move)
return TRUE
- if(user.incapacitated())
+ if(user.incapacitated)
return TRUE
if (ismecha(user.loc)) // stops inventory actions in a mech
return TRUE
@@ -471,7 +471,7 @@
if(world.time <= usr.next_move)
return TRUE
- if(usr.incapacitated())
+ if(usr.incapacitated)
return TRUE
if(ismecha(usr.loc)) // stops inventory actions in a mech
return TRUE
@@ -887,9 +887,9 @@ INITIALIZE_IMMEDIATE(/atom/movable/screen/splash)
/atom/movable/screen/hunger/update_appearance(updates)
var/old_state = state
update_hunger_state() // Do this before we call all the other update procs
- . = ..()
if(state == old_state) // Let's not be wasteful
return
+ . = ..()
if(state == HUNGER_STATE_FINE)
SetInvisibility(INVISIBILITY_ABSTRACT, name)
return
@@ -907,9 +907,10 @@ INITIALIZE_IMMEDIATE(/atom/movable/screen/splash)
remove_filter("hunger_outline")
// Update color of the food
- underlays -= food_image
- food_image.color = state == HUNGER_STATE_FAT ? COLOR_DARK : null
- underlays += food_image
+ if((state == HUNGER_STATE_FAT) != (old_state == HUNGER_STATE_FAT))
+ underlays -= food_image
+ food_image.color = state == HUNGER_STATE_FAT ? COLOR_DARK : null
+ underlays += food_image
/atom/movable/screen/hunger/update_icon_state()
. = ..()
diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm
index 17de9f9d5cb77..5af9b7e016156 100644
--- a/code/_onclick/item_attack.dm
+++ b/code/_onclick/item_attack.dm
@@ -270,12 +270,12 @@
/// Called from [/obj/item/proc/attack_atom] and [/obj/item/proc/attack] if the attack succeeds
/atom/proc/attacked_by(obj/item/attacking_item, mob/living/user)
if(!uses_integrity)
- CRASH("attacked_by() was called on an object that doesnt use integrity!")
+ CRASH("attacked_by() was called on an object that doesn't use integrity!")
if(!attacking_item.force)
return
- var/damage = take_damage(attacking_item.force, attacking_item.damtype, MELEE, 1)
+ var/damage = take_damage(attacking_item.force, attacking_item.damtype, MELEE, 1, get_dir(src, user))
//only witnesses close by and the victim see a hit message.
user.visible_message(span_danger("[user] hits [src] with [attacking_item][damage ? "." : ", without leaving a mark!"]"), \
span_danger("You hit [src] with [attacking_item][damage ? "." : ", without leaving a mark!"]"), null, COMBAT_MESSAGE_RANGE)
diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm
index 2f1465ac4ffe2..eab5f0a7cd9c9 100644
--- a/code/_onclick/other_mobs.dm
+++ b/code/_onclick/other_mobs.dm
@@ -109,11 +109,11 @@
if(!(interaction_flags_atom & INTERACT_ATOM_IGNORE_INCAPACITATED))
var/ignore_flags = NONE
if(interaction_flags_atom & INTERACT_ATOM_IGNORE_RESTRAINED)
- ignore_flags |= IGNORE_RESTRAINTS
+ ignore_flags |= INCAPABLE_RESTRAINTS
if(!(interaction_flags_atom & INTERACT_ATOM_CHECK_GRAB))
- ignore_flags |= IGNORE_GRAB
+ ignore_flags |= INCAPABLE_GRAB
- if(user.incapacitated(ignore_flags))
+ if(INCAPACITATED_IGNORING(user, ignore_flags))
return FALSE
return TRUE
diff --git a/code/controllers/configuration/configuration.dm b/code/controllers/configuration/configuration.dm
index b7f48fcab5e4a..6ba6cd2de09fc 100644
--- a/code/controllers/configuration/configuration.dm
+++ b/code/controllers/configuration/configuration.dm
@@ -506,7 +506,7 @@ Example config:
if(!fexists(file(config_toml)))
SSjob.legacy_mode = TRUE
- message += "jobconfig.toml not found, falling back to legacy mode (using jobs.txt). To surpress this warning, generate a jobconfig.toml by running the verb 'Generate Job Configuration' in the Server tab.\n\
+ message += "jobconfig.toml not found, falling back to legacy mode (using jobs.txt). To suppress this warning, generate a jobconfig.toml by running the verb 'Generate Job Configuration' in the Server tab.\n\
From there, you can then add it to the /config folder of your server to have it take effect for future rounds."
if(!fexists(file(config_txt)))
diff --git a/code/controllers/failsafe.dm b/code/controllers/failsafe.dm
index f6d03eb828d4c..e92e30079b878 100644
--- a/code/controllers/failsafe.dm
+++ b/code/controllers/failsafe.dm
@@ -16,7 +16,7 @@ GLOBAL_REAL(Failsafe, /datum/controller/failsafe)
// The alert level. For every failed poke, we drop a DEFCON level. Once we hit DEFCON 1, restart the MC.
var/defcon = 5
//the world.time of the last check, so the mc can restart US if we hang.
- // (Real friends look out for *eachother*)
+ // (Real friends look out for *each other*)
var/lasttick = 0
// Track the MC iteration to make sure its still on track.
diff --git a/code/controllers/master.dm b/code/controllers/master.dm
index 109a82a697e47..c3f0478cedb96 100644
--- a/code/controllers/master.dm
+++ b/code/controllers/master.dm
@@ -78,6 +78,10 @@ GLOBAL_REAL(Master, /datum/controller/master)
/// Whether the Overview UI will update as fast as possible for viewers.
var/overview_fast_update = FALSE
+ /// Enables rolling usage averaging
+ var/use_rolling_usage = FALSE
+ /// How long to run our rolling usage averaging
+ var/rolling_usage_length = 5 SECONDS
/datum/controller/master/New()
if(!config)
@@ -151,12 +155,32 @@ ADMIN_VERB(cmd_controller_view_ui, R_SERVER|R_DEBUG, "Controller Overview", "Vie
if(isnull(ui))
ui = new /datum/tgui(user, src, "ControllerOverview")
ui.open()
+ use_rolling_usage = TRUE
+
+/datum/controller/master/ui_close(mob/user)
+ var/valid_found = FALSE
+ for(var/datum/tgui/open_ui as anything in open_uis)
+ if(open_ui.user == user)
+ continue
+ valid_found = TRUE
+ if(!valid_found)
+ use_rolling_usage = FALSE
+ return ..()
/datum/controller/master/ui_data(mob/user)
var/list/data = list()
var/list/subsystem_data = list()
for(var/datum/controller/subsystem/subsystem as anything in subsystems)
+ var/list/rolling_usage = subsystem.rolling_usage
+ subsystem.prune_rolling_usage()
+
+ // Then we sum
+ var/sum = 0
+ for(var/i in 2 to length(rolling_usage) step 2)
+ sum += rolling_usage[i]
+ var/average = sum / DS2TICKS(rolling_usage_length)
+
subsystem_data += list(list(
"name" = subsystem.name,
"ref" = REF(subsystem),
@@ -167,6 +191,7 @@ ADMIN_VERB(cmd_controller_view_ui, R_SERVER|R_DEBUG, "Controller Overview", "Vie
"doesnt_fire" = !!(subsystem.flags & SS_NO_FIRE),
"cost_ms" = subsystem.cost,
"tick_usage" = subsystem.tick_usage,
+ "usage_per_tick" = average,
"tick_overrun" = subsystem.tick_overrun,
"initialized" = subsystem.initialized,
"initialization_failure_message" = subsystem.initialization_failure_message,
@@ -175,6 +200,7 @@ ADMIN_VERB(cmd_controller_view_ui, R_SERVER|R_DEBUG, "Controller Overview", "Vie
data["world_time"] = world.time
data["map_cpu"] = world.map_cpu
data["fast_update"] = overview_fast_update
+ data["rolling_length"] = rolling_usage_length
return data
@@ -187,6 +213,13 @@ ADMIN_VERB(cmd_controller_view_ui, R_SERVER|R_DEBUG, "Controller Overview", "Vie
overview_fast_update = !overview_fast_update
return TRUE
+ if("set_rolling_length")
+ var/length = text2num(params["rolling_length"])
+ if(!length || length < 0)
+ return
+ rolling_usage_length = length SECONDS
+ return TRUE
+
if("view_variables")
var/datum/controller/subsystem/subsystem = locate(params["ref"]) in subsystems
if(isnull(subsystem))
@@ -542,7 +575,7 @@ ADMIN_VERB(cmd_controller_view_ui, R_SERVER|R_DEBUG, "Controller Overview", "Vie
//Anti-tick-contention heuristics:
if (init_stage == INITSTAGE_MAX)
- //if there are mutiple sleeping procs running before us hogging the cpu, we have to run later.
+ //if there are multiple sleeping procs running before us hogging the cpu, we have to run later.
// (because sleeps are processed in the order received, longer sleeps are more likely to run first)
if (starting_tick_usage > TICK_LIMIT_MC) //if there isn't enough time to bother doing anything this tick, sleep a bit.
sleep_delta *= 2
@@ -764,6 +797,12 @@ ADMIN_VERB(cmd_controller_view_ui, R_SERVER|R_DEBUG, "Controller Overview", "Vie
var/state = queue_node.ignite(queue_node_paused)
tick_usage = TICK_USAGE - tick_usage
+ if(use_rolling_usage)
+ queue_node.prune_rolling_usage()
+ // Rolling usage is an unrolled list that we know the order off
+ // OPTIMIZATION POSTING
+ queue_node.rolling_usage += list(DS2TICKS(world.time), tick_usage)
+
if(queue_node.profiler_focused)
world.Profile(PROFILE_STOP)
@@ -903,3 +942,4 @@ ADMIN_VERB(cmd_controller_view_ui, R_SERVER|R_DEBUG, "Controller Overview", "Vie
return FALSE
last_profiled = REALTIMEOFDAY
SSprofiler.DumpFile(allow_yield = FALSE)
+
diff --git a/code/controllers/subsystem.dm b/code/controllers/subsystem.dm
index c9a2f07c4ee83..4bde26e3c9d10 100644
--- a/code/controllers/subsystem.dm
+++ b/code/controllers/subsystem.dm
@@ -19,7 +19,7 @@
/// Time to wait (in deciseconds) between each call to fire(). Must be a positive integer.
var/wait = 20
- /// Priority Weight: When mutiple subsystems need to run in the same tick, higher priority subsystems will be given a higher share of the tick before MC_TICK_CHECK triggers a sleep, higher priority subsystems also run before lower priority subsystems
+ /// Priority Weight: When multiple subsystems need to run in the same tick, higher priority subsystems will be given a higher share of the tick before MC_TICK_CHECK triggers a sleep, higher priority subsystems also run before lower priority subsystems
var/priority = FIRE_PRIORITY_DEFAULT
/// [Subsystem Flags][SS_NO_INIT] to control binary behavior. Flags must be set at compile time or before preinit finishes to take full effect. (You can also restart the mc to force them to process again)
@@ -63,6 +63,9 @@
/// Running average of the amount of tick usage (in percents of a game tick) the subsystem has spent past its allocated time without pausing
var/tick_overrun = 0
+ /// Flat list of usage and time, every odd index is a log time, every even index is a usage
+ var/list/rolling_usage = list()
+
/// How much of a tick (in percents of a tick) were we allocated last fire.
var/tick_allocation_last = 0
@@ -269,7 +272,7 @@
/datum/controller/subsystem/proc/OnConfigLoad()
/**
- * Used to initialize the subsystem. This is expected to be overriden by subtypes.
+ * Used to initialize the subsystem. This is expected to be overridden by subtypes.
*/
/datum/controller/subsystem/Initialize()
return SS_INIT_NONE
@@ -299,6 +302,15 @@
if (can_fire && cycles >= 1)
postponed_fires += cycles
+/// Prunes out of date entries in our rolling usage list
+/datum/controller/subsystem/proc/prune_rolling_usage()
+ var/list/rolling_usage = src.rolling_usage
+ var/cut_to = 0
+ while(cut_to + 2 <= length(rolling_usage) && rolling_usage[cut_to + 1] < DS2TICKS(world.time - Master.rolling_usage_length))
+ cut_to += 2
+ if(cut_to)
+ rolling_usage.Cut(1, cut_to + 1)
+
//usually called via datum/controller/subsystem/New() when replacing a subsystem (i.e. due to a recurring crash)
//should attempt to salvage what it can from the old instance of subsystem
/datum/controller/subsystem/Recover()
diff --git a/code/controllers/subsystem/ai_controllers.dm b/code/controllers/subsystem/ai_controllers.dm
index a6badb44a3f0e..30d3c4986f2a2 100644
--- a/code/controllers/subsystem/ai_controllers.dm
+++ b/code/controllers/subsystem/ai_controllers.dm
@@ -6,40 +6,23 @@ SUBSYSTEM_DEF(ai_controllers)
init_order = INIT_ORDER_AI_CONTROLLERS
wait = 0.5 SECONDS //Plan every half second if required, not great not terrible.
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
-
- ///List of all ai_subtree singletons, key is the typepath while assigned value is a newly created instance of the typepath. See setup_subtrees()
- var/list/datum/ai_planning_subtree/ai_subtrees = list()
- ///Assoc List of all AI statuses and all AI controllers with that status.
- var/list/ai_controllers_by_status = list(
- AI_STATUS_ON = list(),
- AI_STATUS_OFF = list(),
- AI_STATUS_IDLE = list(),
- )
- ///Assoc List of all AI controllers and the Z level they are on, which we check when someone enters/leaves a Z level to turn them on/off.
- var/list/ai_controllers_by_zlevel = list()
+ ///type of status we are interested in running
+ var/planning_status = AI_STATUS_ON
/// The tick cost of all active AI, calculated on fire.
- var/cost_on
- /// The tick cost of all idle AI, calculated on fire.
- var/cost_idle
-
+ var/our_cost
/datum/controller/subsystem/ai_controllers/Initialize()
setup_subtrees()
return SS_INIT_SUCCESS
/datum/controller/subsystem/ai_controllers/stat_entry(msg)
- var/list/active_list = ai_controllers_by_status[AI_STATUS_ON]
- var/list/inactive_list = ai_controllers_by_status[AI_STATUS_OFF]
- var/list/idle_list = ai_controllers_by_status[AI_STATUS_IDLE]
- msg = "Active AIs:[length(active_list)]/[round(cost_on,1)]%|Inactive:[length(inactive_list)]|Idle:[length(idle_list)]/[round(cost_idle,1)]%"
+ var/list/planning_list = GLOB.ai_controllers_by_status[planning_status]
+ msg = "Planning AIs:[length(planning_list)]/[round(our_cost,1)]%"
return ..()
/datum/controller/subsystem/ai_controllers/fire(resumed)
var/timer = TICK_USAGE_REAL
- cost_idle = MC_AVERAGE(cost_idle, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
-
- timer = TICK_USAGE_REAL
- for(var/datum/ai_controller/ai_controller as anything in ai_controllers_by_status[AI_STATUS_ON])
+ for(var/datum/ai_controller/ai_controller as anything in GLOB.ai_controllers_by_status[planning_status])
if(!COOLDOWN_FINISHED(ai_controller, failed_planning_cooldown))
continue
@@ -49,18 +32,20 @@ SUBSYSTEM_DEF(ai_controllers)
if(!LAZYLEN(ai_controller.current_behaviors)) //Still no plan
COOLDOWN_START(ai_controller, failed_planning_cooldown, AI_FAILED_PLANNING_COOLDOWN)
- cost_on = MC_AVERAGE(cost_on, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
+ our_cost = MC_AVERAGE(our_cost, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
///Creates all instances of ai_subtrees and assigns them to the ai_subtrees list.
/datum/controller/subsystem/ai_controllers/proc/setup_subtrees()
+ if(length(GLOB.ai_subtrees))
+ return
for(var/subtree_type in subtypesof(/datum/ai_planning_subtree))
var/datum/ai_planning_subtree/subtree = new subtree_type
- ai_subtrees[subtree_type] = subtree
+ GLOB.ai_subtrees[subtree_type] = subtree
///Called when the max Z level was changed, updating our coverage.
/datum/controller/subsystem/ai_controllers/proc/on_max_z_changed()
- if (!islist(ai_controllers_by_zlevel))
- ai_controllers_by_zlevel = new /list(world.maxz,0)
- while (SSai_controllers.ai_controllers_by_zlevel.len < world.maxz)
- SSai_controllers.ai_controllers_by_zlevel.len++
- SSai_controllers.ai_controllers_by_zlevel[ai_controllers_by_zlevel.len] = list()
+ if(!length(GLOB.ai_controllers_by_zlevel))
+ GLOB.ai_controllers_by_zlevel = new /list(world.maxz,0)
+ while (GLOB.ai_controllers_by_zlevel.len < world.maxz)
+ GLOB.ai_controllers_by_zlevel.len++
+ GLOB.ai_controllers_by_zlevel[GLOB.ai_controllers_by_zlevel.len] = list()
diff --git a/code/controllers/subsystem/ai_idle_controllers.dm b/code/controllers/subsystem/ai_idle_controllers.dm
new file mode 100644
index 0000000000000..367a2c82ffc95
--- /dev/null
+++ b/code/controllers/subsystem/ai_idle_controllers.dm
@@ -0,0 +1,8 @@
+AI_CONTROLLER_SUBSYSTEM_DEF(ai_idle_controllers)
+ name = "AI Idle Controllers"
+ flags = SS_POST_FIRE_TIMING | SS_BACKGROUND
+ priority = FIRE_PRIORITY_IDLE_NPC
+ init_order = INIT_ORDER_AI_IDLE_CONTROLLERS
+ wait = 5 SECONDS
+ runlevels = RUNLEVEL_GAME
+ planning_status = AI_STATUS_IDLE
diff --git a/code/controllers/subsystem/air.dm b/code/controllers/subsystem/air.dm
index 1cb3e2dec3783..4557e153db190 100644
--- a/code/controllers/subsystem/air.dm
+++ b/code/controllers/subsystem/air.dm
@@ -559,7 +559,7 @@ SUBSYSTEM_DEF(air)
// If it's already been processed, then it's already talked to us
if(enemy_tile.current_cycle == -INFINITE)
continue
- // .air instead of .return_air() because we can guarentee that the proc won't do anything
+ // .air instead of .return_air() because we can guarantee that the proc won't do anything
if(potential_diff.air.compare(enemy_tile.air))
//testing("Active turf found. Return value of compare(): [T.air.compare(enemy_tile.air)]")
if(!potential_diff.excited)
@@ -707,7 +707,7 @@ SUBSYSTEM_DEF(air)
CHECK_TICK
//this can't be done with setup_atmos_machinery() because
-// all atmos machinery has to initalize before the first
+// all atmos machinery has to initialize before the first
// pipenet can be built.
/datum/controller/subsystem/air/proc/setup_pipenets()
for (var/obj/machinery/atmospherics/AM in atmos_machinery)
diff --git a/code/controllers/subsystem/ambience.dm b/code/controllers/subsystem/ambience.dm
index cae5d85246d80..7258b0b16e948 100644
--- a/code/controllers/subsystem/ambience.dm
+++ b/code/controllers/subsystem/ambience.dm
@@ -124,7 +124,7 @@ SUBSYSTEM_DEF(ambience)
client.current_ambient_sound = null
return
- //Station ambience is dependant on a functioning and charged APC with enviorment power enabled.
+ //Station ambience is dependent on a functioning and charged APC with environment power enabled.
if(!is_mining_level(my_area.z) && ((!my_area.apc || !my_area.apc.operating || !my_area.apc.cell?.charge && my_area.requires_power || !my_area.power_environ)))
SEND_SOUND(src, sound(null, repeat = 0, wait = 0, channel = CHANNEL_BUZZ))
client.current_ambient_sound = null
diff --git a/code/controllers/subsystem/atoms.dm b/code/controllers/subsystem/atoms.dm
index 71eaed14ea23f..20d5a093be6da 100644
--- a/code/controllers/subsystem/atoms.dm
+++ b/code/controllers/subsystem/atoms.dm
@@ -75,7 +75,7 @@ SUBSYSTEM_DEF(atoms)
rustg_file_write(json_encode(mapload_init_times), "[GLOB.log_directory]/init_times.json")
#endif
-/// Actually creates the list of atoms. Exists soley so a runtime in the creation logic doesn't cause initalized to totally break
+/// Actually creates the list of atoms. Exists solely so a runtime in the creation logic doesn't cause initialized to totally break
/datum/controller/subsystem/atoms/proc/CreateAtoms(list/atoms, list/atoms_to_return = null, mapload_source = null)
if (atoms_to_return)
LAZYINITLIST(created_atoms)
@@ -137,8 +137,8 @@ SUBSYSTEM_DEF(atoms)
return null
return initialized_state[state_length][1]
-/// Use this to set initialized to prevent error states where the old initialized is overriden, and we end up losing all context
-/// Accepts a state and a source, the most recent state is used, sources exist to prevent overriding old values accidentially
+/// Use this to set initialized to prevent error states where the old initialized is overridden, and we end up losing all context
+/// Accepts a state and a source, the most recent state is used, sources exist to prevent overriding old values accidentally
/datum/controller/subsystem/atoms/proc/set_tracked_initalized(state, source)
if(!length(initialized_state))
base_initialized = initialized
diff --git a/code/controllers/subsystem/blackbox.dm b/code/controllers/subsystem/blackbox.dm
index 3ea1a9a40d88f..18ba37eb13785 100644
--- a/code/controllers/subsystem/blackbox.dm
+++ b/code/controllers/subsystem/blackbox.dm
@@ -152,6 +152,8 @@ SUBSYSTEM_DEF(blackbox)
record_feedback("tally", "radio_usage", 1, "centcom")
if(FREQ_AI_PRIVATE)
record_feedback("tally", "radio_usage", 1, "ai private")
+ if(FREQ_ENTERTAINMENT)
+ record_feedback("tally", "radio_usage", 1, "entertainment")
if(FREQ_CTF_RED)
record_feedback("tally", "radio_usage", 1, "CTF red team")
if(FREQ_CTF_BLUE)
diff --git a/code/controllers/subsystem/dynamic/dynamic.dm b/code/controllers/subsystem/dynamic/dynamic.dm
index a45644813afc4..56fcaac27fcb2 100644
--- a/code/controllers/subsystem/dynamic/dynamic.dm
+++ b/code/controllers/subsystem/dynamic/dynamic.dm
@@ -140,10 +140,10 @@ SUBSYSTEM_DEF(dynamic)
/// The maximum amount of time for antag random events to be hijacked.
var/random_event_hijack_maximum = 18 MINUTES
- /// What is the lower bound of when the roundstart annoucement is sent out?
+ /// What is the lower bound of when the roundstart announcement is sent out?
var/waittime_l = 600
- /// What is the higher bound of when the roundstart annoucement is sent out?
+ /// What is the higher bound of when the roundstart announcement is sent out?
var/waittime_h = 1800
/// A number between 0 and 100. The maximum amount of threat allowed to generate.
diff --git a/code/controllers/subsystem/dynamic/dynamic_rulesets_latejoin.dm b/code/controllers/subsystem/dynamic/dynamic_rulesets_latejoin.dm
index d853876fed143..b204b62e965aa 100644
--- a/code/controllers/subsystem/dynamic/dynamic_rulesets_latejoin.dm
+++ b/code/controllers/subsystem/dynamic/dynamic_rulesets_latejoin.dm
@@ -167,7 +167,7 @@
/// Checks for revhead loss conditions and other antag datums.
/datum/dynamic_ruleset/latejoin/provocateur/proc/check_eligible(datum/mind/M)
var/turf/T = get_turf(M.current)
- if(!considered_afk(M) && considered_alive(M) && is_station_level(T.z) && !M.antag_datums?.len && !HAS_TRAIT(M, TRAIT_MINDSHIELD))
+ if(!considered_afk(M) && considered_alive(M) && is_station_level(T.z) && !M.antag_datums?.len && !HAS_MIND_TRAIT(M.current, TRAIT_UNCONVERTABLE))
return TRUE
return FALSE
diff --git a/code/controllers/subsystem/dynamic/dynamic_rulesets_midround.dm b/code/controllers/subsystem/dynamic/dynamic_rulesets_midround.dm
index 9396728159480..3476702e741ed 100644
--- a/code/controllers/subsystem/dynamic/dynamic_rulesets_midround.dm
+++ b/code/controllers/subsystem/dynamic/dynamic_rulesets_midround.dm
@@ -349,6 +349,7 @@
requirements = REQUIREMENTS_VERY_HIGH_THREAT_NEEDED
flags = HIGH_IMPACT_RULESET
ruleset_lazy_templates = list(LAZY_TEMPLATE_KEY_WIZARDDEN)
+ signup_item_path = /obj/item/clothing/head/wizard
/datum/dynamic_ruleset/midround/from_ghosts/wizard/ready(forced = FALSE)
if(!check_candidates())
@@ -388,6 +389,7 @@
requirements = REQUIREMENTS_VERY_HIGH_THREAT_NEEDED
ruleset_lazy_templates = list(LAZY_TEMPLATE_KEY_NUKIEBASE)
flags = HIGH_IMPACT_RULESET
+ signup_item_path = /obj/machinery/nuclearbomb
var/list/operative_cap = list(2,2,3,3,4,5,5,5,5,5)
@@ -433,6 +435,7 @@
cost = 8
minimum_players = 25
repeatable = TRUE
+ signup_item_path = /obj/structure/blob/normal
/datum/dynamic_ruleset/midround/from_ghosts/blob/generate_ruleset_body(mob/applicant)
var/body = applicant.become_overmind()
@@ -506,6 +509,7 @@
cost = 10
minimum_players = 25
repeatable = TRUE
+ signup_item_path = /mob/living/basic/alien
var/list/vents = list()
/datum/dynamic_ruleset/midround/from_ghosts/xenomorph/forget_startup()
@@ -554,6 +558,7 @@
cost = 5
minimum_players = 15
repeatable = TRUE
+ signup_item_path = /obj/item/light_eater
/datum/dynamic_ruleset/midround/from_ghosts/nightmare/acceptable(population = 0, threat_level = 0)
var/turf/spawn_loc = find_maintenance_spawn(atmos_sensitive = TRUE, require_darkness = TRUE) //Checks if there's a single safe, dark tile on station.
@@ -590,6 +595,7 @@
cost = 7
minimum_players = 25
repeatable = TRUE
+ signup_item_path = /mob/living/basic/space_dragon
var/list/spawn_locs = list()
/datum/dynamic_ruleset/midround/from_ghosts/space_dragon/forget_startup()
@@ -669,6 +675,7 @@
minimum_players = 30
repeatable = TRUE
ruleset_lazy_templates = list(LAZY_TEMPLATE_KEY_NINJA_HOLDING_FACILITY) // I mean, no one uses the nets anymore but whateva
+ signup_item_path = /obj/item/energy_katana
var/list/spawn_locs = list()
@@ -728,6 +735,7 @@
cost = 5
minimum_players = 15
repeatable = TRUE
+ signup_item_path = /mob/living/basic/revenant
var/dead_mobs_required = 20
var/need_extra_spawns_value = 15
var/list/spawn_locs = list()
@@ -870,6 +878,7 @@
cost = 7
minimum_players = 15
repeatable = TRUE
+ signup_item_path = /obj/effect/meteor/meaty/changeling
/datum/dynamic_ruleset/midround/from_ghosts/changeling_midround/generate_ruleset_body(mob/applicant)
var/body = generate_changeling_meteor(applicant)
diff --git a/code/controllers/subsystem/dynamic/dynamic_rulesets_roundstart.dm b/code/controllers/subsystem/dynamic/dynamic_rulesets_roundstart.dm
index 72554a108e328..999cd156b18d8 100644
--- a/code/controllers/subsystem/dynamic/dynamic_rulesets_roundstart.dm
+++ b/code/controllers/subsystem/dynamic/dynamic_rulesets_roundstart.dm
@@ -574,7 +574,7 @@ GLOBAL_VAR_INIT(revolutionary_win, FALSE)
/// Checks for revhead loss conditions and other antag datums.
/datum/dynamic_ruleset/roundstart/revs/proc/check_eligible(datum/mind/M)
var/turf/T = get_turf(M.current)
- if(!considered_afk(M) && considered_alive(M) && is_station_level(T.z) && !M.antag_datums?.len && !HAS_TRAIT(M, TRAIT_MINDSHIELD))
+ if(!considered_afk(M) && considered_alive(M) && is_station_level(T.z) && !M.antag_datums?.len && !HAS_MIND_TRAIT(M.current, TRAIT_UNCONVERTABLE))
return TRUE
return FALSE
diff --git a/code/controllers/subsystem/events.dm b/code/controllers/subsystem/events.dm
index 897bf0c4549ba..38fbdaa793bbb 100644
--- a/code/controllers/subsystem/events.dm
+++ b/code/controllers/subsystem/events.dm
@@ -8,7 +8,7 @@ SUBSYSTEM_DEF(events)
var/list/running = list()
///cache of currently running events, for lag checking.
var/list/currentrun = list()
- ///The next world.time that a naturally occuring random event can be selected.
+ ///The next world.time that a naturally occurring random event can be selected.
var/scheduled = 0
///The lower bound for how soon another random event can be scheduled.
var/frequency_lower = 2.5 MINUTES
diff --git a/code/controllers/subsystem/id_access.dm b/code/controllers/subsystem/id_access.dm
index 38bf3b568a1f9..b80e5718128bd 100644
--- a/code/controllers/subsystem/id_access.dm
+++ b/code/controllers/subsystem/id_access.dm
@@ -291,7 +291,7 @@ SUBSYSTEM_DEF(id_access)
desc_by_access["[ACCESS_VIROLOGY]"] = "Virology"
desc_by_access["[ACCESS_PSYCHOLOGY]"] = "Psychology"
desc_by_access["[ACCESS_CMO]"] = "CMO Office"
- desc_by_access["[ACCESS_QM]"] = "Quartermaster"
+ desc_by_access["[ACCESS_QM]"] = "QM Office"
desc_by_access["[ACCESS_SURGERY]"] = "Surgery"
desc_by_access["[ACCESS_THEATRE]"] = "Theatre"
desc_by_access["[ACCESS_RESEARCH]"] = "Science"
@@ -398,6 +398,8 @@ SUBSYSTEM_DEF(id_access)
id_card.clear_access()
id_card.trim = trim
+ id_card.big_pointer = trim.big_pointer
+ id_card.pointer_color = trim.pointer_color
if(copy_access)
id_card.access = trim.access.Copy()
@@ -441,6 +443,8 @@ SUBSYSTEM_DEF(id_access)
id_card.department_color_override = trim.department_color
id_card.department_state_override = trim.department_state
id_card.subdepartment_color_override = trim.subdepartment_color
+ id_card.big_pointer = trim.big_pointer
+ id_card.pointer_color = trim.pointer_color
if(!check_forged || !id_card.forged)
id_card.assignment = trim.assignment
@@ -461,6 +465,8 @@ SUBSYSTEM_DEF(id_access)
id_card.department_color_override = null
id_card.department_state_override = null
id_card.subdepartment_color_override = null
+ id_card.big_pointer = id_card.trim.big_pointer
+ id_card.pointer_color = id_card.trim.pointer_color
/**
* Adds the accesses associated with a trim to an ID card.
diff --git a/code/controllers/subsystem/input.dm b/code/controllers/subsystem/input.dm
index 65dc1e31a1e42..e4e12418a7576 100644
--- a/code/controllers/subsystem/input.dm
+++ b/code/controllers/subsystem/input.dm
@@ -19,7 +19,7 @@ VERB_MANAGER_SUBSYSTEM_DEF(input)
///running average of how many movement iterations from player input the server processes every second. used for the subsystem stat entry
var/movements_per_second = 0
///running average of the amount of real time clicks take to truly execute after the command is originally sent to the server.
- ///if a click isnt delayed at all then it counts as 0 deciseconds.
+ ///if a click isn't delayed at all then it counts as 0 deciseconds.
var/average_click_delay = 0
/datum/controller/subsystem/verb_manager/input/Initialize()
@@ -31,7 +31,7 @@ VERB_MANAGER_SUBSYSTEM_DEF(input)
return SS_INIT_SUCCESS
-// This is for when macro sets are eventualy datumized
+// This is for when macro sets are eventually datumized
/datum/controller/subsystem/verb_manager/input/proc/setup_default_macro_sets()
macro_set = list(
"Any" = "\"KeyDown \[\[*\]\]\"",
@@ -75,7 +75,7 @@ VERB_MANAGER_SUBSYSTEM_DEF(input)
movements_per_second = MC_AVG_SECONDS(movements_per_second, moves_this_run, wait TICKS)
/datum/controller/subsystem/verb_manager/input/run_verb_queue()
- var/deferred_clicks_this_run = 0 //acts like current_clicks but doesnt count clicks that dont get processed by SSinput
+ var/deferred_clicks_this_run = 0 //acts like current_clicks but doesn't count clicks that don't get processed by SSinput
for(var/datum/callback/verb_callback/queued_click as anything in verb_queue)
if(!istype(queued_click))
diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm
index 5c1a32d099c1e..8dce11f137746 100644
--- a/code/controllers/subsystem/mapping.dm
+++ b/code/controllers/subsystem/mapping.dm
@@ -184,17 +184,20 @@ SUBSYSTEM_DEF(mapping)
if(index)
lists_to_reserve.Cut(1, index)
return
- var/turf/T = packet[packetlen]
- T.empty(RESERVED_TURF_TYPE, RESERVED_TURF_TYPE, null, TRUE)
- LAZYINITLIST(unused_turfs["[T.z]"])
- unused_turfs["[T.z]"] |= T
- var/area/old_area = T.loc
- LISTASSERTLEN(old_area.turfs_to_uncontain_by_zlevel, T.z, list())
- old_area.turfs_to_uncontain_by_zlevel[T.z] += T
- T.turf_flags = UNUSED_RESERVATION_TURF
- world_contents += T
- LISTASSERTLEN(world_turf_contents_by_z, T.z, list())
- world_turf_contents_by_z[T.z] += T
+ var/turf/reserving_turf = packet[packetlen]
+ reserving_turf.empty(RESERVED_TURF_TYPE, RESERVED_TURF_TYPE, null, TRUE)
+ LAZYINITLIST(unused_turfs["[reserving_turf.z]"])
+ unused_turfs["[reserving_turf.z]"] |= reserving_turf
+ var/area/old_area = reserving_turf.loc
+ LISTASSERTLEN(old_area.turfs_to_uncontain_by_zlevel, reserving_turf.z, list())
+ old_area.turfs_to_uncontain_by_zlevel[reserving_turf.z] += reserving_turf
+ reserving_turf.turf_flags = UNUSED_RESERVATION_TURF
+ // reservation turfs are not allowed to interact with atmos at all
+ reserving_turf.blocks_air = TRUE
+
+ world_contents += reserving_turf
+ LISTASSERTLEN(world_turf_contents_by_z, reserving_turf.z, list())
+ world_turf_contents_by_z[reserving_turf.z] += reserving_turf
packet.len--
packetlen = length(packet)
@@ -739,6 +742,7 @@ ADMIN_VERB(load_away_mission, R_FUN, "Load Away Mission", "Load a specific away
for(var/turf/T as anything in block)
// No need to empty() these, because they just got created and are already /turf/open/space/basic.
T.turf_flags = UNUSED_RESERVATION_TURF
+ T.blocks_air = TRUE
CHECK_TICK
// Gotta create these suckers if we've not done so already
diff --git a/code/controllers/subsystem/materials.dm b/code/controllers/subsystem/materials.dm
index 3a704d01a82fd..f000688fbc71b 100644
--- a/code/controllers/subsystem/materials.dm
+++ b/code/controllers/subsystem/materials.dm
@@ -35,7 +35,7 @@ SUBSYSTEM_DEF(materials)
///A list of dimensional themes used by the dimensional anomaly and other things, most of which require materials to function.
var/list/datum/dimension_theme/dimensional_themes
-///Ran on initialize, populated the materials and materials_by_category dictionaries with their appropiate vars (See these variables for more info)
+///Ran on initialize, populated the materials and materials_by_category dictionaries with their appropriate vars (See these variables for more info)
/datum/controller/subsystem/materials/proc/InitializeMaterials()
materials = list()
materials_by_type = list()
@@ -53,7 +53,7 @@ SUBSYSTEM_DEF(materials)
/** Creates and caches a material datum.
*
- * Arugments:
+ * Arguments:
* - [arguments][/list]: The arguments to use to create the material datum
* - The first element is the type of material to initialize.
*/
@@ -134,7 +134,7 @@ SUBSYSTEM_DEF(materials)
value = arguments[key]
if(!(istext(key) || isnum(key)))
key = REF(key)
- key = "[key]" // Key is stringified so numbers dont break things
+ key = "[key]" // Key is stringified so numbers don't break things
if(!isnull(value))
if(!(istext(value) || isnum(value)))
value = REF(value)
diff --git a/code/controllers/subsystem/modular_computers.dm b/code/controllers/subsystem/modular_computers.dm
index c8efa4aa4ee24..0a985fc055c47 100644
--- a/code/controllers/subsystem/modular_computers.dm
+++ b/code/controllers/subsystem/modular_computers.dm
@@ -1,4 +1,4 @@
-s///The maximum amount of logs that can be generated before they start overwriting eachother.
+s///The maximum amount of logs that can be generated before they start overwriting each other.
#define MAX_LOG_COUNT 300
SUBSYSTEM_DEF(modular_computers)
@@ -47,7 +47,7 @@ SUBSYSTEM_DEF(modular_computers)
var/static/list/discounts = list("0.10" = 7, "0.15" = 16, "0.20" = 20, "0.25" = 16, "0.50" = 8, "0.66" = 1)
var/static/list/flash_discounts = list("0.30" = 3, "0.40" = 8, "0.50" = 8, "0.66" = 2, "0.75" = 1)
- ///Eliminates non-alphanumeri characters, as well as the word "Single-Pack" or "Pack" or "Crate" from the coupon code
+ ///Eliminates non-alphanumeric characters, as well as the word "Single-Pack" or "Pack" or "Crate" from the coupon code
var/static/regex/strip_pack_name = regex("\[^a-zA-Z0-9]|(Single-)?Pack|Crate", "g")
var/datum/supply_pack/discounted_pack = pick(GLOB.discountable_packs[pick_weight(GLOB.pack_discount_odds)])
diff --git a/code/controllers/subsystem/overlays.dm b/code/controllers/subsystem/overlays.dm
index db94c291a18bd..fda892be7a432 100644
--- a/code/controllers/subsystem/overlays.dm
+++ b/code/controllers/subsystem/overlays.dm
@@ -17,7 +17,7 @@ SUBSYSTEM_DEF(overlays)
/// Don't have access to that type tho, so this is the best you're gonna get
/proc/overlays2text(list/overlays)
var/list/unique_overlays = list()
- // As anything because we're basically doing type coerrsion, rather then actually filtering for mutable apperances
+ // As anything because we're basically doing type coercion, rather then actually filtering for mutable appearances
for(var/mutable_appearance/overlay as anything in overlays)
var/key = "[overlay.icon]-[overlay.icon_state]-[overlay.dir]"
unique_overlays[key] += 1
diff --git a/code/controllers/subsystem/pathfinder.dm b/code/controllers/subsystem/pathfinder.dm
index fa1a7af5c8598..70dc152b06df2 100644
--- a/code/controllers/subsystem/pathfinder.dm
+++ b/code/controllers/subsystem/pathfinder.dm
@@ -158,7 +158,7 @@ SUBSYSTEM_DEF(pathfinder)
/// Takes a set of pathfind info, returns the first valid pathmap that would work if one exists
/// Optionally takes a max age to accept (defaults to 0 seconds) and a minimum acceptable range
-/// If include_building is true and we can only find a building path, ew'll use that instead. tho we will wait for it to finish first
+/// If include_building is true and we can only find a building path, we'll use that instead. tho we will wait for it to finish first
/datum/controller/subsystem/pathfinder/proc/get_valid_map(datum/can_pass_info/pass_info, turf/target, simulated_only = TRUE, turf/exclude, age = MAP_REUSE_INSTANT, min_range = -INFINITY, include_building = FALSE)
// Walk all the maps that match our caller's turf OR our target's
// Then hold onto em. If their cache time is short we can reuse/expand them, if not we'll have to make a new one
diff --git a/code/controllers/subsystem/persistence/_persistence.dm b/code/controllers/subsystem/persistence/_persistence.dm
index 36679fa1d2a02..6438015d11d38 100644
--- a/code/controllers/subsystem/persistence/_persistence.dm
+++ b/code/controllers/subsystem/persistence/_persistence.dm
@@ -43,13 +43,22 @@ SUBSYSTEM_DEF(persistence)
/// List of persistene ids which piggy banks.
var/list/queued_broken_piggy_ids
- var/list/broken_piggy_banks
-
var/rounds_since_engine_exploded = 0
var/delam_highscore = 0
var/tram_hits_this_round = 0
var/tram_hits_last_round = 0
+ /// A json database to data/message_bottles.json
+ var/datum/json_database/message_bottles_database
+ /// An index used to create unique ids for the message bottles database
+ var/message_bottles_index = 0
+ /**
+ * A list of non-maploaded photos or papers that met the 0.2% chance to be saved in the message bottles database
+ * because I don't want the database to feel empty unless there's someone constantly throwing bottles in the
+ * sea or beach/ocean fishing portals.
+ */
+ var/list/queued_message_bottles
+
/datum/controller/subsystem/persistence/Initialize()
load_poly()
load_wall_engravings()
@@ -74,11 +83,13 @@ SUBSYSTEM_DEF(persistence)
save_scars()
save_custom_outfits()
save_delamination_counter()
+ save_queued_message_bottles()
if(SStransport.can_fire)
for(var/datum/transport_controller/linear/tram/transport as anything in SStransport.transports_by_type[TRANSPORT_TYPE_TRAM])
save_tram_history(transport.specific_transport_id)
save_tram_counter()
+
///Loads up Poly's speech buffer.
/datum/controller/subsystem/persistence/proc/load_poly()
for(var/mob/living/basic/parrot/poly/bird in GLOB.alive_mob_list)
diff --git a/code/controllers/subsystem/persistence/message_bottles.dm b/code/controllers/subsystem/persistence/message_bottles.dm
new file mode 100644
index 0000000000000..ce1efe5e59c5e
--- /dev/null
+++ b/code/controllers/subsystem/persistence/message_bottles.dm
@@ -0,0 +1,54 @@
+///This proc is used to save photos, papers and cash stored inside a bottle when tossed into the ocean.
+/datum/controller/subsystem/persistence/proc/save_message_bottle(obj/item/message, bottle_type = /obj/item/reagent_containers/cup/glass/bottle)
+ if(isnull(message_bottles_database))
+ message_bottles_database = new("data/message_bottles.json")
+
+ var/list/data = list()
+ data["bottle_type"] = text2path(bottle_type)
+ if(istype(message, /obj/item/paper))
+ var/obj/item/paper/paper = message
+ if(!length(paper.raw_text_inputs) && !length(paper.raw_stamp_data) && !length(paper.raw_field_input_data))
+ return
+ data["paper"] = paper.convert_to_data()
+ else if(istype(message, /obj/item/photo))
+ var/obj/item/photo/photo = message
+ if(!photo.picture?.id)
+ return
+ data["photo_id"] = photo.picture.id
+ else if(istype(message, /obj/item/stack/spacecash))
+ var/obj/item/stack/spacecash/cash = message
+ data["cash"] = text2path(cash.type)
+ data["amount"] = cash.amount
+ message_bottles_index++
+ message_bottles_database.set_key("message-[GLOB.round_id]-[message_bottles_index]", data)
+
+/datum/controller/subsystem/persistence/proc/load_message_bottle(atom/loc)
+ if(isnull(message_bottles_database))
+ message_bottles_database = new("data/message_bottles.json")
+
+ var/list/data = message_bottles_database.pick_and_take_key()
+ if(!data)
+ var/obj/item/reagent_containers/cup/glass/bottle/bottle = new(loc)
+ return bottle
+
+ var/bottle_type = text2path(data["bottle_type"]) || /obj/item/reagent_containers/cup/glass/bottle
+ var/obj/item/reagent_containers/cup/glass/bottle/bottle = new bottle_type(loc)
+ bottle.reagents.remove_all(bottle.reagents.maximum_volume)
+ if(data["photo_id"])
+ var/obj/item/photo/old/photo = load_photo_from_disk(data["photo_id"], bottle)
+ bottle.message_in_a_bottle = photo
+ else if(data["cash"])
+ var/cash_type = text2path(data["cash"]) || /obj/item/stack/spacecash/c10
+ var/obj/item/stack/spacecash/cash = new cash_type(bottle, data["amount"])
+ bottle.message_in_a_bottle = cash
+ else if(data["paper"])
+ var/obj/item/paper/paper = new(bottle)
+ paper.write_from_data(data["paper"])
+ bottle.message_in_a_bottle = paper
+
+ bottle.update_icon(UPDATE_OVERLAYS)
+
+/datum/controller/subsystem/persistence/proc/save_queued_message_bottles()
+ for(var/item in queued_message_bottles)
+ save_message_bottle(item)
+ queued_message_bottles = null
diff --git a/code/controllers/subsystem/polling.dm b/code/controllers/subsystem/polling.dm
index fa219cd3da9f0..6cdcfbfd45949 100644
--- a/code/controllers/subsystem/polling.dm
+++ b/code/controllers/subsystem/polling.dm
@@ -130,10 +130,9 @@ SUBSYSTEM_DEF(polling)
// Image to display
var/image/poll_image
- if(ispath(alert_pic, /atom))
- poll_image = image(alert_pic)
- else if(isatom(alert_pic))
+ if(ispath(alert_pic, /atom) || isatom(alert_pic))
poll_image = new /mutable_appearance(alert_pic)
+ poll_image.pixel_z = 0
else if(!isnull(alert_pic))
poll_image = alert_pic
else
@@ -176,6 +175,8 @@ SUBSYSTEM_DEF(polling)
UNTIL(new_poll.finished)
if(!(amount_to_pick > 0))
return new_poll.signed_up
+ if(length(new_poll.signed_up) < amount_to_pick)
+ return new_poll.signed_up
for(var/pick in 1 to amount_to_pick)
new_poll.chosen_candidates += pick_n_take(new_poll.signed_up)
if(announce_chosen)
diff --git a/code/controllers/subsystem/processing/ai_idle_behaviors.dm b/code/controllers/subsystem/processing/ai_idle_behaviors.dm
new file mode 100644
index 0000000000000..cda3d354882f4
--- /dev/null
+++ b/code/controllers/subsystem/processing/ai_idle_behaviors.dm
@@ -0,0 +1,6 @@
+PROCESSING_SUBSYSTEM_DEF(idle_ai_behaviors)
+ name = "idle_ai_behaviors"
+ flags = SS_NO_INIT | SS_BACKGROUND
+ wait = 1.5 SECONDS
+ priority = FIRE_PRIORITY_IDLE_NPC
+ init_order = INIT_ORDER_AI_IDLE_CONTROLLERS //must execute only after ai behaviors are initialized
diff --git a/code/controllers/subsystem/processing/fishing.dm b/code/controllers/subsystem/processing/fishing.dm
index da10d3d631aef..ca54141de82a8 100644
--- a/code/controllers/subsystem/processing/fishing.dm
+++ b/code/controllers/subsystem/processing/fishing.dm
@@ -1,7 +1,4 @@
-/**
- * So far, only used by the fishing minigame. Feel free to rename it to something like veryfastprocess
- * if you need one that fires 10 times a second
- */
+/// subsystem for the fishing minigame processing.
PROCESSING_SUBSYSTEM_DEF(fishing)
name = "Fishing"
- wait = 0.1 SECONDS
+ wait = 0.05 SECONDS // If you raise it to 0.1 SECONDS, you better also modify [datum/fish_movement/move_fish()]
diff --git a/code/controllers/subsystem/shuttle.dm b/code/controllers/subsystem/shuttle.dm
index f8ee167befbf8..11a055d292ce2 100644
--- a/code/controllers/subsystem/shuttle.dm
+++ b/code/controllers/subsystem/shuttle.dm
@@ -1036,7 +1036,7 @@ SUBSYSTEM_DEF(shuttle)
return data
-/datum/controller/subsystem/shuttle/ui_act(action, params)
+/datum/controller/subsystem/shuttle/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/controllers/subsystem/sprite_accessories.dm b/code/controllers/subsystem/sprite_accessories.dm
index 21bafd5330c97..c59e8d89a0e1f 100644
--- a/code/controllers/subsystem/sprite_accessories.dm
+++ b/code/controllers/subsystem/sprite_accessories.dm
@@ -40,7 +40,6 @@ SUBSYSTEM_DEF(accessories) // just 'accessories' for brevity
var/list/horns_list
var/list/frills_list
var/list/spines_list
- var/list/legs_list
var/list/tail_spines_list
//Mutant Human bits
@@ -99,14 +98,13 @@ SUBSYSTEM_DEF(accessories) // just 'accessories' for brevity
frills_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/frills, add_blank = TRUE)[DEFAULT_SPRITE_LIST]
spines_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/spines, add_blank = TRUE)[DEFAULT_SPRITE_LIST]
tail_spines_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/tail_spines, add_blank = TRUE)[DEFAULT_SPRITE_LIST]
- legs_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/legs)[DEFAULT_SPRITE_LIST]
caps_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/caps)[DEFAULT_SPRITE_LIST]
moth_wings_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/moth_wings)[DEFAULT_SPRITE_LIST]
moth_antennae_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/moth_antennae)[DEFAULT_SPRITE_LIST]
moth_markings_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/moth_markings, add_blank = TRUE)[DEFAULT_SPRITE_LIST]
pod_hair_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/pod_hair)[DEFAULT_SPRITE_LIST]
-/// This proc just intializes all /datum/sprite_accessory/hair_gradient into an list indexed by gradient-style name
+/// This proc just initializes all /datum/sprite_accessory/hair_gradient into an list indexed by gradient-style name
/datum/controller/subsystem/accessories/proc/init_hair_gradients()
hair_gradients_list = list()
facial_hair_gradients_list = list()
diff --git a/code/controllers/subsystem/time_track.dm b/code/controllers/subsystem/time_track.dm
index aaaf5520e0fc3..b3a4fe7e8698f 100644
--- a/code/controllers/subsystem/time_track.dm
+++ b/code/controllers/subsystem/time_track.dm
@@ -108,7 +108,7 @@ SUBSYSTEM_DEF(time_track)
text2file(sendmaps_json,"bad_sendmaps.json")
can_fire = FALSE
return
- var/send_maps_sort = send_maps_data.Copy() //Doing it like this guarentees us a properly sorted list
+ var/send_maps_sort = send_maps_data.Copy() //Doing it like this guarantees us a properly sorted list
for(var/list/packet in send_maps_data)
send_maps_sort[packet["name"]] = packet
diff --git a/code/controllers/subsystem/timer.dm b/code/controllers/subsystem/timer.dm
index 8ecb0c9dc6a56..c314fa7d38ba7 100644
--- a/code/controllers/subsystem/timer.dm
+++ b/code/controllers/subsystem/timer.dm
@@ -524,7 +524,7 @@ SUBSYSTEM_DEF(timer)
2 = timeToRun,
3 = wait,
4 = flags,
- 5 = callBack, /* Safe to hold this directly becasue it's never del'd */
+ 5 = callBack, /* Safe to hold this directly because it's never del'd */
6 = "[callBack.object]",
7 = text_ref(callBack.object),
8 = getcallingtype(),
@@ -539,7 +539,7 @@ SUBSYSTEM_DEF(timer)
2 = timeToRun,
3 = wait,
4 = flags,
- 5 = callBack, /* Safe to hold this directly becasue it's never del'd */
+ 5 = callBack, /* Safe to hold this directly because it's never del'd */
6 = "[callBack.object]",
7 = getcallingtype(),
8 = callBack.delegate,
diff --git a/code/controllers/subsystem/title.dm b/code/controllers/subsystem/title.dm
index 1f40dd921dddf..dbaa7ddeb48c0 100644
--- a/code/controllers/subsystem/title.dm
+++ b/code/controllers/subsystem/title.dm
@@ -60,7 +60,7 @@ SUBSYSTEM_DEF(title)
for(var/thing in GLOB.clients)
if(!thing)
continue
- var/atom/movable/screen/splash/S = new(thing, FALSE)
+ var/atom/movable/screen/splash/S = new(null, thing, FALSE)
S.Fade(FALSE,FALSE)
/datum/controller/subsystem/title/Recover()
diff --git a/code/controllers/subsystem/verb_manager.dm b/code/controllers/subsystem/verb_manager.dm
index 337386cff8e0b..f09c050964154 100644
--- a/code/controllers/subsystem/verb_manager.dm
+++ b/code/controllers/subsystem/verb_manager.dm
@@ -8,15 +8,15 @@
* plus TICK_BYOND_RESERVE from the tick and uses up to that amount of time (minus the percentage of the tick used by the time it executes subsystems)
* on subsystems running cool things like atmospherics or Life or SSInput or whatever.
*
- * Without this subsystem, verbs are likely to cause overtime if the MC uses all of the time it has alloted for itself in the tick, and SendMaps
+ * Without this subsystem, verbs are likely to cause overtime if the MC uses all of the time it has allotted for itself in the tick, and SendMaps
* uses as much as its expected to, and an expensive verb ends up executing that tick. This is because the MC is completely blind to the cost of
* verbs, it can't account for it at all. The only chance for verbs to not cause overtime in a tick where the MC used as much of the tick
- * as it alloted itself and where SendMaps costed as much as it was expected to is if the verb(s) take less than TICK_BYOND_RESERVE percent of
- * the tick, which isnt much. Not to mention if SendMaps takes more than 30% of the tick and the MC forces itself to take at least 70% of the
+ * as it allotted itself and where SendMaps costed as much as it was expected to is if the verb(s) take less than TICK_BYOND_RESERVE percent of
+ * the tick, which isn't much. Not to mention if SendMaps takes more than 30% of the tick and the MC forces itself to take at least 70% of the
* normal tick duration which causes ticks to naturally overrun even in the absence of verbs.
*
* With this subsystem, the MC can account for the cost of verbs and thus stop major overruns of ticks. This means that the most important subsystems
- * like SSinput can start at the same time they were supposed to, leading to a smoother experience for the player since ticks arent riddled with
+ * like SSinput can start at the same time they were supposed to, leading to a smoother experience for the player since ticks aren't riddled with
* minor hangs over and over again.
*/
SUBSYSTEM_DEF(verb_manager)
@@ -36,17 +36,17 @@ SUBSYSTEM_DEF(verb_manager)
///if TRUE we treat usr's with holders just like usr's without holders. otherwise they always execute immediately
var/can_queue_admin_verbs = FALSE
- ///if this is true all verbs immediately execute and dont queue. in case the mc is fucked or something
+ ///if this is true all verbs immediately execute and don't queue. in case the mc is fucked or something
var/FOR_ADMINS_IF_VERBS_FUCKED_immediately_execute_all_verbs = FALSE
///used for subtypes to determine if they use their own stats for the stat entry
var/use_default_stats = TRUE
///if TRUE this will... message admins every time a verb is queued to this subsystem for the next tick with stats.
- ///for obvious reasons dont make this be TRUE on the code level this is for admins to turn on
+ ///for obvious reasons don't make this be TRUE on the code level this is for admins to turn on
var/message_admins_on_queue = FALSE
- ///always queue if possible. overides can_queue_admin_verbs but not FOR_ADMINS_IF_VERBS_FUCKED_immediately_execute_all_verbs
+ ///always queue if possible. overrides can_queue_admin_verbs but not FOR_ADMINS_IF_VERBS_FUCKED_immediately_execute_all_verbs
var/always_queue = FALSE
/**
@@ -87,7 +87,7 @@ SUBSYSTEM_DEF(verb_manager)
#else
if(QDELETED(usr) || isnull(usr.client))
- stack_trace("_queue_verb() returned false because it wasnt called from player input!")
+ stack_trace("_queue_verb() returned false because it wasn't called from player input!")
return FALSE
#endif
diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm
index 1c519e8aff159..7bed63cc36fc8 100644
--- a/code/controllers/subsystem/vote.dm
+++ b/code/controllers/subsystem/vote.dm
@@ -356,7 +356,7 @@ SUBSYSTEM_DEF(vote)
data["VoteCD"] = CONFIG_GET(number/vote_delay)
return data
-/datum/controller/subsystem/vote/ui_act(action, params)
+/datum/controller/subsystem/vote/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/datums/achievements/_awards.dm b/code/datums/achievements/_awards.dm
index d99659ea780f9..e7d18f98124ac 100644
--- a/code/datums/achievements/_awards.dm
+++ b/code/datums/achievements/_awards.dm
@@ -67,7 +67,7 @@
/datum/award/proc/parse_value(raw_value)
return default_value
-///Can be overriden for achievement specific events
+///Can be overridden for achievement specific events
/datum/award/proc/on_unlock(mob/user)
return
diff --git a/code/datums/achievements/misc_achievements.dm b/code/datums/achievements/misc_achievements.dm
index 1d7b9da3a015a..bd1719783e12a 100644
--- a/code/datums/achievements/misc_achievements.dm
+++ b/code/datums/achievements/misc_achievements.dm
@@ -232,3 +232,9 @@
desc = "Successfully carry a boulder from Lavaland all the way to Centcom, without ever dropping it. We must imagine you're happy to unlock this."
database_id = MEDAL_SISYPHUS
icon_state = "sisyphus"
+
+/datum/award/achievement/misc/cigarettes
+ name = "Unhealthy snacks"
+ desc = "You were curious to taste it. And then another. You must have more!"
+ database_id = MEDAL_CIGARETTES
+ icon_state = "cigarettes"
diff --git a/code/datums/actions/items/reload_rebar.dm b/code/datums/actions/items/reload_rebar.dm
new file mode 100644
index 0000000000000..a29b02f6b227e
--- /dev/null
+++ b/code/datums/actions/items/reload_rebar.dm
@@ -0,0 +1,5 @@
+/datum/action/item_action/reload_rebar
+ name = "Reload Rebar"
+ desc = "Reloads a held crossbow"
+ button_icon = 'icons/mob/actions/actions_items.dmi'
+ button_icon_state = "bolts"
diff --git a/code/datums/actions/mobs/blood_warp.dm b/code/datums/actions/mobs/blood_warp.dm
index 4b070eebfe781..1e48c6e5aa419 100644
--- a/code/datums/actions/mobs/blood_warp.dm
+++ b/code/datums/actions/mobs/blood_warp.dm
@@ -21,14 +21,21 @@
/datum/action/cooldown/mob_cooldown/blood_warp/proc/blood_warp(atom/target)
if(owner.Adjacent(target))
return FALSE
- var/list/can_jaunt = get_bloodcrawlable_pools(get_turf(owner), 1)
+
+ var/turf/target_turf = get_turf(target)
+ var/turf/owner_turf = get_turf(owner)
+
+ if (target_turf.z != owner_turf.z)
+ return FALSE
+
+ var/list/can_jaunt = get_bloodcrawlable_pools(owner_turf, 1)
if(!can_jaunt.len)
return FALSE
var/chosen_pick_range = get_pick_range()
- var/list/pools = get_bloodcrawlable_pools(get_turf(target), chosen_pick_range)
+ var/list/pools = get_bloodcrawlable_pools(target_turf, chosen_pick_range)
if(remove_inner_pools)
- var/list/pools_to_remove = get_bloodcrawlable_pools(get_turf(target), chosen_pick_range - 1)
+ var/list/pools_to_remove = get_bloodcrawlable_pools(target_turf, chosen_pick_range - 1)
pools -= pools_to_remove
if(!pools.len)
return FALSE
@@ -42,16 +49,16 @@
qdel(DA)
var/obj/effect/decal/cleanable/blood/found_bloodpool
- pools = get_bloodcrawlable_pools(get_turf(target), chosen_pick_range)
+ pools = get_bloodcrawlable_pools(target_turf, chosen_pick_range)
if(remove_inner_pools)
- var/list/pools_to_remove = get_bloodcrawlable_pools(get_turf(target), chosen_pick_range - 1)
+ var/list/pools_to_remove = get_bloodcrawlable_pools(target_turf, chosen_pick_range - 1)
pools -= pools_to_remove
if(pools.len)
shuffle_inplace(pools)
found_bloodpool = pick(pools)
if(found_bloodpool)
owner.visible_message("[owner] sinks into the blood...")
- playsound(get_turf(owner), 'sound/magic/enter_blood.ogg', 100, TRUE, -1)
+ playsound(owner_turf, 'sound/magic/enter_blood.ogg', 100, TRUE, -1)
owner.forceMove(get_turf(found_bloodpool))
playsound(get_turf(owner), 'sound/magic/exit_blood.ogg', 100, TRUE, -1)
owner.visible_message("And springs back out!")
diff --git a/code/datums/actions/mobs/lava_swoop.dm b/code/datums/actions/mobs/lava_swoop.dm
index 0b0735bc471c0..aa512b2d28e8d 100644
--- a/code/datums/actions/mobs/lava_swoop.dm
+++ b/code/datums/actions/mobs/lava_swoop.dm
@@ -50,7 +50,7 @@
negative = FALSE
else if(target.x == initial_x) //if their x is the same, pick a direction
negative = prob(50)
- var/obj/effect/temp_visual/dragon_flight/F = new /obj/effect/temp_visual/dragon_flight(owner.loc, negative)
+ var/obj/effect/temp_visual/dragon_flight/flight_vis = new /obj/effect/temp_visual/dragon_flight(owner.loc, negative)
negative = !negative //invert it for the swoop down later
@@ -60,7 +60,7 @@
for(var/i in 1 to 3)
sleep(0.1 SECONDS)
if(QDELETED(owner) || owner.stat == DEAD) //we got hit and died, rip us
- qdel(F)
+ qdel(flight_vis)
if(owner.stat == DEAD)
swooping = FALSE
animate(owner, alpha = 255, transform = oldtransform, time = 0, flags = ANIMATION_END_NOW) //reset immediately
@@ -72,9 +72,11 @@
owner.mouse_opacity = MOUSE_OPACITY_TRANSPARENT
SLEEP_CHECK_DEATH(7, owner)
- while(target && owner.loc != get_turf(target))
- owner.forceMove(get_step(owner, get_dir(owner, target)))
+ var/turf/target_turf = get_turf(target)
+ while(!QDELETED(target) && owner.loc != target_turf && owner.z == target_turf.z)
+ owner.forceMove(get_step(owner, get_dir(owner, target_turf)))
SLEEP_CHECK_DEATH(0.5, owner)
+ target_turf = get_turf(target)
// Ash drake flies onto its target and rains fire down upon them
var/descentTime = 10
@@ -82,7 +84,6 @@
if(lava_arena)
lava_success = lava_arena(target)
-
//ensure swoop direction continuity.
if(negative)
if(ISINRANGE(owner.x, initial_x + 1, initial_x + SWOOP_DIRECTION_CHANGE_RANGE))
@@ -96,20 +97,20 @@
SLEEP_CHECK_DEATH(descentTime, owner)
owner.mouse_opacity = initial(owner.mouse_opacity)
playsound(owner.loc, 'sound/effects/meteorimpact.ogg', 200, TRUE)
- for(var/mob/living/L in orange(1, owner) - owner)
- L.adjustBruteLoss(75)
- if(!QDELETED(L)) // Some mobs are deleted on death
- var/throw_dir = get_dir(owner, L)
- if(L.loc == owner.loc)
+ for(var/mob/living/victim in orange(1, owner) - owner)
+ victim.adjustBruteLoss(75)
+ if(!QDELETED(victim)) // Some mobs are deleted on death
+ var/throw_dir = get_dir(owner, victim)
+ if(victim.loc == owner.loc)
throw_dir = pick(GLOB.alldirs)
var/throwtarget = get_edge_target_turf(owner, throw_dir)
- L.throw_at(throwtarget, 3)
- owner.visible_message(span_warning("[L] is thrown clear of [owner]!"))
- for(var/obj/vehicle/sealed/mecha/M in orange(1, owner))
- M.take_damage(75, BRUTE, MELEE, 1)
+ victim.throw_at(throwtarget, 3)
+ owner.visible_message(span_warning("[victim] is thrown clear of [owner]!"))
+ for(var/obj/vehicle/sealed/mecha/mech in orange(1, owner))
+ mech.take_damage(75, BRUTE, MELEE, 1)
- for(var/mob/M in range(7, owner))
- shake_camera(M, 15, 1)
+ for(var/mob/observer in range(7, owner))
+ shake_camera(observer, 15, 1)
REMOVE_TRAIT(owner, TRAIT_UNDENSE, SWOOPING_TRAIT)
SLEEP_CHECK_DEATH(1, owner)
@@ -126,15 +127,16 @@
while(amount > 0)
if(QDELETED(target))
break
- var/turf/TT = get_turf(target)
- var/turf/T = pick(RANGE_TURFS(1,TT))
- var/obj/effect/temp_visual/lava_warning/LW = new /obj/effect/temp_visual/lava_warning(T, 60) // longer reset time for the lava
- LW.owner = owner
+ var/turf/target_turf = get_turf(target)
+ var/turf/lava_turf = pick(RANGE_TURFS(1, target_turf))
+ var/obj/effect/temp_visual/lava_warning/warn_effect = new /obj/effect/temp_visual/lava_warning(lava_turf, 60) // longer reset time for the lava
+ warn_effect.owner = owner
amount--
SLEEP_CHECK_DEATH(delay, owner)
/datum/action/cooldown/mob_cooldown/lava_swoop/proc/lava_arena(atom/target)
- if(!target || !isliving(target))
+ var/turf/target_turf = get_turf(target)
+ if(QDELETED(target) || !isliving(target) || target_turf.z != owner.z)
return
target.visible_message(span_boldwarning("[owner] encases you in an arena of fire!"))
var/amount = 3
@@ -147,9 +149,7 @@
for(var/turf/T in RANGE_TURFS(2, center))
if(isindestructiblefloor(T))
continue
- if(!isindestructiblewall(T))
- T.TerraformTurf(/turf/open/misc/asteroid/basalt/lava_land_surface, flags = CHANGETURF_INHERIT_AIR)
- else
+ if(isindestructiblewall(T))
indestructible_turfs += T
SLEEP_CHECK_DEATH(1 SECONDS, owner) // give them a bit of time to realize what attack is actually happening
diff --git a/code/datums/ai/_ai_controller.dm b/code/datums/ai/_ai_controller.dm
index 33b63f09a01dc..a2fc1cdc62e18 100644
--- a/code/datums/ai/_ai_controller.dm
+++ b/code/datums/ai/_ai_controller.dm
@@ -63,6 +63,12 @@ multiple modular subtrees with behaviors
///What distance should we be checking for interesting things when considering idling/deidling? Defaults to AI_DEFAULT_INTERESTING_DIST
var/interesting_dist = AI_DEFAULT_INTERESTING_DIST
+ /// TRUE if we're able to run, FALSE if we aren't
+ /// Should not be set manually, override get_able_to_run() instead
+ /// Make sure you hook update_able_to_run() in setup_able_to_run() to whatever parameters changing that you added
+ /// Otherwise we will not pay attention to them changing
+ var/able_to_run = FALSE
+
/datum/ai_controller/New(atom/new_pawn)
change_ai_movement_type(ai_movement)
init_subtrees()
@@ -103,12 +109,13 @@ multiple modular subtrees with behaviors
return
var/list/temp_subtree_list = list()
for(var/subtree in planning_subtrees)
- var/subtree_instance = SSai_controllers.ai_subtrees[subtree]
+ var/subtree_instance = GLOB.ai_subtrees[subtree]
temp_subtree_list += subtree_instance
planning_subtrees = temp_subtree_list
///Proc to move from one pawn to another, this will destroy the target's existing controller.
/datum/ai_controller/proc/PossessPawn(atom/new_pawn)
+ SHOULD_CALL_PARENT(TRUE)
if(pawn) //Reset any old signals
UnpossessPawn(FALSE)
@@ -124,7 +131,7 @@ multiple modular subtrees with behaviors
var/turf/pawn_turf = get_turf(pawn)
if(pawn_turf)
- SSai_controllers.ai_controllers_by_zlevel[pawn_turf.z] += src
+ GLOB.ai_controllers_by_zlevel[pawn_turf.z] += src
SEND_SIGNAL(src, COMSIG_AI_CONTROLLER_POSSESSED_PAWN)
@@ -133,6 +140,8 @@ multiple modular subtrees with behaviors
RegisterSignal(pawn, COMSIG_MOB_STATCHANGE, PROC_REF(on_stat_changed))
RegisterSignal(pawn, COMSIG_MOB_LOGIN, PROC_REF(on_sentience_gained))
RegisterSignal(pawn, COMSIG_QDELETING, PROC_REF(on_pawn_qdeleted))
+ update_able_to_run()
+ setup_able_to_run()
our_cells = new(interesting_dist, interesting_dist, 1)
set_new_cells()
@@ -248,14 +257,11 @@ multiple modular subtrees with behaviors
if((mob_pawn?.client && !continue_processing_when_client))
return
if(old_turf)
- SSai_controllers.ai_controllers_by_zlevel[old_turf.z] -= src
- if(new_turf)
- SSai_controllers.ai_controllers_by_zlevel[new_turf.z] += src
- var/new_level_clients = SSmobs.clients_by_zlevel[new_turf.z].len
- if(new_level_clients)
- set_ai_status(AI_STATUS_IDLE)
- else
- set_ai_status(AI_STATUS_OFF)
+ GLOB.ai_controllers_by_zlevel[old_turf.z] -= src
+ if(isnull(new_turf))
+ return
+ GLOB.ai_controllers_by_zlevel[new_turf.z] += src
+ reset_ai_status()
///Abstract proc for initializing the pawn to the new controller
/datum/ai_controller/proc/TryPossessPawn(atom/new_pawn)
@@ -263,25 +269,38 @@ multiple modular subtrees with behaviors
///Proc for deinitializing the pawn to the old controller
/datum/ai_controller/proc/UnpossessPawn(destroy)
+ SHOULD_CALL_PARENT(TRUE)
if(isnull(pawn))
return // instantiated without an applicable pawn, fine
set_ai_status(AI_STATUS_OFF)
UnregisterSignal(pawn, list(COMSIG_MOVABLE_Z_CHANGED, COMSIG_MOB_LOGIN, COMSIG_MOB_LOGOUT, COMSIG_MOB_STATCHANGE, COMSIG_QDELETING))
+ clear_able_to_run()
if(ai_movement.moving_controllers[src])
ai_movement.stop_moving_towards(src)
var/turf/pawn_turf = get_turf(pawn)
if(pawn_turf)
- SSai_controllers.ai_controllers_by_zlevel[pawn_turf.z] -= src
+ GLOB.ai_controllers_by_zlevel[pawn_turf.z] -= src
if(ai_status)
- SSai_controllers.ai_controllers_by_status[ai_status] -= src
+ GLOB.ai_controllers_by_status[ai_status] -= src
pawn.ai_controller = null
pawn = null
if(destroy)
qdel(src)
-///Returns TRUE if the ai controller can actually run at the moment.
-/datum/ai_controller/proc/able_to_run()
+/datum/ai_controller/proc/setup_able_to_run()
+ // paused_until is handled by PauseAi() manually
+ RegisterSignals(pawn, list(SIGNAL_ADDTRAIT(TRAIT_AI_PAUSED), SIGNAL_REMOVETRAIT(TRAIT_AI_PAUSED)), PROC_REF(update_able_to_run))
+
+/datum/ai_controller/proc/clear_able_to_run()
+ UnregisterSignal(pawn, list(SIGNAL_ADDTRAIT(TRAIT_AI_PAUSED), SIGNAL_REMOVETRAIT(TRAIT_AI_PAUSED)))
+
+/datum/ai_controller/proc/update_able_to_run()
+ SIGNAL_HANDLER
+ able_to_run = get_able_to_run()
+
+///Returns TRUE if the ai controller can actually run at the moment, FALSE otherwise
+/datum/ai_controller/proc/get_able_to_run()
if(HAS_TRAIT(pawn, TRAIT_AI_PAUSED))
return FALSE
if(world.time < paused_until)
@@ -291,7 +310,7 @@ multiple modular subtrees with behaviors
///Runs any actions that are currently running
/datum/ai_controller/process(seconds_per_tick)
- if(!able_to_run())
+ if(!able_to_run)
GLOB.move_manager.stop_looping(pawn) //stop moving
return //this should remove them from processing in the future through event-based stuff.
@@ -386,18 +405,30 @@ multiple modular subtrees with behaviors
//remove old status, if we've got one
if(ai_status)
- SSai_controllers.ai_controllers_by_status[ai_status] -= src
+ GLOB.ai_controllers_by_status[ai_status] -= src
+ stop_previous_processing()
ai_status = new_ai_status
- SSai_controllers.ai_controllers_by_status[new_ai_status] += src
+ GLOB.ai_controllers_by_status[new_ai_status] += src
switch(ai_status)
if(AI_STATUS_ON)
START_PROCESSING(SSai_behaviors, src)
- if(AI_STATUS_OFF, AI_STATUS_IDLE)
- STOP_PROCESSING(SSai_behaviors, src)
+ if(AI_STATUS_IDLE)
+ START_PROCESSING(SSidle_ai_behaviors, src)
+ CancelActions()
+ if(AI_STATUS_OFF)
CancelActions()
+/datum/ai_controller/proc/stop_previous_processing()
+ switch(ai_status)
+ if(AI_STATUS_ON)
+ STOP_PROCESSING(SSai_behaviors, src)
+ if(AI_STATUS_IDLE)
+ STOP_PROCESSING(SSidle_ai_behaviors, src)
+
/datum/ai_controller/proc/PauseAi(time)
paused_until = world.time + time
+ update_able_to_run()
+ addtimer(CALLBACK(src, PROC_REF(update_able_to_run)), time)
/datum/ai_controller/proc/modify_cooldown(datum/ai_behavior/behavior, new_cooldown)
behavior_cooldowns[behavior] = new_cooldown
diff --git a/code/datums/ai/bane/bane_controller.dm b/code/datums/ai/bane/bane_controller.dm
index 8d6820a800bdc..64e1dcf31af3a 100644
--- a/code/datums/ai/bane/bane_controller.dm
+++ b/code/datums/ai/bane/bane_controller.dm
@@ -12,7 +12,19 @@ And the only victory you achieved was a lie. Now you understand Gotham is beyond
return AI_CONTROLLER_INCOMPATIBLE
return ..() //Run parent at end
-/datum/ai_controller/bane/able_to_run()
+/datum/ai_controller/bane/on_stat_changed(mob/living/source, new_stat)
+ . = ..()
+ update_able_to_run()
+
+/datum/ai_controller/bane/setup_able_to_run()
+ . = ..()
+ RegisterSignal(pawn, COMSIG_MOB_INCAPACITATE_CHANGED, PROC_REF(update_able_to_run))
+
+/datum/ai_controller/bane/clear_able_to_run()
+ UnregisterSignal(pawn, list(COMSIG_MOB_INCAPACITATE_CHANGED, COMSIG_MOB_STATCHANGE))
+ return ..()
+
+/datum/ai_controller/bane/get_able_to_run()
var/mob/living/living_pawn = pawn
if(IS_DEAD_OR_INCAP(living_pawn))
return FALSE
diff --git a/code/datums/ai/basic_mobs/base_basic_controller.dm b/code/datums/ai/basic_mobs/base_basic_controller.dm
index cd025b28bcb2b..a14630fa0e83a 100644
--- a/code/datums/ai/basic_mobs/base_basic_controller.dm
+++ b/code/datums/ai/basic_mobs/base_basic_controller.dm
@@ -12,17 +12,29 @@
return ..() //Run parent at end
+/datum/ai_controller/basic_controller/on_stat_changed(mob/living/source, new_stat)
+ . = ..()
+ update_able_to_run()
-/datum/ai_controller/basic_controller/able_to_run()
+/datum/ai_controller/basic_controller/setup_able_to_run()
. = ..()
- if(!isliving(pawn))
- return
- var/mob/living/living_pawn = pawn
- var/incap_flags = NONE
- if (ai_traits & CAN_ACT_IN_STASIS)
- incap_flags |= IGNORE_STASIS
- if(!(ai_traits & CAN_ACT_WHILE_DEAD) && (living_pawn.incapacitated(incap_flags) || living_pawn.stat))
+ RegisterSignal(pawn, COMSIG_MOB_INCAPACITATE_CHANGED, PROC_REF(update_able_to_run))
+
+/datum/ai_controller/basic_controller/clear_able_to_run()
+ UnregisterSignal(pawn, list(COMSIG_MOB_INCAPACITATE_CHANGED, COMSIG_MOB_STATCHANGE))
+ return ..()
+
+/datum/ai_controller/basic_controller/get_able_to_run()
+ . = ..()
+ if(!.)
return FALSE
+ var/mob/living/living_pawn = pawn
+ if(!(ai_traits & CAN_ACT_WHILE_DEAD))
+ // Unroll for flags here
+ if (ai_traits & CAN_ACT_IN_STASIS && (living_pawn.stat || INCAPACITATED_IGNORING(living_pawn, INCAPABLE_STASIS)))
+ return FALSE
+ else if(IS_DEAD_OR_INCAP(living_pawn))
+ return FALSE
if(ai_traits & PAUSE_DURING_DO_AFTER && LAZYLEN(living_pawn.do_afters))
return FALSE
diff --git a/code/datums/ai/basic_mobs/basic_subtrees/call_reinforcements.dm b/code/datums/ai/basic_mobs/basic_subtrees/call_reinforcements.dm
index 44d7cb4fe480b..f78697b2b8132 100644
--- a/code/datums/ai/basic_mobs/basic_subtrees/call_reinforcements.dm
+++ b/code/datums/ai/basic_mobs/basic_subtrees/call_reinforcements.dm
@@ -44,6 +44,6 @@
other_mob.ai_controller.set_blackboard_key(BB_BASIC_MOB_REINFORCEMENT_TARGET, pawn_mob)
controller.set_blackboard_key(BB_BASIC_MOB_REINFORCEMENTS_COOLDOWN, world.time + REINFORCEMENTS_COOLDOWN)
- return AI_BEHAVIOR_DELAY
+ return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED
#undef REINFORCEMENTS_COOLDOWN
diff --git a/code/datums/ai/basic_mobs/basic_subtrees/simple_find_nearest_target_to_flee.dm b/code/datums/ai/basic_mobs/basic_subtrees/simple_find_nearest_target_to_flee.dm
index d9e0d1e7fb9ff..83e514f327020 100644
--- a/code/datums/ai/basic_mobs/basic_subtrees/simple_find_nearest_target_to_flee.dm
+++ b/code/datums/ai/basic_mobs/basic_subtrees/simple_find_nearest_target_to_flee.dm
@@ -21,4 +21,5 @@
controller.queue_behavior(/datum/ai_behavior/target_from_retaliate_list/nearest, BB_BASIC_MOB_RETALIATE_LIST, target_key, targeting_key, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION)
/datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee/from_flee_key
+ target_key = BB_BASIC_MOB_FLEE_TARGET
targeting_key = BB_FLEE_TARGETING_STRATEGY
diff --git a/code/datums/ai/basic_mobs/basic_subtrees/simple_find_target.dm b/code/datums/ai/basic_mobs/basic_subtrees/simple_find_target.dm
index 42608730f9891..759355283acd4 100644
--- a/code/datums/ai/basic_mobs/basic_subtrees/simple_find_target.dm
+++ b/code/datums/ai/basic_mobs/basic_subtrees/simple_find_target.dm
@@ -1,8 +1,10 @@
/datum/ai_planning_subtree/simple_find_target
+ /// Variable to store target in
+ var/target_key = BB_BASIC_MOB_CURRENT_TARGET
/datum/ai_planning_subtree/simple_find_target/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
. = ..()
- controller.queue_behavior(/datum/ai_behavior/find_potential_targets, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETING_STRATEGY, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION)
+ controller.queue_behavior(/datum/ai_behavior/find_potential_targets, target_key, BB_TARGETING_STRATEGY, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION)
// Prevents finding a target if a human is nearby
/datum/ai_planning_subtree/simple_find_target/not_while_observed
@@ -12,3 +14,6 @@
if(watcher.stat != DEAD)
return
return ..()
+
+/datum/ai_planning_subtree/simple_find_target/to_flee
+ target_key = BB_BASIC_MOB_FLEE_TARGET
diff --git a/code/datums/ai/basic_mobs/targeting_strategies/basic_targeting_strategy.dm b/code/datums/ai/basic_mobs/targeting_strategies/basic_targeting_strategy.dm
index 2394f2a38623b..709acb8d5e892 100644
--- a/code/datums/ai/basic_mobs/targeting_strategies/basic_targeting_strategy.dm
+++ b/code/datums/ai/basic_mobs/targeting_strategies/basic_targeting_strategy.dm
@@ -29,6 +29,9 @@
if(M.status_flags & GODMODE)
return FALSE
+ if (vision_range && get_dist(living_mob, the_target) > vision_range)
+ return FALSE
+
if(!ignore_sight && !can_see(living_mob, the_target, vision_range)) //Target has moved behind cover and we have lost line of sight to it
return FALSE
@@ -85,6 +88,21 @@
// trust fall exercise
return TRUE
+/datum/targeting_strategy/basic/require_traits
+
+/datum/targeting_strategy/basic/require_traits/can_attack(mob/living/living_mob, atom/the_target, vision_range)
+ . = ..()
+ if (!.)
+ return FALSE
+ var/list/required_traits = living_mob.ai_controller.blackboard[BB_TARGET_ONLY_WITH_TRAITS]
+ if (!length(required_traits))
+ return TRUE
+
+ for (var/trait as anything in required_traits)
+ if (HAS_TRAIT(the_target, trait))
+ return TRUE
+ return FALSE
+
/// Subtype which searches for mobs of a size relative to ours
/datum/targeting_strategy/basic/of_size
/// If true, we will return mobs which are smaller than us. If false, larger.
diff --git a/code/datums/ai/monkey/monkey_behaviors.dm b/code/datums/ai/monkey/monkey_behaviors.dm
index a5febe03143f1..e6720d7d96a78 100644
--- a/code/datums/ai/monkey/monkey_behaviors.dm
+++ b/code/datums/ai/monkey/monkey_behaviors.dm
@@ -197,7 +197,7 @@
var/can_shoot = gun?.can_shoot() || FALSE
if(gun && controller.blackboard[BB_MONKEY_GUN_WORKED] && prob(95))
// We attempt to attack even if we can't shoot so we get the effects of pulling the trigger
- gun.melee_attack_chain(living_pawn, real_target)
+ gun.interact_with_atom(real_target, living_pawn)
controller.set_blackboard_key(BB_MONKEY_GUN_WORKED, can_shoot ? TRUE : prob(80)) // Only 20% likely to notice it didn't work
if(can_shoot)
controller.set_blackboard_key(BB_MONKEY_GUN_NEURONS_ACTIVATED, TRUE)
diff --git a/code/datums/ai/monkey/monkey_controller.dm b/code/datums/ai/monkey/monkey_controller.dm
index 451d692b65d34..e92ec519b209a 100644
--- a/code/datums/ai/monkey/monkey_controller.dm
+++ b/code/datums/ai/monkey/monkey_controller.dm
@@ -104,10 +104,22 @@ have ways of interacting with a specific mob and control it.
. = ..()
set_trip_mode(mode = TRUE)
-/datum/ai_controller/monkey/able_to_run()
+/datum/ai_controller/monkey/on_stat_changed(mob/living/source, new_stat)
+ . = ..()
+ update_able_to_run()
+
+/datum/ai_controller/monkey/setup_able_to_run()
+ . = ..()
+ RegisterSignal(pawn, COMSIG_MOB_INCAPACITATE_CHANGED, PROC_REF(update_able_to_run))
+
+/datum/ai_controller/monkey/clear_able_to_run()
+ UnregisterSignal(pawn, list(COMSIG_MOB_INCAPACITATE_CHANGED, COMSIG_MOB_STATCHANGE))
+ return ..()
+
+/datum/ai_controller/monkey/get_able_to_run()
var/mob/living/living_pawn = pawn
- if(living_pawn.incapacitated(IGNORE_RESTRAINTS | IGNORE_GRAB | IGNORE_STASIS) || living_pawn.stat > CONSCIOUS)
+ if(INCAPACITATED_IGNORING(living_pawn, INCAPABLE_RESTRAINTS|INCAPABLE_STASIS|INCAPABLE_GRAB) || living_pawn.stat > CONSCIOUS)
return FALSE
return ..()
@@ -134,7 +146,7 @@ have ways of interacting with a specific mob and control it.
for(var/obj/item/item in oview(2, living_pawn))
nearby_items += item
- for(var/obj/item/item in living_pawn.held_items) // If we've got some garbage in out hands thats going to stop us from effectivly attacking, we should get rid of it.
+ for(var/obj/item/item in living_pawn.held_items) // If we've got some garbage in out hands that's going to stop us from effectively attacking, we should get rid of it.
if(item.force < 2)
living_pawn.dropItemToGround(item)
@@ -151,7 +163,7 @@ have ways of interacting with a specific mob and control it.
if(!weapon || (weapon in living_pawn.held_items))
return FALSE
- if(weapon.force < 2) // our bite does 2 damage on avarage, no point in settling for anything less
+ if(weapon.force < 2) // our bite does 2 damage on average, no point in settling for anything less
return FALSE
set_blackboard_key(BB_MONKEY_PICKUPTARGET, weapon)
diff --git a/code/datums/ai/movement/_ai_movement.dm b/code/datums/ai/movement/_ai_movement.dm
index d48166eeb23ac..c1b3aae5bd60f 100644
--- a/code/datums/ai/movement/_ai_movement.dm
+++ b/code/datums/ai/movement/_ai_movement.dm
@@ -1,4 +1,4 @@
-///This datum is an abstract class that can be overriden for different types of movement
+///This datum is an abstract class that can be overridden for different types of movement
/datum/ai_movement
///Assoc list ist of controllers that are currently moving as key, and what they are moving to as value
var/list/moving_controllers = list()
@@ -59,7 +59,7 @@
var/datum/ai_controller/controller = source.extra_info
// Check if this controller can actually run, so we don't chase people with corpses
- if(!controller.able_to_run())
+ if(!controller.able_to_run)
controller.CancelActions()
qdel(source) //stop moving
return MOVELOOP_SKIP_STEP
diff --git a/code/datums/ai/oldhostile/hostile_tameable.dm b/code/datums/ai/oldhostile/hostile_tameable.dm
index 1c30cb95487c1..907ab955a8d53 100644
--- a/code/datums/ai/oldhostile/hostile_tameable.dm
+++ b/code/datums/ai/oldhostile/hostile_tameable.dm
@@ -50,7 +50,19 @@
if(buckler != blackboard[BB_HOSTILE_FRIEND])
return COMPONENT_BLOCK_BUCKLE
-/datum/ai_controller/hostile_friend/able_to_run()
+/datum/ai_controller/hostile_friend/on_stat_changed(mob/living/source, new_stat)
+ . = ..()
+ update_able_to_run()
+
+/datum/ai_controller/hostile_friend/setup_able_to_run()
+ . = ..()
+ RegisterSignal(pawn, COMSIG_MOB_INCAPACITATE_CHANGED, PROC_REF(update_able_to_run))
+
+/datum/ai_controller/hostile_friend/clear_able_to_run()
+ UnregisterSignal(pawn, list(COMSIG_MOB_INCAPACITATE_CHANGED, COMSIG_MOB_STATCHANGE))
+ return ..()
+
+/datum/ai_controller/hostile_friend/get_able_to_run()
var/mob/living/living_pawn = pawn
if(IS_DEAD_OR_INCAP(living_pawn))
@@ -77,14 +89,14 @@
if(pawn.Adjacent(pawn, new_friend))
new_friend.visible_message("[pawn] looks at [new_friend] in a friendly manner!", span_notice("[pawn] looks at you in a friendly manner!"))
set_blackboard_key(BB_HOSTILE_FRIEND, new_friend)
- RegisterSignal(new_friend, COMSIG_MOB_POINTED, PROC_REF(check_point))
+ RegisterSignal(new_friend, COMSIG_MOVABLE_POINTED, PROC_REF(check_point))
RegisterSignal(new_friend, COMSIG_MOB_SAY, PROC_REF(check_verbal_command))
/// Someone is being mean to us, take them off our friends (add actual enemies behavior later)
/datum/ai_controller/hostile_friend/proc/unfriend()
var/mob/living/old_friend = blackboard[BB_HOSTILE_FRIEND]
if(old_friend)
- UnregisterSignal(old_friend, list(COMSIG_MOB_POINTED, COMSIG_MOB_SAY))
+ UnregisterSignal(old_friend, list(COMSIG_MOVABLE_POINTED, COMSIG_MOB_SAY))
clear_blackboard_key(BB_HOSTILE_FRIEND)
/// Someone is looking at us, if we're currently carrying something then show what it is, and include a message if they're our friend
@@ -129,7 +141,7 @@
/datum/ai_controller/hostile_friend/proc/check_menu(mob/user)
if(!istype(user))
CRASH("A non-mob is trying to issue an order to [pawn].")
- if(user.incapacitated() || !can_see(user, pawn))
+ if(user.incapacitated || !can_see(user, pawn))
return FALSE
return TRUE
@@ -190,7 +202,7 @@
set_blackboard_key(BB_HOSTILE_ORDER_MODE, HOSTILE_COMMAND_ATTACK)
/// Someone we like is pointing at something, see if it's something we might want to interact with (like if they might want us to fetch something for them)
-/datum/ai_controller/hostile_friend/proc/check_point(mob/pointing_friend, atom/movable/pointed_movable)
+/datum/ai_controller/hostile_friend/proc/check_point(mob/pointing_friend, atom/movable/pointed_movable, obj/effect/temp_visual/point/point)
SIGNAL_HANDLER
var/mob/living/simple_animal/hostile/living_pawn = pawn
diff --git a/code/datums/ai/robot_customer/robot_customer_behaviors.dm b/code/datums/ai/robot_customer/robot_customer_behaviors.dm
index 7aa0f34f5207d..8712049901383 100644
--- a/code/datums/ai/robot_customer/robot_customer_behaviors.dm
+++ b/code/datums/ai/robot_customer/robot_customer_behaviors.dm
@@ -63,7 +63,7 @@
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED
controller.add_blackboard_key(BB_CUSTOMER_PATIENCE, seconds_per_tick * -1 SECONDS) // Convert seconds_per_tick to a SECONDS equivalent.
- if(controller.blackboard[BB_CUSTOMER_PATIENCE] < 0 || controller.blackboard[BB_CUSTOMER_LEAVING]) // Check if we're leaving because sometthing mightve forced us to
+ if(controller.blackboard[BB_CUSTOMER_PATIENCE] < 0 || controller.blackboard[BB_CUSTOMER_LEAVING]) // Check if we're leaving because something might've forced us to
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED
// SPT_PROB 1.5 is about a 40% chance that the tourist will have vocalised at least once every minute.
@@ -78,7 +78,7 @@
if(my_seat)
controller.pawn.setDir(my_seat.dir) //Sit in your seat
- ///Now check if theres a meal infront of us.
+ ///Now check if there's a meal infront of us.
var/datum/venue/attending_venue = controller.blackboard[BB_CUSTOMER_ATTENDING_VENUE]
var/turf/infront_turf = get_step(controller.pawn, controller.pawn.dir)
@@ -100,7 +100,7 @@
if(greytider || QDELETED(src) || QDELETED(customer_pawn))
return
controller.set_blackboard_key(BB_CUSTOMER_LEAVING, TRUE)
- customer_pawn.update_icon() //They might have a special leaving accesoiry (french flag)
+ customer_pawn.update_icon() //They might have a special leaving accessory (French flag)
if(succeeded)
customer_pawn.say(pick(customer_data.leave_happy_lines))
else
diff --git a/code/datums/armor/_armor.dm b/code/datums/armor/_armor.dm
index 616ad00c324ad..961c7827b1de4 100644
--- a/code/datums/armor/_armor.dm
+++ b/code/datums/armor/_armor.dm
@@ -139,15 +139,15 @@ GLOBAL_LIST_INIT(armor_by_type, generate_armor_type_cache())
/// Gets the rating of armor for the specified rating
/datum/armor/proc/get_rating(rating)
- // its not that I dont trust coders, its just that I don't trust coders
+ // its not that I don't trust coders, its just that I don't trust coders
if(!(rating in ARMOR_LIST_ALL()))
- CRASH("Attempted to get a rating '[rating]' that doesnt exist")
+ CRASH("Attempted to get a rating '[rating]' that doesn't exist")
return vars[rating]
/datum/armor/immune/get_rating(rating)
return 100
-/// Converts all the ratings of the armor into a list, optionally inversed
+/// Converts all the ratings of the armor into a list, optionally inverted
/datum/armor/proc/get_rating_list(inverse = FALSE)
var/ratings = list()
for(var/rating in ARMOR_LIST_ALL())
diff --git a/code/datums/bodypart_overlays/bodypart_overlay.dm b/code/datums/bodypart_overlays/bodypart_overlay.dm
index 15b1e01114943..4059e7968d481 100644
--- a/code/datums/bodypart_overlays/bodypart_overlay.dm
+++ b/code/datums/bodypart_overlays/bodypart_overlay.dm
@@ -26,7 +26,7 @@
)
return all_images
-///Generate the image. Needs to be overriden
+///Generate the image. Needs to be overridden
/datum/bodypart_overlay/proc/get_image(layer, obj/item/bodypart/limb)
CRASH("Get image needs to be overridden")
@@ -42,7 +42,7 @@
/datum/bodypart_overlay/proc/removed_from_limb(obj/item/bodypart/limb)
return
-///Use this to change the appearance (and yes you must overwrite hahahahahah) (or dont use this, I just dont want people directly changing the image)
+///Use this to change the appearance (and yes you must overwrite hahahahahah) (or don't use this, I just don't want people directly changing the image)
/datum/bodypart_overlay/proc/set_appearance()
CRASH("Update appearance needs to be overridden")
diff --git a/code/datums/bodypart_overlays/mutant_bodypart_overlay.dm b/code/datums/bodypart_overlays/mutant_bodypart_overlay.dm
index 3115e3ad62ea2..d0250cce686eb 100644
--- a/code/datums/bodypart_overlays/mutant_bodypart_overlay.dm
+++ b/code/datums/bodypart_overlays/mutant_bodypart_overlay.dm
@@ -13,6 +13,24 @@
///Take on the dna/preference from whoever we're gonna be inserted in
var/imprint_on_next_insertion = TRUE
+/datum/bodypart_overlay/mutant/New(obj/item/organ/attached_organ)
+ . = ..()
+
+ RegisterSignal(attached_organ, COMSIG_ORGAN_IMPLANTED, PROC_REF(on_mob_insert))
+
+/datum/bodypart_overlay/mutant/proc/on_mob_insert(obj/item/organ/parent, mob/living/carbon/receiver)
+ SIGNAL_HANDLER
+
+ if(!should_visual_organ_apply_to(parent.type, receiver))
+ stack_trace("adding a [parent.type] to a [receiver.type] when it shouldn't be!")
+
+ if(imprint_on_next_insertion) //We only want this set *once*
+ var/feature_name = receiver.dna.features[feature_key]
+ if (isnull(feature_name))
+ feature_name = receiver.dna.species.mutant_organs[parent.type]
+ set_appearance_from_name(feature_name)
+ imprint_on_next_insertion = FALSE
+
/datum/bodypart_overlay/mutant/get_overlay(layer, obj/item/bodypart/limb)
inherit_color(limb) // If draw_color is not set yet, go ahead and do that
return ..()
@@ -67,7 +85,6 @@
return appearance
/datum/bodypart_overlay/mutant/color_image(image/overlay, layer, obj/item/bodypart/limb)
-
overlay.color = sprite_datum.color_src ? draw_color : null
/datum/bodypart_overlay/mutant/added_to_limb(obj/item/bodypart/limb)
@@ -139,3 +156,4 @@
CRASH("External organ [type] couldn't find sprite accessory [accessory_name]!")
else
CRASH("External organ [type] had fetch_sprite_datum called with a null accessory name!")
+
diff --git a/code/datums/bodypart_overlays/simple_bodypart_overlay.dm b/code/datums/bodypart_overlays/simple_bodypart_overlay.dm
index 6c9eb4240ecd0..20467eede042b 100644
--- a/code/datums/bodypart_overlays/simple_bodypart_overlay.dm
+++ b/code/datums/bodypart_overlays/simple_bodypart_overlay.dm
@@ -25,11 +25,6 @@
icon_state = "sixpack"
layers = EXTERNAL_ADJACENT
-///A creampie drawn on the head
-/datum/bodypart_overlay/simple/creampie
- icon_state = "creampie_human"
- layers = EXTERNAL_FRONT
-
///bags drawn beneath the eyes
/datum/bodypart_overlay/simple/bags
icon_state = "bags"
diff --git a/code/datums/brain_damage/severe.dm b/code/datums/brain_damage/severe.dm
index d5f0a0e91240a..cd45ae1abf468 100644
--- a/code/datums/brain_damage/severe.dm
+++ b/code/datums/brain_damage/severe.dm
@@ -407,7 +407,7 @@
var/obj/item/bodypart/bodypart = owner.get_bodypart(owner.get_random_valid_zone(even_weights = TRUE))
if(!(bodypart && IS_ORGANIC_LIMB(bodypart)) && bodypart.bodypart_flags & BODYPART_PSEUDOPART)
return
- if(owner.incapacitated())
+ if(owner.incapacitated)
return
bodypart.receive_damage(scratch_damage)
if(SPT_PROB(33, seconds_per_tick))
diff --git a/code/datums/brain_damage/split_personality.dm b/code/datums/brain_damage/split_personality.dm
index 325203dbb350a..6d0f8fc565415 100644
--- a/code/datums/brain_damage/split_personality.dm
+++ b/code/datums/brain_damage/split_personality.dm
@@ -322,7 +322,7 @@
if(!. || !client)
return FALSE
to_chat(src, span_notice("You're the incredibly inebriated leftovers of your host's consciousness! Make sure to act the part and leave a trail of confusion and chaos in your wake."))
- to_chat(src, span_boldwarning("Do not commit suicide or put the body in danger, you have a minor liscense to grief just like a clown, do not kill anyone or create a situation leading to the body being in danger or in harm ways. While you're drunk, you're not suicidal."))
+ to_chat(src, span_boldwarning("While you're drunk, you're not suicidal. Do not commit suicide or put the body in danger. You have a minor license to grief just like a clown, but do not kill anyone or create a situation leading to the body being put in danger or at risk of being harmed."))
#undef OWNER
#undef STRANGER
diff --git a/code/datums/browser.dm b/code/datums/browser.dm
index f74ecf6c5a343..b9d859552389d 100644
--- a/code/datums/browser.dm
+++ b/code/datums/browser.dm
@@ -99,7 +99,7 @@
/datum/browser/proc/open(use_onclose = TRUE)
if(isnull(window_id)) //null check because this can potentially nuke goonchat
WARNING("Browser [title] tried to open with a null ID")
- to_chat(user, span_userdanger("The [title] browser you tried to open failed a sanity check! Please report this on github!"))
+ to_chat(user, span_userdanger("The [title] browser you tried to open failed a sanity check! Please report this on GitHub!"))
return
var/window_size = ""
if (width && height)
diff --git a/code/datums/chatmessage.dm b/code/datums/chatmessage.dm
index 998c10a3b9b44..ee278cdae6212 100644
--- a/code/datums/chatmessage.dm
+++ b/code/datums/chatmessage.dm
@@ -314,7 +314,7 @@
speaker = v.source
spans |= "virtual-speaker"
- // Ignore virtual speaker (most often radio messages) from ourself
+ // Ignore virtual speaker (most often radio messages) from ourselves
if (originalSpeaker != src && speaker == src)
return
diff --git a/code/datums/components/acid.dm b/code/datums/components/acid.dm
index fc60e0312fd72..74fa1b1ae7f88 100644
--- a/code/datums/components/acid.dm
+++ b/code/datums/components/acid.dm
@@ -148,7 +148,7 @@ GLOBAL_DATUM_INIT(acid_overlay, /mutable_appearance, mutable_appearance('icons/e
var/acid_used = min(acid_volume * 0.05, 20) * seconds_per_tick
var/applied_targets = 0
for(var/atom/movable/target_movable as anything in target_turf)
- // Dont apply acid to things under the turf
+ // Don't apply acid to things under the turf
if(target_turf.underfloor_accessibility < UNDERFLOOR_INTERACTABLE && HAS_TRAIT(target_movable, TRAIT_T_RAY_VISIBLE))
continue
// Ignore mobs if turf_acid_ignores_mobs is TRUE
diff --git a/code/datums/components/aquarium_content.dm b/code/datums/components/aquarium_content.dm
index 21c6c75ca169a..57d62cdb0ee26 100644
--- a/code/datums/components/aquarium_content.dm
+++ b/code/datums/components/aquarium_content.dm
@@ -24,15 +24,15 @@
//Current layer for the visual object
var/base_layer
-
/**
- * Fish sprite how to:
- * Need to be centered on 16,16 in the dmi and facing left by default.
- * sprite_height/sprite_width is the size it will have in aquarium and used to control animation boundaries.
- * source_height/source_width is the size of the original icon (ideally only the non-empty parts)
+ * Fish sprite how to:
+ * The aquarium icon state needs to be centered on 16,16 in the dmi and facing left by default.
+ * sprite_width/sprite_height are the sizes it will have in aquarium and used to control animation boundaries.
+ * Ideally these two vars represent the size of the aquarium icon state, but they can be one or two units shorter
+ * to give more room for the visual to float around inside the aquarium, since the aquarium tank frame overlay will likely
+ * cover the extra pixels anyway.
*/
-
/// Icon used for in aquarium sprite
var/icon = 'icons/obj/aquarium/fish.dmi'
/// If this is set this icon state will be used for the holder while icon_state will only be used for item/catalog. Transformation from source_width/height WON'T be applied.
@@ -52,10 +52,6 @@
var/sprite_height = 3
var/sprite_width = 3
- //This is the size of the source sprite. This will be used to calculate scale down factor.
- var/source_width = 32
- var/source_height = 32
-
/// Currently playing animation
var/current_animation
@@ -97,6 +93,7 @@
ADD_TRAIT(parent, TRAIT_FISH_CASE_COMPATIBILE, REF(src))
RegisterSignal(parent, COMSIG_TRY_INSERTING_IN_AQUARIUM, PROC_REF(is_ready_to_insert))
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(enter_aquarium))
+ RegisterSignal(parent, COMSIG_FISH_PETTED, PROC_REF(on_fish_petted))
//If component is added to something already in aquarium at the time initialize it properly.
var/atom/movable/movable_parent = parent
@@ -112,18 +109,9 @@
sprite_width = fish.sprite_width
aquarium_vc_color = fish.aquarium_vc_color
- if(fish.dedicated_in_aquarium_icon_state)
- if(fish.dedicated_in_aquarium_icon)
- icon = fish.dedicated_in_aquarium_icon
- icon_state = fish.dedicated_in_aquarium_icon_state
- base_transform = matrix()
- else
- icon_state = fish.icon_state
- var/matrix/matrix = matrix()
- var/x_scale = fish.sprite_width / fish.source_width
- var/y_scale = fish.sprite_height / fish.source_height
- matrix.Scale(x_scale, y_scale)
- base_transform = matrix
+ icon = fish.dedicated_in_aquarium_icon
+ icon_state = fish.dedicated_in_aquarium_icon_state
+ base_transform = matrix()
randomize_position = TRUE
@@ -274,7 +262,6 @@
dead_animation()
return
-
/// Create looping random path animation, pixel offsets parameters include offsets already
/datum/component/aquarium_content/proc/swim_animation()
var/avg_width = round(sprite_width / 2)
@@ -325,6 +312,11 @@
base_layer = current_aquarium.request_layer(layer_mode)
vc_obj.layer = base_layer
+/datum/component/aquarium_content/proc/on_fish_petted()
+ SIGNAL_HANDLER
+
+ new /obj/effect/temp_visual/heart(get_turf(parent))
+
/datum/component/aquarium_content/proc/randomize_base_position()
var/list/aq_properties = current_aquarium.get_surface_properties()
var/avg_width = round(sprite_width / 2)
diff --git a/code/datums/components/bakeable.dm b/code/datums/components/bakeable.dm
index afc71936f1b92..93e96f65d58fc 100644
--- a/code/datums/components/bakeable.dm
+++ b/code/datums/components/bakeable.dm
@@ -93,11 +93,11 @@
var/list/asomnia_hadders = list()
for(var/mob/smeller in get_hearers_in_view(DEFAULT_MESSAGE_RANGE, used_oven))
if(HAS_TRAIT(smeller, TRAIT_ANOSMIA))
- asomnia_hadders += smeller
+ asomnia_hadders += smeller
if(positive_result)
used_oven.visible_message(
- span_notice("You smell something great coming from [used_oven]."),
+ span_notice("You smell something great coming from [used_oven]."),
blind_message = span_notice("You smell something great..."),
ignored_mobs = asomnia_hadders,
)
diff --git a/code/datums/components/caltrop.dm b/code/datums/components/caltrop.dm
index 3f6bba15541b1..cd06bdb2a00d7 100644
--- a/code/datums/components/caltrop.dm
+++ b/code/datums/components/caltrop.dm
@@ -30,7 +30,7 @@
///So we can update ant damage
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
-/datum/component/caltrop/Initialize(min_damage = 0, max_damage = 0, probability = 100, paralyze_duration = 6 SECONDS, flags = NONE, soundfile = null)
+/datum/component/caltrop/Initialize(min_damage = 0, max_damage = 0, probability = 100, paralyze_duration = 2 SECONDS, flags = NONE, soundfile = null)
. = ..()
if(!isatom(parent))
return COMPONENT_INCOMPATIBLE
diff --git a/code/datums/components/chasm.dm b/code/datums/components/chasm.dm
index b4406857ac1e3..6cae053afd17d 100644
--- a/code/datums/components/chasm.dm
+++ b/code/datums/components/chasm.dm
@@ -212,6 +212,10 @@
REMOVE_TRAIT(fallen_mob, TRAIT_NO_TRANSFORM, REF(src))
if (fallen_mob.stat != DEAD)
fallen_mob.investigate_log("has died from falling into a chasm.", INVESTIGATE_DEATHS)
+ if(issilicon(fallen_mob))
+ //Silicons are held together by hopes and dreams, unfortunately, I'm having a nightmare
+ var/mob/living/silicon/robot/fallen_borg = fallen_mob
+ fallen_borg.mmi = null
fallen_mob.death(TRUE)
fallen_mob.apply_damage(300)
@@ -247,14 +251,51 @@ GLOBAL_LIST_EMPTY(chasm_fallen_mobs)
/obj/effect/abstract/chasm_storage/Entered(atom/movable/arrived)
. = ..()
if(isliving(arrived))
+ //Mobs that have fallen in reserved area should be deleted to avoid fishing stuff from the deathmatch or VR.
+ if(is_reserved_level(loc.z) && !istype(get_area(loc), /area/shuttle))
+ qdel(arrived)
+ return
RegisterSignal(arrived, COMSIG_LIVING_REVIVE, PROC_REF(on_revive))
- GLOB.chasm_fallen_mobs += arrived
+ LAZYADD(GLOB.chasm_fallen_mobs[get_chasm_category(loc)], arrived)
/obj/effect/abstract/chasm_storage/Exited(atom/movable/gone)
. = ..()
if(isliving(gone))
UnregisterSignal(gone, COMSIG_LIVING_REVIVE)
- GLOB.chasm_fallen_mobs -= gone
+ LAZYREMOVE(GLOB.chasm_fallen_mobs[get_chasm_category(loc)], gone)
+
+/obj/effect/abstract/chasm_storage/on_changed_z_level(turf/old_turf, turf/new_turf, same_z_layer, notify_contents)
+ . = ..()
+ var/old_cat = get_chasm_category(old_turf)
+ var/new_cat = get_chasm_category(new_turf)
+ var/list/mobs = list()
+ for(var/mob/fallen in src)
+ mobs += fallen
+ LAZYREMOVE(GLOB.chasm_fallen_mobs[old_cat], mobs)
+ LAZYADD(GLOB.chasm_fallen_mobs[new_cat], mobs)
+
+/**
+ * Returns a key to store, remove and access fallen mobs depending on the z-level.
+ * This stops rescuing people from places that are waaaaaaaay too far-fetched.
+ */
+/proc/get_chasm_category(turf/turf)
+ var/z_level = turf?.z
+ var/area/area = get_area(turf)
+ if(istype(area, /area/shuttle)) //shuttle move between z-levels, so they're a special case.
+ return area
+
+ if(is_away_level(z_level))
+ return ZTRAIT_AWAY
+ if(is_mining_level(z_level))
+ return ZTRAIT_MINING
+ if(is_station_level(z_level))
+ return ZTRAIT_STATION
+ if(is_centcom_level(z_level))
+ return ZTRAIT_CENTCOM
+ if(is_reserved_level(z_level))
+ return ZTRAIT_RESERVED
+
+ return ZTRAIT_SPACE_RUINS
#define CHASM_TRAIT "chasm trait"
/**
diff --git a/code/datums/components/connect_mob_behalf.dm b/code/datums/components/connect_mob_behalf.dm
index b8aa014f81010..18ab0eebed8c8 100644
--- a/code/datums/components/connect_mob_behalf.dm
+++ b/code/datums/components/connect_mob_behalf.dm
@@ -1,6 +1,6 @@
/// This component behaves similar to connect_loc_behalf, but working off clients and mobs instead of loc
/// To be clear, we hook into a signal on a tracked client's mob
-/// We retain the ability to react to that signal on a seperate listener, which makes this quite powerful
+/// We retain the ability to react to that signal on a separate listener, which makes this quite powerful
/datum/component/connect_mob_behalf
dupe_mode = COMPONENT_DUPE_UNIQUE
diff --git a/code/datums/components/connect_range.dm b/code/datums/components/connect_range.dm
index d3407f4671456..af8ec247eb262 100644
--- a/code/datums/components/connect_range.dm
+++ b/code/datums/components/connect_range.dm
@@ -1,6 +1,6 @@
/**
* This component behaves similar to connect_loc_behalf but for all turfs in range, hooking into a signal on each of them.
- * Just like connect_loc_behalf, It can react to that signal on behalf of a seperate listener.
+ * Just like connect_loc_behalf, It can react to that signal on behalf of a separate listener.
* Good for components, though it carries some overhead. Can't be an element as that may lead to bugs.
*/
/datum/component/connect_range
diff --git a/code/datums/components/crafting/crafting.dm b/code/datums/components/crafting/crafting.dm
index 8f436faa9c6c4..ec6df83b8042f 100644
--- a/code/datums/components/crafting/crafting.dm
+++ b/code/datums/components/crafting/crafting.dm
@@ -308,7 +308,6 @@
var/datum/reagents/holder
var/list/surroundings
var/list/Deletion = list()
- var/data
var/amt
var/list/requirements = list()
if(R.reqs)
@@ -345,7 +344,6 @@
RC.reagents.trans_to(holder, reagent_volume, target_id = path_key, no_react = TRUE)
surroundings -= RC
amt -= reagent_volume
- SEND_SIGNAL(RC.reagents, COMSIG_REAGENTS_CRAFTING_PING) // - [] TODO: Make this entire thing less spaghetti
else
surroundings -= RC
RC.update_appearance(UPDATE_ICON)
@@ -359,7 +357,7 @@
SD = new S.type()
Deletion += SD
S.use(amt)
- SD = locate(S.type) in Deletion
+ SD = SD || locate(S.type) in Deletion // SD might be already set here, no sense in searching for it again
SD.amount += amt
continue main_loop
else
@@ -367,9 +365,9 @@
if(!locate(S.type) in Deletion)
Deletion += S
else
- data = S.amount
- S = locate(S.type) in Deletion
- S.add(data)
+ SD = SD || locate(S.type) in Deletion
+ SD.add(S.amount) // add the amount to our tally stack, SD
+ qdel(S) // We can just delete it straight away as it's going to be fully consumed anyway, saving some overhead from calling use()
surroundings -= S
else
var/atom/movable/I
@@ -537,7 +535,7 @@
return TRUE
-/datum/component/personal_crafting/ui_act(action, params)
+/datum/component/personal_crafting/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
@@ -611,6 +609,9 @@
data["name"] = "[data["name"]] [recipe.result_amount]x"
data["desc"] = recipe.desc || initial(atom.desc)
+ if(ispath(recipe.result, /obj/item/food))
+ var/obj/item/food/food = recipe.result
+ data["has_food_effect"] = !!food.crafted_food_buff
// Crafting
if(recipe.non_craftable)
diff --git a/code/datums/components/crafting/equipment.dm b/code/datums/components/crafting/equipment.dm
index 75b257156084e..dfd79e696224c 100644
--- a/code/datums/components/crafting/equipment.dm
+++ b/code/datums/components/crafting/equipment.dm
@@ -23,7 +23,7 @@
time = 4 SECONDS
category = CAT_EQUIPMENT
-/datum/crafting_recipe/improvisedshield
+/datum/crafting_recipe/moonflowershield
name = "Moonflower Shield"
result = /obj/item/shield/buckler/moonflower
reqs = list(
diff --git a/code/datums/components/crafting/ranged_weapon.dm b/code/datums/components/crafting/ranged_weapon.dm
index 0e3c7b119169b..174c0226a423e 100644
--- a/code/datums/components/crafting/ranged_weapon.dm
+++ b/code/datums/components/crafting/ranged_weapon.dm
@@ -77,7 +77,7 @@
reqs = list(
/obj/item/assembly/signaler/anomaly/flux = 2,
/obj/item/assembly/signaler/anomaly/grav = 1,
- /obj/item/assembly/signaler/anomaly/vortex = MAX_CORES_VORTEX,
+ /obj/item/assembly/signaler/anomaly/vortex = (MAX_CORES_VORTEX - 1),
/obj/item/assembly/signaler/anomaly/bluespace = 1,
/obj/item/weaponcrafting/gunkit/beam_rifle = 1,
)
diff --git a/code/datums/components/crafting/tailoring.dm b/code/datums/components/crafting/tailoring.dm
index 3c498f74416bd..0bd3194813398 100644
--- a/code/datums/components/crafting/tailoring.dm
+++ b/code/datums/components/crafting/tailoring.dm
@@ -603,3 +603,43 @@
. = ..()
if(HAS_TRAIT(user, TRAIT_BALLOON_SUTRA))
return TRUE
+
+/datum/crafting_recipe/press_armor
+ name = "press armor vest"
+ result = /obj/item/clothing/suit/armor/vest/press
+ time = 2 SECONDS
+ tool_paths = list(/obj/item/clothing/accessory/press_badge)
+ reqs = list(
+ /obj/item/clothing/suit/armor/vest = 1,
+ )
+ category = CAT_CLOTHING
+
+/datum/crafting_recipe/press_helmet
+ name = "press helmet vest"
+ result = /obj/item/clothing/head/helmet/press
+ time = 2 SECONDS
+ tool_paths = list(/obj/item/clothing/accessory/press_badge)
+ reqs = list(
+ /obj/item/clothing/head/helmet/sec = 1,
+ )
+ category = CAT_CLOTHING
+
+/datum/crafting_recipe/press_vest
+ name = "press vest"
+ result = /obj/item/clothing/suit/hazardvest/press
+ time = 2 SECONDS
+ tool_paths = list(/obj/item/clothing/accessory/press_badge)
+ reqs = list(
+ /obj/item/clothing/suit/hazardvest = 1,
+ )
+ category = CAT_CLOTHING
+
+/datum/crafting_recipe/press_fedora
+ name = "press fedora"
+ result = /obj/item/clothing/head/fedora/beige/press
+ time = 2 SECONDS
+ tool_paths = list(/obj/item/clothing/accessory/press_badge)
+ reqs = list(
+ /obj/item/clothing/head/fedora/beige = 1,
+ )
+ category = CAT_CLOTHING
diff --git a/code/datums/components/cult_ritual_item.dm b/code/datums/components/cult_ritual_item.dm
index dedd30bda0ef5..71e07e6380e11 100644
--- a/code/datums/components/cult_ritual_item.dm
+++ b/code/datums/components/cult_ritual_item.dm
@@ -404,7 +404,7 @@
if(!rune.Adjacent(cultist))
return FALSE
- if(cultist.incapacitated())
+ if(cultist.incapacitated)
return FALSE
if(cultist.stat == DEAD)
@@ -427,7 +427,7 @@
if(QDELETED(tool) || !cultist.is_holding(tool))
return FALSE
- if(cultist.incapacitated() || cultist.stat == DEAD)
+ if(cultist.incapacitated || cultist.stat == DEAD)
to_chat(cultist, span_warning("You can't draw a rune right now."))
return FALSE
diff --git a/code/datums/components/dejavu.dm b/code/datums/components/dejavu.dm
index 8a1902526c42a..fefa9d7e6bee8 100644
--- a/code/datums/components/dejavu.dm
+++ b/code/datums/components/dejavu.dm
@@ -2,6 +2,7 @@
* A component to reset the parent to its previous state after some time passes
*/
/datum/component/dejavu
+ dupe_mode = COMPONENT_DUPE_ALLOWED
///message sent when dejavu rewinds
var/rewind_message = "You remember a time not so long ago..."
@@ -16,6 +17,8 @@
var/rewinds_remaining
/// How long to wait between each rewind
var/rewind_interval
+ /// Do we add a new component before teleporting the target to they teleport to the place where *we* teleported them from?
+ var/repeating_component
/// The starting value of toxin loss at the beginning of the effect
var/tox_loss = 0
@@ -34,13 +37,14 @@
/// A list of body parts saved at the beginning of the effect
var/list/datum/saved_bodypart/saved_bodyparts
-/datum/component/dejavu/Initialize(rewinds = 1, interval = 10 SECONDS)
+/datum/component/dejavu/Initialize(rewinds = 1, interval = 10 SECONDS, add_component = FALSE)
if(!isatom(parent))
return COMPONENT_INCOMPATIBLE
starting_turf = get_turf(parent)
rewinds_remaining = rewinds
rewind_interval = interval
+ repeating_component = add_component
if(isliving(parent))
var/mob/living/L = parent
@@ -92,6 +96,9 @@
qdel(src)
/datum/component/dejavu/proc/rewind_living()
+ if (rewinds_remaining == 1 && repeating_component && !iscarbon(parent) && !isanimal_or_basicmob(parent))
+ parent.AddComponent(type, 1, rewind_interval, TRUE)
+
var/mob/living/master = parent
master.setToxLoss(tox_loss)
master.setOxyLoss(oxy_loss)
@@ -100,18 +107,27 @@
rewind()
/datum/component/dejavu/proc/rewind_carbon()
+ if (rewinds_remaining == 1 && repeating_component)
+ parent.AddComponent(type, 1, rewind_interval, TRUE)
+
if(saved_bodyparts)
var/mob/living/carbon/master = parent
master.apply_saved_bodyparts(saved_bodyparts)
rewind_living()
/datum/component/dejavu/proc/rewind_animal()
+ if (rewinds_remaining == 1 && repeating_component)
+ parent.AddComponent(type, 1, rewind_interval, TRUE)
+
var/mob/living/master = parent
master.bruteloss = brute_loss
master.updatehealth()
rewind_living()
/datum/component/dejavu/proc/rewind_obj()
+ if (rewinds_remaining == 1 && repeating_component)
+ parent.AddComponent(type, 1, rewind_interval, TRUE)
+
var/obj/master = parent
master.update_integrity(integrity)
rewind()
@@ -124,3 +140,10 @@
/datum/component/dejavu/timeline/rewind()
playsound(get_turf(parent), 'sound/items/modsuit/rewinder.ogg')
. = ..()
+
+/datum/component/dejavu/wizard
+ rewind_message = "Your temporal ward activated, pulling you through spacetime!"
+
+/datum/component/dejavu/wizard/rewind()
+ playsound(get_turf(parent), 'sound/items/modsuit/rewinder.ogg')
+ . = ..()
diff --git a/code/datums/components/creamed.dm b/code/datums/components/face_decal.dm
similarity index 50%
rename from code/datums/components/creamed.dm
rename to code/datums/components/face_decal.dm
index d1ff1b792e17a..f045a4f18df6e 100644
--- a/code/datums/components/creamed.dm
+++ b/code/datums/components/face_decal.dm
@@ -1,37 +1,37 @@
-GLOBAL_LIST_INIT(creamable, typecacheof(list(
- /mob/living/carbon/human,
- /mob/living/basic/pet/dog/corgi,
- /mob/living/silicon/ai)))
/**
- * Creamed component
+ * Face decal component
*
- * For when you have pie on your face
+ * For when you have some dirt on your face
*/
-/datum/component/creamed
- dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
- /// Creampie overlay we use for non-carbon mobs
+
+/datum/component/face_decal
+ dupe_mode = COMPONENT_DUPE_HIGHLANDER
+ /// Overlay we use for non-carbon mobs
var/mutable_appearance/normal_overlay
- /// Creampie bodypart overlay we use for carbon mobs
- var/datum/bodypart_overlay/simple/creampie/bodypart_overlay
- /// Cached head for carbons, to ensure proper removal of the creampie overlay
+ /// Bodypart overlay we use for carbon mobs
+ var/datum/bodypart_overlay/simple/bodypart_overlay
+ /// Cached head for carbons, to ensure proper removal of our overlay
var/obj/item/bodypart/my_head
+ /// Base icon state we use for the effect
+ var/icon_state
+ /// Layers for the bodypart_overlay to draw on
+ var/layers
+ /// Color that the overlay is modified by
+ var/color
-/datum/component/creamed/Initialize()
- if(!is_type_in_typecache(parent, GLOB.creamable))
- return COMPONENT_INCOMPATIBLE
-
- SEND_SIGNAL(parent, COMSIG_MOB_CREAMED, src)
-
- add_memory_in_range(parent, 7, /datum/memory/witnessed_creampie, protagonist = parent)
+/datum/component/face_decal/Initialize(icon_state, layers, color)
+ src.icon_state = icon_state
+ src.layers = layers
+ src.color = color
-/datum/component/creamed/Destroy(force)
+/datum/component/face_decal/Destroy(force)
. = ..()
normal_overlay = null
my_head = null
QDEL_NULL(bodypart_overlay)
-/datum/component/creamed/RegisterWithParent()
+/datum/component/face_decal/RegisterWithParent()
if(iscarbon(parent))
var/mob/living/carbon/human/carbon_parent = parent
my_head = carbon_parent.get_bodypart(BODY_ZONE_HEAD)
@@ -39,32 +39,38 @@ GLOBAL_LIST_INIT(creamable, typecacheof(list(
qdel(src)
return
bodypart_overlay = new()
+ bodypart_overlay.layers = layers
if(carbon_parent.bodyshape & BODYSHAPE_SNOUTED) //stupid, but external organ bodytypes are not stored on the limb
- bodypart_overlay.icon_state = "creampie_lizard"
+ bodypart_overlay.icon_state = "[icon_state]_lizard"
else if(my_head.bodyshape & BODYSHAPE_MONKEY)
- bodypart_overlay.icon_state = "creampie_monkey"
+ bodypart_overlay.icon_state = "[icon_state]_monkey"
else
- bodypart_overlay.icon_state = "creampie_human"
+ bodypart_overlay.icon_state = "[icon_state]_human"
+ if (!isnull(color))
+ bodypart_overlay.draw_color = color
my_head.add_bodypart_overlay(bodypart_overlay)
RegisterSignals(my_head, list(COMSIG_BODYPART_REMOVED, COMSIG_QDELETING), PROC_REF(lost_head))
- carbon_parent.add_mood_event("creampie", /datum/mood_event/creampie)
carbon_parent.update_body_parts()
- else if(iscorgi(parent))
- normal_overlay = mutable_appearance('icons/mob/effects/creampie.dmi', "creampie_corgi")
- else if(isAI(parent))
- normal_overlay = mutable_appearance('icons/mob/effects/creampie.dmi', "creampie_ai")
+ else
+ normal_overlay = get_normal_overlay()
RegisterSignals(parent, list(
COMSIG_COMPONENT_CLEAN_ACT,
COMSIG_COMPONENT_CLEAN_FACE_ACT),
PROC_REF(clean_up)
)
- if(normal_overlay)
+
+ if (!isnull(normal_overlay))
+ if (!isnull(color))
+ normal_overlay.color = color
var/atom/atom_parent = parent
RegisterSignal(atom_parent, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(update_overlays))
atom_parent.update_appearance()
-/datum/component/creamed/UnregisterFromParent()
+/datum/component/face_decal/proc/get_normal_overlay()
+ return
+
+/datum/component/face_decal/UnregisterFromParent()
UnregisterSignal(parent, list(
COMSIG_COMPONENT_CLEAN_ACT,
COMSIG_COMPONENT_CLEAN_FACE_ACT))
@@ -78,7 +84,6 @@ GLOBAL_LIST_INIT(creamable, typecacheof(list(
my_head = null
if(iscarbon(parent))
var/mob/living/carbon/carbon_parent = parent
- carbon_parent.clear_mood_event("creampie")
carbon_parent.update_body_parts()
if(normal_overlay)
var/atom/atom_parent = parent
@@ -86,8 +91,8 @@ GLOBAL_LIST_INIT(creamable, typecacheof(list(
atom_parent.update_appearance()
normal_overlay = null
-///Callback to remove pieface
-/datum/component/creamed/proc/clean_up(datum/source, clean_types)
+///Callback to remove our decal
+/datum/component/face_decal/proc/clean_up(datum/source, clean_types)
SIGNAL_HANDLER
if(!(clean_types & CLEAN_TYPE_BLOOD))
@@ -97,14 +102,48 @@ GLOBAL_LIST_INIT(creamable, typecacheof(list(
return COMPONENT_CLEANED
/// Ensures normal_overlay overlay in case the mob is not a carbon
-/datum/component/creamed/proc/update_overlays(atom/parent_atom, list/overlays)
+/datum/component/face_decal/proc/update_overlays(atom/parent_atom, list/overlays)
SIGNAL_HANDLER
if(normal_overlay)
overlays += normal_overlay
-/// Removes creampie when the head gets dismembered
-/datum/component/creamed/proc/lost_head(obj/item/bodypart/source, mob/living/carbon/owner, dismembered)
+/// Removes the decal when the head gets dismembered
+/datum/component/face_decal/proc/lost_head(obj/item/bodypart/source, mob/living/carbon/owner, dismembered)
SIGNAL_HANDLER
-
qdel(src)
+
+/// Creampie subtype, handling signals and mood logic
+
+GLOBAL_LIST_INIT(creamable, typecacheof(list(
+ /mob/living/carbon/human,
+ /mob/living/basic/pet/dog/corgi,
+ /mob/living/silicon/ai,
+)))
+
+/datum/component/face_decal/creampie/Initialize()
+ . = ..()
+ if(!is_type_in_typecache(parent, GLOB.creamable))
+ return COMPONENT_INCOMPATIBLE
+
+ SEND_SIGNAL(parent, COMSIG_MOB_CREAMED, src)
+ add_memory_in_range(parent, 7, /datum/memory/witnessed_creampie, protagonist = parent)
+
+/datum/component/face_decal/creampie/get_normal_overlay()
+ if(iscorgi(parent))
+ return mutable_appearance('icons/mob/effects/creampie.dmi', "[icon_state]_corgi")
+
+ if(isAI(parent))
+ return mutable_appearance('icons/mob/effects/creampie.dmi', "[icon_state]_ai")
+
+/datum/component/face_decal/creampie/RegisterWithParent()
+ . = ..()
+ if(iscarbon(parent))
+ var/mob/living/carbon/human/carbon_parent = parent
+ carbon_parent.add_mood_event("creampie", /datum/mood_event/creampie)
+
+/datum/component/face_decal/creampie/UnregisterFromParent()
+ . = ..()
+ if(iscarbon(parent))
+ var/mob/living/carbon/carbon_parent = parent
+ carbon_parent.clear_mood_event("creampie")
diff --git a/code/datums/components/fishing_spot.dm b/code/datums/components/fishing_spot.dm
index 6638c822ff6a5..cc21f22eb4b62 100644
--- a/code/datums/components/fishing_spot.dm
+++ b/code/datums/components/fishing_spot.dm
@@ -12,7 +12,7 @@
fish_source = configuration
else
return COMPONENT_INCOMPATIBLE
- fish_source.on_fishing_spot_init()
+ fish_source.on_fishing_spot_init(src)
RegisterSignal(parent, COMSIG_ATOM_ATTACKBY, PROC_REF(handle_attackby))
RegisterSignal(parent, COMSIG_FISHING_ROD_CAST, PROC_REF(handle_cast))
RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examined))
@@ -22,6 +22,7 @@
ADD_TRAIT(parent, TRAIT_FISHING_SPOT, REF(src))
/datum/component/fishing_spot/Destroy()
+ fish_source.on_fishing_spot_del(src)
fish_source = null
return ..()
diff --git a/code/datums/components/food/edible.dm b/code/datums/components/food/edible.dm
index 056f1e5791e6c..c034300f982fe 100644
--- a/code/datums/components/food/edible.dm
+++ b/code/datums/components/food/edible.dm
@@ -40,6 +40,8 @@ Behavior that's still missing from this component that original food items had t
var/volume = 50
///The flavortext for taste (haha get it flavor text)
var/list/tastes
+ ///Whether to tell the examiner that this is edible or not.
+ var/show_examine = TRUE
/datum/component/edible/Initialize(
list/initial_reagents,
@@ -55,6 +57,7 @@ Behavior that's still missing from this component that original food items had t
datum/callback/on_consume,
datum/callback/check_liked,
reagent_purity = 0.5,
+ show_examine = TRUE,
)
if(!isatom(parent))
return COMPONENT_INCOMPATIBLE
@@ -70,12 +73,13 @@ Behavior that's still missing from this component that original food items had t
src.on_consume = on_consume
src.tastes = string_assoc_list(tastes)
src.check_liked = check_liked
+ src.show_examine = show_examine
setup_initial_reagents(initial_reagents, reagent_purity)
/datum/component/edible/RegisterWithParent()
RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(examine))
- RegisterSignals(parent, COMSIG_ATOM_ATTACK_ANIMAL, PROC_REF(UseByAnimal))
+ RegisterSignal(parent, COMSIG_ATOM_ATTACK_ANIMAL, PROC_REF(UseByAnimal))
RegisterSignal(parent, COMSIG_ATOM_CHECKPARTS, PROC_REF(OnCraft))
RegisterSignal(parent, COMSIG_ATOM_CREATEDBY_PROCESSING, PROC_REF(OnProcessed))
RegisterSignal(parent, COMSIG_FOOD_INGREDIENT_ADDED, PROC_REF(edible_ingredient_added))
@@ -212,7 +216,8 @@ Behavior that's still missing from this component that original food items had t
SIGNAL_HANDLER
var/atom/owner = parent
-
+ if(!show_examine)
+ return
if(foodtypes)
var/list/types = bitfield_to_list(foodtypes, FOOD_FLAGS)
examine_list += span_notice("It is [LOWER_TEXT(english_list(types))].")
@@ -523,13 +528,13 @@ Behavior that's still missing from this component that original food items had t
/datum/component/edible/proc/apply_buff(mob/eater)
var/buff
var/recipe_complexity = get_recipe_complexity()
- if(recipe_complexity == 0)
+ if(recipe_complexity <= 0)
return
var/obj/item/food/food = parent
if(!isnull(food.crafted_food_buff))
buff = food.crafted_food_buff
else
- buff = pick_weight(GLOB.food_buffs[recipe_complexity])
+ buff = pick_weight(GLOB.food_buffs[min(recipe_complexity, FOOD_COMPLEXITY_5)])
if(!isnull(buff))
var/mob/living/living_eater = eater
var/atom/owner = parent
@@ -590,10 +595,13 @@ Behavior that's still missing from this component that original food items had t
/// Get the complexity of the crafted food
/datum/component/edible/proc/get_recipe_complexity()
+ var/list/extra_complexity = list(0)
+ SEND_SIGNAL(parent, COMSIG_FOOD_GET_EXTRA_COMPLEXITY, extra_complexity)
+ var/complexity_to_add = extra_complexity[1]
if(!HAS_TRAIT(parent, TRAIT_FOOD_CHEF_MADE) || !istype(parent, /obj/item/food))
- return 0 // It is factory made. Soulless.
+ return complexity_to_add // It is factory made. Soulless.
var/obj/item/food/food = parent
- return food.crafting_complexity
+ return food.crafting_complexity + complexity_to_add
/// Get food quality adjusted according to eater's preferences
/datum/component/edible/proc/get_perceived_food_quality(mob/living/carbon/human/eater)
diff --git a/code/datums/components/food/germ_sensitive.dm b/code/datums/components/food/germ_sensitive.dm
index d0acc49714ab5..3e47c3fe1ecd8 100644
--- a/code/datums/components/food/germ_sensitive.dm
+++ b/code/datums/components/food/germ_sensitive.dm
@@ -25,7 +25,7 @@ GLOBAL_LIST_INIT(floor_diseases, list(
RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(examine))
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(handle_movement))
- RegisterSignal(parent, COMSIG_COMPONENT_CLEAN_ACT, PROC_REF(wash)) //Wash germs off dirty things
+ RegisterSignals(parent, list(COMSIG_COMPONENT_CLEAN_ACT, COMSIG_ITEM_FRIED, COMSIG_ITEM_BARBEQUE_GRILLED, COMSIG_ATOM_FIRE_ACT), PROC_REF(delete_germs))
RegisterSignals(parent, list(
COMSIG_ITEM_DROPPED, //Dropped into the world
@@ -50,6 +50,9 @@ GLOBAL_LIST_INIT(floor_diseases, list(
COMSIG_ATOM_EXAMINE,
COMSIG_ATOM_EXITED,
COMSIG_COMPONENT_CLEAN_ACT,
+ COMSIG_ITEM_FRIED,
+ COMSIG_ITEM_BARBEQUE_GRILLED,
+ COMSIG_ATOM_FIRE_ACT,
COMSIG_ITEM_DROPPED,
COMSIG_ITEM_PICKUP,
COMSIG_MOVABLE_MOVED,
@@ -116,7 +119,7 @@ GLOBAL_LIST_INIT(floor_diseases, list(
var/random_disease = pick_weight(GLOB.floor_diseases)
parent.AddComponent(/datum/component/infective, new random_disease, weak = TRUE)
-/datum/component/germ_sensitive/proc/wash()
+/datum/component/germ_sensitive/proc/delete_germs()
SIGNAL_HANDLER
if(infective)
infective = FALSE
diff --git a/code/datums/components/fullauto.dm b/code/datums/components/fullauto.dm
index 1faa04ceacc75..a3f2009b3b506 100644
--- a/code/datums/components/fullauto.dm
+++ b/code/datums/components/fullauto.dm
@@ -275,7 +275,7 @@
// Gun procs.
/obj/item/gun/proc/on_autofire_start(mob/living/shooter)
- if(semicd || shooter.incapacitated() || !can_trigger_gun(shooter))
+ if(semicd || shooter.incapacitated || !can_trigger_gun(shooter))
return FALSE
if(!can_shoot())
shoot_with_empty_chamber(shooter)
@@ -295,7 +295,7 @@
/obj/item/gun/proc/do_autofire(datum/source, atom/target, mob/living/shooter, allow_akimbo, params)
SIGNAL_HANDLER
- if(semicd || shooter.incapacitated())
+ if(semicd || shooter.incapacitated)
return NONE
if(!can_shoot())
shoot_with_empty_chamber(shooter)
diff --git a/code/datums/components/gunpoint.dm b/code/datums/components/gunpoint.dm
index ed4142f41ceba..edde591c0c386 100644
--- a/code/datums/components/gunpoint.dm
+++ b/code/datums/components/gunpoint.dm
@@ -48,7 +48,7 @@
RegisterSignals(targ, list(COMSIG_LIVING_DISARM_HIT, COMSIG_LIVING_GET_PULLED), PROC_REF(cancel))
RegisterSignals(weapon, list(COMSIG_ITEM_DROPPED, COMSIG_ITEM_EQUIPPED), PROC_REF(cancel))
- var/distance = min(get_dist(shooter, target), 1) // treat 0 distance as adjacent
+ var/distance = max(get_dist(shooter, target), 1) // treat 0 distance as adjacent
var/distance_description = (distance <= 1 ? "point blank " : "")
shooter.visible_message(span_danger("[shooter] aims [weapon] [distance_description]at [target]!"),
diff --git a/code/datums/components/material/material_container.dm b/code/datums/components/material/material_container.dm
index 6ee50f5d78c94..10544116ce579 100644
--- a/code/datums/components/material/material_container.dm
+++ b/code/datums/components/material/material_container.dm
@@ -124,10 +124,10 @@
* Material Validation : Checks how much materials are available, Extracts materials from items if the container can hold them
* Material Removal : Removes material from the container
*
- * Each Proc furthur belongs to a specific category
+ * Each Proc further belongs to a specific category
* LOW LEVEL: Procs that are used internally & should not be used anywhere else unless you know what your doing
* MID LEVEL: Procs that can be used by machines(like recycler, stacking machines) to bypass majority of checks
- * HIGH LEVEL: Procs that can be used by anyone publically and guarentees safty checks & limits
+ * HIGH LEVEL: Procs that can be used by anyone publicly and guarantees safety checks & limits
*/
//================================Material Insertion procs==============================
@@ -236,7 +236,7 @@
//do the insert
var/last_inserted_id = insert_item_materials(target, multiplier, context)
if(!isnull(last_inserted_id))
- if(delete_item || target != weapon) //we could have split the stack ourself
+ if(delete_item || target != weapon) //we could have split the stack ourselves
qdel(target) //item gone
return material_amount
else if(!isnull(item_stack) && item_stack != target) //insertion failed, merge the split stack back into the original
@@ -250,7 +250,7 @@
//===================================HIGH LEVEL===================================================
/**
- * inserts an item from the players hand into the container. Loops through all the contents inside reccursively
+ * inserts an item from the players hand into the container. Loops through all the contents inside recursively
* Does all explicit checking for mat flags & callbacks to check if insertion is valid
* This proc is what you should be using for almost all cases
*
@@ -259,7 +259,7 @@
* * user - the mob inserting this item
* * context - the atom performing the operation, this is the last argument sent in COMSIG_MATCONTAINER_ITEM_CONSUMED and is used mostly for silo logging
*/
-/datum/component/material_container/proc/user_insert(obj/item/held_item, mob/living/user, atom/context = parent)
+/datum/component/material_container/proc/user_insert(obj/item/held_item, mob/living/user, atom/context = parent, forced_type = FALSE)
set waitfor = FALSE
. = 0
@@ -297,7 +297,7 @@
if(SEND_SIGNAL(src, COMSIG_MATCONTAINER_PRE_USER_INSERT, target_item, user) & MATCONTAINER_BLOCK_INSERT)
continue
//item is either indestructible, not allowed for redemption or not in the allowed types
- if((target_item.resistance_flags & INDESTRUCTIBLE) || (target_item.item_flags & NO_MAT_REDEMPTION) || (allowed_item_typecache && !is_type_in_typecache(target_item, allowed_item_typecache)))
+ if((target_item.resistance_flags & INDESTRUCTIBLE) || (target_item.item_flags & NO_MAT_REDEMPTION) || (allowed_item_typecache && !is_type_in_typecache(target_item, allowed_item_typecache) && !forced_type))
if(!(mat_container_flags & MATCONTAINER_SILENT))
var/list/status_data = chat_msgs["[MATERIAL_INSERT_ITEM_FAILURE]"] || list()
var/list/item_data = status_data[target_item.name] || list()
@@ -455,9 +455,9 @@
if(MATERIAL_INSERT_ITEM_SUCCESS) //no problems full item was consumed
if(chat_data["stack"])
var/sheets = min(count, amount) //minimum between sheets inserted vs sheets consumed(values differ for alloys)
- to_chat(user, span_notice("[sheets > 1 ? sheets : ""] [item_name][sheets > 1 ? "s were" : " was"] added to [parent]."))
+ to_chat(user, span_notice("[sheets > 1 ? "[sheets] " : ""][item_name][sheets > 1 ? "s were" : " was"] added to [parent]."))
else
- to_chat(user, span_notice("[count > 1 ? count : ""] [item_name][count > 1 ? "s" : ""], worth [amount] sheets, [count > 1 ? "were" : "was"] added to [parent]."))
+ to_chat(user, span_notice("[count > 1 ? "[count] " : ""][item_name][count > 1 ? "s" : ""], worth [amount] sheets, [count > 1 ? "were" : "was"] added to [parent]."))
if(MATERIAL_INSERT_ITEM_NO_SPACE) //no space
to_chat(user, span_warning("[parent] has no space to accept [item_name]!"))
if(MATERIAL_INSERT_ITEM_NO_MATS) //no materials inside these items
@@ -584,7 +584,7 @@
for(var/x in mats) //Loop through all required materials
var/wanted = OPTIMAL_COST(mats[x] * coefficient) * multiplier
if(!has_enough_of_material(x, wanted))//Not a category, so just check the normal way
- testing("didnt have: [x] wanted: [wanted]")
+ testing("didn't have: [x] wanted: [wanted]")
return FALSE
return TRUE
@@ -605,7 +605,7 @@
//round amount
amt = OPTIMAL_COST(amt)
- //get ref if nessassary
+ //get ref if necessary
if(!istype(mat))
mat = GET_MATERIAL_REF(mat)
diff --git a/code/datums/components/material/remote_materials.dm b/code/datums/components/material/remote_materials.dm
index d630ce8e77f9b..8ae52069c1bcb 100644
--- a/code/datums/components/material/remote_materials.dm
+++ b/code/datums/components/material/remote_materials.dm
@@ -23,13 +23,16 @@ handles linking back and forth.
var/mat_container_flags = NONE
///List of signals to hook onto the local container
var/list/mat_container_signals
+ ///Typecache for items that the silo will accept through this remote no matter what
+ var/list/whitelist_typecache
/datum/component/remote_materials/Initialize(
mapload,
allow_standalone = TRUE,
force_connect = FALSE,
mat_container_flags = NONE,
- list/mat_container_signals = null
+ list/mat_container_signals = null,
+ list/whitelist_typecache = null
)
if (!isatom(parent))
return COMPONENT_INCOMPATIBLE
@@ -37,6 +40,7 @@ handles linking back and forth.
src.allow_standalone = allow_standalone
src.mat_container_flags = mat_container_flags
src.mat_container_signals = mat_container_signals
+ src.whitelist_typecache = whitelist_typecache
RegisterSignal(parent, COMSIG_ATOM_TOOL_ACT(TOOL_MULTITOOL), PROC_REF(OnMultitool))
@@ -93,6 +97,9 @@ handles linking back and forth.
allowed_items = /obj/item/stack \
)
+ if (whitelist_typecache)
+ mat_container.allowed_item_typecache |= whitelist_typecache
+
/datum/component/remote_materials/proc/toggle_holding(force_hold = FALSE)
if(isnull(silo))
return
@@ -140,7 +147,7 @@ handles linking back and forth.
return
if(silo)
- mat_container.user_insert(target, user, parent)
+ mat_container.user_insert(target, user, parent, (whitelist_typecache && is_type_in_typecache(target, whitelist_typecache)))
return COMPONENT_NO_AFTERATTACK
diff --git a/code/datums/components/mind_linker.dm b/code/datums/components/mind_linker.dm
index ba3f0a6841bee..4449a8fe36e8e 100644
--- a/code/datums/components/mind_linker.dm
+++ b/code/datums/components/mind_linker.dm
@@ -184,7 +184,7 @@
return ..()
/datum/component/mind_linker/active_linking/link_mob(mob/living/to_link)
- if(HAS_TRAIT(to_link, TRAIT_MINDSHIELD)) // Mindshield implant - no dice
+ if(HAS_MIND_TRAIT(to_link, TRAIT_UNCONVERTABLE)) // Protected mind, so they can't be added to the mindlink
return FALSE
if(to_link.can_block_magic(MAGIC_RESISTANCE_MIND, charge_cost = 0))
return FALSE
diff --git a/code/datums/components/omen.dm b/code/datums/components/omen.dm
index e4094ba679a7e..bb72654f978ae 100644
--- a/code/datums/components/omen.dm
+++ b/code/datums/components/omen.dm
@@ -143,12 +143,12 @@
return
for(var/obj/machinery/light/evil_light in the_turf)
- if((evil_light.status == LIGHT_BURNED || evil_light.status == LIGHT_BROKEN) || (HAS_TRAIT(living_guy, TRAIT_SHOCKIMMUNE))) // we cant do anything :( // Why in the world is there no get_siemens_coeff proc???
+ if((evil_light.status == LIGHT_BURNED || evil_light.status == LIGHT_BROKEN) || (HAS_TRAIT(living_guy, TRAIT_SHOCKIMMUNE))) // we can't do anything :( // Why in the world is there no get_siemens_coeff proc???
to_chat(living_guy, span_warning("[evil_light] sparks weakly for a second."))
do_sparks(2, FALSE, evil_light) // hey maybe it'll ignite them
return
- to_chat(living_guy, span_warning("[evil_light] glows ominously...")) // omenously
+ to_chat(living_guy, span_warning("[evil_light] glows ominously...")) // ominously
evil_light.visible_message(span_boldwarning("[evil_light] suddenly flares brightly and sparks!"))
evil_light.break_light_tube(skip_sound_and_sparks = FALSE)
do_sparks(number = 4, cardinal_only = FALSE, source = evil_light)
diff --git a/code/datums/components/overlay_lighting.dm b/code/datums/components/overlay_lighting.dm
index 258b8f87972e0..642feee3ac0e8 100644
--- a/code/datums/components/overlay_lighting.dm
+++ b/code/datums/components/overlay_lighting.dm
@@ -62,13 +62,13 @@
var/directional = FALSE
///Whether we're a beam light
var/beam = FALSE
- ///A cone overlay for directional light, its alpha and color are dependant on the light
+ ///A cone overlay for directional light, its alpha and color are dependent on the light
var/image/cone
///Current tracked direction for the directional cast behaviour
var/current_direction
- ///Tracks current directional x offset so we dont update unecessarily
+ ///Tracks current directional x offset so we don't update unnecessarily
var/directional_offset_x
- ///Tracks current directional y offset so we dont update unecessarily
+ ///Tracks current directional y offset so we don't update unnecessarily
var/directional_offset_y
///Cast range for the directional cast (how far away the atom is moved)
var/cast_range = 2
diff --git a/code/datums/components/pet_commands/pet_command.dm b/code/datums/components/pet_commands/pet_command.dm
index a8db88d3a44ef..52b4cc8834920 100644
--- a/code/datums/components/pet_commands/pet_command.dm
+++ b/code/datums/components/pet_commands/pet_command.dm
@@ -186,14 +186,14 @@
/datum/pet_command/point_targeting/add_new_friend(mob/living/tamer)
. = ..()
- RegisterSignal(tamer, COMSIG_MOB_POINTED, PROC_REF(on_point))
+ RegisterSignal(tamer, COMSIG_MOVABLE_POINTED, PROC_REF(on_point))
/datum/pet_command/point_targeting/remove_friend(mob/living/unfriended)
. = ..()
- UnregisterSignal(unfriended, COMSIG_MOB_POINTED)
+ UnregisterSignal(unfriended, COMSIG_MOVABLE_POINTED)
/// Target the pointed atom for actions
-/datum/pet_command/point_targeting/proc/on_point(mob/living/friend, atom/pointed_atom)
+/datum/pet_command/point_targeting/proc/on_point(mob/living/friend, atom/pointed_atom, obj/effect/temp_visual/point/point)
SIGNAL_HANDLER
var/mob/living/parent = weak_parent.resolve()
diff --git a/code/datums/components/phylactery.dm b/code/datums/components/phylactery.dm
index 4a58660992a8d..572f816b5ad22 100644
--- a/code/datums/components/phylactery.dm
+++ b/code/datums/components/phylactery.dm
@@ -18,7 +18,7 @@
var/phylactery_color = COLOR_VERY_DARK_LIME_GREEN
// Internal vars.
- /// The number of ressurections that have occured from this phylactery.
+ /// The number of resurrections that have occurred from this phylactery.
var/num_resurrections = 0
/// A timerid to the current revival timer.
var/revive_timer
@@ -150,7 +150,7 @@
UnregisterSignal(source, COMSIG_LIVING_REVIVE)
/**
- * Actually undergo the process of reviving the lich at the site of the phylacery.
+ * Actually undergo the process of reviving the lich at the site of the phylactery.
*
* Arguments
* * corpse - optional, the old body of the lich. Can be QDELETED or null.
diff --git a/code/datums/components/pinata.dm b/code/datums/components/pinata.dm
index 064bc2de26b26..62e1a8e55527f 100644
--- a/code/datums/components/pinata.dm
+++ b/code/datums/components/pinata.dm
@@ -1,8 +1,8 @@
-///Objects or mobs with this componenet will drop items when taking damage.
+///Objects or mobs with this component will drop items when taking damage.
/datum/component/pinata
///How much damage does an attack need to do to have a chance to drop "candy"
var/minimum_damage
- ///What is the likelyhood some "candy" should drop when attacked.
+ ///What is the likelihood some "candy" should drop when attacked.
var/drop_chance
///A list of "candy" items that can be dropped when taking damage
var/candy
diff --git a/code/datums/components/profound_fisher.dm b/code/datums/components/profound_fisher.dm
index 4485115db06e6..947e9d26f5197 100644
--- a/code/datums/components/profound_fisher.dm
+++ b/code/datums/components/profound_fisher.dm
@@ -1,39 +1,107 @@
-///component that allows player mobs to play the fishing minigame, non-player mobs will "pretend" fish
+///component that allows player mobs to play the fishing minigame without a rod equipped, non-player mobs will "pretend" fish
/datum/component/profound_fisher
///the fishing rod this mob will use
var/obj/item/fishing_rod/mob_fisher/our_rod
-/datum/component/profound_fisher/Initialize(list/npc_fishing_preset = list())
- if(!isliving(parent))
- return
- our_rod = new(parent)
- ADD_TRAIT(parent, TRAIT_PROFOUND_FISHER, REF(src))
+/datum/component/profound_fisher/Initialize(our_rod)
+ var/isgloves = istype(parent, /obj/item/clothing/gloves)
+ if(!isliving(parent) && !isgloves)
+ return COMPONENT_INCOMPATIBLE
+ src.our_rod = our_rod || new(parent)
+ src.our_rod.internal = TRUE
+ RegisterSignal(src.our_rod, COMSIG_QDELETING, PROC_REF(on_rod_qdel))
+
+ if(!isgloves)
+ RegisterSignal(parent, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(pre_attack))
+ else
+ var/obj/item/clothing/gloves = parent
+ RegisterSignal(gloves, COMSIG_ITEM_EQUIPPED, PROC_REF(on_equip))
+ RegisterSignal(gloves, COMSIG_ITEM_DROPPED, PROC_REF(on_drop))
+ RegisterSignal(gloves, COMSIG_ATOM_ATTACK_HAND_SECONDARY, PROC_REF(open_rod_menu))
+ RegisterSignal(gloves, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine))
+ gloves.flags_1 |= HAS_CONTEXTUAL_SCREENTIPS_1
+ RegisterSignal(gloves, COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM, PROC_REF(on_requesting_context_from_item))
+ var/mob/living/wearer = gloves.loc
+ if(istype(wearer) && wearer.get_item_by_slot(ITEM_SLOT_GLOVES) == gloves)
+ RegisterSignal(wearer, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(on_unarmed_attack))
-/datum/component/profound_fisher/RegisterWithParent()
- RegisterSignal(parent, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(pre_attack))
+/datum/component/profound_fisher/proc/on_requesting_context_from_item(datum/source, list/context, obj/item/held_item, mob/living/user)
+ SIGNAL_HANDLER
+ if(isnull(held_item) && user.contains(parent))
+ context[SCREENTIP_CONTEXT_RMB] = "Open rod UI"
+ return CONTEXTUAL_SCREENTIP_SET
-/datum/component/profound_fisher/UnregisterFromParent()
- UnregisterSignal(parent, COMSIG_HOSTILE_PRE_ATTACKINGTARGET)
- REMOVE_TRAIT(parent, TRAIT_PROFOUND_FISHER, REF(src))
+/datum/component/profound_fisher/proc/on_examine(datum/source, mob/user, list/examine_list)
+ SIGNAL_HANDLER
+ examine_list += span_info("When [EXAMINE_HINT("held")] or [EXAMINE_HINT("equipped")], [EXAMINE_HINT("right-click")] with a empty hand to open the integrated fishing rod interface.")
+ examine_list += span_tinynoticeital("To fish, you need to turn combat mode off.")
+
+/datum/component/profound_fisher/proc/on_rod_qdel(datum/source)
+ SIGNAL_HANDLER
+ qdel(src)
/datum/component/profound_fisher/Destroy()
- QDEL_NULL(our_rod)
+ our_rod.internal = FALSE
+ UnregisterSignal(our_rod, COMSIG_QDELETING)
+ our_rod = null
return ..()
-/datum/component/profound_fisher/proc/pre_attack(datum/source, atom/target)
+/datum/component/profound_fisher/proc/on_equip(obj/item/source, atom/equipper, slot)
SIGNAL_HANDLER
+ if(slot != ITEM_SLOT_GLOVES)
+ return
+ RegisterSignal(equipper, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(on_unarmed_attack))
- if(!HAS_TRAIT(target, TRAIT_FISHING_SPOT))
- return NONE
- var/mob/living/living_parent = parent
- if(living_parent.combat_mode || !living_parent.CanReach(target))
- return NONE
- if(living_parent.client)
- INVOKE_ASYNC(our_rod, TYPE_PROC_REF(/obj/item, melee_attack_chain), parent, target)
+/datum/component/profound_fisher/proc/open_rod_menu(datum/source, mob/user, list/modifiers)
+ SIGNAL_HANDLER
+ INVOKE_ASYNC(our_rod, TYPE_PROC_REF(/datum, ui_interact), user)
+ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
+
+/datum/component/profound_fisher/proc/on_drop(datum/source, atom/dropper)
+ SIGNAL_HANDLER
+ UnregisterSignal(dropper, COMSIG_LIVING_UNARMED_ATTACK)
+ REMOVE_TRAIT(dropper, TRAIT_PROFOUND_FISHER, TRAIT_GENERIC) //this will cancel the current minigame if the fishing rod was internal.
+
+/datum/component/profound_fisher/proc/on_unarmed_attack(mob/living/source, atom/attack_target, proximity_flag, list/modifiers)
+ SIGNAL_HANDLER
+ if(!source.client || !should_fish_on(source, attack_target))
+ return
+ INVOKE_ASYNC(src, PROC_REF(begin_fishing), source, attack_target)
+ return COMPONENT_CANCEL_ATTACK_CHAIN
+
+/datum/component/profound_fisher/proc/pre_attack(mob/living/source, atom/target)
+ SIGNAL_HANDLER
+
+ if(!should_fish_on(source, target))
+ return
+ if(source.client)
+ INVOKE_ASYNC(src, PROC_REF(begin_fishing), source, target)
else
INVOKE_ASYNC(src, PROC_REF(pretend_fish), target)
return COMPONENT_HOSTILE_NO_ATTACK
+/datum/component/profound_fisher/proc/should_fish_on(mob/living/user, atom/target)
+ if(!HAS_TRAIT(target, TRAIT_FISHING_SPOT) || HAS_TRAIT(user, TRAIT_GONE_FISHING))
+ return FALSE
+ if(user.combat_mode || !user.CanReach(target))
+ return FALSE
+ return TRUE
+
+/datum/component/profound_fisher/proc/begin_fishing(mob/living/user, atom/target)
+ RegisterSignal(user, SIGNAL_ADDTRAIT(TRAIT_GONE_FISHING), PROC_REF(actually_fishing_with_internal_rod))
+ our_rod.melee_attack_chain(user, target)
+ UnregisterSignal(user, SIGNAL_ADDTRAIT(TRAIT_GONE_FISHING))
+
+/datum/component/profound_fisher/proc/actually_fishing_with_internal_rod(datum/source)
+ SIGNAL_HANDLER
+ ADD_TRAIT(source, TRAIT_PROFOUND_FISHER, REF(parent))
+ RegisterSignal(source, SIGNAL_REMOVETRAIT(TRAIT_GONE_FISHING), PROC_REF(remove_profound_fisher))
+
+/datum/component/profound_fisher/proc/remove_profound_fisher(datum/source)
+ SIGNAL_HANDLER
+ REMOVE_TRAIT(source, TRAIT_PROFOUND_FISHER, TRAIT_GENERIC)
+ UnregisterSignal(source, SIGNAL_REMOVETRAIT(TRAIT_GONE_FISHING))
+
/datum/component/profound_fisher/proc/pretend_fish(atom/target)
var/mob/living/living_parent = parent
if(DOING_INTERACTION_WITH_TARGET(living_parent, target))
@@ -56,8 +124,6 @@
qdel(lure)
/obj/item/fishing_rod/mob_fisher
- display_fishing_line = FALSE
line = /obj/item/fishing_line/reinforced
bait = /obj/item/food/bait/doughball/synthetic/unconsumable
-
-
+ resistance_flags = INDESTRUCTIBLE
diff --git a/code/datums/components/riding/riding.dm b/code/datums/components/riding/riding.dm
index 7ead11012b024..cfdaf605878bf 100644
--- a/code/datums/components/riding/riding.dm
+++ b/code/datums/components/riding/riding.dm
@@ -9,7 +9,6 @@
/datum/component/riding
dupe_mode = COMPONENT_DUPE_UNIQUE
- var/last_move_diagonal = FALSE
///tick delay between movements, lower = faster, higher = slower
var/vehicle_move_delay = 2
diff --git a/code/datums/components/riding/riding_mob.dm b/code/datums/components/riding/riding_mob.dm
index 50798fce50157..1e3c94d84c6a3 100644
--- a/code/datums/components/riding/riding_mob.dm
+++ b/code/datums/components/riding/riding_mob.dm
@@ -58,10 +58,10 @@
if(living_parent.body_position != STANDING_UP) // if we move while on the ground, the rider falls off
. = FALSE
// for piggybacks and (redundant?) borg riding, check if the rider is stunned/restrained
- else if((ride_check_flags & RIDER_NEEDS_ARMS) && (HAS_TRAIT(rider, TRAIT_RESTRAINED) || rider.incapacitated(IGNORE_RESTRAINTS|IGNORE_GRAB)))
+ else if((ride_check_flags & RIDER_NEEDS_ARMS) && (HAS_TRAIT(rider, TRAIT_RESTRAINED) || INCAPACITATED_IGNORING(rider, INCAPABLE_RESTRAINTS|INCAPABLE_GRAB)))
. = FALSE
// for fireman carries, check if the ridden is stunned/restrained
- else if((ride_check_flags & CARRIER_NEEDS_ARM) && (HAS_TRAIT(living_parent, TRAIT_RESTRAINED) || living_parent.incapacitated(IGNORE_RESTRAINTS|IGNORE_GRAB)))
+ else if((ride_check_flags & CARRIER_NEEDS_ARM) && (HAS_TRAIT(living_parent, TRAIT_RESTRAINED) || INCAPACITATED_IGNORING(living_parent, INCAPABLE_RESTRAINTS|INCAPABLE_GRAB)))
. = FALSE
else if((ride_check_flags & JUST_FRIEND_RIDERS) && !(living_parent.faction.Find(REF(rider))))
. = FALSE
@@ -105,9 +105,7 @@
to_chat(user, span_warning("You need a [initial(key.name)] to ride [movable_parent]!"))
return COMPONENT_DRIVER_BLOCK_MOVE
var/mob/living/living_parent = parent
- var/turf/next = get_step(living_parent, direction)
step(living_parent, direction)
- last_move_diagonal = ((direction & (direction - 1)) && (living_parent.loc == next))
var/modified_move_cooldown = vehicle_move_cooldown
var/modified_move_delay = vehicle_move_delay
if(ishuman(user) && HAS_TRAIT(user, TRAIT_ROUGHRIDER)) // YEEHAW!
@@ -133,7 +131,7 @@
if(SANITY_LEVEL_INSANE)
modified_move_cooldown *= 1.2
modified_move_delay *= 1.2
- COOLDOWN_START(src, vehicle_move_cooldown = modified_move_cooldown, (last_move_diagonal ? 2 : 1) * modified_move_delay)
+ COOLDOWN_START(src, vehicle_move_cooldown = modified_move_cooldown, modified_move_delay)
return ..()
/// Yeets the rider off, used for animals and cyborgs, redefined for humans who shove their piggyback rider off
@@ -515,9 +513,9 @@
/datum/component/riding/creature/leaper/Initialize(mob/living/riding_mob, force = FALSE, ride_check_flags = NONE, potion_boost = FALSE)
. = ..()
- RegisterSignal(riding_mob, COMSIG_MOB_POINTED, PROC_REF(attack_pointed))
+ RegisterSignal(riding_mob, COMSIG_MOVABLE_POINTED, PROC_REF(attack_pointed))
-/datum/component/riding/creature/leaper/proc/attack_pointed(mob/living/rider, atom/pointed)
+/datum/component/riding/creature/leaper/proc/attack_pointed(mob/living/rider, atom/pointed, obj/effect/temp_visual/point/point)
SIGNAL_HANDLER
if(!isclosedturf(pointed))
return
@@ -529,7 +527,7 @@
/datum/component/riding/leaper/handle_unbuckle(mob/living/rider)
. = ..()
- UnregisterSignal(rider, COMSIG_MOB_POINTED)
+ UnregisterSignal(rider, COMSIG_MOVABLE_POINTED)
/datum/component/riding/creature/raptor
require_minigame = TRUE
diff --git a/code/datums/components/riding/riding_vehicle.dm b/code/datums/components/riding/riding_vehicle.dm
index 5555369c67ae8..f7ee78673e057 100644
--- a/code/datums/components/riding/riding_vehicle.dm
+++ b/code/datums/components/riding/riding_vehicle.dm
@@ -97,8 +97,7 @@
return
step(movable_parent, direction)
- last_move_diagonal = ((direction & (direction - 1)) && (movable_parent.loc == next))
- COOLDOWN_START(src, vehicle_move_cooldown, (last_move_diagonal? 2 : 1) * vehicle_move_delay)
+ COOLDOWN_START(src, vehicle_move_cooldown, vehicle_move_delay)
if(QDELETED(src))
return
diff --git a/code/datums/components/soapbox.dm b/code/datums/components/soapbox.dm
index 4622cc089288c..4d4577d5e12c8 100644
--- a/code/datums/components/soapbox.dm
+++ b/code/datums/components/soapbox.dm
@@ -33,7 +33,7 @@
SIGNAL_HANDLER
for(var/atom/movable/loud as anything in soapboxers)
UnregisterSignal(loud, COMSIG_MOB_SAY)
- soapboxers = list()
+ soapboxers.Cut()
///Gives a mob a unique say span
/datum/component/soapbox/proc/soapbox_speech(datum/source, list/speech_args)
diff --git a/code/datums/components/space_kidnap.dm b/code/datums/components/space_kidnap.dm
index 8a1de2123d9d3..7d59a6d7f9fde 100644
--- a/code/datums/components/space_kidnap.dm
+++ b/code/datums/components/space_kidnap.dm
@@ -23,7 +23,7 @@
target.balloon_alert(parent, "is dead!")
return COMPONENT_CANCEL_ATTACK_CHAIN
- if(!victim.incapacitated())
+ if(!victim.incapacitated)
return
if(!isspaceturf(get_turf(target)))
@@ -39,7 +39,7 @@
var/obj/particles = new /obj/effect/abstract/particle_holder (victim, /particles/void_kidnap)
kidnapping = TRUE
- if(do_after(parent, kidnap_time, victim, extra_checks = CALLBACK(victim, TYPE_PROC_REF(/mob, incapacitated))))
+ if(do_after(parent, kidnap_time, victim, extra_checks = victim.incapacitated))
take_them(victim)
qdel(particles)
diff --git a/code/datums/components/speechmod.dm b/code/datums/components/speechmod.dm
index 2506a0b914077..8ffa3e8624e49 100644
--- a/code/datums/components/speechmod.dm
+++ b/code/datums/components/speechmod.dm
@@ -34,6 +34,12 @@
var/atom/owner = parent
+ if (istype(parent, /datum/status_effect))
+ var/datum/status_effect/effect = parent
+ targeted = effect.owner
+ RegisterSignal(targeted, COMSIG_MOB_SAY, PROC_REF(handle_speech))
+ return
+
if (ismob(parent))
targeted = parent
RegisterSignal(targeted, COMSIG_MOB_SAY, PROC_REF(handle_speech))
diff --git a/code/datums/components/squeak.dm b/code/datums/components/squeak.dm
index c5d42797ab433..94521486bcc5f 100644
--- a/code/datums/components/squeak.dm
+++ b/code/datums/components/squeak.dm
@@ -128,7 +128,7 @@
UnregisterSignal(user, COMSIG_QDELETING)
holder = null
-///just gets rid of the reference to holder in the case that theyre qdeleted
+///just gets rid of the reference to holder in the case that they're qdeleted
/datum/component/squeak/proc/holder_deleted(datum/source, datum/possible_holder)
SIGNAL_HANDLER
if(possible_holder == holder)
@@ -138,7 +138,7 @@
/datum/component/squeak/proc/disposing_react(datum/source, obj/structure/disposalholder/disposal_holder, obj/machinery/disposal/disposal_source)
SIGNAL_HANDLER
- //We don't need to worry about unregistering this signal as it will happen for us automaticaly when the holder is qdeleted
+ //We don't need to worry about unregistering this signal as it will happen for us automatically when the holder is qdeleted
RegisterSignal(disposal_holder, COMSIG_ATOM_DIR_CHANGE, PROC_REF(holder_dir_change))
/datum/component/squeak/proc/holder_dir_change(datum/source, old_dir, new_dir)
diff --git a/code/datums/components/sticker.dm b/code/datums/components/sticker.dm
index 2c87d856da872..a11ab10e7c6f8 100644
--- a/code/datums/components/sticker.dm
+++ b/code/datums/components/sticker.dm
@@ -13,18 +13,21 @@
var/atom/movable/our_sticker
/// Reference to the created overlay, used during component deletion.
var/mutable_appearance/sticker_overlay
- // Callback invoked when sticker is applied to the parent.
+ /// Callback invoked when sticker is applied to the parent.
var/datum/callback/stick_callback
- // Callback invoked when sticker is peeled (not removed) from the parent.
+ /// Callback invoked when sticker is peeled (not removed) from the parent.
var/datum/callback/peel_callback
+ /// Text added to the atom's examine when stickered.
+ var/examine_text
-/datum/component/sticker/Initialize(atom/stickering_atom, dir = NORTH, px = 0, py = 0, datum/callback/stick_callback, datum/callback/peel_callback)
+/datum/component/sticker/Initialize(atom/stickering_atom, dir = NORTH, px = 0, py = 0, datum/callback/stick_callback, datum/callback/peel_callback, examine_text)
if(!isatom(parent))
return COMPONENT_INCOMPATIBLE
src.our_sticker = our_sticker
src.stick_callback = stick_callback
src.peel_callback = peel_callback
+ src.examine_text = examine_text
stick(stickering_atom, px, py)
register_turf_signals(dir)
@@ -45,9 +48,10 @@
/datum/component/sticker/RegisterWithParent()
RegisterSignal(parent, COMSIG_LIVING_IGNITED, PROC_REF(on_ignite))
RegisterSignal(parent, COMSIG_COMPONENT_CLEAN_ACT, PROC_REF(on_clean))
+ RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine))
/datum/component/sticker/UnregisterFromParent()
- UnregisterSignal(parent, list(COMSIG_LIVING_IGNITED, COMSIG_COMPONENT_CLEAN_ACT))
+ UnregisterSignal(parent, list(COMSIG_LIVING_IGNITED, COMSIG_COMPONENT_CLEAN_ACT, COMSIG_ATOM_EXAMINE))
/// Subscribes to `COMSIG_TURF_EXPOSE` if parent atom is a turf. If turf is closed - subscribes to signal
/datum/component/sticker/proc/register_turf_signals(dir)
@@ -116,3 +120,9 @@
if(exposed_temperature >= FIRE_MINIMUM_TEMPERATURE_TO_EXIST)
qdel(our_sticker) // which qdels us
+
+/datum/component/sticker/proc/on_examine(atom/source, mob/user, list/examine_list)
+ SIGNAL_HANDLER
+
+ if(!isnull(examine_text))
+ examine_list += span_warning(examine_text)
diff --git a/code/datums/components/style/style.dm b/code/datums/components/style/style.dm
index 9bc420cc175c0..cc8b061fd353e 100644
--- a/code/datums/components/style/style.dm
+++ b/code/datums/components/style/style.dm
@@ -98,8 +98,7 @@
RegisterSignal(parent, COMSIG_USER_ITEM_INTERACTION, PROC_REF(hotswap))
RegisterSignal(parent, COMSIG_MOB_MINED, PROC_REF(on_mine))
RegisterSignal(parent, COMSIG_MOB_APPLY_DAMAGE, PROC_REF(on_take_damage))
- RegisterSignal(parent, COMSIG_MOB_EMOTED("flip"), PROC_REF(on_flip))
- RegisterSignal(parent, COMSIG_MOB_EMOTED("spin"), PROC_REF(on_spin))
+ RegisterSignal(parent, COMSIG_MOB_EMOTED("taunt"), PROC_REF(on_taunt))
RegisterSignal(parent, COMSIG_MOB_ITEM_ATTACK, PROC_REF(on_attack))
RegisterSignal(parent, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(on_punch))
RegisterSignal(SSdcs, COMSIG_GLOB_MOB_DEATH, PROC_REF(on_death))
@@ -114,7 +113,7 @@
UnregisterSignal(parent, COMSIG_USER_ITEM_INTERACTION)
UnregisterSignal(parent, COMSIG_MOB_MINED)
UnregisterSignal(parent, COMSIG_MOB_APPLY_DAMAGE)
- UnregisterSignal(parent, list(COMSIG_MOB_EMOTED("flip"), COMSIG_MOB_EMOTED("spin")))
+ UnregisterSignal(parent, COMSIG_MOB_EMOTED("taunt"))
UnregisterSignal(parent, list(COMSIG_MOB_ITEM_ATTACK, COMSIG_LIVING_UNARMED_ATTACK))
UnregisterSignal(SSdcs, COMSIG_GLOB_MOB_DEATH)
UnregisterSignal(parent, COMSIG_LIVING_RESONATOR_BURST)
@@ -407,19 +406,12 @@
// Emote-based multipliers
-/datum/component/style/proc/on_flip()
+/datum/component/style/proc/on_taunt()
SIGNAL_HANDLER
point_multiplier = round(min(point_multiplier + 0.5, 3), 0.1)
update_screen()
-/datum/component/style/proc/on_spin()
- SIGNAL_HANDLER
-
- point_multiplier = round(min(point_multiplier + 0.3, 3), 0.1)
- update_screen()
-
-
// Negative effects
/datum/component/style/proc/on_take_damage(...)
SIGNAL_HANDLER
diff --git a/code/datums/components/subtype_picker.dm b/code/datums/components/subtype_picker.dm
index 78401c9e02293..2cc76e42ecf1f 100644
--- a/code/datums/components/subtype_picker.dm
+++ b/code/datums/components/subtype_picker.dm
@@ -87,6 +87,6 @@
return FALSE
if(QDELETED(target))
return FALSE
- if(user.incapacitated() || !user.is_holding(target))
+ if(user.incapacitated || !user.is_holding(target))
return FALSE
return TRUE
diff --git a/code/datums/components/tackle.dm b/code/datums/components/tackle.dm
index 8e902ced2fdbf..0c23733ea1658 100644
--- a/code/datums/components/tackle.dm
+++ b/code/datums/components/tackle.dm
@@ -74,10 +74,7 @@
if(modifiers[ALT_CLICK] || modifiers[SHIFT_CLICK] || modifiers[CTRL_CLICK] || modifiers[MIDDLE_CLICK])
return
- if(!modifiers[RIGHT_CLICK])
- return
-
- if(!user.throw_mode || user.get_active_held_item() || user.pulling || user.buckled || user.incapacitated())
+ if(!user.throw_mode || user.get_active_held_item() || user.pulling || user.buckled || user.incapacitated)
return
if(!clicked_atom || !(isturf(clicked_atom) || isturf(clicked_atom.loc)))
diff --git a/code/datums/components/tactical.dm b/code/datums/components/tactical.dm
index 59df008b2b100..17309b888eac3 100644
--- a/code/datums/components/tactical.dm
+++ b/code/datums/components/tactical.dm
@@ -42,6 +42,9 @@
RegisterSignal(parent, COMSIG_ITEM_DROPPED, PROC_REF(unmodify))
RegisterSignal(parent, COMSIG_ATOM_UPDATED_ICON, PROC_REF(on_icon_update))
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved))
+ RegisterSignal(user, COMSIG_HUMAN_GET_VISIBLE_NAME, PROC_REF(on_name_inquiry))
+ RegisterSignal(user, COMSIG_HUMAN_GET_FORCED_NAME, PROC_REF(on_name_inquiry))
+ ADD_TRAIT(user, TRAIT_UNKNOWN, REF(src))
current_slot = slot
@@ -62,6 +65,24 @@
image.plane = FLOAT_PLANE
user.add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/everyone, "sneaking_mission[REF(src)]", image)
+
+/datum/component/tactical/proc/on_name_inquiry(obj/item/source, list/identity)
+ SIGNAL_HANDLER
+
+ var/tactical_disguise_power = INFINITY // it's a flawless plan: they'll never look behind this unassuming potted plant
+ if(identity[VISIBLE_NAME_FORCED])
+ if(identity[VISIBLE_NAME_FORCED] >= tactical_disguise_power) // my disguise is too powerful for you, traveler! but seriously this is bad
+ stack_trace("A name forcing signal ([identity[VISIBLE_NAME_FACE]]) has a priority collision with [src].")
+ else
+ identity[VISIBLE_NAME_FORCED] = tactical_disguise_power
+ else
+ identity[VISIBLE_NAME_FORCED] = tactical_disguise_power
+
+ var/obj/item/flawless_disguise = parent
+ identity[VISIBLE_NAME_FACE] = flawless_disguise.name
+ identity[VISIBLE_NAME_ID] = flawless_disguise.name // for Unknown (as 'potted plant') says
+
+
/datum/component/tactical/proc/unmodify(obj/item/source, mob/user)
SIGNAL_HANDLER
if(!source)
@@ -77,8 +98,14 @@
COMSIG_MOVABLE_MOVED,
COMSIG_ATOM_UPDATED_ICON,
))
+
+ UnregisterSignal(user, list(
+ COMSIG_HUMAN_GET_VISIBLE_NAME,
+ COMSIG_HUMAN_GET_FORCED_NAME,
+ ))
current_slot = null
user.remove_alt_appearance("sneaking_mission[REF(src)]")
+ REMOVE_TRAIT(user, TRAIT_UNKNOWN, REF(src))
///Checks if a mob is holding us, and if so we will modify our appearance to properly match w/ the mob.
/datum/component/tactical/proc/tactical_update(obj/item/source)
diff --git a/code/datums/components/unobserved_actor.dm b/code/datums/components/unobserved_actor.dm
index 7956c9034772a..007d39a0ae845 100644
--- a/code/datums/components/unobserved_actor.dm
+++ b/code/datums/components/unobserved_actor.dm
@@ -6,16 +6,19 @@
/datum/component/unobserved_actor
/// Dictates what behaviour you're blocked from while observed
var/unobserved_flags = NONE
+ /// List of action types which cannot be used while observed. Applies to all actions if not set, and does nothing if NO_OBSERVED_ACTIONS flag isnt present
+ var/list/affected_actions = null
/// Cooldown to prevent message spam when holding a move button
COOLDOWN_DECLARE(message_cooldown)
-/datum/component/unobserved_actor/Initialize(unobserved_flags = NONE)
+/datum/component/unobserved_actor/Initialize(unobserved_flags = NONE, list/affected_actions = null)
. = ..()
if (!isliving(parent))
return ELEMENT_INCOMPATIBLE
if (unobserved_flags == NONE)
CRASH("No behaviour flags provided to unobserved actor element")
src.unobserved_flags = unobserved_flags
+ src.affected_actions = affected_actions
/datum/component/unobserved_actor/RegisterWithParent()
if (unobserved_flags & NO_OBSERVED_MOVEMENT)
@@ -52,17 +55,21 @@
return COMPONENT_ATOM_BLOCK_DIR_CHANGE
/// Called when the mob tries to use an ability
-/datum/component/unobserved_actor/proc/on_tried_ability(mob/living/source)
+/datum/component/unobserved_actor/proc/on_tried_ability(mob/living/source, datum/action)
SIGNAL_HANDLER
if (!check_if_seen(source))
return
+ if (!isnull(affected_actions) && !(action.type in affected_actions))
+ return
return COMPONENT_BLOCK_ABILITY_START
/// Called when the mob tries to cast a spell
-/datum/component/unobserved_actor/proc/on_tried_spell(mob/living/source)
+/datum/component/unobserved_actor/proc/on_tried_spell(mob/living/source, datum/action)
SIGNAL_HANDLER
if (!check_if_seen(source))
return
+ if (!isnull(affected_actions) && !(action.type in affected_actions))
+ return
return SPELL_CANCEL_CAST
/// Called when the mob tries to attack
@@ -92,7 +99,7 @@
// We aren't in darkness, loop for viewers.
for(var/mob/living/mob_target in oview(my_turf, 7)) // They probably cannot see us if we cannot see them... can they?
- if(mob_target.client && !mob_target.is_blind() && !mob_target.has_unlimited_silicon_privilege && !HAS_TRAIT(mob_target, TRAIT_UNOBSERVANT))
+ if(mob_target.client && !mob_target.is_blind() && !HAS_TRAIT(mob_target, TRAIT_UNOBSERVANT))
return TRUE
for(var/obj/vehicle/sealed/mecha/mecha_mob_target in oview(my_turf, 7))
for(var/mob/mechamob_target as anything in mecha_mob_target.occupants)
diff --git a/code/datums/datum.dm b/code/datums/datum.dm
index 59a1d54571d3c..a4169004fc982 100644
--- a/code/datums/datum.dm
+++ b/code/datums/datum.dm
@@ -111,9 +111,6 @@
tag = null
datum_flags &= ~DF_USE_TAG //In case something tries to REF us
weak_reference = null //ensure prompt GCing of weakref.
- if(!(datum_flags & DF_STATIC_OBJECT))
- DREAMLUAU_CLEAR_REF_USERDATA(vars) // vars ceases existing when src does, so we need to clear any lua refs to it that exist.
- DREAMLUAU_CLEAR_REF_USERDATA(src)
if(_active_timers)
var/list/timers = _active_timers
@@ -145,6 +142,10 @@
_clear_signal_refs()
//END: ECS SHIT
+ if(!(datum_flags & DF_STATIC_OBJECT))
+ DREAMLUAU_CLEAR_REF_USERDATA(vars) // vars ceases existing when src does, so we need to clear any lua refs to it that exist.
+ DREAMLUAU_CLEAR_REF_USERDATA(src)
+
return QDEL_HINT_QUEUE
///Only override this if you know what you're doing. You do not know what you're doing
@@ -343,7 +344,7 @@
. = ..()
update_item_action_buttons()
-/** Update a filter's parameter to the new one. If the filter doesnt exist we won't do anything.
+/** Update a filter's parameter to the new one. If the filter doesn't exist we won't do anything.
*
* Arguments:
* * name - Filter name
@@ -361,7 +362,7 @@
filter_data[name][thing] = new_params[thing]
update_filters()
-/** Update a filter's parameter and animate this change. If the filter doesnt exist we won't do anything.
+/** Update a filter's parameter and animate this change. If the filter doesn't exist we won't do anything.
* Basically a [datum/proc/modify_filter] call but with animations. Unmodified filter parameters are kept.
*
* Arguments:
diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm
index aeea8b22cbaab..944532324af10 100644
--- a/code/datums/datumvars.dm
+++ b/code/datums/datumvars.dm
@@ -23,8 +23,8 @@
/**
* Gets all the dropdown options in the vv menu.
- * When overriding, make sure to call . = ..() first and appent to the result, that way parent items are always at the top and child items are further down.
- * Add seperators by doing VV_DROPDOWN_OPTION("", "---")
+ * When overriding, make sure to call . = ..() first and append to the result, that way parent items are always at the top and child items are further down.
+ * Add separators by doing VV_DROPDOWN_OPTION("", "---")
*/
/datum/proc/vv_get_dropdown()
SHOULD_CALL_PARENT(TRUE)
@@ -44,7 +44,7 @@
/**
* This proc is only called if everything topic-wise is verified. The only verifications that should happen here is things like permission checks!
* href_list is a reference, modifying it in these procs WILL change the rest of the proc in topic.dm of admin/view_variables!
- * This proc is for "high level" actions like admin heal/set species/etc/etc. The low level debugging things should go in admin/view_variables/topic_basic.dm incase this runtimes.
+ * This proc is for "high level" actions like admin heal/set species/etc/etc. The low level debugging things should go in admin/view_variables/topic_basic.dm in case this runtimes.
*/
/datum/proc/vv_do_topic(list/href_list)
if(!usr || !usr.client || !usr.client.holder || !check_rights(NONE))
diff --git a/code/datums/diseases/_disease.dm b/code/datums/diseases/_disease.dm
index 9560820f2f048..154027b8b9ae6 100644
--- a/code/datums/diseases/_disease.dm
+++ b/code/datums/diseases/_disease.dm
@@ -146,6 +146,8 @@
cycles_to_beat = max(DISEASE_RECOVERY_SCALING, DISEASE_CYCLES_HARMFUL)
if(DISEASE_SEVERITY_BIOHAZARD)
cycles_to_beat = max(DISEASE_RECOVERY_SCALING, DISEASE_CYCLES_BIOHAZARD)
+ else
+ cycles_to_beat = max(DISEASE_RECOVERY_SCALING, DISEASE_CYCLES_NONTHREAT)
peaked_cycles += stage/max_stages //every cycle we spend sick counts towards eventually curing the virus, faster at higher stages
recovery_prob += DISEASE_RECOVERY_CONSTANT + (peaked_cycles / (cycles_to_beat / DISEASE_RECOVERY_SCALING)) //more severe viruses are beaten back more aggressively after the peak
if(stage_peaked)
diff --git a/code/datums/diseases/adrenal_crisis.dm b/code/datums/diseases/adrenal_crisis.dm
index cd9a2dd318010..aa9587c2e1ab9 100644
--- a/code/datums/diseases/adrenal_crisis.dm
+++ b/code/datums/diseases/adrenal_crisis.dm
@@ -8,7 +8,7 @@
agent = "Shitty Adrenal Glands"
viable_mobtypes = list(/mob/living/carbon/human)
spreading_modifier = 1
- desc = "If left untreated the subject will suffer from lethargy, dizziness and periodic loss of conciousness."
+ desc = "If left untreated the subject will suffer from lethargy, dizziness and periodic loss of consciousness."
severity = DISEASE_SEVERITY_MEDIUM
spread_flags = DISEASE_SPREAD_NON_CONTAGIOUS
spread_text = "Organ failure"
diff --git a/code/datums/diseases/advance/advance.dm b/code/datums/diseases/advance/advance.dm
index 8c8e8e02169b4..82099a7532b52 100644
--- a/code/datums/diseases/advance/advance.dm
+++ b/code/datums/diseases/advance/advance.dm
@@ -265,7 +265,7 @@
properties["severity"] += round((properties["transmittable"] / 8), 1)
properties["severity"] = round((properties["severity"] / 2), 1)
properties["severity"] *= (symptoms.len / VIRUS_SYMPTOM_LIMIT) //fewer symptoms, less severity
- properties["severity"] = clamp(properties["severity"], 1, 7)
+ properties["severity"] = round(clamp(properties["severity"], 1, 7), 1)
properties["capacity"] = get_symptom_weights()
// Assign the properties that are in the list.
diff --git a/code/datums/diseases/advance/symptoms/choking.dm b/code/datums/diseases/advance/symptoms/choking.dm
index 47044068f242e..6ae9fe42b6e3a 100644
--- a/code/datums/diseases/advance/symptoms/choking.dm
+++ b/code/datums/diseases/advance/symptoms/choking.dm
@@ -74,7 +74,7 @@ Asphyxiation
Very very noticable.
Decreases stage speed.
- Decreases transmittablity.
+ Decreases transmittability.
Bonus
Inflicts large spikes of oxyloss
diff --git a/code/datums/diseases/advance/symptoms/fire.dm b/code/datums/diseases/advance/symptoms/fire.dm
index 3ec095feb5c7f..3fe097920cc4b 100644
--- a/code/datums/diseases/advance/symptoms/fire.dm
+++ b/code/datums/diseases/advance/symptoms/fire.dm
@@ -2,7 +2,7 @@
* Slightly hidden.
* Lowers resistance tremendously.
* Decreases stage speed tremendously.
- * Decreases transmittablity tremendously.
+ * Decreases transmittability tremendously.
* Fatal level
* Bonus: Ignites infected mob.
*/
diff --git a/code/datums/diseases/advance/symptoms/flesh_eating.dm b/code/datums/diseases/advance/symptoms/flesh_eating.dm
index 90070aa15fb9f..005a651b7f338 100644
--- a/code/datums/diseases/advance/symptoms/flesh_eating.dm
+++ b/code/datums/diseases/advance/symptoms/flesh_eating.dm
@@ -70,7 +70,7 @@ Autophagocytosis (AKA Programmed mass cell death)
Very noticable.
Lowers resistance.
Fast stage speed.
- Decreases transmittablity.
+ Decreases transmittability.
Fatal Level.
Bonus
diff --git a/code/datums/diseases/chronic_illness.dm b/code/datums/diseases/chronic_illness.dm
index 37778a158ad79..b1afd1d1939a9 100644
--- a/code/datums/diseases/chronic_illness.dm
+++ b/code/datums/diseases/chronic_illness.dm
@@ -1,7 +1,7 @@
/datum/disease/chronic_illness
name = "Hereditary Manifold Sickness"
max_stages = 5
- spread_text = "Unspread Illness"
+ spread_text = "Non-communicable disease"
spread_flags = DISEASE_SPREAD_NON_CONTAGIOUS
disease_flags = CHRONIC
infectable_biotypes = MOB_ORGANIC | MOB_MINERAL | MOB_ROBOTIC
diff --git a/code/datums/dna.dm b/code/datums/dna.dm
index df92d57c59b4c..f16cf5bc50cf0 100644
--- a/code/datums/dna.dm
+++ b/code/datums/dna.dm
@@ -63,7 +63,7 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
var/list/features = list("mcolor" = COLOR_WHITE)
///Stores the hashed values of the person's non-human features
var/unique_features
- ///Stores the real name of the person who originally got this dna datum. Used primarely for changelings,
+ ///Stores the real name of the person who originally got this dna datum. Used primarily for changelings,
var/real_name
///All mutations are from now on here
var/list/mutations = list()
@@ -77,7 +77,7 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
///List of the default genes from this mutation to allow DNA Scanner highlighting
var/default_mutation_genes[DNA_MUTATION_BLOCKS]
var/stability = 100
- ///Did we take something like mutagen? In that case we cant get our genes scanned to instantly cheese all the powers.
+ ///Did we take something like mutagen? In that case we can't get our genes scanned to instantly cheese all the powers.
var/scrambled = FALSE
/// Weighted list of nonlethal meltdowns
var/static/list/nonfatal_meltdowns = list()
@@ -682,8 +682,8 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
if(dna.features["pod_hair"])
dna.features["pod_hair"] = SSaccessories.pod_hair_list[deconstruct_block(get_uni_feature_block(features, DNA_POD_HAIR_BLOCK), length(SSaccessories.pod_hair_list))]
- for(var/obj/item/organ/external/external_organ in organs)
- external_organ.mutate_feature(features, src)
+ for(var/obj/item/organ/organ in organs)
+ organ.mutate_feature(features, src)
if(icon_update)
update_body(is_creating = mutcolor_update)
@@ -743,7 +743,7 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
if(istype(mutation, /datum/mutation/human))
var/datum/mutation/human/M = mutation
mutation_type = M.type
- if(!mutation_in_sequence(mutation_type)) //cant activate what we dont have, use add_mutation
+ if(!mutation_in_sequence(mutation_type)) //can't activate what we don't have, use add_mutation
return FALSE
add_mutation(mutation, MUT_NORMAL)
return TRUE
diff --git a/code/datums/ductnet.dm b/code/datums/ductnet.dm
index e97add695d9a3..5cc241cce2b5b 100644
--- a/code/datums/ductnet.dm
+++ b/code/datums/ductnet.dm
@@ -35,7 +35,7 @@
demanders += P
return TRUE
-///remove a plumber. we dont delete ourselves because ductnets dont persist through plumbing objects
+///remove a plumber. we don't delete ourselves because ductnets don't persist through plumbing objects
/datum/ductnet/proc/remove_plumber(datum/component/plumbing/P)
suppliers.Remove(P) //we're probably only in one of these, but Remove() is inherently sane so this is fine
demanders.Remove(P)
@@ -62,7 +62,7 @@
var/obj/machinery/duct/M = A
M.duct = src //forget your old master
- D.ducts.Cut() //clear this so the other network doesnt clear the ducts along with themselves (this took the life out of me)
+ D.ducts.Cut() //clear this so the other network doesn't clear the ducts along with themselves (this took the life out of me)
D.destroy_network()
///destroy the network and tell all our ducts and plumbers we are gone
@@ -72,5 +72,5 @@
for(var/A in ducts)
var/obj/machinery/duct/D = A
D.duct = null
- if(delete) //I don't want code to run with qdeleted objects because that can never be good, so keep this in-case the ductnet has some business left to attend to before commiting suicide
+ if(delete) //I don't want code to run with qdeleted objects because that can never be good, so keep this in-case the ductnet has some business left to attend to before committing suicide
qdel(src)
diff --git a/code/datums/elements/bane.dm b/code/datums/elements/bane.dm
index 95e21251657d7..110a755de23b0 100644
--- a/code/datums/elements/bane.dm
+++ b/code/datums/elements/bane.dm
@@ -1,6 +1,6 @@
/// Deals extra damage to mobs of a certain type, species, or biotype.
-/// This doesn't directly modify the normal damage of the weapon, instead it applies its own damage seperatedly ON TOP of normal damage
-/// ie. a sword that does 10 damage with a bane elment attacthed that has a 0.5 damage_multiplier will do:
+/// This doesn't directly modify the normal damage of the weapon, instead it applies its own damage separately ON TOP of normal damage
+/// ie. a sword that does 10 damage with a bane element attached that has a 0.5 damage_multiplier will do:
/// 10 damage from the swords normal attack + 5 damage (50%) from the bane element
/datum/element/bane
element_flags = ELEMENT_BESPOKE
diff --git a/code/datums/elements/block_turf_fingerprints.dm b/code/datums/elements/block_turf_fingerprints.dm
new file mode 100644
index 0000000000000..f3b7ab9cf19f1
--- /dev/null
+++ b/code/datums/elements/block_turf_fingerprints.dm
@@ -0,0 +1,56 @@
+/**
+ * ## block_turf_fingerprints
+ *
+ * Attach to a movable, prevents mobs from leaving fingerprints on the turf below it
+ */
+/datum/element/block_turf_fingerprints
+ element_flags = ELEMENT_DETACH_ON_HOST_DESTROY
+
+/datum/element/block_turf_fingerprints/Attach(datum/target)
+ . = ..()
+ if(!ismovable(target))
+ return ELEMENT_INCOMPATIBLE
+
+ var/atom/movable/target_movable = target
+ if(isturf(target_movable.loc))
+ apply_to_turf(target_movable.loc)
+
+ RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(move_turf))
+
+/datum/element/block_turf_fingerprints/Detach(atom/movable/target)
+ . = ..()
+ if(isturf(target.loc))
+ remove_from_turf(target.loc)
+
+ UnregisterSignal(target, COMSIG_MOVABLE_MOVED)
+
+/datum/element/block_turf_fingerprints/proc/apply_to_turf(turf/the_turf)
+ // It's possible two things with this element could be on the same turf, so let's avoid double-applying
+ if(the_turf.interaction_flags_atom & INTERACT_ATOM_NO_FINGERPRINT_ATTACK_HAND)
+ // But what if the turf has this flag by default? We still need to override register a signal.
+ // Otherwise we may run into a very niche bug:
+ // - A turf as this flag by default
+ // - A movable with this element is placed on the turf
+ // - It does not gain the flag nor register a signal
+ // - The turf changes, and the new turf does not gain the flag
+ if(initial(the_turf.interaction_flags_atom) & INTERACT_ATOM_NO_FINGERPRINT_ATTACK_HAND)
+ RegisterSignal(the_turf, COMSIG_TURF_CHANGE, PROC_REF(replace_our_turf), override = TRUE)
+ return
+
+ the_turf.interaction_flags_atom |= INTERACT_ATOM_NO_FINGERPRINT_ATTACK_HAND
+ RegisterSignal(the_turf, COMSIG_TURF_CHANGE, PROC_REF(replace_our_turf))
+
+/datum/element/block_turf_fingerprints/proc/remove_from_turf(turf/the_turf)
+ the_turf.interaction_flags_atom &= ~INTERACT_ATOM_NO_FINGERPRINT_ATTACK_HAND
+ UnregisterSignal(the_turf, COMSIG_TURF_CHANGE)
+
+/datum/element/block_turf_fingerprints/proc/move_turf(atom/movable/source, atom/old_loc)
+ SIGNAL_HANDLER
+ if(isturf(old_loc))
+ remove_from_turf(old_loc)
+ if(isturf(source.loc))
+ apply_to_turf(source.loc)
+
+/datum/element/block_turf_fingerprints/proc/replace_our_turf(datum/source, path, new_baseturfs, flags, post_change_callbacks)
+ SIGNAL_HANDLER
+ post_change_callbacks += CALLBACK(src, PROC_REF(apply_to_turf))
diff --git a/code/datums/elements/elevation.dm b/code/datums/elements/elevation.dm
index b83548c6b5f41..959fa14f79837 100644
--- a/code/datums/elements/elevation.dm
+++ b/code/datums/elements/elevation.dm
@@ -151,8 +151,8 @@
/datum/element/elevation_core/proc/on_initialized_on(turf/source, atom/movable/spawned)
SIGNAL_HANDLER
- if(isliving(spawned))
- elevate_mob(spawned)
+ if(isliving(spawned) && !HAS_TRAIT(spawned, TRAIT_ON_ELEVATED_SURFACE))
+ on_entered(entered = spawned)
/datum/element/elevation_core/proc/on_exited(turf/source, atom/movable/gone)
SIGNAL_HANDLER
diff --git a/code/datums/elements/fish_safe_storage.dm b/code/datums/elements/fish_safe_storage.dm
new file mode 100644
index 0000000000000..bb7864ced0e6a
--- /dev/null
+++ b/code/datums/elements/fish_safe_storage.dm
@@ -0,0 +1,53 @@
+///An element that puts in stasis any fish that enters the atom.
+/datum/element/fish_safe_storage
+ element_flags = ELEMENT_DETACH_ON_HOST_DESTROY
+ var/list/tracked_fish = list()
+
+/datum/element/fish_safe_storage/New()
+ . = ..()
+ START_PROCESSING(SSprocessing, src)
+
+/datum/element/fish_safe_storage/Attach(atom/target)
+ . = ..()
+ if(!isatom(target))
+ return ELEMENT_INCOMPATIBLE
+
+ RegisterSignal(target, COMSIG_ATOM_ENTERED, PROC_REF(on_enter))
+ RegisterSignal(target, COMSIG_ATOM_EXITED, PROC_REF(on_exit))
+ RegisterSignal(target, COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZED_ON, PROC_REF(on_init_on))
+ for(var/obj/item/fish/fish in target)
+ tracked_fish |= fish
+ fish.enter_stasis()
+
+/datum/element/fish_safe_storage/Detach(atom/source)
+ for(var/obj/item/fish/fish in source)
+ tracked_fish -= fish
+ fish.exit_stasis()
+ UnregisterSignal(source, list(COMSIG_ATOM_ENTERED, COMSIG_ATOM_EXITED, COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZED_ON))
+ return ..()
+
+/datum/element/fish_safe_storage/proc/on_enter(datum/source, obj/item/fish/arrived)
+ SIGNAL_HANDLER
+ if(isfish(arrived))
+ tracked_fish |= arrived
+ arrived.enter_stasis()
+
+/datum/element/fish_safe_storage/proc/on_init_on(datum/source, obj/item/fish/created)
+ SIGNAL_HANDLER
+ if(isfish(created) && !QDELETED(created))
+ tracked_fish |= created
+ created.enter_stasis()
+
+/datum/element/fish_safe_storage/proc/on_exit(datum/source, obj/item/fish/gone)
+ SIGNAL_HANDLER
+ if(isfish(gone))
+ tracked_fish -= gone
+ gone.exit_stasis()
+
+/datum/element/fish_safe_storage/process(seconds_per_tick)
+ for(var/obj/item/fish/fish as anything in tracked_fish)
+ ///Keep delaying hunger and breeding while in stasis, and also heal them.
+ fish.last_feeding += seconds_per_tick SECONDS
+ fish.breeding_wait += seconds_per_tick SECONDS
+ if(fish.health < initial(fish.health) * 0.65)
+ fish.adjust_health(fish.health + 0.75 * seconds_per_tick)
diff --git a/code/datums/elements/food/grilled_item.dm b/code/datums/elements/food/grilled_item.dm
index de6c2ef41c1b9..74e772eb73c92 100644
--- a/code/datums/elements/food/grilled_item.dm
+++ b/code/datums/elements/food/grilled_item.dm
@@ -28,6 +28,8 @@
if(grill_time > 30 SECONDS && isnull(this_food.GetComponent(/datum/component/edible)))
this_food.AddComponent(/datum/component/edible, foodtypes = FRIED)
+ SEND_SIGNAL(this_food, COMSIG_ITEM_BARBEQUE_GRILLED)
+
/datum/element/grilled_item/Detach(atom/source, ...)
source.name = initial(source.name)
source.desc = initial(source.desc)
diff --git a/code/datums/elements/food/microwavable.dm b/code/datums/elements/food/microwavable.dm
index 8e7305545c0b0..5fdd4c084add1 100644
--- a/code/datums/elements/food/microwavable.dm
+++ b/code/datums/elements/food/microwavable.dm
@@ -44,6 +44,7 @@
var/efficiency = istype(used_microwave) ? used_microwave.efficiency : 1
SEND_SIGNAL(result, COMSIG_ITEM_MICROWAVE_COOKED, source, efficiency)
+ SEND_SIGNAL(source, COMSIG_ITEM_MICROWAVE_COOKED_FROM, result, efficiency)
if(IS_EDIBLE(result) && (result_typepath != default_typepath))
BLACKBOX_LOG_FOOD_MADE(result.type)
diff --git a/code/datums/elements/leeching_walk.dm b/code/datums/elements/leeching_walk.dm
index c0afc52b24583..c9f547189e699 100644
--- a/code/datums/elements/leeching_walk.dm
+++ b/code/datums/elements/leeching_walk.dm
@@ -55,3 +55,5 @@
// Heals blood loss
if(source.blood_volume < BLOOD_VOLUME_NORMAL)
source.blood_volume += 2.5 * seconds_per_tick
+ // Slowly regulates your body temp
+ source.adjust_bodytemperature((source.get_body_temp_normal() - source.bodytemperature)/5)
diff --git a/code/datums/elements/quality_food_ingredient.dm b/code/datums/elements/quality_food_ingredient.dm
new file mode 100644
index 0000000000000..e9bfec246c52c
--- /dev/null
+++ b/code/datums/elements/quality_food_ingredient.dm
@@ -0,0 +1,71 @@
+///An element that adds extra food quality to any edible that was made from an atom with this attached.
+/datum/element/quality_food_ingredient
+ element_flags = ELEMENT_BESPOKE
+ argument_hash_start_idx = 2
+ ///The increase of recipe complexity (basically hardcoded food quality) of edibles made with this.
+ var/complexity_increase = 0
+
+/datum/element/quality_food_ingredient/Attach(datum/target, complexity_increase)
+ . = ..()
+ if(!isatom(target))
+ return ELEMENT_INCOMPATIBLE
+ if(HAS_TRAIT_FROM(target, TRAIT_QUALITY_FOOD_INGREDIENT, REF(src))) //It already has this element attached.
+ return
+
+ src.complexity_increase = complexity_increase
+
+ RegisterSignal(target, COMSIG_ATOM_USED_IN_CRAFT, PROC_REF(used_in_craft))
+ RegisterSignal(target, COMSIG_ITEM_BAKED, PROC_REF(item_baked))
+ RegisterSignal(target, COMSIG_ITEM_MICROWAVE_COOKED_FROM, PROC_REF(microwaved_from))
+ RegisterSignal(target, COMSIG_ITEM_GRILLED, PROC_REF(item_grilled))
+ RegisterSignals(target, list(COMSIG_ITEM_BARBEQUE_GRILLED, COMSIG_ITEM_FRIED), PROC_REF(simply_cooked))
+ RegisterSignal(target, COMSIG_ITEM_USED_AS_INGREDIENT, PROC_REF(used_as_ingredient))
+
+/datum/element/quality_food_ingredient/Detach(datum/source)
+ UnregisterSignal(source, list(
+ COMSIG_ATOM_USED_IN_CRAFT,
+ COMSIG_ITEM_BAKED,
+ COMSIG_ITEM_MICROWAVE_COOKED_FROM,
+ COMSIG_ITEM_GRILLED,
+ COMSIG_ITEM_BARBEQUE_GRILLED,
+ COMSIG_ITEM_FRIED,
+ COMSIG_ITEM_USED_AS_INGREDIENT,
+ COMSIG_FOOD_GET_EXTRA_COMPLEXITY,
+ ))
+ REMOVE_TRAIT(source, TRAIT_QUALITY_FOOD_INGREDIENT, REF(src))
+ return ..()
+
+/datum/element/quality_food_ingredient/proc/used_in_craft(datum/source, atom/result)
+ SIGNAL_HANDLER
+ add_quality(result)
+
+/datum/element/quality_food_ingredient/proc/item_baked(datum/source, atom/baked_result)
+ SIGNAL_HANDLER
+ add_quality(baked_result)
+
+/datum/element/quality_food_ingredient/proc/microwaved_from(datum/source, atom/result)
+ SIGNAL_HANDLER
+ add_quality(result)
+
+/datum/element/quality_food_ingredient/proc/item_grilled(datum/source, atom/grill_result)
+ SIGNAL_HANDLER
+ add_quality(grill_result)
+
+/datum/element/quality_food_ingredient/proc/simply_cooked(datum/source)
+ SIGNAL_HANDLER
+ //The target of the food quality and the source are the same, there's no need to re-add the whole element.
+ RegisterSignal(source, COMSIG_FOOD_GET_EXTRA_COMPLEXITY, PROC_REF(add_complexity), TRUE)
+ ADD_TRAIT(source, TRAIT_QUALITY_FOOD_INGREDIENT, REF(src))
+
+/datum/element/quality_food_ingredient/proc/used_as_ingredient(datum/source, atom/container)
+ SIGNAL_HANDLER
+ add_quality(container)
+
+/datum/element/quality_food_ingredient/proc/add_quality(atom/target)
+ target.AddElement(/datum/element/quality_food_ingredient, complexity_increase)
+ RegisterSignal(target, COMSIG_FOOD_GET_EXTRA_COMPLEXITY, PROC_REF(add_complexity), TRUE)
+ ADD_TRAIT(target, TRAIT_QUALITY_FOOD_INGREDIENT, REF(src))
+
+/datum/element/quality_food_ingredient/proc/add_complexity(datum/source, list/extra_complexity)
+ SIGNAL_HANDLER
+ extra_complexity[1] += complexity_increase
diff --git a/code/datums/elements/undertile.dm b/code/datums/elements/undertile.dm
index ed901b196c1aa..229b292b31ae9 100644
--- a/code/datums/elements/undertile.dm
+++ b/code/datums/elements/undertile.dm
@@ -43,8 +43,13 @@
var/turf/T = get_turf(source)
if(underfloor_accessibility < UNDERFLOOR_INTERACTABLE)
- SET_PLANE_IMPLICIT(source, FLOOR_PLANE) // We do this so that turfs that allow you to see what's underneath them don't have to be on the game plane (which causes ambient occlusion weirdness)
- source.layer = ABOVE_OPEN_TURF_LAYER
+ // We only want to change the layer/plane for things that aren't already on the floor plane,
+ // as overriding the settings for those would cause layering issues
+ if(PLANE_TO_TRUE(source.plane) != FLOOR_PLANE)
+ // We do this so that turfs that allow you to see what's underneath them don't have to be on the game plane (which causes ambient occlusion weirdness)
+ SET_PLANE_IMPLICIT(source, FLOOR_PLANE)
+ source.layer = ABOVE_OPEN_TURF_LAYER
+
ADD_TRAIT(source, TRAIT_UNDERFLOOR, REF(src))
if(tile_overlay)
@@ -77,6 +82,8 @@
if(use_anchor)
source.set_anchored(FALSE)
+ SEND_SIGNAL(source, COMSIG_UNDERTILE_UPDATED)
+
/datum/element/undertile/Detach(atom/movable/source, visibility_trait, invisibility_level = INVISIBILITY_MAXIMUM)
. = ..()
diff --git a/code/datums/elements/waddling.dm b/code/datums/elements/waddling.dm
index e63d0329bb630..45c7fe5e93773 100644
--- a/code/datums/elements/waddling.dm
+++ b/code/datums/elements/waddling.dm
@@ -18,7 +18,7 @@
return
if(isliving(moved))
var/mob/living/living_moved = moved
- if (living_moved.incapacitated() || living_moved.body_position == LYING_DOWN)
+ if (living_moved.incapacitated || living_moved.body_position == LYING_DOWN)
return
waddling_animation(moved)
diff --git a/code/datums/elements/wheel.dm b/code/datums/elements/wheel.dm
index 2bb8977ca5cae..a50addb15a382 100644
--- a/code/datums/elements/wheel.dm
+++ b/code/datums/elements/wheel.dm
@@ -17,7 +17,7 @@
return
if(isliving(moved))
var/mob/living/living_moved = moved
- if (living_moved.incapacitated() || living_moved.body_position == LYING_DOWN)
+ if (living_moved.incapacitated || living_moved.body_position == LYING_DOWN)
return
var/rotation_degree = (360 / 3)
if(direction & SOUTHWEST)
diff --git a/code/datums/ert.dm b/code/datums/ert.dm
index 7e358b38cecb4..58500bb3cc33c 100644
--- a/code/datums/ert.dm
+++ b/code/datums/ert.dm
@@ -1,5 +1,4 @@
/datum/ert
- var/mobtype = /mob/living/carbon/human
var/team = /datum/team/ert
var/opendoors = TRUE
var/leader_role = /datum/antagonist/ert/commander
@@ -20,6 +19,8 @@
var/datum/map_template/ert_template
/// If we should actually _use_ the ert_template custom shuttle
var/use_custom_shuttle = TRUE
+ /// Used for spawning bodies for your ERT. Unless customized in the Summon-ERT verb settings, will be overridden and should not be defined at the datum level.
+ var/mob/living/carbon/human/mob_type
/datum/ert/New()
if (!polldesc)
diff --git a/code/datums/greyscale/README.md b/code/datums/greyscale/README.md
index 9ff6bbca1d189..0d8106ebec687 100644
--- a/code/datums/greyscale/README.md
+++ b/code/datums/greyscale/README.md
@@ -4,7 +4,7 @@ If you're wanting to add easy recolors for your sprite then this is the system f
- Multiple color layers so your sprite can be generated from more than one color.
- Mixed greyscale and colored sprite layers; You can choose to only greyscale a part of the sprite or have premade filters applied to layers.
-- Blend modes; Instead of just putting layers of sprites on top of eachother you can use the more advanced blend modes.
+- Blend modes; Instead of just putting layers of sprites on top of each other you can use the more advanced blend modes.
- Reusable configurations; You can reference greyscale sprites from within the configuration of another, allowing you to have a bunch of styles with minimal additional configuration.
## Other Documents
@@ -31,7 +31,7 @@ This is simply some pointers in the code linking together your dmi and the json
## Json Configuration File
-The json is made up of some metadata and a list of layers used while creating the sprite. Inner lists are processed as their own chunk before being applied elsewhere, this is useful when you start using more advanced blend modes. Most of the time though you're just going to want a list of icons overlaid on top of eachother.
+The json is made up of some metadata and a list of layers used while creating the sprite. Inner lists are processed as their own chunk before being applied elsewhere, this is useful when you start using more advanced blend modes. Most of the time though you're just going to want a list of icons overlaid on top of each other.
```json
{
diff --git a/code/datums/greyscale/config_types/greyscale_configs/greyscale_clothes.dm b/code/datums/greyscale/config_types/greyscale_configs/greyscale_clothes.dm
index 377a2fa16938e..bdc2a7d2928c5 100644
--- a/code/datums/greyscale/config_types/greyscale_configs/greyscale_clothes.dm
+++ b/code/datums/greyscale/config_types/greyscale_configs/greyscale_clothes.dm
@@ -276,6 +276,11 @@
icon_file = 'icons/mob/inhands/clothing/suits_righthand.dmi'
json_config = 'code/datums/greyscale/json_configs/jumpsuit_prison_inhand.json'
+/datum/greyscale_config/jumpsuit/worn_digi
+ name = "Jumpsuit Worn (Digitigrate)"
+ icon_file = 'icons/mob/clothing/under/digi_template.dmi'
+ json_config = 'code/datums/greyscale/json_configs/jumpsuit_worn_digilegs.json'
+
/datum/greyscale_config/eth_tunic
name = "Ethereal Tunic"
icon_file = 'icons/obj/clothing/under/ethereal.dmi'
diff --git a/code/datums/greyscale/config_types/greyscale_configs/greyscale_effects.dm b/code/datums/greyscale/config_types/greyscale_configs/greyscale_effects.dm
index 34db9013a893d..91cfb618c210f 100644
--- a/code/datums/greyscale/config_types/greyscale_configs/greyscale_effects.dm
+++ b/code/datums/greyscale/config_types/greyscale_configs/greyscale_effects.dm
@@ -2,3 +2,8 @@
name = "Transmutation Rune"
icon_file = 'icons/effects/96x96.dmi'
json_config = 'code/datums/greyscale/json_configs/heretic_rune.json'
+
+/datum/greyscale_config/manipulator_hand
+ name = "Manipulator Hand"
+ icon_file = 'icons/obj/machines/big_manipulator_parts/big_manipulator_hand.dmi'
+ json_config = 'code/datums/greyscale/json_configs/manipulator_hand.json'
diff --git a/code/datums/greyscale/config_types/greyscale_configs/greyscale_objects.dm b/code/datums/greyscale/config_types/greyscale_configs/greyscale_objects.dm
index 7202c41ecc540..9556612be189c 100644
--- a/code/datums/greyscale/config_types/greyscale_configs/greyscale_objects.dm
+++ b/code/datums/greyscale/config_types/greyscale_configs/greyscale_objects.dm
@@ -3,6 +3,11 @@
icon_file = 'icons/obj/doors/airlocks/material/material.dmi'
json_config = 'code/datums/greyscale/json_configs/material_airlock.json'
+/datum/greyscale_config/big_manipulator
+ name = "Big Manipulator"
+ icon_file = 'icons/obj/machines/big_manipulator_parts/big_manipulator_core.dmi'
+ json_config = 'code/datums/greyscale/json_configs/big_manipulator.json'
+
//
// BENCHES
//
diff --git a/code/datums/greyscale/json_configs/big_manipulator.json b/code/datums/greyscale/json_configs/big_manipulator.json
new file mode 100644
index 0000000000000..c7f96bac2abaa
--- /dev/null
+++ b/code/datums/greyscale/json_configs/big_manipulator.json
@@ -0,0 +1,15 @@
+{
+ "core": [
+ {
+ "type": "icon_state",
+ "icon_state": "core",
+ "blend_mode": "overlay"
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "core_colour",
+ "blend_mode": "overlay",
+ "color_ids": [ 1 ]
+ }
+ ]
+}
diff --git a/code/datums/greyscale/json_configs/jumpsuit_worn_digilegs.json b/code/datums/greyscale/json_configs/jumpsuit_worn_digilegs.json
new file mode 100644
index 0000000000000..9aa201cece3c1
--- /dev/null
+++ b/code/datums/greyscale/json_configs/jumpsuit_worn_digilegs.json
@@ -0,0 +1,10 @@
+{
+ "": [
+ {
+ "type": "icon_state",
+ "icon_state": "jumpsuit",
+ "blend_mode": "overlay",
+ "color_ids": [ 1 ]
+ }
+ ]
+}
diff --git a/code/datums/greyscale/json_configs/manipulator_hand.json b/code/datums/greyscale/json_configs/manipulator_hand.json
new file mode 100644
index 0000000000000..be7c96df62b64
--- /dev/null
+++ b/code/datums/greyscale/json_configs/manipulator_hand.json
@@ -0,0 +1,15 @@
+{
+ "hand": [
+ {
+ "type": "icon_state",
+ "icon_state": "hand",
+ "blend_mode": "overlay"
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "hand_colour",
+ "blend_mode": "overlay",
+ "color_ids": [ 1 ]
+ }
+ ]
+}
diff --git a/code/datums/greyscale/layer.dm b/code/datums/greyscale/layer.dm
index 06a001c1ad835..f12fb1992c9db 100644
--- a/code/datums/greyscale/layer.dm
+++ b/code/datums/greyscale/layer.dm
@@ -64,7 +64,7 @@
/datum/greyscale_layer/proc/CrossVerify()
return
-/// Used to actualy create the layer using the given colors
+/// Used to actually create the layer using the given colors
/// Do not override, use InternalGenerate instead
/datum/greyscale_layer/proc/Generate(list/colors, list/render_steps, icon/new_icon)
var/list/processed_colors = list()
diff --git a/code/datums/holocall.dm b/code/datums/holocall.dm
index c69a279938dd1..fead0417db9b2 100644
--- a/code/datums/holocall.dm
+++ b/code/datums/holocall.dm
@@ -179,7 +179,7 @@
if(QDELETED(src))
return FALSE
- . = !QDELETED(user) && !user.incapacitated() && !QDELETED(calling_holopad) && calling_holopad.is_operational && user.loc == calling_holopad.loc
+ . = !QDELETED(user) && !user.incapacitated && !QDELETED(calling_holopad) && calling_holopad.is_operational && user.loc == calling_holopad.loc
if(.)
if(!connected_holopad)
diff --git a/code/datums/hud.dm b/code/datums/hud.dm
index 10a623b394e8b..fbe99dd8095ac 100644
--- a/code/datums/hud.dm
+++ b/code/datums/hud.dm
@@ -39,11 +39,11 @@ GLOBAL_LIST_INIT(trait_to_hud, list(
// by z level so when they change z's we can adjust what images they see from this hud.
var/list/hud_users = list()
- ///used for signal tracking purposes, associative list of the form: list(hud atom = TRUE) that isnt separated by z level
+ ///used for signal tracking purposes, associative list of the form: list(hud atom = TRUE) that isn't separated by z level
var/list/atom/hud_atoms_all_z_levels = list()
///used for signal tracking purposes, associative list of the form: list(hud user = number of times this hud was added to this user).
- ///that isnt separated by z level
+ ///that isn't separated by z level
var/list/mob/hud_users_all_z_levels = list()
///these will be the indexes for the atom's hud_list
@@ -53,10 +53,10 @@ GLOBAL_LIST_INIT(trait_to_hud, list(
var/list/next_time_allowed = list()
///mobs that have triggered the cooldown and are queued to see the hud, but do not yet
var/list/queued_to_see = list()
- /// huduser = list(atoms with their hud hidden) - aka everyone hates targeted invisiblity
+ /// huduser = list(atoms with their hud hidden) - aka everyone hates targeted invisibility
var/list/hud_exceptions = list()
///whether or not this atom_hud type updates the global huds_by_category list.
- ///some subtypes cant work like this since theyre supposed to "belong" to
+ ///some subtypes can't work like this since they're supposed to "belong" to
///one target atom each. it will still go in the other global hud lists.
var/uses_global_hud_category = TRUE
@@ -175,9 +175,9 @@ GLOBAL_LIST_INIT(trait_to_hud, list(
hud_users_all_z_levels[former_viewer] -= 1//decrement number of sources for this hud on this user (bad way to track i know)
- if (absolute || hud_users_all_z_levels[former_viewer] <= 0)//if forced or there arent any sources left, remove the user
+ if (absolute || hud_users_all_z_levels[former_viewer] <= 0)//if forced or there aren't any sources left, remove the user
- if(!hud_atoms_all_z_levels[former_viewer])//make sure we arent unregistering changes on a mob thats also a hud atom for this hud
+ if(!hud_atoms_all_z_levels[former_viewer])//make sure we aren't unregistering changes on a mob that's also a hud atom for this hud
UnregisterSignal(former_viewer, COMSIG_MOVABLE_Z_CHANGED)
UnregisterSignal(former_viewer, COMSIG_QDELETING)
@@ -222,7 +222,7 @@ GLOBAL_LIST_INIT(trait_to_hud, list(
if(!hud_atom_to_remove || !hud_atoms_all_z_levels[hud_atom_to_remove])
return FALSE
- //make sure we arent unregistering a hud atom thats also a hud user mob
+ //make sure we aren't unregistering a hud atom that's also a hud user mob
if(!hud_users_all_z_levels[hud_atom_to_remove])
UnregisterSignal(hud_atom_to_remove, COMSIG_MOVABLE_Z_CHANGED)
UnregisterSignal(hud_atom_to_remove, COMSIG_QDELETING)
@@ -278,12 +278,12 @@ GLOBAL_LIST_INIT(trait_to_hud, list(
for(var/mob/hud_user as anything in get_hud_users_for_z_level(atom_turf.z))
if(!hud_user.client)
continue
- hud_user.client.images -= hud_atom.active_hud_list[hud_category_to_remove]//by this point it shouldnt be in active_hud_list
+ hud_user.client.images -= hud_atom.active_hud_list[hud_category_to_remove]//by this point it shouldn't be in active_hud_list
return TRUE
-///when a hud atom or hud user changes z levels this makes sure it gets the images it needs and removes the images it doesnt need.
-///because of how signals work we need the same proc to handle both use cases because being a hud atom and being a hud user arent mutually exclusive
+///when a hud atom or hud user changes z levels this makes sure it gets the images it needs and removes the images it doesn't need.
+///because of how signals work we need the same proc to handle both use cases because being a hud atom and being a hud user aren't mutually exclusive
/datum/atom_hud/proc/on_atom_or_user_z_level_changed(atom/movable/moved_atom, turf/old_turf, turf/new_turf)
SIGNAL_HANDLER
if(old_turf)
@@ -300,7 +300,7 @@ GLOBAL_LIST_INIT(trait_to_hud, list(
if(new_turf)
if(hud_users_all_z_levels[moved_atom])
- hud_users[new_turf.z][moved_atom] = TRUE //hud users is associative, hud atoms isnt
+ hud_users[new_turf.z][moved_atom] = TRUE //hud users is associative, hud atoms isn't
add_all_atoms_to_single_mob_hud(moved_atom, get_hud_atoms_for_z_level(new_turf.z))
diff --git a/code/datums/id_trim/_id_trim.dm b/code/datums/id_trim/_id_trim.dm
index 067e2e3826390..562232214b3d1 100644
--- a/code/datums/id_trim/_id_trim.dm
+++ b/code/datums/id_trim/_id_trim.dm
@@ -24,6 +24,11 @@
/// Accesses that this trim unlocks on a card that require wildcard slots to apply. If a card cannot accept all a trim's wildcard accesses, the card is incompatible with the trim.
var/list/wildcard_access = list()
+ ///If true, IDs with this trim will grant wearers with bigger arrows when pointing
+ var/big_pointer = FALSE
+ ///If set, IDs with this trim will give wearers arrows of different colors when pointing
+ var/pointer_color
+
/// Returns the SecHUD job icon state for whatever this object's ID card is, if it has one.
/obj/item/proc/get_sechud_job_icon_state()
var/obj/item/card/id/id_card = GetID()
diff --git a/code/datums/id_trim/admin.dm b/code/datums/id_trim/admin.dm
index 9de155c9a0468..ee0cf1b977e0a 100644
--- a/code/datums/id_trim/admin.dm
+++ b/code/datums/id_trim/admin.dm
@@ -5,6 +5,8 @@
department_color = COLOR_CENTCOM_BLUE
subdepartment_color = COLOR_SERVICE_LIME
threat_modifier = -INFINITY
+ big_pointer = TRUE
+ pointer_color = COLOR_GREEN
/datum/id_trim/admin/New()
. = ..()
diff --git a/code/datums/id_trim/centcom.dm b/code/datums/id_trim/centcom.dm
index 5cc24f4bd6e19..498a4de254e3b 100644
--- a/code/datums/id_trim/centcom.dm
+++ b/code/datums/id_trim/centcom.dm
@@ -7,6 +7,8 @@
department_color = COLOR_CENTCOM_BLUE
subdepartment_color = COLOR_CENTCOM_BLUE
threat_modifier = -10 // Centcom are legally allowed to do whatever they want
+ big_pointer = TRUE
+ pointer_color = COLOR_CENTCOM_BLUE
/// Trim for Centcom VIPs
/datum/id_trim/centcom/vip
@@ -20,6 +22,7 @@
trim_state = "trim_janitor"
department_color = COLOR_CENTCOM_BLUE
subdepartment_color = COLOR_SERVICE_LIME
+ big_pointer = FALSE
/// Trim for Centcom Thunderdome Overseers.
/datum/id_trim/centcom/thunderdome_overseer
@@ -35,10 +38,12 @@
/datum/id_trim/centcom/intern
access = list(ACCESS_CENT_GENERAL, ACCESS_CENT_LIVING, ACCESS_WEAPONS)
assignment = "CentCom Intern"
+ big_pointer = FALSE
/// Trim for Centcom Head Interns. Different assignment, common station access added on.
/datum/id_trim/centcom/intern/head
assignment = "CentCom Head Intern"
+ big_pointer = TRUE
/datum/id_trim/centcom/intern/head/New()
. = ..()
@@ -49,11 +54,13 @@
/datum/id_trim/centcom/bounty_hunter
access = list(ACCESS_CENT_GENERAL)
assignment = "Bounty Hunter"
+ big_pointer = FALSE
/// Trim for Centcom Bartenders.
/datum/id_trim/centcom/bartender
access = list(ACCESS_CENT_GENERAL, ACCESS_CENT_LIVING, ACCESS_CENT_BAR)
assignment = JOB_CENTCOM_BARTENDER
+ big_pointer = FALSE
/// Trim for Centcom Medical Officers.
/datum/id_trim/centcom/medical_officer
@@ -68,6 +75,7 @@
/// Trim for Centcom Specops Officers. All Centcom and Station Access.
/datum/id_trim/centcom/specops_officer
assignment = JOB_CENTCOM_SPECIAL_OFFICER
+ big_pointer = FALSE
/datum/id_trim/centcom/specops_officer/New()
. = ..()
@@ -129,6 +137,7 @@
trim_state = "trim_securityofficer"
subdepartment_color = COLOR_SECURITY_RED
sechud_icon_state = SECHUD_SECURITY_RESPONSE_OFFICER
+ big_pointer = FALSE
/datum/id_trim/centcom/ert/security/New()
. = ..()
@@ -141,6 +150,7 @@
trim_state = "trim_stationengineer"
subdepartment_color = COLOR_ENGINEERING_ORANGE
sechud_icon_state = SECHUD_ENGINEERING_RESPONSE_OFFICER
+ big_pointer = FALSE
/datum/id_trim/centcom/ert/engineer/New()
. = ..()
@@ -153,6 +163,7 @@
trim_state = "trim_medicaldoctor"
subdepartment_color = COLOR_MEDICAL_BLUE
sechud_icon_state = SECHUD_MEDICAL_RESPONSE_OFFICER
+ big_pointer = FALSE
/datum/id_trim/centcom/ert/medical/New()
. = ..()
@@ -165,6 +176,7 @@
trim_state = "trim_chaplain"
subdepartment_color = COLOR_SERVICE_LIME
sechud_icon_state = SECHUD_RELIGIOUS_RESPONSE_OFFICER
+ big_pointer = FALSE
/datum/id_trim/centcom/ert/chaplain/New()
. = ..()
@@ -177,6 +189,7 @@
trim_state = "trim_ert_janitor"
subdepartment_color = COLOR_SERVICE_LIME
sechud_icon_state = SECHUD_JANITORIAL_RESPONSE_OFFICER
+ big_pointer = FALSE
/datum/id_trim/centcom/ert/janitor/New()
. = ..()
@@ -189,6 +202,7 @@
trim_state = "trim_clown"
subdepartment_color = COLOR_MAGENTA
sechud_icon_state = SECHUD_ENTERTAINMENT_RESPONSE_OFFICER
+ big_pointer = FALSE
/datum/id_trim/centcom/ert/clown/New()
. = ..()
@@ -197,6 +211,8 @@
/datum/id_trim/centcom/ert/militia
assignment = "Frontier Militia"
+ big_pointer = FALSE
/datum/id_trim/centcom/ert/militia/general
assignment = "Frontier Militia General"
+ big_pointer = TRUE
diff --git a/code/datums/id_trim/jobs.dm b/code/datums/id_trim/jobs.dm
index 190c4a38a299c..a42018406b2a5 100644
--- a/code/datums/id_trim/jobs.dm
+++ b/code/datums/id_trim/jobs.dm
@@ -238,6 +238,8 @@
ACCESS_CHANGE_IDS,
)
job = /datum/job/captain
+ big_pointer = TRUE
+ pointer_color = COLOR_COMMAND_BLUE
/// Captain gets all station accesses hardcoded in because it's the Captain.
/datum/id_trim/job/captain/New()
@@ -360,6 +362,8 @@
ACCESS_CHANGE_IDS,
)
job = /datum/job/chief_engineer
+ big_pointer = TRUE
+ pointer_color = COLOR_ENGINEERING_ORANGE
/datum/id_trim/job/chief_medical_officer
assignment = JOB_CHIEF_MEDICAL_OFFICER
@@ -399,6 +403,8 @@
ACCESS_CHANGE_IDS,
)
job = /datum/job/chief_medical_officer
+ big_pointer = TRUE
+ pointer_color = COLOR_MEDICAL_BLUE
/datum/id_trim/job/clown
assignment = JOB_CLOWN
@@ -612,6 +618,8 @@
ACCESS_CHANGE_IDS,
)
job = /datum/job/head_of_personnel
+ big_pointer = TRUE
+ pointer_color = COLOR_SERVICE_LIME
/datum/id_trim/job/head_of_security
assignment = JOB_HEAD_OF_SECURITY
@@ -661,6 +669,8 @@
ACCESS_CHANGE_IDS,
)
job = /datum/job/head_of_security
+ big_pointer = TRUE
+ pointer_color = COLOR_SECURITY_RED
/datum/id_trim/job/head_of_security/refresh_trim_access()
. = ..()
@@ -893,6 +903,8 @@
ACCESS_CHANGE_IDS,
)
job = /datum/job/quartermaster
+ big_pointer = TRUE
+ pointer_color = COLOR_CARGO_BROWN
/datum/id_trim/job/research_director
assignment = JOB_RESEARCH_DIRECTOR
@@ -941,6 +953,8 @@
ACCESS_CHANGE_IDS,
)
job = /datum/job/research_director
+ big_pointer = TRUE
+ pointer_color = COLOR_SCIENCE_PINK
/datum/id_trim/job/roboticist
assignment = JOB_ROBOTICIST
@@ -957,13 +971,13 @@
ACCESS_ROBOTICS,
ACCESS_SCIENCE,
ACCESS_TECH_STORAGE,
+ ACCESS_ORDNANCE,
+ ACCESS_ORDNANCE_STORAGE,
)
extra_access = list(
ACCESS_GENETICS,
ACCESS_XENOBIOLOGY,
ACCESS_MORGUE_SECURE,
- ACCESS_ORDNANCE,
- ACCESS_ORDNANCE_STORAGE,
)
template_access = list(
ACCESS_CAPTAIN,
@@ -1206,6 +1220,7 @@
extra_access = list()
template_access = list()
job = /datum/job/veteran_advisor
+ big_pointer = TRUE
/datum/id_trim/job/veteran_advisor/refresh_trim_access()
. = ..()
@@ -1275,3 +1290,5 @@
extra_access = list()
template_access = list()
job = /datum/job/human_ai
+ big_pointer = TRUE
+ pointer_color = COLOR_MODERATE_BLUE
diff --git a/code/datums/id_trim/ruins.dm b/code/datums/id_trim/ruins.dm
index e308287ec5c5d..1eccc77a985b5 100644
--- a/code/datums/id_trim/ruins.dm
+++ b/code/datums/id_trim/ruins.dm
@@ -72,6 +72,7 @@
/datum/id_trim/centcom/corpse/commander
assignment = "Commander"
access = list(ACCESS_CENT_CAPTAIN, ACCESS_CENT_GENERAL, ACCESS_CENT_SPECOPS, ACCESS_CENT_MEDICAL, ACCESS_CENT_STORAGE)
+ big_pointer = TRUE
/// Trim for various Centcom corpses.
/datum/id_trim/centcom/corpse/private_security
@@ -115,6 +116,7 @@
/datum/id_trim/pirate/captain
assignment = "Pirate Captain"
trim_state = "trim_captain"
+ big_pointer = TRUE
/datum/id_trim/pirate/silverscale
assignment = "Silver Scale Member"
@@ -130,6 +132,7 @@
/datum/id_trim/away/dangerous_research/head_occultist
assignment = "Head Occultist"
access = list(ACCESS_AWAY_SCIENCE, ACCESS_AWAY_COMMAND)
+ big_pointer = TRUE
//Trims for waystation.dmm space ruin
/datum/id_trim/away/waystation/cargo_technician
@@ -143,6 +146,7 @@
trim_state = "trim_quartermaster"
department_color = COLOR_CARGO_BROWN
access = list(ACCESS_AWAY_SUPPLY, ACCESS_AWAY_COMMAND)
+ big_pointer = TRUE
/datum/id_trim/away/waystation/security
assignment = "Waystation Security Officer"
@@ -162,8 +166,9 @@
/datum/id_trim/away/the_outlet/mad_manager
assignment = "The Mad Manager"
access = list(ACCESS_AWAY_GENERAL, ACCESS_AWAY_MEDICAL, ACCESS_AWAY_SEC)
+ big_pointer = TRUE
-//Haunted Trading Post IDs //
+//Haunted Trading Post IDs
/datum/id_trim/away/hauntedtradingpost
assignment = "Donk Co. Employee"
department_color = COLOR_ENGINEERING_ORANGE
@@ -174,4 +179,4 @@
/datum/id_trim/away/hauntedtradingpost/boss
assignment = "Donk Co. Executive"
access = list(ACCESS_SYNDICATE, ACCESS_AWAY_COMMAND)
-// //
+ big_pointer = TRUE
diff --git a/code/datums/id_trim/syndicate.dm b/code/datums/id_trim/syndicate.dm
index 9a3e0c5fc9173..41c76aaf3784c 100644
--- a/code/datums/id_trim/syndicate.dm
+++ b/code/datums/id_trim/syndicate.dm
@@ -7,11 +7,14 @@
sechud_icon_state = SECHUD_SYNDICATE
access = list(ACCESS_SYNDICATE)
threat_modifier = 5 // Bad guy on deck
+ big_pointer = TRUE
+ pointer_color = COLOR_SYNDIE_RED
/// Trim for Syndicate mobs, outfits and corpses.
/datum/id_trim/syndicom/crew
assignment = "Syndicate Operative"
access = list(ACCESS_SYNDICATE, ACCESS_ROBOTICS)
+ big_pointer = FALSE
/// Interdyne medical Staff
/datum/id_trim/syndicom/Interdyne/pharmacist
@@ -19,6 +22,8 @@
trim_state = "trim_medicaldoctor"
sechud_icon_state = SECHUD_SYNDICATE_INTERDYNE
access = list(ACCESS_SYNDICATE, ACCESS_ROBOTICS, ACCESS_SURGERY)
+ big_pointer = FALSE
+ pointer_color = null
/// Interdyne head medical Staff
/datum/id_trim/syndicom/Interdyne/pharmacist_director
@@ -28,6 +33,8 @@
subdepartment_color = COLOR_SYNDIE_RED_HEAD
sechud_icon_state = SECHUD_SYNDICATE_INTERDYNE_HEAD
access = list(ACCESS_SYNDICATE, ACCESS_ROBOTICS, ACCESS_SURGERY)
+ big_pointer = TRUE
+ pointer_color = COLOR_SYNDIE_RED_HEAD
/// Trim for the space IRS agents (why are they syndie access? I wouldn't worry about it.)
/datum/id_trim/syndicom/irs
@@ -37,11 +44,14 @@
subdepartment_color = COLOR_COMMAND_BLUE
sechud_icon_state = SECHUD_DEATH_COMMANDO
access = list(ACCESS_SYNDICATE, ACCESS_MAINT_TUNNELS)
+ big_pointer = FALSE
+ pointer_color = null
/datum/id_trim/syndicom/irs/auditor
assignment = "Internal Revenue Service Head Auditor"
trim_state = "trim_quartermaster"
sechud_icon_state = SECHUD_QUARTERMASTER
+ big_pointer = TRUE
/// Trim for Syndicate mobs, outfits and corpses.
/datum/id_trim/syndicom/captain
@@ -60,6 +70,8 @@
/datum/id_trim/battlecruiser/captain
assignment = "Syndicate Battlecruiser Captain"
access = list(ACCESS_SYNDICATE, ACCESS_SYNDICATE_LEADER)
+ big_pointer = TRUE
+ pointer_color = COLOR_SYNDIE_RED
/// Trim for Chameleon ID cards. Many outfits, nuke ops and some corpses hold Chameleon ID cards.
/datum/id_trim/chameleon
@@ -79,6 +91,8 @@
/datum/id_trim/chameleon/operative/nuke_leader
assignment = "Syndicate Operative Leader"
access = list(ACCESS_MAINT_TUNNELS, ACCESS_SYNDICATE, ACCESS_SYNDICATE_LEADER)
+ big_pointer = TRUE
+ pointer_color = COLOR_SYNDIE_RED
/// Trim for Chameleon ID cards. Many outfits, nuke ops and some corpses hold Chameleon ID cards.
/datum/id_trim/chameleon/operative/clown
@@ -89,3 +103,5 @@
/datum/id_trim/chameleon/operative/clown_leader
assignment = "Syndicate Entertainment Operative Leader"
access = list(ACCESS_MAINT_TUNNELS, ACCESS_SYNDICATE, ACCESS_SYNDICATE_LEADER)
+ big_pointer = TRUE
+ pointer_color = COLOR_SYNDIE_RED
diff --git a/code/datums/json_database.dm b/code/datums/json_database.dm
index ea3ff354b48ce..6baeb44ab091b 100644
--- a/code/datums/json_database.dm
+++ b/code/datums/json_database.dm
@@ -61,6 +61,16 @@
/datum/json_database/proc/get_key(key)
return cached_data[key]
+/// Picks the data of a random key and then removes that key from the database.
+/// Since the list is no longer inside the database, you can mutate and use it as you like.
+/datum/json_database/proc/pick_and_take_key()
+ if(!length(cached_data))
+ return null
+ var/key = pick(cached_data)
+ . = cached_data[key]
+ cached_data -= key
+ queue_save()
+
/// Sets the data at the key to the value, and queues a save.
/datum/json_database/proc/set_key(key, value)
cached_data[key] = value
diff --git a/code/datums/looping_sounds/_looping_sound.dm b/code/datums/looping_sounds/_looping_sound.dm
index 54185efdb8dda..122eab2861e99 100644
--- a/code/datums/looping_sounds/_looping_sound.dm
+++ b/code/datums/looping_sounds/_looping_sound.dm
@@ -2,7 +2,7 @@
* A datum for sounds that need to loop, with a high amount of configurability.
*/
/datum/looping_sound
- /// (list or soundfile) Since this can be either a list or a single soundfile you can have random sounds. May contain further lists but must contain a soundfile at the end.
+ /// (list or soundfile) Since this can be either a list or a single soundfile you can have random sounds. May contain further lists but must contain a soundfile at the end. In a list, path must have also be assigned a value or it will be assigned 0 and not play.
var/mid_sounds
/// The length of time to wait between playing mid_sounds.
var/mid_length
diff --git a/code/datums/looping_sounds/breathing.dm b/code/datums/looping_sounds/breathing.dm
index 82b33ee8311b1..73474149ae4bb 100644
--- a/code/datums/looping_sounds/breathing.dm
+++ b/code/datums/looping_sounds/breathing.dm
@@ -1,8 +1,19 @@
/datum/looping_sound/breathing
- mid_sounds = 'sound/voice/breathing.ogg'
+ mid_sounds = list(
+ 'sound/voice/breathing/internals_breathing1.ogg' = 1,
+ 'sound/voice/breathing/internals_breathing2.ogg' = 1,
+ 'sound/voice/breathing/internals_breathing3.ogg' = 1,
+ 'sound/voice/breathing/internals_breathing4.ogg' = 1,
+ 'sound/voice/breathing/internals_breathing5.ogg' = 1,
+ 'sound/voice/breathing/internals_breathing6.ogg' = 1,
+ 'sound/voice/breathing/internals_breathing7.ogg' = 1,
+ 'sound/voice/breathing/internals_breathing8.ogg' = 1,
+ )
//Calculated this by using the average breathing time of an adult (12 to 20 per minute, which on average is 16 per minute)
- mid_length = 3.75 SECONDS
- mid_length_vary = 0.2 SECONDS
+ // realism is overrated, make it longer to reduce ear fatigue
+ mid_length = 7 SECONDS
+ mid_length_vary = 0.7 SECONDS
//spess station-
- volume = 13
+ volume = 7
pressure_affected = FALSE
+ vary = TRUE
diff --git a/code/datums/looping_sounds/machinery_sounds.dm b/code/datums/looping_sounds/machinery_sounds.dm
index 2d5e3564e6d09..bc32b03125660 100644
--- a/code/datums/looping_sounds/machinery_sounds.dm
+++ b/code/datums/looping_sounds/machinery_sounds.dm
@@ -116,7 +116,7 @@
start_sound = 'sound/machines/computer/computer_start.ogg'
start_length = 7.2 SECONDS
start_volume = 10
- mid_sounds = list('sound/machines/computer/computer_mid1.ogg', 'sound/machines/computer/computer_mid2.ogg')
+ mid_sounds = list('sound/machines/computer/computer_mid1.ogg' = 1, 'sound/machines/computer/computer_mid2.ogg' = 1)
mid_length = 1.8 SECONDS
end_sound = 'sound/machines/computer/computer_end.ogg'
end_volume = 10
@@ -126,10 +126,17 @@
falloff_distance = 1 //Instant falloff after initial tile
/datum/looping_sound/gravgen
- mid_sounds = list('sound/machines/gravgen/gravgen_mid1.ogg' = 1, 'sound/machines/gravgen/gravgen_mid2.ogg' = 1, 'sound/machines/gravgen/gravgen_mid3.ogg' = 1, 'sound/machines/gravgen/gravgen_mid4.ogg' = 1)
- mid_length = 1.8 SECONDS
- extra_range = 10
- volume = 20
+ start_sound = 'sound/machines/gravgen/grav_gen_start.ogg'
+ start_length = 1 SECONDS
+ mid_sounds = list(
+ 'sound/machines/gravgen/grav_gen_mid1.ogg' = 12,
+ 'sound/machines/gravgen/grav_gen_mid2.ogg' = 1,
+ )
+ mid_length = 1.1 SECONDS
+ end_sound = 'sound/machines/gravgen/grav_gen_end.ogg'
+ extra_range = 8
+ vary = TRUE
+ volume = 70
falloff_distance = 5
falloff_exponent = 20
diff --git a/code/datums/martial/_martial.dm b/code/datums/martial/_martial.dm
index e5dc7860b0b2a..8475c9e43f9f0 100644
--- a/code/datums/martial/_martial.dm
+++ b/code/datums/martial/_martial.dm
@@ -211,7 +211,7 @@
* Resets the current streak.
*
* Arguments
- * * mob/living/new_target - (Optional) The mob being attacked while the reset is occuring.
+ * * mob/living/new_target - (Optional) The mob being attacked while the reset is occurring.
* * update_icon - If TRUE, the combo display will be updated.
*/
/datum/martial_art/proc/reset_streak(mob/living/new_target, update_icon = TRUE)
diff --git a/code/datums/martial/boxing.dm b/code/datums/martial/boxing.dm
index 5c24aaf45b7b2..9d6252855d3e1 100644
--- a/code/datums/martial/boxing.dm
+++ b/code/datums/martial/boxing.dm
@@ -7,8 +7,10 @@
name = "Boxing"
id = MARTIALART_BOXING
pacifist_style = TRUE
- ///Boolean on whether we are sportsmanlike in our tussling; TRUE means we have restrictions
+ /// Boolean on whether we are sportsmanlike in our tussling; TRUE means we have restrictions
var/honorable_boxer = TRUE
+ /// Default damage type for our boxing.
+ var/default_damage_type = STAMINA
/// List of traits applied to users of this martial art.
var/list/boxing_traits = list(TRAIT_BOXING_READY)
/// Balloon alert cooldown for warning our boxer to alternate their blows to get more damage
@@ -40,10 +42,16 @@
if(findtext(streak, LEFT_RIGHT_COMBO) || findtext(streak, RIGHT_LEFT_COMBO))
reset_streak()
+ // If we have an extra effect from the combo, perform it here. By default, we have no extra effect.
+ perform_extra_effect(attacker, defender)
return combo_multiplier * 1.5
return combo_multiplier
+/// An extra effect on some moves and attacks.
+/datum/martial_art/boxing/proc/perform_extra_effect(mob/living/attacker, mob/living/defender)
+ return
+
/datum/martial_art/boxing/disarm_act(mob/living/attacker, mob/living/defender)
if(honor_check(defender))
add_to_streak("D", defender)
@@ -88,8 +96,8 @@
// If true, grants experience for punching; we only gain experience if we punch another boxer.
var/grant_experience = FALSE
- // What type of damage does our kind of boxing do? Defaults to STAMINA, unless you're performing EVIL BOXING
- var/damage_type = honorable_boxer ? STAMINA : attacker.get_attack_type()
+ // What type of damage does our kind of boxing do? Defaults to STAMINA for normal boxing, unless you're performing EVIL BOXING. Subtypes use different damage types.
+ var/damage_type = honorable_boxer ? default_damage_type : attacker.get_attack_type()
attacker.do_attack_animation(defender, ATTACK_EFFECT_PUNCH)
@@ -147,12 +155,12 @@
log_combat(attacker, defender, "punched (boxing) ")
+ if(defender.stat == DEAD || !honor_check(defender)) //early returning here so we don't worry about knockout probs or experience gain
+ return TRUE
+
if(grant_experience)
skill_experience_adjustment(attacker, (damage/lower_force))
- if(defender.stat == DEAD || !honor_check(defender)) //early returning here so we don't worry about knockout probs
- return TRUE
-
//Determine our attackers athletics level as a knockout probability bonus
var/attacker_athletics_skill = (attacker.mind?.get_skill_modifier(/datum/skill/athletics, SKILL_RANDS_MODIFIER) + base_unarmed_effectiveness)
@@ -165,6 +173,18 @@
if(!prob(final_knockout_probability))
return TRUE
+ crit_effect(attacker, defender, armor_block, damage_type, damage)
+
+ experience_earned *= 2 //Double our experience gain on a crit hit
+
+ playsound(defender, 'sound/effects/coin2.ogg', 40, TRUE)
+ new /obj/effect/temp_visual/crit(get_turf(defender))
+ skill_experience_adjustment(attacker, experience_earned) //double experience for a successful crit
+
+ return TRUE
+
+/// Our crit effect. For normal boxing, this applies a stagger, then applies a knockout if they're staggered. Other types of boxing apply different kinds of effects.
+/datum/martial_art/boxing/proc/crit_effect(mob/living/attacker, mob/living/defender, armor_block = 0, damage_type = STAMINA, damage = 0)
if(defender.get_timed_status_effect_duration(/datum/status_effect/staggered))
defender.visible_message(
span_danger("[attacker] knocks [defender] out with a haymaker!"),
@@ -189,14 +209,6 @@
to_chat(attacker, span_danger("You stagger [defender] with a haymaker!"))
log_combat(attacker, defender, "staggered (boxing) ")
- experience_earned *= 2 //Double our experience gain on a crit hit
-
- playsound(defender, 'sound/effects/coin2.ogg', 40, TRUE)
- new /obj/effect/temp_visual/crit(get_turf(defender))
- skill_experience_adjustment(attacker, experience_earned) //double experience for a successful crit
-
- return TRUE
-
/// Returns whether whoever is checked by this proc is complying with the rules of boxing. The boxer cannot block non-boxers, and cannot apply their scariest moves against non-boxers.
/datum/martial_art/boxing/proc/honor_check(mob/living/possible_boxer)
if(!honorable_boxer)
@@ -220,7 +232,7 @@
/datum/martial_art/boxing/proc/check_block(mob/living/boxer, atom/movable/hitby, damage, attack_text, attack_type, ...)
SIGNAL_HANDLER
- if(!can_use(boxer) || !boxer.throw_mode || boxer.incapacitated(IGNORE_GRAB))
+ if(!can_use(boxer) || !boxer.throw_mode || INCAPACITATED_IGNORING(boxer, INCAPABLE_GRAB))
return NONE
if(attack_type != UNARMED_ATTACK)
@@ -254,8 +266,9 @@
return NONE
if(istype(attacker) && boxer.Adjacent(attacker))
- attacker.apply_damage(10, STAMINA)
+ attacker.apply_damage(10, default_damage_type)
boxer.apply_damage(5, STAMINA)
+ perform_extra_effect(boxer, attacker)
boxer.visible_message(
span_danger("[boxer] [block_text]s [attack_text]!"),
@@ -271,6 +284,8 @@
return FALSE
return ..()
+// Boxing Variants!
+
/// Evil Boxing; for sick, evil scoundrels. Has no honor, making it more lethal (therefore unable to be used by pacifists).
/// Grants Strength and Stimmed to speed up any experience gain.
@@ -281,6 +296,68 @@
honorable_boxer = FALSE
boxing_traits = list(TRAIT_BOXING_READY, TRAIT_STRENGTH, TRAIT_STIMMED)
+/// Hunter Boxing: for the uncaring, completely deranged one-spacer ecological disaster.
+/// The honor check accepts boxing ready targets, OR various biotypes as valid targets. Uses a special crit effect rather than the standard one (against monsters).
+/// I guess technically, this allows for lethal boxing. If you want.
+/datum/martial_art/boxing/hunter
+ name = "Hunter Boxing"
+ id = MARTIALART_HUNTER_BOXING
+ pacifist_style = FALSE
+ default_damage_type = BRUTE
+ boxing_traits = list(TRAIT_BOXING_READY)
+ /// The mobs we are looking for to pass the honor check
+ var/honorable_mob_biotypes = MOB_BEAST | MOB_SPECIAL | MOB_PLANT | MOB_BUG
+ /// Our crit shout words. First word is then paired with a second word to form an attack name.
+ var/list/first_word_strike = list("Extinction", "Brutalization", "Explosion", "Adventure", "Thunder", "Lightning", "Sonic", "Atomizing", "Whirlwind", "Tornado", "Shark", "Falcon")
+ var/list/second_word_strike = list(" Punch", " Pawnch", "-punch", " Jab", " Hook", " Fist", " Uppercut", " Straight", " Strike", " Lunge")
+
+/datum/martial_art/boxing/hunter/honor_check(mob/living/possible_boxer)
+ if(HAS_TRAIT(possible_boxer, TRAIT_BOXING_READY))
+ return TRUE
+
+ if(possible_boxer.mob_biotypes & MOB_HUMANOID && !istype(possible_boxer, /mob/living/simple_animal/hostile/megafauna)) //We're after animals, not people. Unless they want to box. (Or a megafauna)
+ return FALSE
+
+ if(possible_boxer.mob_biotypes & honorable_mob_biotypes) //We're after animals, not people
+ return TRUE
+
+ return FALSE //rather than default assume TRUE, we default assume FALSE. After all, there could be mobs that are none of our biotypes and also not humanoid. By default, they would be valid for being boxed if TRUE.
+
+// Our hunter boxer applies a rebuke and double damage against the target of their crit. If the target is humanoid, we just perform our regular crit effect instead.
+
+/datum/martial_art/boxing/hunter/crit_effect(mob/living/attacker, mob/living/defender, armor_block = 0, damage_type = STAMINA, damage = 0)
+ if(defender.mob_biotypes & MOB_HUMANOID && !istype(defender, /mob/living/simple_animal/hostile/megafauna))
+ return ..() //Applies the regular crit effect if it is a normal human, and not a megafauna
+
+ var/first_word_pick = pick(first_word_strike)
+ var/second_word_pick = pick(second_word_strike)
+
+ defender.visible_message(
+ span_danger("[attacker] knocks the absolute bajeezus out of [defender] utilizing the terrifying [first_word_pick][second_word_pick]!!!"),
+ span_userdanger("You have the absolute bajeezus knocked out of you by [attacker]!!!"),
+ span_hear("You hear a sickening sound of flesh hitting flesh!"),
+ COMBAT_MESSAGE_RANGE,
+ attacker,
+ )
+ to_chat(attacker, span_danger("You knock the absolute bajeezus out of [defender] out with the terrifying [first_word_pick][second_word_pick]!!!"))
+ if(ishuman(attacker))
+ var/mob/living/carbon/human/human_attacker = attacker
+ human_attacker.force_say()
+ human_attacker.say("[first_word_pick][second_word_pick]!!!", forced = "hunter boxing enthusiastic battlecry")
+ defender.apply_status_effect(/datum/status_effect/rebuked)
+ defender.apply_damage(damage * 2, default_damage_type, BODY_ZONE_CHEST, armor_block) //deals double our damage AGAIN
+ attacker.reagents.add_reagent(/datum/reagent/medicine/omnizine/godblood, 3) //Get a little healing in return for a successful crit
+ log_combat(attacker, defender, "hunter crit punched (boxing)")
+
+// Our hunter boxer speeds up their attacks when completing a combo against a valid target, and does a sizable amount of extra damage.
+
+/datum/martial_art/boxing/hunter/perform_extra_effect(mob/living/attacker, mob/living/defender)
+ if(defender.mob_biotypes & MOB_HUMANOID && !istype(defender, /mob/living/simple_animal/hostile/megafauna))
+ return // Does not apply to humans (who aren't megafauna)
+
+ attacker.changeNext_move(CLICK_CD_RAPID)
+ defender.apply_damage(rand(15,20), default_damage_type, BODY_ZONE_CHEST)
+
#undef LEFT_RIGHT_COMBO
#undef RIGHT_LEFT_COMBO
#undef LEFT_LEFT_COMBO
diff --git a/code/datums/martial/cqc.dm b/code/datums/martial/cqc.dm
index 8e33ac5a851ea..28b820278e21b 100644
--- a/code/datums/martial/cqc.dm
+++ b/code/datums/martial/cqc.dm
@@ -46,7 +46,7 @@
/datum/martial_art/cqc/proc/check_block(mob/living/cqc_user, atom/movable/hitby, damage, attack_text, attack_type, ...)
SIGNAL_HANDLER
- if(!can_use(cqc_user) || !cqc_user.throw_mode || cqc_user.incapacitated(IGNORE_GRAB))
+ if(!can_use(cqc_user) || !cqc_user.throw_mode || INCAPACITATED_IGNORING(cqc_user, INCAPABLE_GRAB))
return NONE
if(attack_type == PROJECTILE_ATTACK)
return NONE
diff --git a/code/datums/martial/sleeping_carp.dm b/code/datums/martial/sleeping_carp.dm
index 330c224070c3e..02d0452fad265 100644
--- a/code/datums/martial/sleeping_carp.dm
+++ b/code/datums/martial/sleeping_carp.dm
@@ -184,7 +184,7 @@
/datum/martial_art/the_sleeping_carp/proc/can_deflect(mob/living/carp_user)
if(!can_use(carp_user) || !carp_user.combat_mode)
return FALSE
- if(carp_user.incapacitated(IGNORE_GRAB)) //NO STUN
+ if(INCAPACITATED_IGNORING(carp_user, INCAPABLE_GRAB)) //NO STUN
return FALSE
if(!(carp_user.mobility_flags & MOBILITY_USE)) //NO UNABLE TO USE
return FALSE
@@ -263,11 +263,10 @@
AddComponent(/datum/component/two_handed, \
force_unwielded = 10, \
force_wielded = 24, \
- icon_wielded = "[base_icon_state]1", \
)
/obj/item/staff/bostaff/update_icon_state()
- icon_state = "[base_icon_state]0"
+ icon_state = inhand_icon_state = "[base_icon_state][HAS_TRAIT(src, TRAIT_WIELDED)]"
return ..()
/obj/item/staff/bostaff/attack(mob/target, mob/living/user, params)
diff --git a/code/datums/materials/_material.dm b/code/datums/materials/_material.dm
index b340d95e90fbd..5dc8c26d0f6a3 100644
--- a/code/datums/materials/_material.dm
+++ b/code/datums/materials/_material.dm
@@ -70,7 +70,7 @@ Simple datum which is instanced once per type and is used for every object of sa
/** Handles initializing the material.
*
- * Arugments:
+ * Arguments:
* - _id: The ID the material should use. Overrides the existing ID.
*/
/datum/material/proc/Initialize(_id, ...)
diff --git a/code/datums/mind/_mind.dm b/code/datums/mind/_mind.dm
index f7597da54cc48..36e9d7ba6d024 100644
--- a/code/datums/mind/_mind.dm
+++ b/code/datums/mind/_mind.dm
@@ -64,7 +64,6 @@
///If this mind's master is another mob (i.e. adamantine golems). Weakref of a /living.
var/datum/weakref/enslaved_to
- var/unconvertable = FALSE
var/late_joiner = FALSE
/// has this mind ever been an AI
var/has_ever_been_ai = FALSE
diff --git a/code/datums/mood.dm b/code/datums/mood.dm
index 8193f9c1c15c9..3834ea866b8da 100644
--- a/code/datums/mood.dm
+++ b/code/datums/mood.dm
@@ -288,7 +288,7 @@
if (SANITY_LEVEL_INSANE)
mood_screen_object.color = "#f15d36"
- if (!conflicting_moodies.len) // theres no special icons, use the normal icon states
+ if (!conflicting_moodies.len) // there's no special icons, use the normal icon states
mood_screen_object.icon_state = "mood[mood_level]"
return
diff --git a/code/datums/mutations/body.dm b/code/datums/mutations/body.dm
index 60551f73911d1..c86f7d7003334 100644
--- a/code/datums/mutations/body.dm
+++ b/code/datums/mutations/body.dm
@@ -160,8 +160,7 @@
// This is specifically happening because they're not used to their new height and are stumbling around into machinery made for normal humans
/datum/mutation/human/acromegaly/proc/head_bonk(mob/living/parent)
SIGNAL_HANDLER
- var/turf/airlock_turf = get_turf(parent)
- var/atom/movable/whacked_by = locate(/obj/machinery/door/airlock) in airlock_turf || locate(/obj/machinery/door/firedoor) in airlock_turf || locate(/obj/structure/mineral_door) in airlock_turf
+ var/atom/movable/whacked_by = (locate(/obj/machinery/door/airlock) in parent.loc) || (locate(/obj/machinery/door/firedoor) in parent.loc) || (locate(/obj/structure/mineral_door) in parent.loc)
if(!whacked_by || prob(100 - (8 * GET_MUTATION_SYNCHRONIZER(src))))
return
to_chat(parent, span_danger("You hit your head on \the [whacked_by]'s header!"))
diff --git a/code/datums/mutations/hulk.dm b/code/datums/mutations/hulk.dm
index 4bc6c77a9fe81..38ecb0fa07356 100644
--- a/code/datums/mutations/hulk.dm
+++ b/code/datums/mutations/hulk.dm
@@ -113,7 +113,7 @@
return
if(!user.throw_mode || user.get_active_held_item() || user.zone_selected != BODY_ZONE_PRECISE_GROIN)
return
- if(user.grab_state < GRAB_NECK || !iscarbon(user.pulling) || user.buckled || user.incapacitated())
+ if(user.grab_state < GRAB_NECK || !iscarbon(user.pulling) || user.buckled || user.incapacitated)
return
var/mob/living/carbon/possible_throwable = user.pulling
@@ -166,7 +166,7 @@
* For each step of the swinging, with the delay getting shorter along the way. Checks to see we still have them in our grasp at each step.
*/
/datum/mutation/human/hulk/proc/swing_loop(mob/living/carbon/human/the_hulk, mob/living/carbon/yeeted_person, step, original_dir)
- if(!yeeted_person || !the_hulk || the_hulk.incapacitated())
+ if(!yeeted_person || !the_hulk || the_hulk.incapacitated)
return
if(get_dist(the_hulk, yeeted_person) > 1 || !isturf(the_hulk.loc) || !isturf(yeeted_person.loc))
to_chat(the_hulk, span_warning("You lose your grasp on [yeeted_person]!"))
@@ -237,7 +237,7 @@
/// Time to toss the victim at high speed
/datum/mutation/human/hulk/proc/finish_swing(mob/living/carbon/human/the_hulk, mob/living/carbon/yeeted_person, original_dir)
- if(!yeeted_person || !the_hulk || the_hulk.incapacitated())
+ if(!yeeted_person || !the_hulk || the_hulk.incapacitated)
return
if(get_dist(the_hulk, yeeted_person) > 1 || !isturf(the_hulk.loc) || !isturf(yeeted_person.loc))
to_chat(the_hulk, span_warning("You lose your grasp on [yeeted_person]!"))
diff --git a/code/datums/mutations/sight.dm b/code/datums/mutations/sight.dm
index 3aceb3e7d8ad2..5a8d7458f3d0f 100644
--- a/code/datums/mutations/sight.dm
+++ b/code/datums/mutations/sight.dm
@@ -110,7 +110,7 @@
///X-ray Vision lets you see through walls.
/datum/mutation/human/xray
name = "X Ray Vision"
- desc = "A strange genome that allows the user to see between the spaces of walls." //actual x-ray would mean you'd constantly be blasting rads, wich might be fun for later //hmb
+ desc = "A strange genome that allows the user to see between the spaces of walls." //actual x-ray would mean you'd constantly be blasting rads, which might be fun for later //hmb
text_gain_indication = span_notice("The walls suddenly disappear!")
instability = POSITIVE_INSTABILITY_MAJOR
locked = TRUE
diff --git a/code/datums/mutations/speech.dm b/code/datums/mutations/speech.dm
index d6b6f714e5964..b9367cfdcdc81 100644
--- a/code/datums/mutations/speech.dm
+++ b/code/datums/mutations/speech.dm
@@ -2,9 +2,6 @@
//Individual ones aren't commented since their functions should be evident at a glance
// no they arent bro
-#define ALPHABET list("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z")
-#define VOWELS list("a", "e", "i", "o", "u")
-#define CONSONANTS (ALPHABET - VOWELS)
/datum/mutation/human/nervousness
name = "Nervousness"
@@ -300,7 +297,3 @@
var/spoken_message = speech_args[SPEECH_MESSAGE]
spoken_message = piglatin_sentence(spoken_message)
speech_args[SPEECH_MESSAGE] = spoken_message
-
-#undef ALPHABET
-#undef VOWELS
-#undef CONSONANTS
diff --git a/code/datums/mutations/touch.dm b/code/datums/mutations/touch.dm
index 98d3d18807fea..2483ef2e0fa1a 100644
--- a/code/datums/mutations/touch.dm
+++ b/code/datums/mutations/touch.dm
@@ -51,7 +51,7 @@
/datum/action/cooldown/spell/touch/shock/cast_on_hand_hit(obj/item/melee/touch_attack/hand, atom/victim, mob/living/carbon/caster)
if(iscarbon(victim))
var/mob/living/carbon/carbon_victim = victim
- if(carbon_victim.electrocute_act(15, caster, 1, SHOCK_NOGLOVES | SHOCK_NOSTUN))//doesnt stun. never let this stun
+ if(carbon_victim.electrocute_act(15, caster, 1, SHOCK_NOGLOVES | SHOCK_NOSTUN))//doesn't stun. never let this stun
carbon_victim.dropItemToGround(carbon_victim.get_active_held_item())
carbon_victim.dropItemToGround(carbon_victim.get_inactive_held_item())
carbon_victim.adjust_confusion(15 SECONDS)
@@ -156,7 +156,7 @@
heal_multiplier = initial(heal_multiplier) * power_coefficient
pain_multiplier = initial(pain_multiplier) * synchronizer_coefficient
- // Message to show on a succesful heal if the healer has a special pacifism interaction with the mutation.
+ // Message to show on a successful heal if the healer has a special pacifism interaction with the mutation.
var/peaceful_message = null
// Heal more, hurt a bit more.
@@ -340,7 +340,7 @@
/obj/item/melee/touch_attack/lay_on_hands
name = "mending touch"
- desc = "Unlike in your favorite tabletop games, you sadly can't cast this on yourself, so you can't use that as a Scapegoat." // mayus is reference. if you get it youre cool
+ desc = "Unlike in your favorite tabletop games, you sadly can't cast this on yourself, so you can't use that as a Scapegoat." // mayus is reference. if you get it you're cool
icon = 'icons/obj/weapons/hand.dmi'
icon_state = "greyscale"
color = COLOR_VERY_PALE_LIME_GREEN
diff --git a/code/datums/outfit.dm b/code/datums/outfit.dm
index e427b2994f066..542d0d6504672 100644
--- a/code/datums/outfit.dm
+++ b/code/datums/outfit.dm
@@ -49,6 +49,13 @@
/// Type path of item to go in belt slot
var/belt = null
+ /**
+ * list of items that should go in the belt of the user
+ *
+ * Format of this list should be: list(path=count,otherpath=count)
+ */
+ var/list/belt_contents = null
+
/// Type path of item to go in ears slot
var/ears = null
@@ -252,6 +259,14 @@
for(var/i in 1 to number)
EQUIP_OUTFIT_ITEM(path, ITEM_SLOT_BACKPACK)
+ if(belt_contents)
+ for(var/path in belt_contents)
+ var/number = belt_contents[path]
+ if(!isnum(number))//Default to 1
+ number = 1
+ for(var/i in 1 to number)
+ EQUIP_OUTFIT_ITEM(path, ITEM_SLOT_BELTPACK)
+
post_equip(user, visualsOnly)
if(!visualsOnly)
@@ -354,8 +369,18 @@
preload += suit_store
preload += back
//Load in backpack gear and shit
- for(var/datum/type_to_load in backpack_contents)
- for(var/i in 1 to backpack_contents[type_to_load])
+ for(var/type_to_load in backpack_contents)
+ var/num_to_load = backpack_contents[type_to_load]
+ if(!isnum(num_to_load))
+ num_to_load = 1
+ for(var/i in 1 to num_to_load)
+ preload += type_to_load
+ //Load in belt gear and shit
+ for(var/type_to_load in belt_contents)
+ var/num_to_load = belt_contents[type_to_load]
+ if(!isnum(num_to_load))
+ num_to_load = 1
+ for(var/i in 1 to num_to_load)
preload += type_to_load
preload += belt
preload += ears
@@ -403,6 +428,7 @@
.["l_hand"] = l_hand
.["internals_slot"] = internals_slot
.["backpack_contents"] = backpack_contents
+ .["belt_contents"] = belt_contents
.["box"] = box
.["implants"] = implants
.["accessory"] = accessory
@@ -430,6 +456,7 @@
l_hand = target.l_hand
internals_slot = target.internals_slot
backpack_contents = target.backpack_contents
+ belt_contents = target.belt_contents
box = target.box
implants = target.implants
accessory = target.accessory
@@ -473,6 +500,12 @@
var/itype = text2path(item)
if(itype)
backpack_contents[itype] = backpack[item]
+ var/list/beltpack = outfit_data["belt_contents"]
+ belt_contents = list()
+ for(var/item in beltpack)
+ var/itype = text2path(item)
+ if(itype)
+ belt_contents[itype] = belt[item]
box = text2path(outfit_data["box"])
var/list/impl = outfit_data["implants"]
implants = list()
diff --git a/code/datums/pod_style.dm b/code/datums/pod_style.dm
index 483f46209eda0..5dc09e3751303 100644
--- a/code/datums/pod_style.dm
+++ b/code/datums/pod_style.dm
@@ -67,7 +67,7 @@
/datum/pod_style/missile
name = "cruise missile"
ui_name = "Missile"
- desc = "A big ass missile that didn't seem to fully detonate. It was likely launched from some far-off deep space missile silo. There appears to be an auxillery payload hatch on the side, though manually opening it is likely impossible."
+ desc = "A big ass missile that didn't seem to fully detonate. It was likely launched from some far-off deep space missile silo. There appears to be an auxiliary payload hatch on the side, though manually opening it is likely impossible."
shape = POD_SHAPE_OTHER
icon_state = "missile"
has_door = FALSE
@@ -79,7 +79,7 @@
/datum/pod_style/missile/syndicate
name = "\improper Syndicate cruise missile"
ui_name = "Syndie Missile"
- desc = "A big ass, blood-red missile that didn't seem to fully detonate. It was likely launched from some deep space Syndicate missile silo. There appears to be an auxillery payload hatch on the side, though manually opening it is likely impossible."
+ desc = "A big ass, blood-red missile that didn't seem to fully detonate. It was likely launched from some deep space Syndicate missile silo. There appears to be an auxiliary payload hatch on the side, though manually opening it is likely impossible."
icon_state = "smissile"
id = "syndie_missile"
diff --git a/code/datums/proximity_monitor/fields/gravity.dm b/code/datums/proximity_monitor/fields/gravity.dm
index b7e22840041dc..745072d69e10a 100644
--- a/code/datums/proximity_monitor/fields/gravity.dm
+++ b/code/datums/proximity_monitor/fields/gravity.dm
@@ -63,3 +63,63 @@
/datum/proximity_monitor/advanced/gravity/warns_on_entrance/proc/clear_recent_warning(mob_ref_key)
LAZYREMOVE(recently_warned, mob_ref_key)
+
+/obj/gravity_fluff_field
+ icon = 'icons/obj/smooth_structures/grav_field.dmi'
+ icon_state = "grav_field-0"
+ base_icon_state = "grav_field"
+ obj_flags = NONE
+ anchored = TRUE
+ move_resist = INFINITY
+ resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ pass_flags_self = LETPASSCLICKS
+ smoothing_flags = SMOOTH_BITMASK
+ smoothing_groups = SMOOTH_GROUP_GRAV_FIELD
+ canSmoothWith = SMOOTH_GROUP_GRAV_FIELD
+ alpha = 200
+ /// our emissive appearance
+ var/mutable_appearance/emissive
+
+/obj/gravity_fluff_field/Initialize(mapload, strength)
+ . = ..()
+ if(isnull(strength))
+ return INITIALIZE_HINT_QDEL
+ QUEUE_SMOOTH(src)
+ QUEUE_SMOOTH_NEIGHBORS(src)
+ switch(strength)
+ if(2 to INFINITY)
+ particles = new /particles/grav_field_down/strong()
+ if(1 to 2)
+ particles = new /particles/grav_field_down()
+ if(0 to 1)
+ particles = new /particles/grav_field_float()
+ if(-INFINITY to -1)
+ particles = new /particles/grav_field_up()
+ color = particles.color
+ RegisterSignal(src, COMSIG_ATOM_SMOOTHED_ICON, PROC_REF(smoothed))
+
+/obj/gravity_fluff_field/Destroy(force)
+ . = ..()
+ QDEL_NULL(particles)
+ emissive = null
+
+/obj/gravity_fluff_field/proc/smoothed(datum/source)
+ SIGNAL_HANDLER
+ cut_overlay(emissive)
+ // because it uses a different name
+ emissive = emissive_appearance('icons/obj/smooth_structures/grav_field_emissive.dmi', "grav_field_emissive-[splittext(icon_state, "-")[2]]", src)
+ add_overlay(emissive)
+
+// Subtype which adds a subtle overlay to all turfs
+/datum/proximity_monitor/advanced/gravity/subtle_effect
+
+/datum/proximity_monitor/advanced/gravity/subtle_effect/setup_field_turf(turf/target)
+ . = ..()
+ if(!isopenturf(target))
+ return
+ new /obj/gravity_fluff_field(target, gravity_value)
+
+/datum/proximity_monitor/advanced/gravity/subtle_effect/cleanup_field_turf(turf/target)
+ . = ..()
+ qdel(locate(/obj/gravity_fluff_field) in target)
diff --git a/code/datums/quirks/_quirk_constant_data.dm b/code/datums/quirks/_quirk_constant_data.dm
index 1984acecec06e..34bde6d9883f2 100644
--- a/code/datums/quirks/_quirk_constant_data.dm
+++ b/code/datums/quirks/_quirk_constant_data.dm
@@ -35,7 +35,7 @@ GLOBAL_LIST_INIT_TYPED(all_quirk_constant_data, /datum/quirk_constant_data, gene
/datum/quirk_constant_data/New()
. = ..()
- ASSERT(abstract_type != type && !isnull(associated_typepath), "associated_typepath null - please set it! occured on: [src.type]")
+ ASSERT(abstract_type != type && !isnull(associated_typepath), "associated_typepath null - please set it! occurred on: [src.type]")
/// Returns a list of savefile_keys derived from the preference typepaths in [customization_options]. Used in quirks middleware to supply the preferences to render.
/datum/quirk_constant_data/proc/get_customization_data()
@@ -47,7 +47,7 @@ GLOBAL_LIST_INIT_TYPED(all_quirk_constant_data, /datum/quirk_constant_data, gene
var/datum/preference/pref_instance = GLOB.preference_entries[pref_type]
if (isnull(pref_instance))
stack_trace("get_customization_data was called before instantiation of [pref_type]!")
- continue // just in case its a fluke and its only this one thats not instantiated, we'll check the other pref entries
+ continue // just in case its a fluke and its only this one that's not instantiated, we'll check the other pref entries
customization_data += pref_instance.savefile_key
diff --git a/code/datums/quirks/negative_quirks/paraplegic.dm b/code/datums/quirks/negative_quirks/paraplegic.dm
index 58e1c4ba31e87..1cbb2dbac1017 100644
--- a/code/datums/quirks/negative_quirks/paraplegic.dm
+++ b/code/datums/quirks/negative_quirks/paraplegic.dm
@@ -9,6 +9,10 @@
hardcore_value = 15
mail_goodies = list(/obj/vehicle/ridden/wheelchair/motorized) //yes a fullsized unfolded motorized wheelchair does fit
+/datum/quirk_constant_data/paraplegic
+ associated_typepath = /datum/quirk/paraplegic
+ customization_options = list(/datum/preference/choiced/paraplegic)
+
/datum/quirk/paraplegic/add_unique(client/client_source)
if(quirk_holder.buckled) // Handle late joins being buckled to arrival shuttle chairs.
quirk_holder.buckled.unbuckle_mob(quirk_holder)
@@ -32,6 +36,16 @@
if(dropped_item.fingerprintslast == quirk_holder.ckey)
quirk_holder.put_in_hands(dropped_item)
+ // Finally, removes their legs if they have opted as such, deleting the shoes
+ var/amputee = GLOB.paraplegic_choice[client_source?.prefs?.read_preference(/datum/preference/choiced/paraplegic)]
+ if(amputee)
+ delete_legs(quirk_holder)
+
+/datum/quirk/paraplegic/proc/delete_legs(mob/living/carbon/human/human_holder)
+ qdel(human_holder.get_item_by_slot(ITEM_SLOT_FEET))
+ qdel(human_holder.get_bodypart(BODY_ZONE_L_LEG))
+ qdel(human_holder.get_bodypart(BODY_ZONE_R_LEG))
+
/datum/quirk/paraplegic/add(client/client_source)
var/mob/living/carbon/human/human_holder = quirk_holder
human_holder.gain_trauma(/datum/brain_trauma/severe/paralysis/paraplegic, TRAUMA_RESILIENCE_ABSOLUTE)
diff --git a/code/datums/quirks/neutral_quirks/transhumanist.dm b/code/datums/quirks/neutral_quirks/transhumanist.dm
index ea6494a6b327b..aa8ae075df395 100644
--- a/code/datums/quirks/neutral_quirks/transhumanist.dm
+++ b/code/datums/quirks/neutral_quirks/transhumanist.dm
@@ -127,10 +127,10 @@
else if(isorgan(new_part))
var/obj/item/organ/new_organ = new_part
old_part = human_holder.get_organ_slot(new_organ.slot)
- if(new_organ.Insert(human_holder, special = TRUE))
- old_part.moveToNullspace()
- STOP_PROCESSING(SSobj, old_part)
- slot_string = new_organ.name
+ new_organ.Insert(human_holder, special = TRUE)
+ old_part.moveToNullspace()
+ STOP_PROCESSING(SSobj, old_part)
+ slot_string = new_organ.name
/datum/quirk/transhumanist/post_add()
if(!slot_string)
diff --git a/code/datums/quirks/positive_quirks/spacer.dm b/code/datums/quirks/positive_quirks/spacer.dm
index 4be27fe16b2e2..051798b4c06a6 100644
--- a/code/datums/quirks/positive_quirks/spacer.dm
+++ b/code/datums/quirks/positive_quirks/spacer.dm
@@ -4,7 +4,7 @@
/datum/quirk/spacer_born
name = "Spacer"
desc = "You were born in space, and have never known the comfort of a planet's gravity. Your body has adapted to this. \
- You are more comfortable in zero and artifical gravity and are more resistant to the effects of space, \
+ You are more comfortable in zero and artificial gravity and are more resistant to the effects of space, \
but travelling to a planet's surface for an extended period of time will make you feel sick."
gain_text = span_notice("You feel at home in space.")
lose_text = span_danger("You feel homesick.")
diff --git a/code/datums/records/crime.dm b/code/datums/records/crime.dm
index a22ce7c816ad2..729b85c56b8e3 100644
--- a/code/datums/records/crime.dm
+++ b/code/datums/records/crime.dm
@@ -12,6 +12,8 @@
var/time
/// Whether the crime is active or not
var/valid = TRUE
+ /// Player that marked the crime as invalid
+ var/voider
/datum/crime/New(name = "Crime", details = "No details provided.", author = "Anonymous")
src.author = author
diff --git a/code/datums/ruins/icemoon.dm b/code/datums/ruins/icemoon.dm
index 14909ab0861f5..2445b4da242e6 100644
--- a/code/datums/ruins/icemoon.dm
+++ b/code/datums/ruins/icemoon.dm
@@ -167,7 +167,7 @@
suffix = "icemoon_underground_frozen_comms.dmm"
/datum/map_template/ruin/icemoon/underground/comms_agent
- name = "Icemoon Listening Post"
+ name = "Ice-Ruin Listening Post"
id = "icemoon_comms_agent"
description = "Radio signals are being detected and the source is this completely innocent pile of snow."
suffix = "icemoon_underground_comms_agent.dmm"
diff --git a/code/datums/ruins/lavaland.dm b/code/datums/ruins/lavaland.dm
index 2cde66f187d14..bb5f58500e2d1 100644
--- a/code/datums/ruins/lavaland.dm
+++ b/code/datums/ruins/lavaland.dm
@@ -323,3 +323,10 @@
description = "Not every shuttle makes it back to CentCom."
suffix = "lavaland_surface_shuttle_wreckage.dmm"
allow_duplicates = FALSE
+
+/datum/map_template/ruin/lavaland/crashsite
+ name = "Lava-Ruin Pod Crashsite"
+ id = "crashsite"
+ description = "They launched too early"
+ suffix = "lavaland_surface_crashsite.dmm"
+ allow_duplicates = FALSE
diff --git a/code/datums/skills/fishing.dm b/code/datums/skills/fishing.dm
index fac1855c98dbc..93c1a57d44175 100644
--- a/code/datums/skills/fishing.dm
+++ b/code/datums/skills/fishing.dm
@@ -11,11 +11,17 @@
/datum/skill/fishing/New()
. = ..()
+ levelUpMessages[SKILL_LEVEL_NOVICE] = span_nicegreen("I'm starting to figure out what [name] really is! I can guess a fish size and weight at a glance.")
+ levelUpMessages[SKILL_LEVEL_APPRENTICE] = span_nicegreen("I'm getting a little better at [name]! I can tell if a fish is hungry, dying and otherwise.")
levelUpMessages[SKILL_LEVEL_JOURNEYMAN] = span_nicegreen("I feel like I've become quite proficient at [name]! I can tell what fishes I can catch at any given fishing spot.")
levelUpMessages[SKILL_LEVEL_MASTER] = span_nicegreen("I've begun to truly understand the surprising depth behind [name]. As a master [title], I can guess what I'm going to catch now!")
/datum/skill/fishing/level_gained(datum/mind/mind, new_level, old_level, silent)
. = ..()
+ if(new_level >= SKILL_LEVEL_NOVICE && old_level < SKILL_LEVEL_NOVICE)
+ ADD_TRAIT(mind, TRAIT_EXAMINE_FISH, SKILL_TRAIT)
+ if(new_level >= SKILL_LEVEL_APPRENTICE && old_level < SKILL_LEVEL_APPRENTICE)
+ ADD_TRAIT(mind, TRAIT_EXAMINE_DEEPER_FISH, SKILL_TRAIT)
if(new_level >= SKILL_LEVEL_JOURNEYMAN && old_level < SKILL_LEVEL_JOURNEYMAN)
ADD_TRAIT(mind, TRAIT_EXAMINE_FISHING_SPOT, SKILL_TRAIT)
if(new_level >= SKILL_LEVEL_MASTER && old_level < SKILL_LEVEL_MASTER)
@@ -27,3 +33,7 @@
REMOVE_TRAIT(mind, TRAIT_REVEAL_FISH, SKILL_TRAIT)
if(old_level >= SKILL_LEVEL_JOURNEYMAN && new_level < SKILL_LEVEL_JOURNEYMAN)
REMOVE_TRAIT(mind, TRAIT_EXAMINE_FISHING_SPOT, SKILL_TRAIT)
+ if(old_level >= SKILL_LEVEL_APPRENTICE && new_level < SKILL_LEVEL_APPRENTICE)
+ REMOVE_TRAIT(mind, TRAIT_EXAMINE_DEEPER_FISH, SKILL_TRAIT)
+ if(old_level >= SKILL_LEVEL_NOVICE && new_level < SKILL_LEVEL_NOVICE)
+ REMOVE_TRAIT(mind, TRAIT_EXAMINE_FISH, SKILL_TRAIT)
diff --git a/code/datums/sprite_accessories.dm b/code/datums/sprite_accessories.dm
index a37926405f9c0..a4394b64d52e5 100644
--- a/code/datums/sprite_accessories.dm
+++ b/code/datums/sprite_accessories.dm
@@ -34,8 +34,6 @@
* This is the source that this accessory will get its color from. Default is MUTCOLOR, but can also be HAIR, FACEHAIR, EYECOLOR and 0 if none.
*/
var/color_src = MUTANT_COLOR
- /// Decides if this sprite has an "inner" part, such as the fleshy parts on ears.
- var/hasinner = FALSE
/// Is this part locked from roundstart selection? Used for parts that apply effects.
var/locked = FALSE
/// Should we center the sprite?
@@ -1890,7 +1888,6 @@
/datum/sprite_accessory/ears/cat
name = "Cat"
icon_state = "cat"
- hasinner = TRUE
color_src = HAIR_COLOR
/datum/sprite_accessory/ears/cat/big
@@ -1917,7 +1914,6 @@
icon = 'icons/mob/human/fox_features.dmi'
name = "Fox"
icon_state = "fox"
- hasinner = TRUE
color_src = HAIR_COLOR
locked = TRUE
@@ -2124,16 +2120,6 @@
name = "Aquatic"
icon_state = "aqua"
-/datum/sprite_accessory/legs //legs are a special case, they aren't actually sprite_accessories but are updated with them.
- icon = null //These datums exist for selecting legs on preference, and little else
- em_block = TRUE
-
-/datum/sprite_accessory/legs/none
- name = "Normal Legs"
-
-/datum/sprite_accessory/legs/digitigrade_lizard
- name = DIGITIGRADE_LEGS
-
/datum/sprite_accessory/caps
icon = 'icons/mob/human/species/mush_cap.dmi'
color_src = HAIR_COLOR
diff --git a/code/datums/station_alert.dm b/code/datums/station_alert.dm
index 5b969afb00513..4c5f3ca7c51c5 100644
--- a/code/datums/station_alert.dm
+++ b/code/datums/station_alert.dm
@@ -61,7 +61,7 @@
data["alarms"] += list(nominal_category)
return data
-/datum/station_alert/ui_act(action, params)
+/datum/station_alert/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/datums/station_traits/_station_trait.dm b/code/datums/station_traits/_station_trait.dm
index 174b127b2d474..ef91a183d9f27 100644
--- a/code/datums/station_traits/_station_trait.dm
+++ b/code/datums/station_traits/_station_trait.dm
@@ -95,6 +95,7 @@ GLOBAL_LIST_EMPTY(lobby_station_traits)
/// Apply any additional handling we need to our lobby button
/datum/station_trait/proc/setup_lobby_button(atom/movable/screen/lobby/button/sign_up/lobby_button)
SHOULD_CALL_PARENT(TRUE)
+ lobby_button.name = name
lobby_buttons |= lobby_button
RegisterSignal(lobby_button, COMSIG_ATOM_UPDATE_ICON, PROC_REF(on_lobby_button_update_icon))
RegisterSignal(lobby_button, COMSIG_SCREEN_ELEMENT_CLICK, PROC_REF(on_lobby_button_click))
diff --git a/code/datums/station_traits/negative_traits.dm b/code/datums/station_traits/negative_traits.dm
index d92467e5edf01..83d1bfa14f4c9 100644
--- a/code/datums/station_traits/negative_traits.dm
+++ b/code/datums/station_traits/negative_traits.dm
@@ -618,8 +618,14 @@
send_supply_pod_to_area(supply_pack_shielding.generate(null), /area/station/command/bridge, /obj/structure/closet/supplypod/centcompod)
// Let medical know resistence is futile
- send_fax_to_area(new /obj/item/paper/fluff/radiation_nebula_virologist(), /area/station/medical/virology, "NT Virology Department", \
- force = TRUE, force_pod_type = /obj/structure/closet/supplypod/centcompod)
+ if (/area/station/medical/virology in GLOB.areas_by_type)
+ send_fax_to_area(
+ new /obj/item/paper/fluff/radiation_nebula_virologist,
+ /area/station/medical/virology,
+ "NT Virology Department",
+ force = TRUE,
+ force_pod_type = /obj/structure/closet/supplypod/centcompod,
+ )
//Disables radstorms, they don't really make sense since we already have the nebula causing storms
var/datum/round_event_control/modified_event = locate(/datum/round_event_control/radiation_storm) in SSevents.control
diff --git a/code/datums/station_traits/neutral_traits.dm b/code/datums/station_traits/neutral_traits.dm
index 3069e644d6e1b..5432701992b29 100644
--- a/code/datums/station_traits/neutral_traits.dm
+++ b/code/datums/station_traits/neutral_traits.dm
@@ -479,7 +479,7 @@
return
if((skub_stance == RANDOM_SKUB && prob(50)) || skub_stance == PRO_SKUB)
- var/obj/item/storage/box/skub/boxie = new(spawned.loc)
+ var/obj/item/storage/box/stickers/skub/boxie = new(spawned.loc)
spawned.equip_to_slot_if_possible(boxie, ITEM_SLOT_BACKPACK, indirect_action = TRUE)
if(ishuman(spawned))
var/obj/item/clothing/suit/costume/wellworn_shirt/skub/shirt = new(spawned.loc)
@@ -496,24 +496,28 @@
shirt.forceMove(boxie)
/// A box containing a skub, for easier carry because skub is a bulky item.
-/obj/item/storage/box/skub
- name = "skub box"
- desc = "A box to store your skub and pro-skub shirt in. A label on the back reads: \"Skubtide, Stationwide\"."
- icon_state = "hugbox"
- illustration = "skub"
-
-/obj/item/storage/box/skub/Initialize(mapload)
+/obj/item/storage/box/stickers/skub
+ name = "skub fan pack"
+ desc = "A vinyl pouch to store your skub and pro-skub shirt in. A label on the back reads: \"Skubtide, Stationwide\"."
+ icon_state = "skubpack"
+ illustration = "label_skub"
+ w_class = WEIGHT_CLASS_SMALL
+
+/obj/item/storage/box/stickers/skub/Initialize(mapload)
. = ..()
+ atom_storage.max_slots = 3
atom_storage.exception_hold = typecacheof(list(/obj/item/skub, /obj/item/clothing/suit/costume/wellworn_shirt/skub))
-/obj/item/storage/box/skub/PopulateContents()
+/obj/item/storage/box/stickers/skub/PopulateContents()
new /obj/item/skub(src)
new /obj/item/sticker/skub(src)
new /obj/item/sticker/skub(src)
/obj/item/storage/box/stickers/anti_skub
- name = "anti-skub stickers box"
- desc = "The enemy may have been given a skub and a shirt, but I've more stickers! Plus the box can hold my anti-skub shirt."
+ name = "anti-skub stickers pack"
+ desc = "The enemy may have been given a skub and a shirt, but I've got more stickers! Plus the pack can hold my anti-skub shirt."
+ icon_state = "skubpack"
+ illustration = "label_anti_skub"
/obj/item/storage/box/stickers/anti_skub/Initialize(mapload)
. = ..()
diff --git a/code/datums/status_effects/food_effects.dm b/code/datums/status_effects/buffs/food/_food_effect.dm
similarity index 64%
rename from code/datums/status_effects/food_effects.dm
rename to code/datums/status_effects/buffs/food/_food_effect.dm
index f36f1e2034d9c..fe63df29e3a8a 100644
--- a/code/datums/status_effects/food_effects.dm
+++ b/code/datums/status_effects/buffs/food/_food_effect.dm
@@ -1,19 +1,18 @@
/// Buffs given by eating hand-crafted food. The duration scales with consumable reagents purity.
/datum/status_effect/food
- id = "food_buff"
+ id = "food_effect"
duration = 5 MINUTES // Same as food mood buffs
status_type = STATUS_EFFECT_REPLACE // Only one food buff allowed
alert_type = /atom/movable/screen/alert/status_effect/food
show_duration = TRUE
- /// Buff power
+ /// Buff power equal to food complexity (1 to 5)
var/strength
/datum/status_effect/food/on_creation(mob/living/new_owner, timeout_mod = 1, strength = 1)
+ . = ..()
src.strength = strength
- //Generate alert when not specified
if(isnum(timeout_mod))
duration *= timeout_mod
- . = ..()
if(istype(linked_alert, /atom/movable/screen/alert/status_effect/food))
linked_alert.icon_state = "[linked_alert.base_icon_state]_[strength]"
@@ -22,19 +21,3 @@
desc = "Eating it made me feel better."
icon_state = "food_buff_1"
base_icon_state = "food_buff"
-
-/// Makes you gain a trait
-/datum/status_effect/food/trait
- var/trait = TRAIT_DUMB // You need to override this
-
-/datum/status_effect/food/trait/on_apply()
- ADD_TRAIT(owner, trait, type)
- return ..()
-
-/datum/status_effect/food/trait/be_replaced()
- REMOVE_TRAIT(owner, trait, type)
- return ..()
-
-/datum/status_effect/food/trait/on_remove()
- REMOVE_TRAIT(owner, trait, type)
- return ..()
diff --git a/code/datums/status_effects/buffs/food/food_traits.dm b/code/datums/status_effects/buffs/food/food_traits.dm
deleted file mode 100644
index dfd0b888aa096..0000000000000
--- a/code/datums/status_effects/buffs/food/food_traits.dm
+++ /dev/null
@@ -1,7 +0,0 @@
-/datum/status_effect/food/trait/shockimmune
- alert_type = /atom/movable/screen/alert/status_effect/food/trait_shockimmune
- trait = TRAIT_SHOCKIMMUNE
-
-/atom/movable/screen/alert/status_effect/food/trait_shockimmune
- name = "Grounded"
- desc = "That meal made me feel like a superconductor..."
diff --git a/code/datums/status_effects/buffs/food/grant_trait.dm b/code/datums/status_effects/buffs/food/grant_trait.dm
new file mode 100644
index 0000000000000..f25be3b0b3bfd
--- /dev/null
+++ b/code/datums/status_effects/buffs/food/grant_trait.dm
@@ -0,0 +1,56 @@
+/// Makes you gain a trait
+/datum/status_effect/food/trait
+ var/trait = TRAIT_DUMB // You need to override this
+
+/datum/status_effect/food/trait/on_apply()
+ if(!HAS_TRAIT_FROM(owner, trait, type)) // Check if trait was already applied
+ ADD_TRAIT(owner, trait, type)
+ return ..()
+
+/datum/status_effect/food/trait/be_replaced()
+ REMOVE_TRAIT(owner, trait, type)
+ return ..()
+
+/datum/status_effect/food/trait/on_remove()
+ REMOVE_TRAIT(owner, trait, type)
+ return ..()
+
+/datum/status_effect/food/trait/shockimmune
+ alert_type = /atom/movable/screen/alert/status_effect/shockimmune
+ trait = TRAIT_SHOCKIMMUNE
+
+/atom/movable/screen/alert/status_effect/shockimmune
+ name = "Grounded"
+ desc = "That meal made me feel like a superconductor..."
+ icon_state = "shock_immune"
+
+/datum/status_effect/food/trait/mute
+ alert_type = /atom/movable/screen/alert/status_effect/mute
+ trait = TRAIT_MUTE
+
+/atom/movable/screen/alert/status_effect/mute
+ name = "..."
+ desc = "..."
+ icon_state = "mute"
+
+/datum/status_effect/food/trait/ashstorm_immune
+ alert_type = /atom/movable/screen/alert/status_effect/ashstorm_immune
+ trait = TRAIT_ASHSTORM_IMMUNE
+
+/atom/movable/screen/alert/status_effect/ashstorm_immune
+ name = "Ashstorm-proof"
+ desc = "That meal makes me feel born on Lavaland."
+ icon_state = "ashstorm_immune"
+
+/datum/status_effect/food/trait/waddle
+ alert_type = /atom/movable/screen/alert/status_effect/waddle
+ trait = TRAIT_WADDLING
+
+/datum/status_effect/food/trait/waddle/on_apply()
+ owner.AddElementTrait(trait, type, /datum/element/waddling)
+ return ..()
+
+/atom/movable/screen/alert/status_effect/waddle
+ name = "Waddling"
+ desc = "That meal makes me want to joke around."
+ icon_state = "waddle"
diff --git a/code/datums/status_effects/buffs/food/speech.dm b/code/datums/status_effects/buffs/food/speech.dm
new file mode 100644
index 0000000000000..634fd739709b3
--- /dev/null
+++ b/code/datums/status_effects/buffs/food/speech.dm
@@ -0,0 +1,45 @@
+///Temporary modifies the speech using the /datum/component/speechmod
+/datum/status_effect/food/speech
+
+/datum/status_effect/food/speech/italian
+ alert_type = /atom/movable/screen/alert/status_effect/italian_speech
+
+/datum/status_effect/food/speech/italian/on_apply()
+ AddComponent( \
+ /datum/component/speechmod, \
+ replacements = strings("italian_replacement.json", "italian"), \
+ end_string = list(
+ " Ravioli, ravioli, give me the formuoli!",
+ " Mamma-mia!",
+ " Mamma-mia! That's a spicy meat-ball!",
+ " La la la la la funiculi funicula!"
+ ), \
+ end_string_chance = 3 \
+ )
+ return ..()
+
+/atom/movable/screen/alert/status_effect/italian_speech
+ name = "Linguini Embrace"
+ desc = "You feel a sudden urge to gesticulate wildly."
+ icon_state = "food_italian"
+
+/datum/status_effect/food/speech/french
+ alert_type = /atom/movable/screen/alert/status_effect/french_speech
+
+/datum/status_effect/food/speech/french/on_apply()
+ AddComponent( \
+ /datum/component/speechmod, \
+ replacements = strings("french_replacement.json", "french"), \
+ end_string = list(
+ " Honh honh honh!",
+ " Honh!",
+ " Zut Alors!"
+ ), \
+ end_string_chance = 3, \
+ )
+ return ..()
+
+/atom/movable/screen/alert/status_effect/french_speech
+ name = "Café Chic"
+ desc = "Suddenly, everything seems worthy of a passionate debate."
+ icon_state = "food_french"
diff --git a/code/datums/status_effects/debuffs/debuffs.dm b/code/datums/status_effects/debuffs/debuffs.dm
index df93089633629..08f5ae101bf77 100644
--- a/code/datums/status_effects/debuffs/debuffs.dm
+++ b/code/datums/status_effects/debuffs/debuffs.dm
@@ -1,11 +1,11 @@
/// The damage healed per tick while sleeping without any modifiers
#define HEALING_SLEEP_DEFAULT 0.2
-/// The sleep healing multipler for organ passive healing (since organs heal slowly)
+/// The sleep healing multiplier for organ passive healing (since organs heal slowly)
#define HEALING_SLEEP_ORGAN_MULTIPLIER 5
-/// The sleep multipler for fitness xp conversion
+/// The sleep multiplier for fitness xp conversion
#define SLEEP_QUALITY_WORKOUT_MULTIPLER 10
-//Largely negative status effects go here, even if they have small benificial effects
+//Largely negative status effects go here, even if they have small beneficial effects
//STUN EFFECTS
/datum/status_effect/incapacitating
tick_interval = -1
@@ -606,7 +606,7 @@
alert_type = null
/datum/status_effect/spasms/tick(seconds_between_ticks)
- if(owner.stat >= UNCONSCIOUS || owner.incapacitated() || HAS_TRAIT(owner, TRAIT_HANDS_BLOCKED) || HAS_TRAIT(owner, TRAIT_IMMOBILIZED))
+ if(owner.stat >= UNCONSCIOUS || owner.incapacitated || HAS_TRAIT(owner, TRAIT_HANDS_BLOCKED) || HAS_TRAIT(owner, TRAIT_IMMOBILIZED))
return
if(!prob(15))
return
@@ -732,7 +732,7 @@
status_type = STATUS_EFFECT_REPLACE
tick_interval = 0.2 SECONDS
alert_type = null
- var/msg_stage = 0//so you dont get the most intense messages immediately
+ var/msg_stage = 0//so you don't get the most intense messages immediately
/datum/status_effect/fake_virus/on_apply()
if(HAS_TRAIT(owner, TRAIT_VIRUSIMMUNE))
diff --git a/code/datums/status_effects/debuffs/slime/slime_leech.dm b/code/datums/status_effects/debuffs/slime/slime_leech.dm
index 49bd0f7b82c84..78ccacc89d8cb 100644
--- a/code/datums/status_effects/debuffs/slime/slime_leech.dm
+++ b/code/datums/status_effects/debuffs/slime/slime_leech.dm
@@ -66,7 +66,7 @@
if(need_mob_update)
owner.updatehealth()
- if(totaldamage >= 0) // AdjustBruteLoss returns a negative value on succesful damage adjustment
+ if(totaldamage >= 0) // AdjustBruteLoss returns a negative value on successful damage adjustment
our_slime.balloon_alert(our_slime, "not food!")
our_slime.stop_feeding()
return
diff --git a/code/datums/status_effects/debuffs/staggered.dm b/code/datums/status_effects/debuffs/staggered.dm
index 9db72e1fd06ee..1291da1307a61 100644
--- a/code/datums/status_effects/debuffs/staggered.dm
+++ b/code/datums/status_effects/debuffs/staggered.dm
@@ -4,7 +4,7 @@
/// Staggered can occur most often via shoving, but can also occur in other places too.
/datum/status_effect/staggered
id = "staggered"
- tick_interval = 0.5 SECONDS
+ tick_interval = 0.8 SECONDS
alert_type = null
remove_on_fullheal = TRUE
@@ -25,7 +25,7 @@
UnregisterSignal(owner, COMSIG_LIVING_DEATH)
owner.remove_movespeed_modifier(/datum/movespeed_modifier/staggered)
// Resetting both X on remove so we're back to normal
- owner.pixel_x = owner.base_pixel_x
+ animate(owner, pixel_x = owner.base_pixel_x, time = 0.2 SECONDS, flags = ANIMATION_PARALLEL)
/// Signal proc that self deletes our staggered effect
/datum/status_effect/staggered/proc/clear_staggered(datum/source)
@@ -40,13 +40,16 @@
return
if(HAS_TRAIT(owner, TRAIT_FAKEDEATH))
return
- owner.do_stagger_animation()
+ INVOKE_ASYNC(owner, TYPE_PROC_REF(/mob/living, do_stagger_animation))
/// Helper proc that causes the mob to do a stagger animation.
/// Doesn't change significantly, just meant to represent swaying back and forth
/mob/living/proc/do_stagger_animation()
- animate(src, pixel_x = 4, time = 0.2 SECONDS, loop = 6, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL)
- animate(pixel_x = -4, time = 0.2 SECONDS, flags = ANIMATION_RELATIVE)
+ animate(src, pixel_x = 4, time = 0.2 SECONDS, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL)
+ sleep(0.2 SECONDS)
+ animate(src, pixel_x = -8, time = 0.2 SECONDS, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL)
+ sleep(0.2 SECONDS)
+ animate(src, pixel_x = 4, time = 0.2 SECONDS, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL)
/// Status effect specifically for instances where someone is vulnerable to being stunned when shoved.
/datum/status_effect/next_shove_stuns
diff --git a/code/datums/status_effects/debuffs/strandling.dm b/code/datums/status_effects/debuffs/strandling.dm
index 6050a3df304da..0ce0ad4188221 100644
--- a/code/datums/status_effects/debuffs/strandling.dm
+++ b/code/datums/status_effects/debuffs/strandling.dm
@@ -57,7 +57,7 @@
* tool - the tool the user's using to remove the strange. Can be null.
*/
/datum/status_effect/strandling/proc/try_remove_effect(mob/user, obj/item/tool)
- if(user.incapacitated() || HAS_TRAIT(user, TRAIT_HANDS_BLOCKED))
+ if(user.incapacitated || HAS_TRAIT(user, TRAIT_HANDS_BLOCKED))
return
user.visible_message(
diff --git a/code/datums/status_effects/drug_effects.dm b/code/datums/status_effects/drug_effects.dm
index 1d37c8f0e43eb..bb86e2b014bf3 100644
--- a/code/datums/status_effects/drug_effects.dm
+++ b/code/datums/status_effects/drug_effects.dm
@@ -52,7 +52,7 @@
owner.set_jitter_if_lower(100 SECONDS)
owner.Paralyze(duration)
owner.visible_message(span_warning("[owner] drops to the ground as [owner.p_they()] start seizing up."), \
- span_warning("[pick("You can't collect your thoughts...", "You suddenly feel extremely dizzy...", "You cant think straight...","You can't move your face properly anymore...")]"))
+ span_warning("[pick("You can't collect your thoughts...", "You suddenly feel extremely dizzy...", "You can't think straight...","You can't move your face properly anymore...")]"))
return TRUE
/atom/movable/screen/alert/status_effect/seizure
diff --git a/code/datums/status_effects/stacking_effect.dm b/code/datums/status_effects/stacking_effect.dm
index 98dd1c3ad14e7..b54734155ad92 100644
--- a/code/datums/status_effects/stacking_effect.dm
+++ b/code/datums/status_effects/stacking_effect.dm
@@ -8,7 +8,7 @@
/// How many stacks are currently accumulated.
/// Also, the default stacks number given on application.
var/stacks = 0
- // Deciseconds until ticks start occuring, which removes stacks
+ // Deciseconds until ticks start occurring, which removes stacks
/// (first stack will be removed at this time plus tick_interval)
var/delay_before_decay
/// How many stacks are lost per tick (decay trigger)
@@ -31,11 +31,11 @@
/// Put the state name without the number in these state vars
var/overlay_state
/// Icon state for underlays applied when the status effect is applied
- /// The number is concatonated onto the string based on the number of stacks to get the correct state name.
+ /// The number is concatenated onto the string based on the number of stacks to get the correct state name.
var/underlay_state
/// A reference to our overlay appearance
var/mutable_appearance/status_overlay
- /// A referenceto our underlay appearance
+ /// A reference to our underlay appearance
var/mutable_appearance/status_underlay
/// Effects that occur when the stack count crosses stack_threshold
@@ -90,7 +90,7 @@
owner.underlays -= status_underlay
stacks += stacks_added
if(stacks > 0)
- if(stacks >= stack_threshold && !threshold_crossed) //threshold_crossed check prevents threshold effect from occuring if changing from above threshold to still above threshold
+ if(stacks >= stack_threshold && !threshold_crossed) //threshold_crossed check prevents threshold effect from occurring if changing from above threshold to still above threshold
threshold_crossed = TRUE
on_threshold_cross()
if(consumed_on_threshold)
diff --git a/code/datums/storage/storage.dm b/code/datums/storage/storage.dm
index 7cdb9d406152b..8bdfa3f3de2a3 100644
--- a/code/datums/storage/storage.dm
+++ b/code/datums/storage/storage.dm
@@ -43,7 +43,10 @@
/// Determines whether we play a rustle animation when inserting/removing items.
var/animated = TRUE
/// Determines whether we play a rustle sound when inserting/removing items.
- var/rustle_sound = TRUE
+ var/do_rustle = TRUE
+ var/rustle_vary = TRUE
+ /// Path for the item's rustle sound.
+ var/rustle_sound = SFX_RUSTLE
/// The sound to play when we open/access the storage
var/open_sound
var/open_sound_vary = TRUE
@@ -386,7 +389,7 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches)
user.balloon_alert(user, "no room!")
return FALSE
- var/can_hold_it = isnull(can_hold) || is_type_in_typecache(to_insert, can_hold)
+ var/can_hold_it = isnull(can_hold) || is_type_in_typecache(to_insert, can_hold) || is_type_in_typecache(to_insert, exception_hold)
var/cant_hold_it = is_type_in_typecache(to_insert, cant_hold)
var/trait_says_no = HAS_TRAIT(to_insert, TRAIT_NO_STORAGE_INSERT)
if(!can_hold_it || cant_hold_it || trait_says_no)
@@ -529,8 +532,8 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches)
if(silent)
return
- if(rustle_sound)
- playsound(parent, SFX_RUSTLE, 50, TRUE, -5)
+ if(do_rustle)
+ playsound(parent, rustle_sound, 50, rustle_vary, -5)
if(!silent_for_user)
to_chat(user, span_notice("You put [thing] [insert_preposition]to [parent]."))
@@ -560,7 +563,7 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches)
reset_item(thing)
thing.forceMove(remove_to_loc)
- if(rustle_sound && !silent)
+ if(do_rustle && !silent)
playsound(parent, SFX_RUSTLE, 50, TRUE, -5)
else
thing.moveToNullspace()
@@ -735,7 +738,7 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches)
/datum/storage/proc/on_mousedrop_onto(datum/source, atom/over_object, mob/user)
SIGNAL_HANDLER
- if(ismecha(user.loc) || !user.canUseStorage())
+ if(ismecha(user.loc) || user.incapacitated || !user.canUseStorage())
return
if(istype(over_object, /atom/movable/screen/inventory/hand))
@@ -794,7 +797,7 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches)
if(dest_object.atom_storage)
to_chat(user, span_notice("You dump the contents of [parent] into [dest_object]."))
- if(rustle_sound)
+ if(do_rustle)
playsound(parent, SFX_RUSTLE, 50, TRUE, -5)
for(var/obj/item/to_dump in real_location)
@@ -824,6 +827,9 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches)
return
if(!iscarbon(user) && !isdrone(user))
return
+ var/mob/living/user_living = user
+ if(user_living.incapacitated)
+ return
attempt_insert(dropping, user)
return COMPONENT_CANCEL_MOUSEDROPPED_ONTO
@@ -957,7 +963,7 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches)
if(animated)
animate_parent()
- if(rustle_sound)
+ if(do_rustle && !silent)
playsound(parent, (open_sound ? open_sound : SFX_RUSTLE), 50, open_sound_vary, -5)
return TRUE
diff --git a/code/datums/storage/subtypes/extract_inventory.dm b/code/datums/storage/subtypes/extract_inventory.dm
index 9d75b6eb1d336..621e44654511c 100644
--- a/code/datums/storage/subtypes/extract_inventory.dm
+++ b/code/datums/storage/subtypes/extract_inventory.dm
@@ -5,7 +5,7 @@
attack_hand_interact = FALSE
quickdraw = FALSE
locked = STORAGE_FULLY_LOCKED
- rustle_sound = FALSE
+ do_rustle = FALSE
silent = TRUE
// Snowflake so you can feed it
insert_on_attack = FALSE
diff --git a/code/datums/storage/subtypes/fish_case.dm b/code/datums/storage/subtypes/fish_case.dm
index 82733d37ad985..47103e931b1f8 100644
--- a/code/datums/storage/subtypes/fish_case.dm
+++ b/code/datums/storage/subtypes/fish_case.dm
@@ -1,6 +1,6 @@
/datum/storage/fish_case
max_slots = 1
- max_specific_storage = WEIGHT_CLASS_HUGE
+ max_specific_storage = WEIGHT_CLASS_GIGANTIC
can_hold_description = "Fish and aquarium equipment"
/datum/storage/fish_case/can_insert(obj/item/to_insert, mob/user, messages, force)
@@ -13,11 +13,13 @@
return FALSE
return .
+/datum/storage/fish_case/adjust_size
+
/*
* Change the size of the storage item to match the inserted item's
* Because of that, we also check if conditions to keep it inside another storage or pockets are still met.
*/
-/datum/storage/fish_case/handle_enter(datum/source, obj/item/arrived)
+/datum/storage/fish_case/adjust_size/handle_enter(datum/source, obj/item/arrived)
. = ..()
if(!isitem(parent) || !istype(arrived))
return
@@ -26,7 +28,7 @@
return
item_parent.update_weight_class(arrived.w_class)
-/datum/storage/fish_case/handle_exit(datum/source, obj/item/gone)
+/datum/storage/fish_case/adjust_size/handle_exit(datum/source, obj/item/gone)
. = ..()
if(!isitem(parent) || !istype(gone))
return
diff --git a/code/datums/storage/subtypes/pockets.dm b/code/datums/storage/subtypes/pockets.dm
index edf3816c274ee..4e0e233121a28 100644
--- a/code/datums/storage/subtypes/pockets.dm
+++ b/code/datums/storage/subtypes/pockets.dm
@@ -2,7 +2,7 @@
max_slots = 2
max_specific_storage = WEIGHT_CLASS_SMALL
max_total_storage = 50
- rustle_sound = FALSE
+ do_rustle = FALSE
/datum/storage/pockets/attempt_insert(obj/item/to_insert, mob/user, override, force, messages)
. = ..()
diff --git a/code/datums/view.dm b/code/datums/view.dm
index 19ba66c390040..90d07c667967c 100644
--- a/code/datums/view.dm
+++ b/code/datums/view.dm
@@ -1,19 +1,19 @@
//This is intended to be a full wrapper. DO NOT directly modify its values
///Container for client viewsize
/datum/view_data
- /// Width offset to apply to the default view string if we're not supressed for some reason
+ /// Width offset to apply to the default view string if we're not suppressed for some reason
var/width = 0
/// Height offset to apply to the default view string, see above
var/height = 0
/// This client's current "default" view, in the format "WidthxHeight"
/// We add/remove from this when we want to change their window size
var/default = ""
- /// This client's current zoom level, if it's not being supressed
+ /// This client's current zoom level, if it's not being suppressed
/// If it's 0, we autoscale to the size of the window. Otherwise it's treated as the ratio between
/// the pixels on the map and output pixels. Only looks proper nice in increments of whole numbers (iirc)
/// Stored here so other parts of the code have a non blocking way of getting a user's functional zoom
var/zoom = 0
- /// If the view is currently being supressed by some other "monitor"
+ /// If the view is currently being suppressed by some other "monitor"
/// For when you want to own the client's eye without fucking with their viewport
/// Doesn't make sense for a binocoler to effect your view in a camera console
var/is_suppressed = FALSE
@@ -73,7 +73,7 @@
apply()
/datum/view_data/proc/setTo(toAdd)
- var/list/shitcode = getviewsize(toAdd) //Backward compatability to account
+ var/list/shitcode = getviewsize(toAdd) //Backward compatibility to account
width = shitcode[1] //for a change in how sizes get calculated. we used to include world.view in
height = shitcode[2] //this, but it was jank, so I had to move it
apply()
diff --git a/code/datums/weather/weather_types/radiation_storm.dm b/code/datums/weather/weather_types/radiation_storm.dm
index a20b552df4f04..8a1cfff765733 100644
--- a/code/datums/weather/weather_types/radiation_storm.dm
+++ b/code/datums/weather/weather_types/radiation_storm.dm
@@ -20,7 +20,7 @@
protected_areas = list(/area/station/maintenance, /area/station/ai_monitored/turret_protected/ai_upload, /area/station/ai_monitored/turret_protected/ai_upload_foyer,
/area/station/ai_monitored/turret_protected/aisat/maint, /area/station/ai_monitored/command/storage/satellite,
/area/station/ai_monitored/turret_protected/ai, /area/station/commons/storage/emergency/starboard, /area/station/commons/storage/emergency/port,
- /area/shuttle, /area/station/security/prison/safe, /area/station/security/prison/toilet, /area/icemoon/underground, /area/ruin/comms_agent/maint)
+ /area/shuttle, /area/station/security/prison/safe, /area/station/security/prison/toilet, /area/mine/maintenance, /area/icemoon/underground, /area/ruin/comms_agent/maint)
target_trait = ZTRAIT_STATION
immunity_type = TRAIT_RADSTORM_IMMUNE
diff --git a/code/datums/weather/weather_types/void_storm.dm b/code/datums/weather/weather_types/void_storm.dm
index 4d3638c582711..90cc7d44cfbe1 100644
--- a/code/datums/weather/weather_types/void_storm.dm
+++ b/code/datums/weather/weather_types/void_storm.dm
@@ -34,8 +34,8 @@
/datum/weather/void_storm/weather_act(mob/living/victim)
var/need_mob_update = FALSE
- victim.adjustFireLoss(1, updating_health = FALSE)
- victim.adjustOxyLoss(rand(1, 3), updating_health = FALSE)
+ need_mob_update += victim.adjustFireLoss(1, updating_health = FALSE)
+ need_mob_update += victim.adjustOxyLoss(rand(1, 3), updating_health = FALSE)
if(need_mob_update)
victim.updatehealth()
victim.adjust_eye_blur(rand(0 SECONDS, 2 SECONDS))
diff --git a/code/datums/wires/_wires.dm b/code/datums/wires/_wires.dm
index c3c8a1c0e93e1..73bdc511ee4ba 100644
--- a/code/datums/wires/_wires.dm
+++ b/code/datums/wires/_wires.dm
@@ -348,7 +348,7 @@
data["proper_name"] = (proper_name != "Unknown") ? proper_name : null
return data
-/datum/wires/ui_act(action, params)
+/datum/wires/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(. || !interactable(usr))
return
diff --git a/code/datums/wires/mecha.dm b/code/datums/wires/mecha.dm
index 4e11eda65f7f6..2fe8f19517403 100644
--- a/code/datums/wires/mecha.dm
+++ b/code/datums/wires/mecha.dm
@@ -95,12 +95,13 @@
if(mecha.Adjacent(target) && !TIMER_COOLDOWN_RUNNING(mecha, COOLDOWN_MECHA_MELEE_ATTACK) && target.mech_melee_attack(mecha))
TIMER_COOLDOWN_START(mecha, COOLDOWN_MECHA_MELEE_ATTACK, mecha.melee_cooldown)
-/datum/wires/mecha/ui_act(action, params)
+/datum/wires/mecha/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
+ var/mob/user = ui.user
var/obj/vehicle/sealed/mecha/mecha = holder
- if(!HAS_SILICON_ACCESS(usr) && mecha.internal_damage & MECHA_INT_SHORT_CIRCUIT && mecha.shock(usr))
+ if(!HAS_SILICON_ACCESS(user) && mecha.internal_damage & MECHA_INT_SHORT_CIRCUIT && mecha.shock(usr))
return FALSE
/datum/wires/mecha/can_reveal_wires(mob/user)
diff --git a/code/datums/wires/mod.dm b/code/datums/wires/mod.dm
index 00d836a52eba4..8250bc45f69c9 100644
--- a/code/datums/wires/mod.dm
+++ b/code/datums/wires/mod.dm
@@ -50,9 +50,10 @@
if(WIRE_INTERFACE)
mod.interface_break = !mend
-/datum/wires/mod/ui_act(action, params)
+/datum/wires/mod/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
var/obj/item/mod/control/mod = holder
- if(!HAS_SILICON_ACCESS(usr) && mod.seconds_electrified && mod.shock(usr))
+ var/mob/user = ui.user
+ if(!HAS_SILICON_ACCESS(user) && mod.seconds_electrified && mod.shock(user))
return FALSE
return ..()
diff --git a/code/datums/wounds/_wound_static_data.dm b/code/datums/wounds/_wound_static_data.dm
index f996bb258c795..f8b03d1856b5d 100644
--- a/code/datums/wounds/_wound_static_data.dm
+++ b/code/datums/wounds/_wound_static_data.dm
@@ -1,6 +1,6 @@
// This datum is merely a singleton instance that allows for custom "can be applied" behaviors without instantiating a wound instance.
// For example: You can make a pregen_data subtype for your wound that overrides can_be_applied_to to only apply to specifically slimeperson limbs.
-// Without this, youre stuck with very static initial variables.
+// Without this, you're stuck with very static initial variables.
/// A singleton datum that holds pre-gen and static data about a wound. Each wound datum should have a corresponding wound_pregen_data.
/datum/wound_pregen_data
@@ -56,9 +56,9 @@
if (!abstract)
if (required_limb_biostate == null)
- stack_trace("required_limb_biostate null - please set it! occured on: [src.type]")
+ stack_trace("required_limb_biostate null - please set it! occurred on: [src.type]")
if (wound_path_to_generate == null)
- stack_trace("wound_path_to_generate null - please set it! occured on: [src.type]")
+ stack_trace("wound_path_to_generate null - please set it! occurred on: [src.type]")
scar_priorities = generate_scar_priorities()
@@ -82,8 +82,8 @@
* * random_roll = FALSE: If this is in the context of a random wound generation, and this wound wasn't specifically checked.
*
* Returns:
- * FALSE if the limb cannot be wounded, if the wounding types dont match ours (via wounding_types_valid()), if we have a higher severity wound already in our series,
- * if we have a biotype mismatch, if the limb isnt in a viable zone, or if theres any duplicate wound types.
+ * FALSE if the limb cannot be wounded, if the wounding types don't match ours (via wounding_types_valid()), if we have a higher severity wound already in our series,
+ * if we have a biotype mismatch, if the limb isn't in a viable zone, or if there's any duplicate wound types.
* TRUE otherwise.
*/
/datum/wound_pregen_data/proc/can_be_applied_to(obj/item/bodypart/limb, list/suggested_wounding_types = required_wounding_types, datum/wound/old_wound, random_roll = FALSE, duplicates_allowed = src.duplicates_allowed, care_about_existing_wounds = TRUE)
diff --git a/code/datums/wounds/_wounds.dm b/code/datums/wounds/_wounds.dm
index 47f29a21e9dd5..eb531dd3dc92b 100644
--- a/code/datums/wounds/_wounds.dm
+++ b/code/datums/wounds/_wounds.dm
@@ -127,7 +127,7 @@
return ..()
-/// If we should have an actionspeed_mod, ensures we do and updates its slowdown. Otherwise, ensures we dont have one
+/// If we should have an actionspeed_mod, ensures we do and updates its slowdown. Otherwise, ensures we don't have one
/// by qdeleting any existing modifier.
/datum/wound/proc/update_actionspeed_modifier()
if (should_have_actionspeed_modifier())
@@ -323,7 +323,7 @@
SIGNAL_HANDLER
qdel(src)
-/// Remove the wound from whatever it's afflicting, and cleans up whateverstatus effects it had or modifiers it had on interaction times. ignore_limb is used for detachments where we only want to forget the victim
+/// Remove the wound from whatever it's afflicting, and cleans up whatever status effects it had or modifiers it had on interaction times. ignore_limb is used for detachments where we only want to forget the victim
/datum/wound/proc/remove_wound(ignore_limb, replaced = FALSE)
//TODO: have better way to tell if we're getting removed without replacement (full heal) scar stuff
var/old_victim = victim
@@ -341,7 +341,7 @@
if(limb && !ignore_limb)
set_limb(null, replaced) // since we're removing limb's ref to us, we should do the same
- // if you want to keep the ref, do it externally, theres no reason for us to remember it
+ // if you want to keep the ref, do it externally, there's no reason for us to remember it
if (ismob(old_victim))
var/mob/mob_victim = old_victim
@@ -688,7 +688,7 @@
/datum/wound/proc/get_limb_examine_description()
return
-/// Gets the flat percentage chance increment of a dismember occuring, if a dismember is attempted (requires mangled flesh and bone). returning 15 = +15%.
+/// Gets the flat percentage chance increment of a dismember occurring, if a dismember is attempted (requires mangled flesh and bone). returning 15 = +15%.
/datum/wound/proc/get_dismember_chance_bonus(existing_chance)
SHOULD_BE_PURE(TRUE)
diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm
index 0c6847e7db348..04d26a5e50a5a 100644
--- a/code/game/area/areas.dm
+++ b/code/game/area/areas.dm
@@ -128,7 +128,7 @@
* A list of teleport locations
*
* Adding a wizard area teleport list because motherfucking lag -- Urist
- * I am far too lazy to make it a proper list of areas so I'll just make it run the usual telepot routine at the start of the game
+ * I am far too lazy to make it a proper list of areas so I'll just make it run the usual teleport routine at the start of the game
*/
GLOBAL_LIST_EMPTY(teleportlocs)
@@ -168,9 +168,9 @@ GLOBAL_LIST_EMPTY(teleportlocs)
return ..()
/*
- * Initalize this area
+ * Initialize this area
*
- * intializes the dynamic area lighting and also registers the area with the z level via
+ * initializes the dynamic area lighting and also registers the area with the z level via
* reg_in_areas_in_z
*
* returns INITIALIZE_HINT_LATELOAD
@@ -414,7 +414,7 @@ GLOBAL_LIST_EMPTY(teleportlocs)
/**
* Update the icon state of the area
*
- * Im not sure what the heck this does, somethign to do with weather being able to set icon
+ * I'm not sure what the heck this does, something to do with weather being able to set icon
* states on areas?? where the heck would that even display?
*/
/area/update_icon_state()
@@ -439,7 +439,7 @@ GLOBAL_LIST_EMPTY(teleportlocs)
/**
* Returns int 1 or 0 if the area has power for the given channel
*
- * evalutes a mixture of variables mappers can set, requires_power, always_unpowered and then
+ * evaluates a mixture of variables mappers can set, requires_power, always_unpowered and then
* per channel power_equip, power_light, power_environ
*/
/area/proc/powered(chan) // return true if the area has power to given channel
diff --git a/code/game/area/areas/away_content.dm b/code/game/area/areas/away_content.dm
index ded38af6201ab..5e2219ef857e0 100644
--- a/code/game/area/areas/away_content.dm
+++ b/code/game/area/areas/away_content.dm
@@ -13,16 +13,6 @@ Unused icons for new areas are "awaycontent1" ~ "awaycontent30"
sound_environment = SOUND_ENVIRONMENT_ROOM
area_flags = UNIQUE_AREA
-/area/awaymission/beach
- name = "Beach"
- icon_state = "away"
- static_lighting = FALSE
- base_lighting_alpha = 255
- base_lighting_color = "#FFFFCC"
- requires_power = FALSE
- has_gravity = STANDARD_GRAVITY
- ambientsounds = list('sound/ambience/shore.ogg', 'sound/ambience/seag1.ogg','sound/ambience/seag2.ogg','sound/ambience/seag2.ogg','sound/ambience/ambiodd.ogg','sound/ambience/ambinice.ogg')
-
/area/awaymission/museum
name = "Nanotrasen Museum"
icon_state = "awaycontent28"
diff --git a/code/game/area/areas/ruins/icemoon.dm b/code/game/area/areas/ruins/icemoon.dm
index fd983f763a3a2..d0049e7007c49 100644
--- a/code/game/area/areas/ruins/icemoon.dm
+++ b/code/game/area/areas/ruins/icemoon.dm
@@ -44,7 +44,7 @@
mood_message = "I feel like I am being watched..."
/area/ruin/bughabitat
- name = "\improper Entemology Outreach Center"
+ name = "\improper Entomology Outreach Center"
mood_bonus = 1
mood_message = "This place seems strangely serene."
diff --git a/code/game/atom/alternate_appearance.dm b/code/game/atom/alternate_appearance.dm
index 228462f7936a4..108b72b95d286 100644
--- a/code/game/atom/alternate_appearance.dm
+++ b/code/game/atom/alternate_appearance.dm
@@ -35,20 +35,51 @@ GLOBAL_LIST_EMPTY(active_alternate_appearances)
GLOB.active_alternate_appearances += src
for(var/mob in GLOB.player_list)
- if(mobShouldSee(mob))
- show_to(mob)
+ apply_to_new_mob(mob)
/datum/atom_hud/alternate_appearance/Destroy()
GLOB.active_alternate_appearances -= src
return ..()
-/datum/atom_hud/alternate_appearance/proc/onNewMob(mob/M)
- if(mobShouldSee(M))
- show_to(M)
+/// Wrapper for applying this alt hud to the passed mob (if they should see it)
+/datum/atom_hud/alternate_appearance/proc/apply_to_new_mob(mob/applying_to)
+ if(mobShouldSee(applying_to))
+ if(!hud_users_all_z_levels[applying_to])
+ show_to(applying_to)
+ return TRUE
+ return FALSE
+/// Checks if the passed mob should be seeing this hud
/datum/atom_hud/alternate_appearance/proc/mobShouldSee(mob/M)
return FALSE
+/datum/atom_hud/alternate_appearance/show_to(mob/new_viewer)
+ . = ..()
+ if(!new_viewer)
+ return
+ track_mob(new_viewer)
+
+/// Registers some signals to track the mob's state to determine if they should be seeing the hud still
+/datum/atom_hud/alternate_appearance/proc/track_mob(mob/new_viewer)
+ return
+
+/datum/atom_hud/alternate_appearance/hide_from(mob/former_viewer, absolute)
+ . = ..()
+ if(!former_viewer || hud_atoms_all_z_levels[former_viewer] >= 1)
+ return
+ untrack_mob(former_viewer)
+
+/// Unregisters the signals that were tracking the mob's state
+/datum/atom_hud/alternate_appearance/proc/untrack_mob(mob/former_viewer)
+ return
+
+/datum/atom_hud/alternate_appearance/proc/check_hud(mob/source)
+ SIGNAL_HANDLER
+ // Attempt to re-apply the hud entirely
+ if(!apply_to_new_mob(source))
+ // If that failed, probably shouldn't be seeing it at all, so nuke it
+ hide_from(source, absolute = TRUE)
+
/datum/atom_hud/alternate_appearance/add_atom_to_hud(atom/A, image/I)
. = ..()
if(.)
@@ -99,6 +130,22 @@ GLOBAL_LIST_EMPTY(active_alternate_appearances)
if(ghost_appearance)
QDEL_NULL(ghost_appearance)
+/datum/atom_hud/alternate_appearance/basic/track_mob(mob/new_viewer)
+ RegisterSignals(new_viewer, list(
+ COMSIG_MOB_ANTAGONIST_REMOVED,
+ COMSIG_MOB_GHOSTIZED,
+ COMSIG_MOB_MIND_TRANSFERRED_INTO,
+ COMSIG_MOB_MIND_TRANSFERRED_OUT_OF,
+ ), PROC_REF(check_hud), override = TRUE)
+
+/datum/atom_hud/alternate_appearance/basic/untrack_mob(mob/former_viewer)
+ UnregisterSignal(former_viewer, list(
+ COMSIG_MOB_ANTAGONIST_REMOVED,
+ COMSIG_MOB_GHOSTIZED,
+ COMSIG_MOB_MIND_TRANSFERRED_INTO,
+ COMSIG_MOB_MIND_TRANSFERRED_OUT_OF,
+ ))
+
/datum/atom_hud/alternate_appearance/basic/add_atom_to_hud(atom/A)
LAZYINITLIST(A.hud_list)
A.hud_list[appearance_key] = image
@@ -136,16 +183,10 @@ GLOBAL_LIST_EMPTY(active_alternate_appearances)
/datum/atom_hud/alternate_appearance/basic/noncult
/datum/atom_hud/alternate_appearance/basic/noncult/mobShouldSee(mob/M)
- if(!IS_CULTIST(M))
- return TRUE
- return FALSE
-
-/datum/atom_hud/alternate_appearance/basic/cult
+ return !IS_CULTIST(M)
-/datum/atom_hud/alternate_appearance/basic/cult/mobShouldSee(mob/M)
- if(IS_CULTIST(M))
- return TRUE
- return FALSE
+/datum/atom_hud/alternate_appearance/basic/has_antagonist/cult
+ antag_datum_type = /datum/antagonist/cult
/datum/atom_hud/alternate_appearance/basic/blessed_aware
diff --git a/code/game/atom/atom_act.dm b/code/game/atom/atom_act.dm
index acd33976e51b6..c9951b9209422 100644
--- a/code/game/atom/atom_act.dm
+++ b/code/game/atom/atom_act.dm
@@ -208,7 +208,7 @@
///wrapper proc that passes our mob's rust_strength to the target we are rusting
/mob/living/proc/do_rust_heretic_act(atom/target)
- var/datum/antagonist/heretic/heretic_data = IS_HERETIC(src)
+ var/datum/antagonist/heretic/heretic_data = GET_HERETIC(src)
target.rust_heretic_act(heretic_data?.rust_strength)
/mob/living/basic/heretic_summon/rust_walker/do_rust_heretic_act(atom/target)
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index 046478c9b366a..e4aadc639e486 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -66,7 +66,7 @@
/**
* In case you have multiple types, you automatically use the most useful one.
* IE: Skating on ice, flippers on water, flying over chasm/space, etc.
- * I reccomend you use the movetype_handler system and not modify this directly, especially for living mobs.
+ * I recommend you use the movetype_handler system and not modify this directly, especially for living mobs.
*/
var/movement_type = GROUND
@@ -130,7 +130,7 @@
/mutable_appearance/emissive_blocker/New()
. = ..()
- // Need to do this here because it's overriden by the parent call
+ // Need to do this here because it's overridden by the parent call
color = EM_BLOCK_COLOR
appearance_flags = EMISSIVE_APPEARANCE_FLAGS
@@ -142,7 +142,7 @@
#endif
#if EMISSIVE_BLOCK_GENERIC != 0
- #error EMISSIVE_BLOCK_GENERIC is expected to be 0 to faciliate a weird optimization hack where we rely on it being the most common.
+ #error EMISSIVE_BLOCK_GENERIC is expected to be 0 to facilitate a weird optimization hack where we rely on it being the most common.
#error Read the comment in code/game/atoms_movable.dm for details.
#endif
@@ -632,7 +632,7 @@
if(!newloc || newloc == loc)
return
- // A mid-movement... movement... occured, resolve that first.
+ // A mid-movement... movement... occurred, resolve that first.
RESOLVE_ACTIVE_MOVEMENT
if(!direction)
@@ -799,7 +799,7 @@
if (pulledby)
if (pulledby.currently_z_moving)
check_pulling(z_allowed = TRUE)
- //dont call check_pulling() here at all if there is a pulledby that is not currently z moving
+ //don't call check_pulling() here at all if there is a pulledby that is not currently z moving
//because it breaks stair conga lines, for some fucking reason.
//it's fine because the pull will be checked when this whole proc is called by the mob doing the pulling anyways
else
@@ -1086,7 +1086,7 @@
for(var/atom/movable/location as anything in get_nested_locs(src) + src)
LAZYREMOVEASSOC(location.important_recursive_contents, RECURSIVE_CONTENTS_ACTIVE_STORAGE, src)
-///Sets the anchored var and returns if it was sucessfully changed or not.
+///Sets the anchored var and returns if it was successfully changed or not.
/atom/movable/proc/set_anchored(anchorvalue)
SHOULD_CALL_PARENT(TRUE)
if(anchored == anchorvalue)
diff --git a/code/game/communications.dm b/code/game/communications.dm
index 6d26a9779937d..aba409b558710 100644
--- a/code/game/communications.dm
+++ b/code/game/communications.dm
@@ -104,6 +104,7 @@ GLOBAL_LIST_INIT(radiochannels, list(
RADIO_CHANNEL_SUPPLY = FREQ_SUPPLY,
RADIO_CHANNEL_SERVICE = FREQ_SERVICE,
RADIO_CHANNEL_AI_PRIVATE = FREQ_AI_PRIVATE,
+ RADIO_CHANNEL_ENTERTAINMENT = FREQ_ENTERTAINMENT,
RADIO_CHANNEL_CTF_RED = FREQ_CTF_RED,
RADIO_CHANNEL_CTF_BLUE = FREQ_CTF_BLUE,
RADIO_CHANNEL_CTF_GREEN = FREQ_CTF_GREEN,
@@ -123,6 +124,7 @@ GLOBAL_LIST_INIT(reverseradiochannels, list(
"[FREQ_SUPPLY]" = RADIO_CHANNEL_SUPPLY,
"[FREQ_SERVICE]" = RADIO_CHANNEL_SERVICE,
"[FREQ_AI_PRIVATE]" = RADIO_CHANNEL_AI_PRIVATE,
+ "[FREQ_ENTERTAINMENT]" = RADIO_CHANNEL_ENTERTAINMENT,
"[FREQ_CTF_RED]" = RADIO_CHANNEL_CTF_RED,
"[FREQ_CTF_BLUE]" = RADIO_CHANNEL_CTF_BLUE,
"[FREQ_CTF_GREEN]" = RADIO_CHANNEL_CTF_GREEN,
@@ -141,10 +143,11 @@ GLOBAL_LIST_INIT(radiocolors, list(
RADIO_CHANNEL_SUPPLY = "#a8732b",
RADIO_CHANNEL_SERVICE = "#6eaa2c",
RADIO_CHANNEL_AI_PRIVATE = "#ff00ff",
+ RADIO_CHANNEL_ENTERTAINMENT = "#00ff99",
RADIO_CHANNEL_CTF_RED = "#ff0000",
RADIO_CHANNEL_CTF_BLUE = "#0000ff",
RADIO_CHANNEL_CTF_GREEN = "#00ff00",
- RADIO_CHANNEL_CTF_YELLOW = "#d1ba22"
+ RADIO_CHANNEL_CTF_YELLOW = "#d1ba22",
))
/datum/radio_frequency
diff --git a/code/game/machinery/PDApainter.dm b/code/game/machinery/PDApainter.dm
index 679a3182a57cd..16a6615497ce4 100644
--- a/code/game/machinery/PDApainter.dm
+++ b/code/game/machinery/PDApainter.dm
@@ -279,7 +279,7 @@
return data
-/obj/machinery/pdapainter/ui_act(action, params)
+/obj/machinery/pdapainter/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm
index 45a75f06133dd..8a7e9846561be 100644
--- a/code/game/machinery/_machinery.dm
+++ b/code/game/machinery/_machinery.dm
@@ -686,10 +686,11 @@
return ..()
/obj/machinery/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
- add_fingerprint(usr)
- update_last_used(usr)
- if(HAS_AI_ACCESS(usr) && !GLOB.cameranet.checkTurfVis(get_turf(src))) //We check if they're an AI specifically here, so borgs can still access off-camera stuff.
- to_chat(usr, span_warning("You can no longer connect to this device!"))
+ var/mob/user = ui.user
+ add_fingerprint(user)
+ update_last_used(user)
+ if(isAI(user) && !GLOB.cameranet.checkTurfVis(get_turf(src))) //We check if they're an AI specifically here, so borgs/adminghosts/human wand can still access off-camera stuff.
+ to_chat(user, span_warning("You can no longer connect to this device!"))
return FALSE
return ..()
diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm
index 07c3b0c057584..0a89c4e8b5b08 100644
--- a/code/game/machinery/autolathe.dm
+++ b/code/game/machinery/autolathe.dm
@@ -100,7 +100,7 @@
/obj/machinery/autolathe/proc/AfterMaterialInsert(container, obj/item/item_inserted, last_inserted_id, mats_consumed, amount_inserted, atom/context)
SIGNAL_HANDLER
- //we use initial(active_power_usage) because higher tier parts will have higher active usage but we have no benifit from it
+ //we use initial(active_power_usage) because higher tier parts will have higher active usage but we have no benefit from it
if(directly_use_energy(ROUND_UP((amount_inserted / (MAX_STACK_SIZE * SHEET_MATERIAL_AMOUNT)) * 0.4 * initial(active_power_usage))))
flick_overlay_view(mutable_appearance('icons/obj/machines/lathes.dmi', "autolathe_mat"), 1 SECONDS)
diff --git a/code/game/machinery/barsigns.dm b/code/game/machinery/barsigns.dm
index e59de18ffcb18..11dc005269b7b 100644
--- a/code/game/machinery/barsigns.dm
+++ b/code/game/machinery/barsigns.dm
@@ -425,7 +425,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/barsign, 32)
/datum/barsign/maltroach
name = "Maltroach"
icon_state = "maltroach"
- desc = "Mothroaches politely greet you into the bar, or are they greeting eachother?"
+ desc = "Mothroaches politely greet you into the bar, or are they greeting each other?"
neon_color = "#649e8a"
/datum/barsign/rock_bottom
diff --git a/code/game/machinery/big_manipulator.dm b/code/game/machinery/big_manipulator.dm
new file mode 100644
index 0000000000000..8d2bde3e145ae
--- /dev/null
+++ b/code/game/machinery/big_manipulator.dm
@@ -0,0 +1,282 @@
+/// Manipulator Core. Main part of the mechanism that carries out the entire process.
+/obj/machinery/big_manipulator
+ name = "Big Manipulator"
+ desc = "Take and drop objects. Innovation..."
+ icon = 'icons/obj/machines/big_manipulator_parts/big_manipulator_core.dmi'
+ icon_state = "core"
+ density = TRUE
+ circuit = /obj/item/circuitboard/machine/big_manipulator
+ greyscale_colors = "#d8ce13"
+ greyscale_config = /datum/greyscale_config/big_manipulator
+ /// How many time manipulator need to take and drop item.
+ var/working_speed = 2 SECONDS
+ /// Using high tier manipulators speeds up big manipulator and requires more energy.
+ var/power_use_lvl = 0.2
+ /// When manipulator already working with item inside he don't take any new items.
+ var/on_work = FALSE
+ /// Activate mechanism.
+ var/on = FALSE
+ /// Dir to get turf where we take items.
+ var/take_here = NORTH
+ /// Dir to get turf where we drop items.
+ var/drop_here = SOUTH
+ /// Turf where we take items.
+ var/turf/take_turf
+ /// Turf where we drop items.
+ var/turf/drop_turf
+ /// Obj inside manipulator.
+ var/datum/weakref/containment_obj
+ /// Other manipulator component.
+ var/obj/effect/manipulator_hand
+
+/obj/machinery/big_manipulator/Initialize(mapload)
+ . = ..()
+ take_and_drop_turfs_check()
+ create_manipulator_hand()
+ RegisterSignal(manipulator_hand, COMSIG_QDELETING, PROC_REF(on_hand_qdel))
+ manipulator_lvl()
+ if(on)
+ press_on(pressed_by = null)
+
+/obj/machinery/big_manipulator/examine(mob/user)
+ . = ..()
+ . += "You can change direction with alternative wrench usage."
+
+/obj/machinery/big_manipulator/Destroy(force)
+ . = ..()
+ qdel(manipulator_hand)
+ if(isnull(containment_obj))
+ return
+ var/obj/obj_resolve = containment_obj?.resolve()
+ obj_resolve?.forceMove(get_turf(obj_resolve))
+
+/obj/machinery/big_manipulator/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change)
+ . = ..()
+ take_and_drop_turfs_check()
+ if(isnull(get_turf(src)))
+ qdel(manipulator_hand)
+ return
+ if(!manipulator_hand)
+ create_manipulator_hand()
+
+/obj/machinery/big_manipulator/wrench_act(mob/living/user, obj/item/tool)
+ . = ..()
+ default_unfasten_wrench(user, tool, time = 1 SECONDS)
+ return ITEM_INTERACT_SUCCESS
+
+/obj/machinery/big_manipulator/wrench_act_secondary(mob/living/user, obj/item/tool)
+ . = ..()
+ if(on_work || on)
+ to_chat(user, span_warning("[src] is activated!"))
+ return ITEM_INTERACT_BLOCKING
+ rotate_big_hand()
+ playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE)
+ return ITEM_INTERACT_SUCCESS
+
+/obj/machinery/big_manipulator/can_be_unfasten_wrench(mob/user, silent)
+ if(on_work || on)
+ to_chat(user, span_warning("[src] is activated!"))
+ return FAILED_UNFASTEN
+ return ..()
+
+/obj/machinery/big_manipulator/default_unfasten_wrench(mob/user, obj/item/wrench, time)
+ . = ..()
+ if(. == SUCCESSFUL_UNFASTEN)
+ take_and_drop_turfs_check()
+
+/obj/machinery/big_manipulator/screwdriver_act(mob/living/user, obj/item/tool)
+ if(default_deconstruction_screwdriver(user, icon_state, icon_state, tool))
+ return ITEM_INTERACT_SUCCESS
+ return ITEM_INTERACT_BLOCKING
+
+/obj/machinery/big_manipulator/crowbar_act(mob/living/user, obj/item/tool)
+ . = ..()
+ if(default_deconstruction_crowbar(tool))
+ return ITEM_INTERACT_SUCCESS
+ return ITEM_INTERACT_BLOCKING
+
+/obj/machinery/big_manipulator/RefreshParts()
+ . = ..()
+
+ manipulator_lvl()
+
+/// Creat manipulator hand effect on manipulator core.
+/obj/machinery/big_manipulator/proc/create_manipulator_hand()
+ manipulator_hand = new/obj/effect/big_manipulator_hand(src)
+ manipulator_hand.dir = take_here
+ vis_contents += manipulator_hand
+
+/// Check servo tier and change manipulator speed, power_use and colour.
+/obj/machinery/big_manipulator/proc/manipulator_lvl()
+ var/datum/stock_part/servo/locate_servo = locate() in component_parts
+ if(!locate_servo)
+ return
+ switch(locate_servo.tier)
+ if(-INFINITY to 1)
+ working_speed = 2 SECONDS
+ power_use_lvl = 0.2
+ set_greyscale(COLOR_YELLOW)
+ manipulator_hand?.set_greyscale(COLOR_YELLOW)
+ if(2)
+ working_speed = 1.4 SECONDS
+ power_use_lvl = 0.4
+ set_greyscale(COLOR_ORANGE)
+ manipulator_hand?.set_greyscale(COLOR_ORANGE)
+ if(3)
+ working_speed = 0.8 SECONDS
+ power_use_lvl = 0.6
+ set_greyscale(COLOR_RED)
+ manipulator_hand?.set_greyscale(COLOR_RED)
+ if(4 to INFINITY)
+ working_speed = 0.2 SECONDS
+ power_use_lvl = 0.8
+ set_greyscale(COLOR_PURPLE)
+ manipulator_hand?.set_greyscale(COLOR_PURPLE)
+
+ active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * power_use_lvl
+
+/// Changing take and drop turf tiles when we anchore manipulator or if manipulator not in turf.
+/obj/machinery/big_manipulator/proc/take_and_drop_turfs_check()
+ if(anchored && isturf(src.loc))
+ take_turf = get_step(src, take_here)
+ drop_turf = get_step(src, drop_here)
+ else
+ take_turf = null
+ drop_turf = null
+
+/// Changing take and drop turf dirs and also changing manipulator hand sprite dir.
+/obj/machinery/big_manipulator/proc/rotate_big_hand()
+ switch(take_here)
+ if(NORTH)
+ take_here = EAST
+ drop_here = WEST
+ if(EAST)
+ take_here = SOUTH
+ drop_here = NORTH
+ if(SOUTH)
+ take_here = WEST
+ drop_here = EAST
+ if(WEST)
+ take_here = NORTH
+ drop_here = SOUTH
+ manipulator_hand.dir = take_here
+ take_and_drop_turfs_check()
+
+/// Deliting hand will destroy our manipulator core.
+/obj/machinery/big_manipulator/proc/on_hand_qdel()
+ SIGNAL_HANDLER
+
+ deconstruct(TRUE)
+
+/// Pre take and drop proc from [take and drop procs loop]:
+/// Check if we can start take and drop loop
+/obj/machinery/big_manipulator/proc/is_work_check()
+ if(isclosedturf(drop_turf))
+ on = !on
+ say("Output blocked")
+ return FALSE
+ for(var/obj/item/take_item in take_turf.contents)
+ try_take_thing(take_turf, take_item)
+ break
+
+ return TRUE
+
+/// First take and drop proc from [take and drop procs loop]:
+/// Check if we can take item from take_turf to work with him. This proc also calling from ATOM_ENTERED signal.
+/obj/machinery/big_manipulator/proc/try_take_thing(datum/source, atom/movable/target)
+ SIGNAL_HANDLER
+
+ if(!on)
+ return
+ if(!anchored)
+ return
+ if(QDELETED(source) || QDELETED(target))
+ return
+ if(!isturf(target.loc))
+ return
+ if(on_work)
+ return
+ if(!use_energy(active_power_usage, force = FALSE))
+ on = FALSE
+ say("Not enough energy!")
+ return
+ if(isitem(target))
+ start_work(target)
+
+/// Second take and drop proc from [take and drop procs loop]:
+/// Taking our item and start manipulator hand rotate animation.
+/obj/machinery/big_manipulator/proc/start_work(atom/movable/target)
+ target.forceMove(src)
+ containment_obj = WEAKREF(target)
+ on_work = TRUE
+ do_rotate_animation(1)
+ addtimer(CALLBACK(src, PROC_REF(drop_thing), target), working_speed)
+
+/// Third take and drop proc from [take and drop procs loop]:
+/// Drop our item and start manipulator hand backward animation.
+/obj/machinery/big_manipulator/proc/drop_thing(atom/movable/target)
+ target.forceMove(drop_turf)
+ do_rotate_animation(0)
+ addtimer(CALLBACK(src, PROC_REF(end_work)), working_speed)
+
+/// Fourth and last take and drop proc from [take and drop procs loop]:
+/// Finishes work and begins to look for a new item for [take and drop procs loop].
+/obj/machinery/big_manipulator/proc/end_work()
+ on_work = FALSE
+ is_work_check()
+
+/// Rotates manipulator hand 90 degrees.
+/obj/machinery/big_manipulator/proc/do_rotate_animation(backward)
+ animate(manipulator_hand, transform = matrix(90, MATRIX_ROTATE), working_speed*0.5)
+ addtimer(CALLBACK(src, PROC_REF(finish_rotate_animation), backward), working_speed*0.5)
+
+/// Rotates manipulator hand from 90 degrees to 180 or 0 if backward.
+/obj/machinery/big_manipulator/proc/finish_rotate_animation(backward)
+ animate(manipulator_hand, transform = matrix(180 * backward, MATRIX_ROTATE), working_speed*0.5)
+
+/// Proc call when we press on/off button
+/obj/machinery/big_manipulator/proc/press_on(pressed_by)
+ if(pressed_by)
+ on = !on
+ if(!is_work_check())
+ return
+ if(on)
+ RegisterSignal(take_turf, COMSIG_ATOM_ENTERED, PROC_REF(try_take_thing))
+ else
+ UnregisterSignal(take_turf, COMSIG_ATOM_ENTERED)
+
+/obj/machinery/big_manipulator/ui_interact(mob/user, datum/tgui/ui)
+ if(!anchored)
+ to_chat(user, span_warning("[src] isn't attached to the ground!"))
+ ui?.close()
+ return
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "BigManipulator")
+ ui.open()
+
+/obj/machinery/big_manipulator/ui_data(mob/user)
+ var/list/data = list()
+ data["active"] = on
+ return data
+
+/obj/machinery/big_manipulator/ui_act(action, params, datum/tgui/ui)
+ . = ..()
+ if(.)
+ return
+ switch(action)
+ if("on")
+ press_on(pressed_by = TRUE)
+ return TRUE
+
+/// Manipulator hand. Effect we animate to show that the manipulator is working and moving something.
+/obj/effect/big_manipulator_hand
+ name = "Manipulator claw"
+ desc = "Take and drop objects. Innovation..."
+ icon = 'icons/obj/machines/big_manipulator_parts/big_manipulator_hand.dmi'
+ icon_state = "hand"
+ layer = LOW_ITEM_LAYER
+ anchored = TRUE
+ greyscale_config = /datum/greyscale_config/manipulator_hand
+ pixel_x = -32
+ pixel_y = -32
diff --git a/code/game/machinery/civilian_bounties.dm b/code/game/machinery/civilian_bounties.dm
index fa0d28c999c88..7760a646d9fae 100644
--- a/code/game/machinery/civilian_bounties.dm
+++ b/code/game/machinery/civilian_bounties.dm
@@ -151,7 +151,7 @@
say("Requesting ID card has no job assignment registered!")
return FALSE
var/list/datum/bounty/crumbs = list(random_bounty(pot_acc.account_job.bounty_types), // We want to offer 2 bounties from their appropriate job catagories
- random_bounty(pot_acc.account_job.bounty_types), // and 1 guarenteed assistant bounty if the other 2 suck.
+ random_bounty(pot_acc.account_job.bounty_types), // and 1 guaranteed assistant bounty if the other 2 suck.
random_bounty(CIV_JOB_BASIC))
COOLDOWN_START(pot_acc, bounty_timer, (5 MINUTES) - cooldown_reduction)
pot_acc.bounties = crumbs
@@ -203,7 +203,7 @@
return data
-/obj/machinery/computer/piratepad_control/civilian/ui_act(action, params)
+/obj/machinery/computer/piratepad_control/civilian/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/game/machinery/computer/_computer.dm b/code/game/machinery/computer/_computer.dm
index 3292cbf977b5f..6e1009def324f 100644
--- a/code/game/machinery/computer/_computer.dm
+++ b/code/game/machinery/computer/_computer.dm
@@ -135,6 +135,12 @@
. = ..()
update_use_power(ACTIVE_POWER_USE)
+/obj/machinery/computer/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
+ SHOULD_CALL_PARENT(TRUE)
+ . = ..()
+ if(!issilicon(ui.user))
+ playsound(src, SFX_KEYBOARD_CLICKS, 10, TRUE, FALSE)
+
/obj/machinery/computer/ui_close(mob/user)
SHOULD_CALL_PARENT(TRUE)
. = ..()
diff --git a/code/game/machinery/computer/aifixer.dm b/code/game/machinery/computer/aifixer.dm
index ba3041cc4840c..e0a7f36460041 100644
--- a/code/game/machinery/computer/aifixer.dm
+++ b/code/game/machinery/computer/aifixer.dm
@@ -46,7 +46,7 @@
return data
-/obj/machinery/computer/aifixer/ui_act(action, params)
+/obj/machinery/computer/aifixer/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/game/machinery/computer/arcade/orion.dm b/code/game/machinery/computer/arcade/orion.dm
index 85bebddd25c6d..3300370d18e49 100644
--- a/code/game/machinery/computer/arcade/orion.dm
+++ b/code/game/machinery/computer/arcade/orion.dm
@@ -181,7 +181,7 @@
return static_data
-/obj/machinery/computer/arcade/orion_trail/ui_act(action, list/params)
+/obj/machinery/computer/arcade/orion_trail/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/game/machinery/computer/atmos_alert.dm b/code/game/machinery/computer/atmos_alert.dm
index 5f3d7dd6e9e9d..3ed359a006296 100644
--- a/code/game/machinery/computer/atmos_alert.dm
+++ b/code/game/machinery/computer/atmos_alert.dm
@@ -28,7 +28,7 @@
return data
-/obj/machinery/computer/atmos_alert/ui_act(action, params)
+/obj/machinery/computer/atmos_alert/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/game/machinery/computer/atmos_computers/__identifiers.dm b/code/game/machinery/computer/atmos_computers/__identifiers.dm
index 653f0fbaa3868..be1f01aecb549 100644
--- a/code/game/machinery/computer/atmos_computers/__identifiers.dm
+++ b/code/game/machinery/computer/atmos_computers/__identifiers.dm
@@ -1,7 +1,7 @@
// ATMOSIA GAS MONITOR SUITE TAGS
// Things that use these include atmos control monitors, sensors, inputs, and outlets.
// They last three adds _sensor, _in, and _out respectively to the id_tag variable.
-// Dont put underscores here, we use them as delimiters.
+// Don't put underscores here, we use them as delimiters.
#define ATMOS_GAS_MONITOR_O2 GAS_O2
#define ATMOS_GAS_MONITOR_PLAS GAS_PLASMA
diff --git a/code/game/machinery/computer/atmos_computers/_atmos_control.dm b/code/game/machinery/computer/atmos_computers/_atmos_control.dm
index cdd0349ac85b9..25e51738611f1 100644
--- a/code/game/machinery/computer/atmos_computers/_atmos_control.dm
+++ b/code/game/machinery/computer/atmos_computers/_atmos_control.dm
@@ -152,7 +152,7 @@
data["chambers"] += list(chamber_info)
return data
-/obj/machinery/computer/atmos_control/ui_act(action, params)
+/obj/machinery/computer/atmos_control/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(. || !(control || reconnecting))
return
diff --git a/code/game/machinery/computer/camera.dm b/code/game/machinery/computer/camera.dm
index b5bb04fac35e1..2d8fd7e7dcaed 100644
--- a/code/game/machinery/computer/camera.dm
+++ b/code/game/machinery/computer/camera.dm
@@ -108,7 +108,7 @@
return data
-/obj/machinery/computer/security/ui_act(action, params)
+/obj/machinery/computer/security/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
@@ -116,7 +116,6 @@
if(action == "switch_camera")
var/obj/machinery/camera/selected_camera = locate(params["camera"]) in GLOB.cameranet.cameras
active_camera = selected_camera
- playsound(src, SFX_TERMINAL_TYPE, 25, FALSE)
if(isnull(active_camera))
return TRUE
diff --git a/code/game/machinery/computer/camera_advanced.dm b/code/game/machinery/computer/camera_advanced.dm
index 45bfeb9fcef36..0e47a752b01d2 100644
--- a/code/game/machinery/computer/camera_advanced.dm
+++ b/code/game/machinery/computer/camera_advanced.dm
@@ -60,7 +60,7 @@
return ..()
/obj/machinery/computer/camera_advanced/process()
- if(!can_use(current_user) || (issilicon(current_user) && !current_user.has_unlimited_silicon_privilege))
+ if(!can_use(current_user) || (issilicon(current_user) && !HAS_SILICON_ACCESS(current_user)))
unset_machine()
return PROCESS_KILL
diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm
index 8fb1e71f05ed7..d48b62977893c 100644
--- a/code/game/machinery/computer/communications.dm
+++ b/code/game/machinery/computer/communications.dm
@@ -142,7 +142,7 @@
playsound(src, 'sound/machines/terminal_alert.ogg', 50, FALSE)
return TRUE
-/obj/machinery/computer/communications/ui_act(action, list/params)
+/obj/machinery/computer/communications/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
var/static/list/approved_states = list(STATE_BUYING_SHUTTLE, STATE_CHANGING_STATUS, STATE_MAIN, STATE_MESSAGES)
. = ..()
@@ -152,11 +152,12 @@
if (!has_communication())
return
+ var/mob/user = ui.user
. = TRUE
switch (action)
if ("answerMessage")
- if (!authenticated(usr))
+ if (!authenticated(user))
return
var/answer_index = params["answer"]
@@ -164,7 +165,7 @@
// If either of these aren't numbers, then bad voodoo.
if(!isnum(answer_index) || !isnum(message_index))
- message_admins("[ADMIN_LOOKUPFLW(usr)] provided an invalid index type when replying to a message on [src] [ADMIN_JMP(src)]. This should not happen. Please check with a maintainer and/or consult tgui logs.")
+ message_admins("[ADMIN_LOOKUPFLW(user)] provided an invalid index type when replying to a message on [src] [ADMIN_JMP(src)]. This should not happen. Please check with a maintainer and/or consult tgui logs.")
CRASH("Non-numeric index provided when answering comms console message.")
if (!answer_index || !message_index || answer_index < 1 || message_index < 1)
@@ -175,27 +176,27 @@
message.answered = answer_index
message.answer_callback.InvokeAsync()
if ("callShuttle")
- if (!authenticated(usr) || syndicate)
+ if (!authenticated(user) || syndicate)
return
var/reason = trim(params["reason"], MAX_MESSAGE_LEN)
if (length(reason) < CALL_SHUTTLE_REASON_LENGTH)
return
- SSshuttle.requestEvac(usr, reason)
+ SSshuttle.requestEvac(user, reason)
post_status("shuttle")
if ("changeSecurityLevel")
- if (!authenticated_as_silicon_or_captain(usr))
+ if (!authenticated_as_silicon_or_captain(user))
return
// Check if they have
- if (!HAS_SILICON_ACCESS(usr))
- var/obj/item/held_item = usr.get_active_held_item()
+ if (!HAS_SILICON_ACCESS(user))
+ var/obj/item/held_item = user.get_active_held_item()
var/obj/item/card/id/id_card = held_item?.GetID()
if (!istype(id_card))
- to_chat(usr, span_warning("You need to swipe your ID!"))
+ to_chat(user, span_warning("You need to swipe your ID!"))
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE)
return
if (!(ACCESS_CAPTAIN in id_card.access))
- to_chat(usr, span_warning("You are not authorized to do this!"))
+ to_chat(user, span_warning("You are not authorized to do this!"))
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE)
return
@@ -207,28 +208,28 @@
SSsecurity_level.set_level(new_sec_level)
- to_chat(usr, span_notice("Authorization confirmed. Modifying security level."))
+ to_chat(user, span_notice("Authorization confirmed. Modifying security level."))
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE)
// Only notify people if an actual change happened
- usr.log_message("changed the security level to [params["newSecurityLevel"]] with [src].", LOG_GAME)
- message_admins("[ADMIN_LOOKUPFLW(usr)] has changed the security level to [params["newSecurityLevel"]] with [src] at [AREACOORD(usr)].")
- deadchat_broadcast(" has changed the security level to [params["newSecurityLevel"]] with [src] at [span_name("[get_area_name(usr, TRUE)]")].", span_name("[usr.real_name]"), usr, message_type=DEADCHAT_ANNOUNCEMENT)
+ user.log_message("changed the security level to [params["newSecurityLevel"]] with [src].", LOG_GAME)
+ message_admins("[ADMIN_LOOKUPFLW(user)] has changed the security level to [params["newSecurityLevel"]] with [src] at [AREACOORD(user)].")
+ deadchat_broadcast(" has changed the security level to [params["newSecurityLevel"]] with [src] at [span_name("[get_area_name(user, TRUE)]")].", span_name("[user.real_name]"), user, message_type=DEADCHAT_ANNOUNCEMENT)
alert_level_tick += 1
if ("deleteMessage")
- if (!authenticated(usr))
+ if (!authenticated(user))
return
var/message_index = text2num(params["message"])
if (!message_index)
return
LAZYREMOVE(messages, LAZYACCESS(messages, message_index))
if ("makePriorityAnnouncement")
- if (!authenticated_as_silicon_or_captain(usr) && !syndicate)
+ if (!authenticated_as_silicon_or_captain(user) && !syndicate)
return
- make_announcement(usr)
+ make_announcement(user)
if ("messageAssociates")
- if (!authenticated_as_non_silicon_captain(usr))
+ if (!authenticated_as_non_silicon_captain(user))
return
if (!COOLDOWN_FINISHED(src, important_action_cooldown))
return
@@ -238,24 +239,24 @@
var/emagged = obj_flags & EMAGGED
if (emagged)
- message_syndicate(message, usr)
- to_chat(usr, span_danger("SYSERR @l(19833)of(transmit.dm): !@$ MESSAGE TRANSMITTED TO SYNDICATE COMMAND."))
+ message_syndicate(message, user)
+ to_chat(user, span_danger("SYSERR @l(19833)of(transmit.dm): !@$ MESSAGE TRANSMITTED TO SYNDICATE COMMAND."))
else if(syndicate)
- message_syndicate(message, usr)
- to_chat(usr, span_danger("Message transmitted to Syndicate Command."))
+ message_syndicate(message, user)
+ to_chat(user, span_danger("Message transmitted to Syndicate Command."))
else
- message_centcom(message, usr)
- to_chat(usr, span_notice("Message transmitted to Central Command."))
+ message_centcom(message, user)
+ to_chat(user, span_notice("Message transmitted to Central Command."))
var/associates = (emagged || syndicate) ? "the Syndicate": "CentCom"
- usr.log_talk(message, LOG_SAY, tag = "message to [associates]")
- deadchat_broadcast(" has messaged [associates], \"[message]\" at [span_name("[get_area_name(usr, TRUE)]")].", span_name("[usr.real_name]"), usr, message_type = DEADCHAT_ANNOUNCEMENT)
+ user.log_talk(message, LOG_SAY, tag = "message to [associates]")
+ deadchat_broadcast(" has messaged [associates], \"[message]\" at [span_name("[get_area_name(user, TRUE)]")].", span_name("[user.real_name]"), user, message_type = DEADCHAT_ANNOUNCEMENT)
COOLDOWN_START(src, important_action_cooldown, IMPORTANT_ACTION_COOLDOWN)
if ("purchaseShuttle")
- var/can_buy_shuttles_or_fail_reason = can_buy_shuttles(usr)
+ var/can_buy_shuttles_or_fail_reason = can_buy_shuttles(user)
if (can_buy_shuttles_or_fail_reason != TRUE)
if (can_buy_shuttles_or_fail_reason != FALSE)
- to_chat(usr, span_alert("[can_buy_shuttles_or_fail_reason]"))
+ to_chat(user, span_alert("[can_buy_shuttles_or_fail_reason]"))
return
var/list/shuttles = flatten_list(SSmapping.shuttle_templates)
var/datum/map_template/shuttle/shuttle = locate(params["shuttle"]) in shuttles
@@ -264,7 +265,7 @@
if (!can_purchase_this_shuttle(shuttle))
return
if (!shuttle.prerequisites_met())
- to_chat(usr, span_alert("You have not met the requirements for purchasing this shuttle."))
+ to_chat(user, span_alert("You have not met the requirements for purchasing this shuttle."))
return
var/datum/bank_account/bank_account = SSeconomy.get_dep_account(ACCOUNT_CAR)
if (bank_account.account_balance < shuttle.credit_cost)
@@ -277,42 +278,42 @@
SSshuttle.action_load(shuttle, replace = TRUE)
bank_account.adjust_money(-shuttle.credit_cost)
- var/purchaser_name = (obj_flags & EMAGGED) ? scramble_message_replace_chars("AUTHENTICATION FAILURE: CVE-2018-17107", 60) : usr.real_name
+ var/purchaser_name = (obj_flags & EMAGGED) ? scramble_message_replace_chars("AUTHENTICATION FAILURE: CVE-2018-17107", 60) : user.real_name
minor_announce("[purchaser_name] has purchased [shuttle.name] for [shuttle.credit_cost] credits.[shuttle.extra_desc ? " [shuttle.extra_desc]" : ""]" , "Shuttle Purchase")
- message_admins("[ADMIN_LOOKUPFLW(usr)] purchased [shuttle.name].")
- log_shuttle("[key_name(usr)] has purchased [shuttle.name].")
+ message_admins("[ADMIN_LOOKUPFLW(user)] purchased [shuttle.name].")
+ log_shuttle("[key_name(user)] has purchased [shuttle.name].")
SSblackbox.record_feedback("text", "shuttle_purchase", 1, shuttle.name)
state = STATE_MAIN
if ("recallShuttle")
// AIs cannot recall the shuttle
- if (!authenticated(usr) || HAS_SILICON_ACCESS(usr) || syndicate)
+ if (!authenticated(user) || HAS_SILICON_ACCESS(user) || syndicate)
return
- SSshuttle.cancelEvac(usr)
+ SSshuttle.cancelEvac(user)
if ("requestNukeCodes")
- if (!authenticated_as_non_silicon_captain(usr))
+ if (!authenticated_as_non_silicon_captain(user))
return
if (!COOLDOWN_FINISHED(src, important_action_cooldown))
return
var/reason = trim(html_encode(params["reason"]), MAX_MESSAGE_LEN)
- nuke_request(reason, usr)
- to_chat(usr, span_notice("Request sent."))
- usr.log_message("has requested the nuclear codes from CentCom with reason \"[reason]\"", LOG_SAY)
- priority_announce("The codes for the on-station nuclear self-destruct have been requested by [usr]. Confirmation or denial of this request will be sent shortly.", "Nuclear Self-Destruct Codes Requested", SSstation.announcer.get_rand_report_sound())
+ nuke_request(reason, user)
+ to_chat(user, span_notice("Request sent."))
+ user.log_message("has requested the nuclear codes from CentCom with reason \"[reason]\"", LOG_SAY)
+ priority_announce("The codes for the on-station nuclear self-destruct have been requested by [user]. Confirmation or denial of this request will be sent shortly.", "Nuclear Self-Destruct Codes Requested", SSstation.announcer.get_rand_report_sound())
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, FALSE)
COOLDOWN_START(src, important_action_cooldown, IMPORTANT_ACTION_COOLDOWN)
if ("restoreBackupRoutingData")
- if (!authenticated_as_non_silicon_captain(usr))
+ if (!authenticated_as_non_silicon_captain(user))
return
if (!(obj_flags & EMAGGED))
return
- to_chat(usr, span_notice("Backup routing data restored."))
+ to_chat(user, span_notice("Backup routing data restored."))
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE)
obj_flags &= ~EMAGGED
if ("sendToOtherSector")
- if (!authenticated_as_non_silicon_captain(usr))
+ if (!authenticated_as_non_silicon_captain(user))
return
- if (!can_send_messages_to_other_sectors(usr))
+ if (!can_send_messages_to_other_sectors(user))
return
if (!COOLDOWN_FINISHED(src, important_action_cooldown))
return
@@ -324,54 +325,52 @@
GLOB.communications_controller.soft_filtering = FALSE
var/list/hard_filter_result = is_ic_filtered(message)
if(hard_filter_result)
- tgui_alert(usr, "Your message contains: (\"[hard_filter_result[CHAT_FILTER_INDEX_WORD]]\"), which is not allowed on this server.")
+ tgui_alert(user, "Your message contains: (\"[hard_filter_result[CHAT_FILTER_INDEX_WORD]]\"), which is not allowed on this server.")
return
var/list/soft_filter_result = is_soft_ooc_filtered(message)
if(soft_filter_result)
- if(tgui_alert(usr,"Your message contains \"[soft_filter_result[CHAT_FILTER_INDEX_WORD]]\". \"[soft_filter_result[CHAT_FILTER_INDEX_REASON]]\", Are you sure you want to use it?", "Soft Blocked Word", list("Yes", "No")) != "Yes")
+ if(tgui_alert(user,"Your message contains \"[soft_filter_result[CHAT_FILTER_INDEX_WORD]]\". \"[soft_filter_result[CHAT_FILTER_INDEX_REASON]]\", Are you sure you want to use it?", "Soft Blocked Word", list("Yes", "No")) != "Yes")
return
- message_admins("[ADMIN_LOOKUPFLW(usr)] has passed the soft filter for \"[soft_filter_result[CHAT_FILTER_INDEX_WORD]]\". They may be using a disallowed term for a cross-station message. Increasing delay time to reject.\n\n Message: \"[html_encode(message)]\"")
- log_admin_private("[key_name(usr)] has passed the soft filter for \"[soft_filter_result[CHAT_FILTER_INDEX_WORD]]\". They may be using a disallowed term for a cross-station message. Increasing delay time to reject.\n\n Message: \"[message]\"")
+ message_admins("[ADMIN_LOOKUPFLW(user)] has passed the soft filter for \"[soft_filter_result[CHAT_FILTER_INDEX_WORD]]\". They may be using a disallowed term for a cross-station message. Increasing delay time to reject.\n\n Message: \"[html_encode(message)]\"")
+ log_admin_private("[key_name(user)] has passed the soft filter for \"[soft_filter_result[CHAT_FILTER_INDEX_WORD]]\". They may be using a disallowed term for a cross-station message. Increasing delay time to reject.\n\n Message: \"[message]\"")
GLOB.communications_controller.soft_filtering = TRUE
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE)
var/destination = params["destination"]
- usr.log_message("is about to send the following message to [destination]: [message]", LOG_GAME)
+ user.log_message("is about to send the following message to [destination]: [message]", LOG_GAME)
to_chat(
GLOB.admins,
span_adminnotice( \
- "CROSS-SECTOR MESSAGE (OUTGOING): [ADMIN_LOOKUPFLW(usr)] is about to send \
+ "CROSS-SECTOR MESSAGE (OUTGOING): [ADMIN_LOOKUPFLW(user)] is about to send \
the following message to [destination] (will autoapprove in [GLOB.communications_controller.soft_filtering ? DisplayTimeText(EXTENDED_CROSS_SECTOR_CANCEL_TIME) : DisplayTimeText(CROSS_SECTOR_CANCEL_TIME)]): \
REJECT
\
[html_encode(message)]" \
)
)
- send_cross_comms_message_timer = addtimer(CALLBACK(src, PROC_REF(send_cross_comms_message), usr, destination, message), GLOB.communications_controller.soft_filtering ? EXTENDED_CROSS_SECTOR_CANCEL_TIME : CROSS_SECTOR_CANCEL_TIME, TIMER_STOPPABLE)
+ send_cross_comms_message_timer = addtimer(CALLBACK(src, PROC_REF(send_cross_comms_message), user, destination, message), GLOB.communications_controller.soft_filtering ? EXTENDED_CROSS_SECTOR_CANCEL_TIME : CROSS_SECTOR_CANCEL_TIME, TIMER_STOPPABLE)
COOLDOWN_START(src, important_action_cooldown, IMPORTANT_ACTION_COOLDOWN)
if ("setState")
- if (!authenticated(usr))
+ if (!authenticated(user))
return
if (!(params["state"] in approved_states))
return
- if (state == STATE_BUYING_SHUTTLE && can_buy_shuttles(usr) != TRUE)
+ if (state == STATE_BUYING_SHUTTLE && can_buy_shuttles(user) != TRUE)
return
set_state(usr, params["state"])
- playsound(src, SFX_TERMINAL_TYPE, 50, FALSE)
if ("setStatusMessage")
- if (!authenticated(usr))
+ if (!authenticated(user))
return
var/line_one = reject_bad_text(params["upperText"] || "", MAX_STATUS_LINE_LENGTH)
var/line_two = reject_bad_text(params["lowerText"] || "", MAX_STATUS_LINE_LENGTH)
post_status("message", line_one, line_two)
last_status_display = list(line_one, line_two)
- playsound(src, SFX_TERMINAL_TYPE, 50, FALSE)
if ("setStatusPicture")
- if (!authenticated(usr))
+ if (!authenticated(user))
return
var/picture = params["picture"]
if (!(picture in GLOB.status_display_approved_pictures))
@@ -384,7 +383,6 @@
else
post_status("alert", picture)
- playsound(src, SFX_TERMINAL_TYPE, 50, FALSE)
if ("toggleAuthentication")
// Log out if we're logged in
if (authorize_name)
@@ -398,10 +396,10 @@
authenticated = TRUE
authorize_access = SSid_access.get_region_access_list(list(REGION_ALL_STATION))
authorize_name = "Unknown"
- to_chat(usr, span_warning("[src] lets out a quiet alarm as its login is overridden."))
+ to_chat(user, span_warning("[src] lets out a quiet alarm as its login is overridden."))
playsound(src, 'sound/machines/terminal_alert.ogg', 25, FALSE)
- else if(isliving(usr))
- var/mob/living/L = usr
+ else if(isliving(user))
+ var/mob/living/L = user
var/obj/item/card/id/id_card = L.get_idcard(hand_first = TRUE)
if (check_access(id_card))
authenticated = TRUE
@@ -413,36 +411,36 @@
imprint_gps(gps_tag = "Encrypted Communications Channel")
if ("toggleEmergencyAccess")
- if(emergency_access_cooldown(usr)) //if were in cooldown, dont allow the following code
+ if(emergency_access_cooldown(user)) //if were in cooldown, dont allow the following code
return
- if (!authenticated_as_silicon_or_captain(usr))
+ if (!authenticated_as_silicon_or_captain(user))
return
if (GLOB.emergency_access)
revoke_maint_all_access()
- usr.log_message("disabled emergency maintenance access.", LOG_GAME)
- message_admins("[ADMIN_LOOKUPFLW(usr)] disabled emergency maintenance access.")
- deadchat_broadcast(" disabled emergency maintenance access at [span_name("[get_area_name(usr, TRUE)]")].", span_name("[usr.real_name]"), usr, message_type = DEADCHAT_ANNOUNCEMENT)
+ user.log_message("disabled emergency maintenance access.", LOG_GAME)
+ message_admins("[ADMIN_LOOKUPFLW(user)] disabled emergency maintenance access.")
+ deadchat_broadcast(" disabled emergency maintenance access at [span_name("[get_area_name(user, TRUE)]")].", span_name("[user.real_name]"), user, message_type = DEADCHAT_ANNOUNCEMENT)
else
make_maint_all_access()
- usr.log_message("enabled emergency maintenance access.", LOG_GAME)
- message_admins("[ADMIN_LOOKUPFLW(usr)] enabled emergency maintenance access.")
- deadchat_broadcast(" enabled emergency maintenance access at [span_name("[get_area_name(usr, TRUE)]")].", span_name("[usr.real_name]"), usr, message_type = DEADCHAT_ANNOUNCEMENT)
+ user.log_message("enabled emergency maintenance access.", LOG_GAME)
+ message_admins("[ADMIN_LOOKUPFLW(user)] enabled emergency maintenance access.")
+ deadchat_broadcast(" enabled emergency maintenance access at [span_name("[get_area_name(user, TRUE)]")].", span_name("[user.real_name]"), user, message_type = DEADCHAT_ANNOUNCEMENT)
// Request codes for the Captain's Spare ID safe.
if("requestSafeCodes")
if(SSjob.assigned_captain)
- to_chat(usr, span_warning("There is already an assigned Captain or Acting Captain on deck!"))
+ to_chat(user, span_warning("There is already an assigned Captain or Acting Captain on deck!"))
return
if(SSjob.safe_code_timer_id)
- to_chat(usr, span_warning("The safe code has already been requested and is being delivered to your station!"))
+ to_chat(user, span_warning("The safe code has already been requested and is being delivered to your station!"))
return
if(SSjob.safe_code_requested)
- to_chat(usr, span_warning("The safe code has already been requested and delivered to your station!"))
+ to_chat(user, span_warning("The safe code has already been requested and delivered to your station!"))
return
if(!SSid_access.spare_id_safe_code)
- to_chat(usr, span_warning("There is no safe code to deliver to your station!"))
+ to_chat(user, span_warning("There is no safe code to deliver to your station!"))
return
var/turf/pod_location = get_turf(src)
@@ -475,7 +473,7 @@
var/list/payload = list()
- payload["sender_ckey"] = usr.ckey
+ payload["sender_ckey"] = user.ckey
var/network_name = CONFIG_GET(string/cross_comms_network)
if(network_name)
payload["network"] = network_name
@@ -484,9 +482,9 @@
send2otherserver(html_decode(station_name()), message, "Comms_Console", destination == "all" ? null : list(destination), additional_data = payload)
minor_announce(message, title = "Outgoing message to allied station")
- usr.log_talk(message, LOG_SAY, tag = "message to the other server")
- message_admins("[ADMIN_LOOKUPFLW(usr)] has sent a message to the other server\[s].")
- deadchat_broadcast(" has sent an outgoing message to the other station(s).", "[usr.real_name]", usr, message_type = DEADCHAT_ANNOUNCEMENT)
+ user.log_talk(message, LOG_SAY, tag = "message to the other server")
+ message_admins("[ADMIN_LOOKUPFLW(user)] has sent a message to the other server\[s].")
+ deadchat_broadcast(" has sent an outgoing message to the other station(s).", "[user.real_name]", user, message_type = DEADCHAT_ANNOUNCEMENT)
GLOB.communications_controller.soft_filtering = FALSE // set it to false at the end of the proc to ensure that everything prior reads as intended
/obj/machinery/computer/communications/ui_data(mob/user)
@@ -742,7 +740,7 @@
var/list/players = get_communication_players()
GLOB.communications_controller.make_announcement(user, is_ai, input, syndicate || (obj_flags & EMAGGED), players)
- deadchat_broadcast(" made a priority announcement from [span_name("[get_area_name(usr, TRUE)]")].", span_name("[user.real_name]"), user, message_type=DEADCHAT_ANNOUNCEMENT)
+ deadchat_broadcast(" made a priority announcement from [span_name("[get_area_name(user, TRUE)]")].", span_name("[user.real_name]"), user, message_type=DEADCHAT_ANNOUNCEMENT)
/obj/machinery/computer/communications/proc/get_communication_players()
return GLOB.player_list
diff --git a/code/game/machinery/computer/crew.dm b/code/game/machinery/computer/crew.dm
index 268b675871ab2..b5e5a915ce2bf 100644
--- a/code/game/machinery/computer/crew.dm
+++ b/code/game/machinery/computer/crew.dm
@@ -182,7 +182,7 @@ GLOBAL_DATUM_INIT(crewmonitor, /datum/crewmonitor, new)
z = T.z
. = list(
"sensors" = update_data(z),
- "link_allowed" = HAS_AI_ACCESS(user)
+ "link_allowed" = HAS_AI_ACCESS(user),
)
/datum/crewmonitor/proc/update_data(z)
@@ -274,7 +274,7 @@ GLOBAL_DATUM_INIT(crewmonitor, /datum/crewmonitor, new)
return results
-/datum/crewmonitor/ui_act(action, params)
+/datum/crewmonitor/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/game/machinery/computer/dna_console.dm b/code/game/machinery/computer/dna_console.dm
index 41c46c0cb205b..e1612ae7ef2e5 100644
--- a/code/game/machinery/computer/dna_console.dm
+++ b/code/game/machinery/computer/dna_console.dm
@@ -398,7 +398,7 @@
return data
-/obj/machinery/computer/scan_consolenew/ui_act(action, list/params)
+/obj/machinery/computer/scan_consolenew/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
var/static/list/gene_letters = list("A", "T", "C", "G");
var/static/gene_letter_count = length(gene_letters)
diff --git a/code/game/machinery/computer/launchpad_control.dm b/code/game/machinery/computer/launchpad_control.dm
index 7c6d1307b76b1..1502e5af50621 100644
--- a/code/game/machinery/computer/launchpad_control.dm
+++ b/code/game/machinery/computer/launchpad_control.dm
@@ -116,7 +116,7 @@
return data
-/obj/machinery/computer/launchpad/ui_act(action, params)
+/obj/machinery/computer/launchpad/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/game/machinery/computer/mechlaunchpad.dm b/code/game/machinery/computer/mechlaunchpad.dm
index 46c0045fb3568..050f3447a8ce4 100644
--- a/code/game/machinery/computer/mechlaunchpad.dm
+++ b/code/game/machinery/computer/mechlaunchpad.dm
@@ -205,7 +205,7 @@
data["mechonly"] = current_pad.mech_only
return data
-/obj/machinery/computer/mechpad/ui_act(action, params)
+/obj/machinery/computer/mechpad/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/game/machinery/computer/operating_computer.dm b/code/game/machinery/computer/operating_computer.dm
index 43a18c7081f30..0354806d85ebd 100644
--- a/code/game/machinery/computer/operating_computer.dm
+++ b/code/game/machinery/computer/operating_computer.dm
@@ -163,7 +163,7 @@
))
return data
-/obj/machinery/computer/operating/ui_act(action, params)
+/obj/machinery/computer/operating/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/game/machinery/computer/orders/order_computer/mining_order.dm b/code/game/machinery/computer/orders/order_computer/mining_order.dm
index 7e7eabcc1bfd5..94fda727d5f79 100644
--- a/code/game/machinery/computer/orders/order_computer/mining_order.dm
+++ b/code/game/machinery/computer/orders/order_computer/mining_order.dm
@@ -62,7 +62,7 @@
/obj/machinery/computer/order_console/mining/retrieve_points(obj/item/card/id/id_card)
return round(id_card.registered_account.mining_points)
-/obj/machinery/computer/order_console/mining/ui_act(action, params)
+/obj/machinery/computer/order_console/mining/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(!.)
flick("mining-deny", src)
@@ -121,7 +121,7 @@
/obj/machinery/computer/order_console/mining/proc/check_menu(obj/item/mining_voucher/voucher, mob/living/redeemer)
if(!istype(redeemer))
return FALSE
- if(redeemer.incapacitated())
+ if(redeemer.incapacitated)
return FALSE
if(QDELETED(voucher))
return FALSE
diff --git a/code/game/machinery/computer/orders/order_computer/order_computer.dm b/code/game/machinery/computer/orders/order_computer/order_computer.dm
index b3644efeeff68..1b20e876ce583 100644
--- a/code/game/machinery/computer/orders/order_computer/order_computer.dm
+++ b/code/game/machinery/computer/orders/order_computer/order_computer.dm
@@ -124,7 +124,7 @@ GLOBAL_LIST_EMPTY(order_console_products)
))
return data
-/obj/machinery/computer/order_console/ui_act(action, params)
+/obj/machinery/computer/order_console/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/game/machinery/computer/pod.dm b/code/game/machinery/computer/pod.dm
index 4cc32401704d2..798f20c21a8f0 100644
--- a/code/game/machinery/computer/pod.dm
+++ b/code/game/machinery/computer/pod.dm
@@ -78,7 +78,7 @@
break
return data
-/obj/machinery/computer/pod/ui_act(action, list/params)
+/obj/machinery/computer/pod/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/game/machinery/computer/prisoner/gulag_teleporter.dm b/code/game/machinery/computer/prisoner/gulag_teleporter.dm
index 4c2f4dacde3f2..f03c08a8d821b 100644
--- a/code/game/machinery/computer/prisoner/gulag_teleporter.dm
+++ b/code/game/machinery/computer/prisoner/gulag_teleporter.dm
@@ -67,7 +67,7 @@
return data
-/obj/machinery/computer/prisoner/gulag_teleporter_computer/ui_act(action, list/params)
+/obj/machinery/computer/prisoner/gulag_teleporter_computer/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/game/machinery/computer/prisoner/management.dm b/code/game/machinery/computer/prisoner/management.dm
index ada71bad02304..32c2ddba984df 100644
--- a/code/game/machinery/computer/prisoner/management.dm
+++ b/code/game/machinery/computer/prisoner/management.dm
@@ -20,7 +20,7 @@ GLOBAL_LIST_EMPTY_TYPED(tracked_implants, /obj/item/implant)
/obj/machinery/computer/prisoner/management/ui_data(mob/user)
var/list/data = list()
- data["authorized"] = (authenticated && isliving(user)) || isAdminGhostAI(user) || issilicon(user)
+ data["authorized"] = (authenticated && isliving(user)) || HAS_SILICON_ACCESS(user)
data["inserted_id"] = null
if(!isnull(contained_id))
data["inserted_id"] = list(
@@ -43,7 +43,7 @@ GLOBAL_LIST_EMPTY_TYPED(tracked_implants, /obj/item/implant)
return data
-/obj/machinery/computer/prisoner/management/ui_act(action, list/params)
+/obj/machinery/computer/prisoner/management/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/game/machinery/computer/records/records.dm b/code/game/machinery/computer/records/records.dm
index e8d8beef854dd..d53895300438d 100644
--- a/code/game/machinery/computer/records/records.dm
+++ b/code/game/machinery/computer/records/records.dm
@@ -100,7 +100,6 @@
if(!target)
return FALSE
- playsound(src, SFX_TERMINAL_TYPE, 50, TRUE)
update_preview(user, params["assigned_view"], target)
return TRUE
diff --git a/code/game/machinery/computer/records/security.dm b/code/game/machinery/computer/records/security.dm
index dac62612a4c74..bdfa996dad68f 100644
--- a/code/game/machinery/computer/records/security.dm
+++ b/code/game/machinery/computer/records/security.dm
@@ -102,6 +102,7 @@
paid = warrant.paid,
time = warrant.time,
valid = warrant.valid,
+ voider = warrant.voider,
))
var/list/crimes = list()
@@ -113,6 +114,7 @@
name = crime.name,
time = crime.time,
valid = crime.valid,
+ voider = crime.voider,
))
records += list(list(
@@ -250,8 +252,8 @@
editing_crime.name = new_name
return TRUE
- if(params["details"] && length(params["description"]) > 2 && params["name"] != editing_crime.name)
- var/new_details = strip_html_full(params["details"], MAX_MESSAGE_LEN)
+ if(params["description"] && length(params["description"]) > 2 && params["name"] != editing_crime.name)
+ var/new_details = strip_html_full(params["description"], MAX_MESSAGE_LEN)
investigate_log("[user] edited crime \"[editing_crime.name]\" for target: \"[target.name]\", changing the details to: \"[new_details]\" from: \"[editing_crime.details]\".", INVESTIGATE_RECORDS)
editing_crime.details = new_details
return TRUE
@@ -269,6 +271,9 @@
/// Only qualified personnel can edit records.
/obj/machinery/computer/records/security/proc/has_armory_access(mob/user)
+ if (HAS_SILICON_ACCESS(user))
+ return TRUE
+
if(!isliving(user))
return FALSE
var/mob/living/player = user
@@ -284,16 +289,22 @@
/// Voids crimes, or sets someone to discharged if they have none left.
/obj/machinery/computer/records/security/proc/invalidate_crime(mob/user, datum/record/crew/target, list/params)
- if(!has_armory_access(user))
- return FALSE
var/datum/crime/to_void = locate(params["crime_ref"]) in target.crimes
+ var/acquitted = TRUE
if(!to_void)
+ to_void = locate(params["crime_ref"]) in target.citations
+ // No need to change status after invalidatation of citation
+ acquitted = FALSE
+ if(!to_void)
+ return FALSE
+
+ if(user != to_void.author && !has_armory_access(user))
return FALSE
to_void.valid = FALSE
+ to_void.voider = user
investigate_log("[key_name(user)] has invalidated [target.name]'s crime: [to_void.name]", INVESTIGATE_RECORDS)
- var/acquitted = TRUE
for(var/datum/crime/incident in target.crimes)
if(!incident.valid)
continue
diff --git a/code/game/machinery/computer/robot.dm b/code/game/machinery/computer/robot.dm
index 0c8b6e58d6e7e..12aa1c3ce0362 100644
--- a/code/game/machinery/computer/robot.dm
+++ b/code/game/machinery/computer/robot.dm
@@ -81,7 +81,7 @@
return data
-/obj/machinery/computer/robotics/ui_act(action, params)
+/obj/machinery/computer/robotics/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/game/machinery/computer/teleporter.dm b/code/game/machinery/computer/teleporter.dm
index d00c5824d8bd3..8cd12610c748b 100644
--- a/code/game/machinery/computer/teleporter.dm
+++ b/code/game/machinery/computer/teleporter.dm
@@ -84,7 +84,7 @@
power_station.teleporter_hub.update_appearance()
power_station.teleporter_hub.calibrated = FALSE
-/obj/machinery/computer/teleporter/ui_act(action, params)
+/obj/machinery/computer/teleporter/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/game/machinery/computer/telescreen.dm b/code/game/machinery/computer/telescreen.dm
index deca4ec8245e1..6058d3bf131ab 100644
--- a/code/game/machinery/computer/telescreen.dm
+++ b/code/game/machinery/computer/telescreen.dm
@@ -40,6 +40,8 @@
circuit = null
interaction_flags_atom = INTERACT_ATOM_UI_INTERACT | INTERACT_ATOM_NO_FINGERPRINT_INTERACT | INTERACT_ATOM_NO_FINGERPRINT_ATTACK_HAND | INTERACT_MACHINE_REQUIRES_SIGHT
frame_type = /obj/item/wallframe/telescreen/entertainment
+ /// Virtual radio inside of the entertainment monitor to broadcast audio
+ var/obj/item/radio/entertainment/speakers/speakers
var/icon_state_off = "entertainment_blank"
var/icon_state_on = "entertainment"
@@ -55,8 +57,13 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/computer/security/telescreen/entertai
. = ..()
RegisterSignal(src, COMSIG_CLICK, PROC_REF(BigClick))
find_and_hang_on_wall()
+ speakers = new(src)
-// Bypass clickchain to allow humans to use the telescreen from a distance
+/obj/machinery/computer/security/telescreen/entertainment/Destroy()
+ . = ..()
+ QDEL_NULL(speakers)
+
+/// Bypass clickchain to allow humans to use the telescreen from a distance
/obj/machinery/computer/security/telescreen/entertainment/proc/BigClick()
SIGNAL_HANDLER
@@ -66,7 +73,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/computer/security/telescreen/entertai
INVOKE_ASYNC(src, TYPE_PROC_REF(/atom, interact), usr)
-///Sets the monitor's icon to the selected state, and says an announcement
+/// Sets the monitor's icon to the selected state, and says an announcement
/obj/machinery/computer/security/telescreen/entertainment/proc/notify(on, announcement)
if(on && icon_state == icon_state_off)
icon_state = icon_state_on
diff --git a/code/game/machinery/computer/warrant.dm b/code/game/machinery/computer/warrant.dm
index 1e3557f76f046..3b73a8b75bfea 100644
--- a/code/game/machinery/computer/warrant.dm
+++ b/code/game/machinery/computer/warrant.dm
@@ -133,6 +133,7 @@
return TRUE
warrant.alert_owner(user, src, target.name, "One of your outstanding warrants has been completely paid.")
+ warrant.valid = FALSE
return TRUE
/// Finishes printing, resets the printer.
diff --git a/code/game/machinery/dance_machine.dm b/code/game/machinery/dance_machine.dm
index 45daa1966a635..d2e3c895ebd1d 100644
--- a/code/game/machinery/dance_machine.dm
+++ b/code/game/machinery/dance_machine.dm
@@ -67,7 +67,7 @@
/obj/machinery/jukebox/ui_data(mob/user)
return music_player.get_ui_data()
-/obj/machinery/jukebox/ui_act(action, list/params)
+/obj/machinery/jukebox/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/game/machinery/dish_drive.dm b/code/game/machinery/dish_drive.dm
index b386ebb376f57..74ca492657b6e 100644
--- a/code/game/machinery/dish_drive.dm
+++ b/code/game/machinery/dish_drive.dm
@@ -12,7 +12,6 @@
interaction_flags_click = ALLOW_SILICON_REACH
/// List of dishes the drive can hold
var/static/list/collectable_items = list(
- /obj/item/trash/waffles,
/obj/item/broken_bottle,
/obj/item/kitchen/fork,
/obj/item/plate,
@@ -24,7 +23,6 @@
)
/// List of items the drive detects as trash
var/static/list/disposable_items = list(
- /obj/item/trash/waffles,
/obj/item/broken_bottle,
/obj/item/plate_shard,
/obj/item/shard,
diff --git a/code/game/machinery/dna_infuser/infuser_entries/infuser_tier_one_entries.dm b/code/game/machinery/dna_infuser/infuser_entries/infuser_tier_one_entries.dm
index d24a951d76b52..bd8734643f898 100644
--- a/code/game/machinery/dna_infuser/infuser_entries/infuser_tier_one_entries.dm
+++ b/code/game/machinery/dna_infuser/infuser_entries/infuser_tier_one_entries.dm
@@ -1,6 +1,6 @@
/*
* Tier one entries are unlocked at the start, and are for dna mutants that are:
- * - easy to aquire (rats)
+ * - easy to acquire (rats)
* - have a bonus for getting past a threshold
* - might serve a job purpose for others (goliath) and thus should be gainable early enough
*/
diff --git a/code/game/machinery/dna_infuser/infuser_entries/infuser_tier_two_entries.dm b/code/game/machinery/dna_infuser/infuser_entries/infuser_tier_two_entries.dm
index 5eb13847bb5a0..1620607d5f09c 100644
--- a/code/game/machinery/dna_infuser/infuser_entries/infuser_tier_two_entries.dm
+++ b/code/game/machinery/dna_infuser/infuser_entries/infuser_tier_two_entries.dm
@@ -1,6 +1,6 @@
/*
* Tier two entries are unlocked after infusing someone/being infused and achieving a bonus, and are for dna mutants that are:
- * - harder to aquire (gondolas) but not *necessarily* requiring job help
+ * - harder to acquire (gondolas) but not *necessarily* requiring job help
* - have a bonus for getting past a threshold
*
* todos for the future:
diff --git a/code/game/machinery/dna_infuser/organ_sets/carp_organs.dm b/code/game/machinery/dna_infuser/organ_sets/carp_organs.dm
index aa3e9441d84a0..10fcae90a9591 100644
--- a/code/game/machinery/dna_infuser/organ_sets/carp_organs.dm
+++ b/code/game/machinery/dna_infuser/organ_sets/carp_organs.dm
@@ -58,11 +58,12 @@
var/datum/species/rec_species = human_receiver.dna.species
rec_species.update_no_equip_flags(tongue_owner, rec_species.no_equip_flags | ITEM_SLOT_MASK)
-/obj/item/organ/internal/tongue/carp/on_bodypart_insert(obj/item/bodypart/limb)
+/obj/item/organ/internal/tongue/carp/on_bodypart_insert(obj/item/bodypart/head)
. = ..()
- limb.unarmed_damage_low = 10
- limb.unarmed_damage_high = 15
- limb.unarmed_effectiveness = 15
+ head.unarmed_damage_low = 10
+ head.unarmed_damage_high = 15
+ head.unarmed_effectiveness = 15
+ head.unarmed_attack_effect = ATTACK_EFFECT_BITE
/obj/item/organ/internal/tongue/carp/on_mob_remove(mob/living/carbon/tongue_owner)
. = ..()
@@ -76,10 +77,10 @@
/obj/item/organ/internal/tongue/carp/on_bodypart_remove(obj/item/bodypart/head)
. = ..()
-
head.unarmed_damage_low = initial(head.unarmed_damage_low)
head.unarmed_damage_high = initial(head.unarmed_damage_high)
head.unarmed_effectiveness = initial(head.unarmed_effectiveness)
+ head.unarmed_attack_effect = initial(head.unarmed_attack_effect)
/obj/item/organ/internal/tongue/carp/on_life(seconds_per_tick, times_fired)
. = ..()
diff --git a/code/game/machinery/dna_infuser/organ_sets/fly_organs.dm b/code/game/machinery/dna_infuser/organ_sets/fly_organs.dm
index e3e7112b0fec9..4786bf5753c9f 100644
--- a/code/game/machinery/dna_infuser/organ_sets/fly_organs.dm
+++ b/code/game/machinery/dna_infuser/organ_sets/fly_organs.dm
@@ -125,7 +125,6 @@
//useless organs we throw in just to fuck with surgeons a bit more. they aren't part of a bonus, just the (absolute) state of flies
/obj/item/organ/internal/fly
desc = FLY_INFUSED_ORGAN_DESC
- visual = FALSE
/obj/item/organ/internal/fly/Initialize(mapload)
. = ..()
diff --git a/code/game/machinery/dna_infuser/organ_sets/fox_organs.dm b/code/game/machinery/dna_infuser/organ_sets/fox_organs.dm
index ab33c1ad57ef3..3fecac3bb6dbf 100644
--- a/code/game/machinery/dna_infuser/organ_sets/fox_organs.dm
+++ b/code/game/machinery/dna_infuser/organ_sets/fox_organs.dm
@@ -6,17 +6,4 @@
visual = TRUE
damage_multiplier = 2
-/obj/item/organ/internal/ears/fox/on_mob_insert(mob/living/carbon/human/ear_owner)
- . = ..()
- if(istype(ear_owner) && ear_owner.dna)
- color = ear_owner.hair_color
- ear_owner.dna.features["ears"] = ear_owner.dna.species.mutant_bodyparts["ears"] = "Fox"
- ear_owner.dna.update_uf_block(DNA_EARS_BLOCK)
- ear_owner.update_body()
-
-/obj/item/organ/internal/ears/fox/on_mob_remove(mob/living/carbon/human/ear_owner)
- . = ..()
- if(istype(ear_owner) && ear_owner.dna)
- color = ear_owner.hair_color
- ear_owner.dna.species.mutant_bodyparts -= "ears"
- ear_owner.update_body()
+ sprite_accessory_override = /datum/sprite_accessory/ears/fox
diff --git a/code/game/machinery/dna_infuser/organ_sets/gondola_organs.dm b/code/game/machinery/dna_infuser/organ_sets/gondola_organs.dm
index 797c7839b2c29..9fcf7e483bba9 100644
--- a/code/game/machinery/dna_infuser/organ_sets/gondola_organs.dm
+++ b/code/game/machinery/dna_infuser/organ_sets/gondola_organs.dm
@@ -34,7 +34,7 @@ Fluoride Stare: After someone says 5 words, blah blah blah...
AddElement(/datum/element/noticable_organ, "%PRONOUN_They radiate%PRONOUN_s an aura of serenity.")
AddElement(/datum/element/update_icon_blocker)
-/obj/item/organ/internal/heart/gondola/Insert(mob/living/carbon/receiver, special, movement_flags)
+/obj/item/organ/internal/heart/gondola/mob_insert(mob/living/carbon/receiver, special, movement_flags)
. = ..()
if(!(FACTION_HOSTILE in receiver.faction))
factions_to_remove += FACTION_HOSTILE
@@ -42,7 +42,7 @@ Fluoride Stare: After someone says 5 words, blah blah blah...
factions_to_remove += FACTION_MINING
receiver.faction |= list(FACTION_HOSTILE, FACTION_MINING)
-/obj/item/organ/internal/heart/gondola/Remove(mob/living/carbon/heartless, special, movement_flags)
+/obj/item/organ/internal/heart/gondola/mob_remove(mob/living/carbon/heartless, special, movement_flags)
. = ..()
for(var/faction in factions_to_remove)
heartless.faction -= faction
@@ -64,11 +64,11 @@ Fluoride Stare: After someone says 5 words, blah blah blah...
AddElement(/datum/element/noticable_organ, "%PRONOUN_Their mouth is permanently affixed into a relaxed smile.", BODY_ZONE_PRECISE_MOUTH)
AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/gondola)
-/obj/item/organ/internal/tongue/gondola/Insert(mob/living/carbon/tongue_owner, special, movement_flags)
+/obj/item/organ/internal/tongue/gondola/mob_insert(mob/living/carbon/tongue_owner, special, movement_flags)
. = ..()
tongue_owner.add_mood_event("gondola_zen", /datum/mood_event/gondola_serenity)
-/obj/item/organ/internal/tongue/gondola/Remove(mob/living/carbon/tongue_owner, special, movement_flags)
+/obj/item/organ/internal/tongue/gondola/mob_remove(mob/living/carbon/tongue_owner, special, movement_flags)
tongue_owner.clear_mood_event("gondola_zen")
return ..()
@@ -87,7 +87,7 @@ Fluoride Stare: After someone says 5 words, blah blah blah...
AddElement(/datum/element/noticable_organ, "%PRONOUN_Their left arm has small needles breaching the skin all over it.", BODY_ZONE_L_ARM)
AddElement(/datum/element/noticable_organ, "%PRONOUN_Their right arm has small needles breaching the skin all over it.", BODY_ZONE_R_ARM)
-/obj/item/organ/internal/liver/gondola/Insert(mob/living/carbon/liver_owner, special, movement_flags)
+/obj/item/organ/internal/liver/gondola/mob_insert(mob/living/carbon/liver_owner, special, movement_flags)
. = ..()
var/has_left = liver_owner.has_left_hand(check_disabled = FALSE)
var/has_right = liver_owner.has_right_hand(check_disabled = FALSE)
@@ -102,7 +102,7 @@ Fluoride Stare: After someone says 5 words, blah blah blah...
RegisterSignal(liver_owner, COMSIG_LIVING_TRY_PULL, PROC_REF(on_owner_try_pull))
RegisterSignal(liver_owner, COMSIG_CARBON_HELPED, PROC_REF(on_hug))
-/obj/item/organ/internal/liver/gondola/Remove(mob/living/carbon/liver_owner, special, movement_flags)
+/obj/item/organ/internal/liver/gondola/mob_remove(mob/living/carbon/liver_owner, special, movement_flags)
. = ..()
UnregisterSignal(liver_owner, list(COMSIG_HUMAN_EQUIPPING_ITEM, COMSIG_LIVING_TRY_PULL, COMSIG_CARBON_HELPED))
diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm
index 7188ba7c8353a..a33895e5569b7 100644
--- a/code/game/machinery/doors/airlock.dm
+++ b/code/game/machinery/doors/airlock.dm
@@ -1660,7 +1660,7 @@
data["wires"] = wire
return data
-/obj/machinery/door/airlock/ui_act(action, params)
+/obj/machinery/door/airlock/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/game/machinery/doors/airlock_electronics.dm b/code/game/machinery/doors/airlock_electronics.dm
index 73ae0994eb517..2973579153a84 100644
--- a/code/game/machinery/doors/airlock_electronics.dm
+++ b/code/game/machinery/doors/airlock_electronics.dm
@@ -109,7 +109,7 @@
var/new_cycle_id = trim(params["passedCycleId"], 30)
passed_cycle_id = new_cycle_id
-/obj/item/electronics/airlock/ui_act(action, params)
+/obj/item/electronics/airlock/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/game/machinery/doors/brigdoors.dm b/code/game/machinery/doors/brigdoors.dm
index 26dc09204a70c..10aa52cfd7bed 100644
--- a/code/game/machinery/doors/brigdoors.dm
+++ b/code/game/machinery/doors/brigdoors.dm
@@ -214,7 +214,7 @@
break
return data
-/obj/machinery/status_display/door_timer/ui_act(action, params)
+/obj/machinery/status_display/door_timer/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm
index 601ad67a6e9a4..d75b5e17174c5 100644
--- a/code/game/machinery/doors/door.dm
+++ b/code/game/machinery/doors/door.dm
@@ -371,6 +371,12 @@
return TRUE
return ..()
+/obj/machinery/door/item_interaction_secondary(mob/living/user, obj/item/tool, list/modifiers)
+ // allows you to crowbar doors while in combat mode
+ if(user.combat_mode && tool.tool_behaviour == TOOL_CROWBAR)
+ return crowbar_act_secondary(user, tool)
+ return ..()
+
/obj/machinery/door/welder_act_secondary(mob/living/user, obj/item/tool)
try_to_weld_secondary(tool, user)
return ITEM_INTERACT_SUCCESS
@@ -605,6 +611,10 @@
/obj/machinery/door/morgue
icon = 'icons/obj/doors/doormorgue.dmi'
+/obj/machinery/door/morgue/Initialize(mapload)
+ . = ..()
+ AddComponent(/datum/component/redirect_attack_hand_from_turf)
+
/obj/machinery/door/get_dumping_location()
return null
diff --git a/code/game/machinery/embedded_controller/airlock_controller.dm b/code/game/machinery/embedded_controller/airlock_controller.dm
index a1cc608c2ec9d..18e880902963d 100644
--- a/code/game/machinery/embedded_controller/airlock_controller.dm
+++ b/code/game/machinery/embedded_controller/airlock_controller.dm
@@ -244,7 +244,7 @@
return data
-/obj/machinery/airlock_controller/ui_act(action, params)
+/obj/machinery/airlock_controller/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/game/machinery/flatpacker.dm b/code/game/machinery/flatpacker.dm
index 182db1edc08d9..01224ad8b00fa 100644
--- a/code/game/machinery/flatpacker.dm
+++ b/code/game/machinery/flatpacker.dm
@@ -112,7 +112,7 @@
/obj/machinery/flatpacker/proc/AfterMaterialInsert(container, obj/item/item_inserted, last_inserted_id, mats_consumed, amount_inserted, atom/context)
SIGNAL_HANDLER
- //we use initial(active_power_usage) because higher tier parts will have higher active usage but we have no benifit from it
+ //we use initial(active_power_usage) because higher tier parts will have higher active usage but we have no benefit from it
if(directly_use_energy(ROUND_UP((amount_inserted / (MAX_STACK_SIZE * SHEET_MATERIAL_AMOUNT)) * 0.4 * initial(active_power_usage))))
flick_overlay_view(mutable_appearance('icons/obj/machines/lathes.dmi', "flatpacker_bar"), 1 SECONDS)
@@ -292,7 +292,7 @@
if(isnull(amount))
return
- //we use initial(active_power_usage) because higher tier parts will have higher active usage but we have no benifit from it
+ //we use initial(active_power_usage) because higher tier parts will have higher active usage but we have no benefit from it
if(!directly_use_energy(ROUND_UP((amount / MAX_STACK_SIZE) * 0.4 * initial(active_power_usage))))
say("No power to dispense sheets")
return
diff --git a/code/game/machinery/gulag_item_reclaimer.dm b/code/game/machinery/gulag_item_reclaimer.dm
index 72ac0e746f4b0..93f60beeb8a14 100644
--- a/code/game/machinery/gulag_item_reclaimer.dm
+++ b/code/game/machinery/gulag_item_reclaimer.dm
@@ -82,7 +82,7 @@
return data
-/obj/machinery/gulag_item_reclaimer/ui_act(action, params)
+/obj/machinery/gulag_item_reclaimer/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm
index cbb7eede250b9..bf3d97426fd24 100644
--- a/code/game/machinery/hologram.dm
+++ b/code/game/machinery/hologram.dm
@@ -168,7 +168,7 @@ Possible to do for anyone motivated enough:
/obj/machinery/holopad/tutorial/attack_hand(mob/user, list/modifiers)
if(!istype(user))
return
- if(user.incapacitated() || !is_operational)
+ if(user.incapacitated || !is_operational)
return
if(replay_mode)
replay_stop()
@@ -308,7 +308,7 @@ Possible to do for anyone motivated enough:
data["holo_calls"] += list(call_data)
return data
-/obj/machinery/holopad/ui_act(action, list/params)
+/obj/machinery/holopad/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
@@ -675,7 +675,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
if(!isliving(owner))
return TRUE
var/mob/living/user = owner
- if(user.incapacitated() || !user.client)
+ if(user.incapacitated || !user.client)
return FALSE
return TRUE
diff --git a/code/game/machinery/hypnochair.dm b/code/game/machinery/hypnochair.dm
index f8f3ed49be598..b5ec2c58b3870 100644
--- a/code/game/machinery/hypnochair.dm
+++ b/code/game/machinery/hypnochair.dm
@@ -63,7 +63,7 @@
return data
-/obj/machinery/hypnochair/ui_act(action, params)
+/obj/machinery/hypnochair/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/game/machinery/iv_drip.dm b/code/game/machinery/iv_drip.dm
index 4ac2a177e76bc..e1b10dae6e43e 100644
--- a/code/game/machinery/iv_drip.dm
+++ b/code/game/machinery/iv_drip.dm
@@ -106,7 +106,7 @@
.["containerMaxVolume"] = drip_reagents.maximum_volume
.["containerReagentColor"] = mix_color_from_reagents(drip_reagents.reagent_list)
-/obj/machinery/iv_drip/ui_act(action, params)
+/obj/machinery/iv_drip/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
@@ -322,7 +322,7 @@
return
if(!usr.can_perform_action(src))
return
- if(usr.incapacitated())
+ if(usr.incapacitated)
return
if(reagent_container)
if(attached)
@@ -340,7 +340,7 @@
if(!isliving(usr))
to_chat(usr, span_warning("You can't do that!"))
return
- if(!usr.can_perform_action(src) || usr.incapacitated())
+ if(!usr.can_perform_action(src) || usr.incapacitated)
return
if(inject_only)
mode = IV_INJECTING
diff --git a/code/game/machinery/launch_pad.dm b/code/game/machinery/launch_pad.dm
index 8733ca548632e..67ad91681506d 100644
--- a/code/game/machinery/launch_pad.dm
+++ b/code/game/machinery/launch_pad.dm
@@ -417,7 +417,7 @@
return
pad.doteleport(user, sending)
-/obj/item/launchpad_remote/ui_act(action, params)
+/obj/item/launchpad_remote/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/game/machinery/limbgrower.dm b/code/game/machinery/limbgrower.dm
index b63d13648eb76..cd36dcce09ad0 100644
--- a/code/game/machinery/limbgrower.dm
+++ b/code/game/machinery/limbgrower.dm
@@ -149,7 +149,7 @@
if(user.combat_mode) //so we can hit the machine
return ..()
-/obj/machinery/limbgrower/ui_act(action, list/params)
+/obj/machinery/limbgrower/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
@@ -233,7 +233,7 @@
*/
/obj/machinery/limbgrower/proc/build_limb(buildpath)
/// The limb we're making with our buildpath, so we can edit it.
- //i need to create a body part manually using a set icon (otherwise it doesnt appear)
+ //i need to create a body part manually using a set icon (otherwise it doesn't appear)
var/obj/item/bodypart/limb
limb = new buildpath(loc)
limb.name = "\improper synthetic [selected_category] [limb.plaintext_zone]"
diff --git a/code/game/machinery/machine_frame.dm b/code/game/machinery/machine_frame.dm
index ccdcddc87052d..d39d065232426 100644
--- a/code/game/machinery/machine_frame.dm
+++ b/code/game/machinery/machine_frame.dm
@@ -454,7 +454,7 @@
var/obj/item/circuitboard/machine/leaving_circuit = circuit
circuit = null
// Assign the circuit & parts & move them all at once into the machine
- // no need to seperatly move circuit board as its already part of the components list
+ // no need to separately move circuit board as its already part of the components list
new_machine.circuit = leaving_circuit
new_machine.component_parts = components
for (var/obj/new_part in components)
diff --git a/code/game/machinery/modular_shield.dm b/code/game/machinery/modular_shield.dm
index cac65a032dff4..b4fa6bed17bb0 100644
--- a/code/game/machinery/modular_shield.dm
+++ b/code/game/machinery/modular_shield.dm
@@ -1,22 +1,22 @@
/obj/machinery/modular_shield_generator
name = "modular shield generator"
- desc = "A forcefield generator, it seems more stationary than its cousins. It cant handle G-force and will require frequent reboots when built on mobile craft."
+ desc = "A forcefield generator, it seems more stationary than its cousins. It can't handle G-force and will require frequent reboots when built on mobile craft."
icon = 'icons/obj/machines/modular_shield_generator.dmi'
icon_state = "gen_recovering_closed"
density = TRUE
circuit = /obj/item/circuitboard/machine/modular_shield_generator
processing_flags = START_PROCESSING_ON_INIT
- ///Doesnt actually control it, just tells us if its running or not, you can control by calling procs activate_shields and deactivate_shields
+ ///Doesn't actually control it, just tells us if its running or not, you can control by calling procs activate_shields and deactivate_shields
var/active = FALSE
///If the generator is currently spawning the forcefield in
var/initiating = FALSE
- ///Determins if we can turn it on or not, no longer recovering when back to max strength
+ ///Determines if we can turn it on or not, no longer recovering when back to max strength
var/recovering = TRUE
- ///Determins max health of the shield
+ ///Determines max health of the shield
var/max_strength = 40
///Current health of shield
@@ -28,13 +28,13 @@
///The regeneration that the shield can support
var/current_regeneration
- ///Determins the max radius the shield can support
+ ///Determines the max radius the shield can support
var/max_radius = 3
///Current radius the shield is set to, minimum 3
var/radius = 3
- ///Determins if we only generate a shield on space turfs or not
+ ///Determines if we only generate a shield on space turfs or not
var/exterior_only = FALSE
///The lazy list of shields that are ours
@@ -276,7 +276,7 @@
data["initiating_field"] = initiating
return data
-/obj/machinery/modular_shield_generator/ui_act(action, params)
+/obj/machinery/modular_shield_generator/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
@@ -286,7 +286,7 @@
return
var/change_radius = max(1,(text2num(params["new_radius"])))
if(change_radius >= 10)
- radius = round(change_radius)//if its over 10 we dont allow decimals
+ radius = round(change_radius)//if its over 10 we don't allow decimals
return
radius = change_radius
@@ -370,7 +370,7 @@
recovering = FALSE
calculate_regeneration()
update_icon_state()
- end_processing() //we dont care about continuing to update the alpha, we want to show history of damage to show its unstable
+ end_processing() //we don't care about continuing to update the alpha, we want to show history of damage to show its unstable
if (active)
var/random_num = rand(1,deployed_shields.len)
var/obj/structure/emergency_shield/modular/random_shield = deployed_shields[random_num]
@@ -383,7 +383,7 @@
/obj/machinery/modular_shield/module
name = "modular shield debugger" //Filler name and sprite for testing
- desc = "This is filler for testing you shouldn`t see this."
+ desc = "This is filler for testing you shouldn't see this."
icon = 'icons/obj/machines/mech_bay.dmi'
icon_state = "recharge_port"
density = TRUE
@@ -677,7 +677,7 @@
color = "#00ffff"
density = FALSE
alpha = 100
- resistance_flags = INDESTRUCTIBLE //the shield itself is indestructible or atleast should be
+ resistance_flags = INDESTRUCTIBLE //the shield itself is indestructible or at least should be
no_damage_feedback = "weakening the generator sustaining it"
///The shield generator sustaining us
diff --git a/code/game/machinery/navbeacon.dm b/code/game/machinery/navbeacon.dm
index c15421cbf5abb..f6f4270835ca0 100644
--- a/code/game/machinery/navbeacon.dm
+++ b/code/game/machinery/navbeacon.dm
@@ -181,16 +181,17 @@
data["static_controls"] = static_controls
return data
-/obj/machinery/navbeacon/ui_act(action, params)
+/obj/machinery/navbeacon/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
+ var/mob/user = ui.user
- if(action == "lock" && allowed(usr))
+ if(action == "lock" && allowed(user))
controls_locked = !controls_locked
return TRUE
- if(controls_locked && !HAS_SILICON_ACCESS(usr))
+ if(controls_locked && !HAS_SILICON_ACCESS(user))
return
switch(action)
@@ -210,7 +211,7 @@
toggle_code(NAVBEACON_DELIVERY_MODE)
return TRUE
if("set_location")
- var/input_text = tgui_input_text(usr, "Enter the beacon's location tag", "Beacon Location", location, 20)
+ var/input_text = tgui_input_text(user, "Enter the beacon's location tag", "Beacon Location", location, 20)
if (!input_text || location == input_text)
return
glob_lists_deregister()
@@ -219,7 +220,7 @@
return TRUE
if("set_patrol_next")
var/next_patrol = codes[NAVBEACON_PATROL_NEXT]
- var/input_text = tgui_input_text(usr, "Enter the tag of the next patrol location", "Beacon Location", next_patrol, 20)
+ var/input_text = tgui_input_text(user, "Enter the tag of the next patrol location", "Beacon Location", next_patrol, 20)
if (!input_text || location == input_text)
return
codes[NAVBEACON_PATROL_NEXT] = input_text
diff --git a/code/game/machinery/newscaster/newscaster_data.dm b/code/game/machinery/newscaster/newscaster_data.dm
index 94449808857e1..89e491532c458 100644
--- a/code/game/machinery/newscaster/newscaster_data.dm
+++ b/code/game/machinery/newscaster/newscaster_data.dm
@@ -107,17 +107,17 @@ GLOBAL_LIST_EMPTY(request_list)
channel_ID = random_channel_id_setup()
/**
- * This proc assigns each feed_channel a random integer, from 1-999 as a unique identifer.
+ * This proc assigns each feed_channel a random integer, from 1-999 as a unique identifier.
* Using this value, the TGUI window has a unique identifier to attach to messages that can be used to reattach them
* to their parent channels back in dreammaker.
- * Based on implementation, we're limiting outselves to only 998 player made channels maximum. How we'd use all of them, I don't know.
+ * Based on implementation, we're limiting ourselves to only 998 player made channels maximum. How we'd use all of them, I don't know.
*/
/datum/feed_channel/proc/random_channel_id_setup()
if(!GLOB.news_network)
return //Should only apply to channels made before setup is finished, use hardset_channel for these
if(!GLOB.news_network.channel_IDs)
GLOB.news_network.channel_IDs += rand(1,999)
- return //This will almost always be the station annoucements channel here.
+ return //This will almost always be the station announcements channel here.
var/channel_id
for(var/i in 1 to 10000)
channel_id = rand(1, 999)
@@ -155,7 +155,7 @@ GLOBAL_LIST_EMPTY(request_list)
var/active
/// What is the criminal in question's name? Not a mob reference as this is a text field.
var/criminal
- /// Message body used to describe what crime has been comitted.
+ /// Message body used to describe what crime has been committed.
var/body
/// Who was it that created this wanted message?
var/scanned_user
@@ -181,7 +181,7 @@ GLOBAL_LIST_EMPTY(request_list)
var/message_count = 0
/datum/feed_network/New()
- create_feed_channel("Station Announcements", "SS13", "Company news, staff annoucements, and all the latest information. Have a secure shift!", locked = TRUE, hardset_channel = 1000)
+ create_feed_channel("Station Announcements", "SS13", "Company news, staff announcements, and all the latest information. Have a secure shift!", locked = TRUE, hardset_channel = 1000)
wanted_issue = new /datum/wanted_message
/datum/feed_network/proc/create_feed_channel(channel_name, author, desc, locked, adminChannel = FALSE, hardset_channel)
diff --git a/code/game/machinery/newscaster/newscaster_machine.dm b/code/game/machinery/newscaster/newscaster_machine.dm
index 7f3d8ea806f46..3186d2081e5a7 100644
--- a/code/game/machinery/newscaster/newscaster_machine.dm
+++ b/code/game/machinery/newscaster/newscaster_machine.dm
@@ -64,7 +64,7 @@
acid = 30
/obj/machinery/newscaster/pai/ui_state(mob/user)
- return GLOB.reverse_contained_state
+ return GLOB.deep_inventory_state
MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/newscaster, 30)
@@ -264,7 +264,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/newscaster, 30)
return data
-/obj/machinery/newscaster/ui_act(action, params)
+/obj/machinery/newscaster/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/game/machinery/newscaster/newspaper.dm b/code/game/machinery/newscaster/newspaper.dm
index 2bd8187b9f8c0..c381f2f506304 100644
--- a/code/game/machinery/newscaster/newspaper.dm
+++ b/code/game/machinery/newscaster/newspaper.dm
@@ -132,6 +132,15 @@
/// Called when someone tries to figure out what our identity is, but they can't see it because of the newspaper
/obj/item/newspaper/proc/holder_checked_name(mob/living/carbon/human/source, list/identity)
SIGNAL_HANDLER
+
+ var/newspaper_obscurity_priority = 100 // how powerful obscuring your appearance with a newspaper is
+ if(identity[VISIBLE_NAME_FORCED])
+ if(identity[VISIBLE_NAME_FORCED] > newspaper_obscurity_priority) // the other set forced name is forcier than breaking news
+ return
+ else if(identity[VISIBLE_NAME_FORCED] == newspaper_obscurity_priority)
+ stack_trace("A name-setting signal operation ([identity[VISIBLE_NAME_FACE]]) has a priority collision with [src].")
+ else
+ identity[VISIBLE_NAME_FORCED] = newspaper_obscurity_priority
identity[VISIBLE_NAME_FACE] = ""
identity[VISIBLE_NAME_ID] = ""
diff --git a/code/game/machinery/pipe/construction.dm b/code/game/machinery/pipe/construction.dm
index ef18dc6b068ae..39d6fe7d2ea0c 100644
--- a/code/game/machinery/pipe/construction.dm
+++ b/code/game/machinery/pipe/construction.dm
@@ -175,7 +175,7 @@ Buildable meters
set name = "Invert Pipe"
set src in view(1)
- if ( usr.incapacitated() )
+ if ( usr.incapacitated )
return
do_a_flip()
diff --git a/code/game/machinery/pipe/pipe_dispenser.dm b/code/game/machinery/pipe/pipe_dispenser.dm
index eb5b499bce79e..1e90b270c8c8d 100644
--- a/code/game/machinery/pipe/pipe_dispenser.dm
+++ b/code/game/machinery/pipe/pipe_dispenser.dm
@@ -62,7 +62,7 @@
data["init_directions"] = init_directions
return data
-/obj/machinery/pipedispenser/ui_act(action, params)
+/obj/machinery/pipedispenser/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
if(..())
return
switch(action)
@@ -187,6 +187,9 @@
//Allow you to drag-drop disposal pipes and transit tubes into it
/obj/machinery/pipedispenser/disposal/mouse_drop_receive(obj/structure/pipe, mob/user, params)
+ if(user.incapacitated)
+ return
+
if (!istype(pipe, /obj/structure/disposalconstruct) && !istype(pipe, /obj/structure/c_transit_tube) && !istype(pipe, /obj/structure/c_transit_tube_pod))
return
diff --git a/code/game/machinery/porta_turret/portable_turret.dm b/code/game/machinery/porta_turret/portable_turret.dm
index c9694730a3f8a..b1b5fc2b8f8d6 100644
--- a/code/game/machinery/porta_turret/portable_turret.dm
+++ b/code/game/machinery/porta_turret/portable_turret.dm
@@ -264,7 +264,7 @@ DEFINE_BITFIELD(turret_flags, list(
data["allow_manual_control"] = TRUE
return data
-/obj/machinery/porta_turret/ui_act(action, list/params)
+/obj/machinery/porta_turret/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
@@ -1025,34 +1025,36 @@ DEFINE_BITFIELD(turret_flags, list(
/obj/machinery/turretid/ui_data(mob/user)
var/list/data = list()
data["locked"] = locked
- data["siliconUser"] = user.has_unlimited_silicon_privilege
+ data["siliconUser"] = HAS_SILICON_ACCESS(user)
data["enabled"] = enabled
data["lethal"] = lethal
data["shootCyborgs"] = shoot_cyborgs
return data
-/obj/machinery/turretid/ui_act(action, list/params)
+/obj/machinery/turretid/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
+ var/mob/user = ui.user
+
switch(action)
if("lock")
- if(!usr.has_unlimited_silicon_privilege)
+ if(!HAS_SILICON_ACCESS(user))
return
if((obj_flags & EMAGGED) || (machine_stat & BROKEN))
- to_chat(usr, span_warning("The turret control is unresponsive!"))
+ to_chat(user, span_warning("The turret control is unresponsive!"))
return
locked = !locked
return TRUE
if("power")
- toggle_on(usr)
+ toggle_on(user)
return TRUE
if("mode")
- toggle_lethal(usr)
+ toggle_lethal(user)
return TRUE
if("shoot_silicons")
- shoot_silicons(usr)
+ shoot_silicons(user)
return TRUE
/obj/machinery/turretid/proc/toggle_lethal(mob/user)
diff --git a/code/game/machinery/portagrav.dm b/code/game/machinery/portagrav.dm
new file mode 100644
index 0000000000000..c970fa5f8f1c6
--- /dev/null
+++ b/code/game/machinery/portagrav.dm
@@ -0,0 +1,268 @@
+/obj/machinery/power/portagrav
+ anchored = FALSE
+ density = TRUE
+ interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON
+ icon = 'icons/obj/machines/gravity_generator.dmi'
+ icon_state = "portagrav"
+ base_icon_state = "portagrav"
+ name = "Portable Gravity Unit"
+ desc = "Generates gravity around itself. Powered by wire or cell. Must be anchored before use."
+ max_integrity = 250
+ circuit = /obj/item/circuitboard/machine/portagrav
+ armor_type = /datum/armor/portable_gravity
+ interaction_flags_click = ALLOW_SILICON_REACH
+ //We don't use area power
+ use_power = NO_POWER_USE
+ ///The cell we spawn with
+ var/obj/item/stock_parts/power_store/cell/cell = /obj/item/stock_parts/power_store/cell/high
+ ///Is the machine on?
+ var/on = FALSE
+ /// do we use power from wire instead
+ var/wire_mode = FALSE
+ /// our gravity field
+ var/datum/proximity_monitor/advanced/gravity/subtle_effect/gravity_field
+ /// strength of our gravity
+ var/grav_strength = STANDARD_GRAVITY
+ /// gravity range
+ var/range = 4
+ /// max gravity range
+ var/max_range = 6
+ /// draw per range
+ var/draw_per_range = BASE_MACHINE_ACTIVE_CONSUMPTION
+
+/datum/armor/portable_gravity
+ fire = 100
+ melee = 10
+ bomb = 40
+
+/obj/machinery/power/portagrav/Initialize(mapload)
+ . = ..()
+ if(ispath(cell))
+ cell = new cell(src)
+ if(anchored && wire_mode)
+ connect_to_network()
+
+ AddElement( \
+ /datum/element/contextual_screentip_bare_hands, \
+ rmb_text = "Toggle power", \
+ )
+
+ var/static/list/tool_behaviors = list(
+ TOOL_WRENCH = list(
+ SCREENTIP_CONTEXT_LMB = "Anchor",
+ ),
+ )
+ AddElement(/datum/element/contextual_screentip_tools, tool_behaviors)
+
+/obj/machinery/power/portagrav/Destroy()
+ . = ..()
+ cell = null
+
+/obj/machinery/power/portagrav/update_overlays()
+ . = ..()
+ if(anchored)
+ . += "portagrav_anchors"
+ if(on)
+ . += "portagrav_o"
+ . += "activated"
+
+/obj/machinery/power/portagrav/examine(mob/user)
+ . = ..()
+ . += "It is [on ? "on" : "off"]."
+ . += "The charge meter reads: [!isnull(cell) ? "[round(cell.percent(), 1)]%" : "NO CELL"]."
+ . += "It is[anchored ? "" : " not"] anchored."
+ if(in_range(user, src) || isobserver(user))
+ . += span_notice("Right-click to toggle [on ? "off" : "on"].")
+
+/obj/machinery/power/portagrav/RefreshParts()
+ . = ..()
+ var/power_usage = initial(draw_per_range)
+ for(var/datum/stock_part/micro_laser/laser in component_parts)
+ power_usage -= BASE_MACHINE_ACTIVE_CONSUMPTION / 10 * (laser.tier - 1)
+ draw_per_range = power_usage
+ var/new_range = 4
+ for(var/datum/stock_part/capacitor/capacitor in component_parts)
+ new_range += capacitor.tier
+ max_range = new_range
+ update_field()
+
+/obj/machinery/power/portagrav/screwdriver_act(mob/living/user, obj/item/tool)
+ . = NONE
+ if(default_deconstruction_screwdriver(user, "[base_icon_state]_o", base_icon_state, tool))
+ return ITEM_INTERACT_SUCCESS
+
+/obj/machinery/power/portagrav/crowbar_act(mob/living/user, obj/item/tool)
+ . = NONE
+ if(default_deconstruction_crowbar(tool))
+ return ITEM_INTERACT_SUCCESS
+
+/obj/machinery/power/portagrav/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
+ . = NONE
+ if(!istype(tool, /obj/item/stock_parts/power_store/cell))
+ return
+ if(!panel_open)
+ balloon_alert(user, "must open panel!")
+ return ITEM_INTERACT_BLOCKING
+ if(cell)
+ balloon_alert(user, "already has a cell!")
+ return ITEM_INTERACT_BLOCKING
+ if(!user.transferItemToLoc(tool, src))
+ return ITEM_INTERACT_FAILURE
+ cell = tool
+ return ITEM_INTERACT_SUCCESS
+
+/obj/machinery/power/portagrav/should_have_node()
+ return anchored
+
+/obj/machinery/power/portagrav/connect_to_network()
+ if(!anchored)
+ return FALSE
+ . = ..()
+
+/obj/machinery/power/portagrav/wrench_act(mob/living/user, obj/item/tool)
+ . = ..()
+ if(on)
+ balloon_alert(user, "turn off first!")
+ return
+ default_unfasten_wrench(user, tool)
+ if(anchored && wire_mode)
+ connect_to_network()
+ else
+ disconnect_from_network()
+ update_appearance()
+ return ITEM_INTERACT_SUCCESS
+
+/obj/machinery/power/portagrav/get_cell()
+ return cell
+
+/obj/machinery/power/portagrav/attack_hand(mob/living/carbon/user, list/modifiers)
+ . = ..()
+ if(!panel_open || isnull(cell) || !istype(user) || user.combat_mode)
+ return
+ if(user.put_in_hands(cell))
+ cell = null
+
+/obj/machinery/power/portagrav/attack_hand_secondary(mob/user, list/modifiers)
+ if(!can_interact(user))
+ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
+ toggle_on(user)
+ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
+
+/obj/machinery/power/portagrav/emag_act(mob/user, obj/item/card/emag/emag_card)
+ if(obj_flags & EMAGGED)
+ return FALSE
+ obj_flags |= EMAGGED
+ visible_message(span_warning("Sparks fly out of [src]!"))
+ if(user)
+ balloon_alert(user, "unsafe gravity unlocked")
+ user.log_message("emagged [src].", LOG_ATTACK)
+ playsound(src, SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
+ return TRUE
+
+/obj/machinery/power/portagrav/proc/toggle_on(mob/user)
+ if(on)
+ turn_off(user)
+ else
+ turn_on(user)
+
+/obj/machinery/power/portagrav/proc/turn_on(mob/user)
+ if(!anchored)
+ if(!isnull(user))
+ balloon_alert(user, "not anchored!")
+ return FALSE
+ if((!wire_mode && cell?.charge < draw_per_range * range) || (wire_mode && surplus() < draw_per_range * range))
+ if(!isnull(user))
+ balloon_alert(user, "not enough power!")
+ return FALSE
+ if(!isnull(user))
+ balloon_alert(user, "turned on")
+ on = TRUE
+ START_PROCESSING(SSmachines, src)
+ gravity_field = new(src, range = src.range, gravity = grav_strength)
+ update_appearance()
+
+/obj/machinery/power/portagrav/proc/turn_off(mob/user)
+ on = FALSE
+ if(!isnull(user))
+ balloon_alert(user, "turned off")
+ STOP_PROCESSING(SSmachines, src)
+ QDEL_NULL(gravity_field)
+ update_appearance()
+
+/obj/machinery/power/portagrav/process(seconds_per_tick)
+ if(!on || !anchored)
+ return PROCESS_KILL
+ if(wire_mode)
+ if(powernet && surplus() >= draw_per_range * range)
+ add_load(draw_per_range * range)
+ else
+ turn_off()
+ else
+ if(!cell?.use(draw_per_range * range))
+ turn_off()
+
+/obj/machinery/power/portagrav/proc/update_field()
+ if(isnull(gravity_field))
+ return
+ gravity_field.set_range(range)
+ gravity_field.gravity_value = grav_strength
+ gravity_field.recalculate_field(full_recalc = TRUE)
+
+/obj/machinery/power/portagrav/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "Portagrav", name)
+ ui.open()
+
+/obj/machinery/power/portagrav/ui_data(mob/user)
+ . = list()
+ if(!isnull(cell))
+ .["percentage"] = (cell.charge / cell.maxcharge) * 100
+ .["gravity"] = grav_strength
+ .["range"] = range
+ .["maxrange"] = max_range
+ .["on"] = on
+ .["wiremode"] = wire_mode
+ .["draw"] = display_power(draw_per_range * range)
+
+/obj/machinery/power/portagrav/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
+ . = ..()
+ if(.)
+ return
+ playsound(src, 'sound/machines/terminal_button07.ogg', 45, TRUE)
+ switch(action)
+ if("adjust_grav")
+ var/adjustment = text2num(params["adjustment"])
+ if(isnull(adjustment))
+ return
+ var/bonus = (obj_flags & EMAGGED) ? 2 : 0
+ // REPLACE 0 with NEGATIVE_GRAVITY ONCE NEGATIVE GRAVITY IS SOMETHING ACTUALLY FUNCTIONAL
+ var/result = clamp(grav_strength + adjustment, 0, GRAVITY_DAMAGE_THRESHOLD - 1 + bonus)
+ if(result == grav_strength)
+ return
+ grav_strength = result
+ update_field()
+ return TRUE
+ if("toggle_power")
+ toggle_on(usr)
+ return TRUE
+ if("toggle_wire")
+ wire_mode = !wire_mode
+ if(wire_mode && anchored)
+ connect_to_network()
+ else
+ disconnect_from_network()
+ return TRUE
+ if("adjust_range")
+ var/adjustment = text2num(params["adjustment"])
+ if(isnull(adjustment))
+ return
+ var/result = clamp(range + adjustment, 0, max_range)
+ if(result == range)
+ return
+ range = result
+ update_field()
+ return TRUE
+
+/obj/machinery/power/portagrav/anchored
+ anchored = TRUE
diff --git a/code/game/machinery/roulette_machine.dm b/code/game/machinery/roulette_machine.dm
index 2a8dc8bb49b22..bb43b7a46db9e 100644
--- a/code/game/machinery/roulette_machine.dm
+++ b/code/game/machinery/roulette_machine.dm
@@ -98,7 +98,7 @@
return data
-/obj/machinery/roulette/ui_act(action, params)
+/obj/machinery/roulette/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/game/machinery/satellite/satellite_control.dm b/code/game/machinery/satellite/satellite_control.dm
index c0875d9e26a6b..9983cc439e366 100644
--- a/code/game/machinery/satellite/satellite_control.dm
+++ b/code/game/machinery/satellite/satellite_control.dm
@@ -11,7 +11,7 @@
ui = new(user, src, "SatelliteControl", name)
ui.open()
-/obj/machinery/computer/sat_control/ui_act(action, params)
+/obj/machinery/computer/sat_control/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/game/machinery/scanner_gate.dm b/code/game/machinery/scanner_gate.dm
index fd99f3ccfb8a3..85d816543926b 100644
--- a/code/game/machinery/scanner_gate.dm
+++ b/code/game/machinery/scanner_gate.dm
@@ -331,7 +331,7 @@
data["contraband_enabled"] = !!n_spect
return data
-/obj/machinery/scanner_gate/ui_act(action, params)
+/obj/machinery/scanner_gate/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/game/machinery/sleepers.dm b/code/game/machinery/sleepers.dm
index 63291035e784f..9b843cd550612 100644
--- a/code/game/machinery/sleepers.dm
+++ b/code/game/machinery/sleepers.dm
@@ -237,7 +237,7 @@
return data
-/obj/machinery/sleeper/ui_act(action, params)
+/obj/machinery/sleeper/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
@@ -300,17 +300,21 @@
* Can be controlled from the inside and can be deconstructed.
*/
/obj/machinery/sleeper/syndie
+ name = "syndicate sleeper"
icon_state = "sleeper_s"
base_icon_state = "sleeper_s"
controls_inside = TRUE
deconstructable = TRUE
+ circuit = /obj/item/circuitboard/machine/sleeper/syndie
///Fully upgraded variant, the circuit using tier 4 parts.
/obj/machinery/sleeper/syndie/fullupgrade
+ name = "upgraded syndicate sleeper"
circuit = /obj/item/circuitboard/machine/sleeper/fullupgrade
///Fully upgraded, not deconstructable, while using the normal sprite.
/obj/machinery/sleeper/syndie/fullupgrade/nt
+ name = "\improper Nanotrasen sleeper"
icon_state = "sleeper"
base_icon_state = "sleeper"
deconstructable = FALSE
diff --git a/code/game/machinery/slotmachine.dm b/code/game/machinery/slotmachine.dm
index bb93b7d00f5b6..41aa0876169ed 100644
--- a/code/game/machinery/slotmachine.dm
+++ b/code/game/machinery/slotmachine.dm
@@ -109,7 +109,7 @@
else
if(!user.temporarilyRemoveItemFromInventory(inserted_coin))
return ITEM_INTERACT_BLOCKING
- balloon_alert(user, "coin insterted")
+ balloon_alert(user, "coin inserted")
balance += inserted_coin.value
qdel(inserted_coin)
return ITEM_INTERACT_SUCCESS
diff --git a/code/game/machinery/spaceheater.dm b/code/game/machinery/spaceheater.dm
index af6221d89219d..cbd5dbb84e37c 100644
--- a/code/game/machinery/spaceheater.dm
+++ b/code/game/machinery/spaceheater.dm
@@ -262,7 +262,7 @@
data["currentTemp"] = round(current_temperature - T0C, 1)
return data
-/obj/machinery/space_heater/ui_act(action, params)
+/obj/machinery/space_heater/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
@@ -387,7 +387,7 @@
.["beaker"] = beaker
.["currentTemp"] = beaker ? (round(beaker.reagents.chem_temp - T0C)) : "N/A"
-/obj/machinery/space_heater/improvised_chem_heater/ui_act(action, params)
+/obj/machinery/space_heater/improvised_chem_heater/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/game/machinery/stasis.dm b/code/game/machinery/stasis.dm
index 9ef3d8e3a99a9..bf33530b93e3e 100644
--- a/code/game/machinery/stasis.dm
+++ b/code/game/machinery/stasis.dm
@@ -9,6 +9,7 @@
obj_flags = BLOCKS_CONSTRUCTION
can_buckle = TRUE
buckle_lying = 90
+ buckle_dir = SOUTH
circuit = /obj/item/circuitboard/machine/stasis
fair_market_price = 10
payment_department = ACCOUNT_MED
@@ -22,6 +23,7 @@
/obj/machinery/stasis/Initialize(mapload)
. = ..()
AddElement(/datum/element/elevation, pixel_shift = 6)
+ update_buckle_vars(dir)
/obj/machinery/stasis/examine(mob/user)
. = ..()
@@ -57,6 +59,13 @@
thaw_them(L)
return ..()
+/obj/machinery/stasis/setDir(newdir)
+ . = ..()
+ update_buckle_vars(newdir)
+
+/obj/machinery/stasis/proc/update_buckle_vars(newdir)
+ buckle_lying = newdir & NORTHEAST ? 270 : 90
+
/obj/machinery/stasis/proc/stasis_running()
return stasis_enabled && is_operational
diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm
index 6b04b2c6f340d..3232dc524ab89 100644
--- a/code/game/machinery/suit_storage_unit.dm
+++ b/code/game/machinery/suit_storage_unit.dm
@@ -230,7 +230,7 @@
/obj/machinery/suit_storage_unit/update_overlays()
. = ..()
- //if things arent powered, these show anyways
+ //if things aren't powered, these show anyways
if(panel_open)
. += "[base_icon_state]_panel"
if(state_open)
@@ -793,7 +793,7 @@
*/
/obj/machinery/suit_storage_unit/default_deconstruction_screwdriver(mob/user, icon_state_open, icon_state_closed, obj/item/screwdriver)
if(screwdriver.tool_behaviour == TOOL_SCREWDRIVER && (uv || locked))
- to_chat(user, span_warning("You cant open the panel while its [locked ? "locked" : "decontaminating"]"))
+ to_chat(user, span_warning("You can't open the panel while its [locked ? "locked" : "decontaminating"]"))
return TRUE
return ..()
diff --git a/code/game/machinery/syndicatebomb.dm b/code/game/machinery/syndicatebomb.dm
index 3a7cc849acd30..0ac1f7ee44df8 100644
--- a/code/game/machinery/syndicatebomb.dm
+++ b/code/game/machinery/syndicatebomb.dm
@@ -621,7 +621,7 @@
balloon_alert(user, "set to [chosen_theme?.name || DIMENSION_CHOICE_RANDOM]")
/obj/item/bombcore/dimensional/proc/check_menu(mob/user)
- if(!user.is_holding(src) || user.incapacitated())
+ if(!user.is_holding(src) || user.incapacitated)
return FALSE
return TRUE
diff --git a/code/game/machinery/telecomms/broadcasting.dm b/code/game/machinery/telecomms/broadcasting.dm
index 2c31dcbd98955..06d390e5f2e27 100644
--- a/code/game/machinery/telecomms/broadcasting.dm
+++ b/code/game/machinery/telecomms/broadcasting.dm
@@ -155,7 +155,7 @@
if (TRANSMISSION_SUPERSPACE)
// Only radios which are independent
for(var/obj/item/radio/independent_radio in GLOB.all_radios["[frequency]"])
- if(independent_radio.independent && independent_radio.can_receive(frequency, signal_reaches_every_z_level))
+ if((independent_radio.special_channels & RADIO_SPECIAL_CENTCOM) && independent_radio.can_receive(frequency, signal_reaches_every_z_level))
radios += independent_radio
for(var/obj/item/radio/called_radio as anything in radios)
diff --git a/code/game/machinery/telecomms/computers/logbrowser.dm b/code/game/machinery/telecomms/computers/logbrowser.dm
index 25b5ddd212710..22a41a6ada66b 100644
--- a/code/game/machinery/telecomms/computers/logbrowser.dm
+++ b/code/game/machinery/telecomms/computers/logbrowser.dm
@@ -95,7 +95,7 @@
return data
-/obj/machinery/computer/telecomms/server/ui_act(action, params)
+/obj/machinery/computer/telecomms/server/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/game/machinery/telecomms/computers/message.dm b/code/game/machinery/telecomms/computers/message.dm
index a38f18231fb76..05186da8bc08c 100644
--- a/code/game/machinery/telecomms/computers/message.dm
+++ b/code/game/machinery/telecomms/computers/message.dm
@@ -117,7 +117,7 @@
data["requests"] = request_list
return data
-/obj/machinery/computer/message_monitor/ui_act(action, params)
+/obj/machinery/computer/message_monitor/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return .
diff --git a/code/game/machinery/telecomms/computers/telemonitor.dm b/code/game/machinery/telecomms/computers/telemonitor.dm
index abc2b7dbdbff4..e70c7f7de172a 100644
--- a/code/game/machinery/telecomms/computers/telemonitor.dm
+++ b/code/game/machinery/telecomms/computers/telemonitor.dm
@@ -81,7 +81,7 @@
return data
-/obj/machinery/computer/telecomms/monitor/ui_act(action, params)
+/obj/machinery/computer/telecomms/monitor/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/game/machinery/telecomms/machine_interactions.dm b/code/game/machinery/telecomms/machine_interactions.dm
index fb68631b76676..c92384aa4b6c1 100644
--- a/code/game/machinery/telecomms/machine_interactions.dm
+++ b/code/game/machinery/telecomms/machine_interactions.dm
@@ -82,7 +82,7 @@
return data
-/obj/machinery/telecomms/ui_act(action, params)
+/obj/machinery/telecomms/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/game/machinery/telecomms/machines/bus.dm b/code/game/machinery/telecomms/machines/bus.dm
index 15d20b3d1eb25..b56b4811083d3 100644
--- a/code/game/machinery/telecomms/machines/bus.dm
+++ b/code/game/machinery/telecomms/machines/bus.dm
@@ -60,8 +60,8 @@
/obj/machinery/telecomms/bus/preset_two
id = "Bus 2"
network = "tcommsat"
- freq_listening = list(FREQ_SUPPLY, FREQ_SERVICE)
- autolinkers = list("processor2", "supply", "service")
+ freq_listening = list(FREQ_SUPPLY, FREQ_SERVICE, FREQ_ENTERTAINMENT)
+ autolinkers = list("processor2", "supply", "service", "entertainment")
/obj/machinery/telecomms/bus/preset_three
id = "Bus 3"
diff --git a/code/game/machinery/telecomms/machines/hub.dm b/code/game/machinery/telecomms/machines/hub.dm
index 8136aed843514..6583cfe410577 100644
--- a/code/game/machinery/telecomms/machines/hub.dm
+++ b/code/game/machinery/telecomms/machines/hub.dm
@@ -70,6 +70,7 @@
"common",
"command",
"engineering",
+ "entertainment",
"security",
"receiverA",
"receiverB",
diff --git a/code/game/machinery/telecomms/machines/receiver.dm b/code/game/machinery/telecomms/machines/receiver.dm
index 8d6f8c85f43a1..875398fb8f245 100644
--- a/code/game/machinery/telecomms/machines/receiver.dm
+++ b/code/game/machinery/telecomms/machines/receiver.dm
@@ -57,7 +57,7 @@
id = "Receiver A"
network = "tcommsat"
autolinkers = list("receiverA") // link to relay
- freq_listening = list(FREQ_SCIENCE, FREQ_MEDICAL, FREQ_SUPPLY, FREQ_SERVICE)
+ freq_listening = list(FREQ_SCIENCE, FREQ_MEDICAL, FREQ_SUPPLY, FREQ_SERVICE, FREQ_ENTERTAINMENT)
//--PRESET RIGHT--//
diff --git a/code/game/machinery/telecomms/machines/server.dm b/code/game/machinery/telecomms/machines/server.dm
index 0c87a6101d182..1c7557b79def8 100644
--- a/code/game/machinery/telecomms/machines/server.dm
+++ b/code/game/machinery/telecomms/machines/server.dm
@@ -100,9 +100,9 @@
autolinkers = list("supply")
/obj/machinery/telecomms/server/presets/service
- id = "Service Server"
- freq_listening = list(FREQ_SERVICE)
- autolinkers = list("service")
+ id = "Service & Entertainment Server"
+ freq_listening = list(FREQ_SERVICE, FREQ_ENTERTAINMENT)
+ autolinkers = list("service", "entertainment")
/obj/machinery/telecomms/server/presets/common
id = "Common Server"
diff --git a/code/game/objects/buckling.dm b/code/game/objects/buckling.dm
index fd57b24da099f..f06ac5d920916 100644
--- a/code/game/objects/buckling.dm
+++ b/code/game/objects/buckling.dm
@@ -3,6 +3,8 @@
var/can_buckle = FALSE
/// Bed-like behaviour, forces mob.lying = buckle_lying if not set to [NO_BUCKLE_LYING].
var/buckle_lying = NO_BUCKLE_LYING
+ /// Bed-like behaviour, sets mob dir to buckle_dir if not set to [BUCKLE_MATCH_DIR]. If set to [BUCKLE_MATCH_DIR], makes mob dir match ours.
+ var/buckle_dir = BUCKLE_MATCH_DIR
/// Require people to be handcuffed before being able to buckle. eg: pipes
var/buckle_requires_restraints = FALSE
/// The mobs currently buckled to this atom
@@ -106,7 +108,10 @@
M.set_glide_size(glide_size)
M.Move(loc)
- M.setDir(dir)
+ if(buckle_dir == BUCKLE_MATCH_DIR)
+ M.setDir(dir)
+ else
+ M.setDir(buckle_dir)
//Something has unbuckled us in reaction to the above movement
if(!M.buckled)
@@ -261,7 +266,7 @@
*/
/atom/movable/proc/is_user_buckle_possible(mob/living/target, mob/user, check_loc = TRUE)
// Standard adjacency and other checks.
- if(!Adjacent(user) || !Adjacent(target) || !isturf(user.loc) || user.incapacitated() || target.anchored)
+ if(!Adjacent(user) || !Adjacent(target) || !isturf(user.loc) || user.incapacitated || target.anchored)
return FALSE
if(iscarbon(user))
diff --git a/code/game/objects/effects/anomalies/_anomalies.dm b/code/game/objects/effects/anomalies/_anomalies.dm
index ce9bab6a511cc..f249d22500c30 100644
--- a/code/game/objects/effects/anomalies/_anomalies.dm
+++ b/code/game/objects/effects/anomalies/_anomalies.dm
@@ -95,6 +95,15 @@
/obj/effect/anomaly/proc/anomalyNeutralize()
new /obj/effect/particle_effect/fluid/smoke/bad(loc)
+ SSblackbox.record_feedback(
+ "nested tally",
+ "anomaly_defused",
+ 1,
+ list(
+ "[type]",
+ immortal ? "immortal" : "[round((death_time - world.time) / 10)]ds time left",
+ )
+ )
if(drops_core)
if(isnull(anomaly_core))
diff --git a/code/game/objects/effects/anomalies/anomalies_bluespace.dm b/code/game/objects/effects/anomalies/anomalies_bluespace.dm
index 2ed19adb4f2c8..0a71427776eea 100644
--- a/code/game/objects/effects/anomalies/anomalies_bluespace.dm
+++ b/code/game/objects/effects/anomalies/anomalies_bluespace.dm
@@ -31,8 +31,16 @@
// Calculate new position (searches through beacons in world)
var/obj/item/beacon/chosen
var/list/possible = list()
- for(var/obj/item/beacon/W in GLOB.teleportbeacons)
- possible += W
+ for(var/obj/item/beacon/beacon in GLOB.teleportbeacons)
+ var/turf/turf = get_turf(beacon)
+ if(!turf)
+ continue
+ if(is_centcom_level(turf.z) || is_away_level(turf.z))
+ continue
+ var/area/area = get_area(turf)
+ if(!area || (area.area_flags & NOTELEPORT))
+ continue
+ possible += beacon
if(possible.len > 0)
chosen = pick(possible)
diff --git a/code/game/objects/effects/decals/crayon.dm b/code/game/objects/effects/decals/crayon.dm
index e42ee4d491fd2..eced2fb66f1ee 100644
--- a/code/game/objects/effects/decals/crayon.dm
+++ b/code/game/objects/effects/decals/crayon.dm
@@ -11,11 +11,14 @@
var/rotation = 0
var/paint_colour = COLOR_WHITE
-/obj/effect/decal/cleanable/crayon/Initialize(mapload, main, type, e_name, graf_rot, alt_icon = null)
+/obj/effect/decal/cleanable/crayon/Initialize(mapload, main, type, e_name, graf_rot, alt_icon = null, desc_override = null)
. = ..()
if(e_name)
name = e_name
- desc = "A [name] vandalizing the station."
+ if(desc_override)
+ desc = "[desc_override]"
+ else
+ desc = "A [name] vandalizing the station."
if(alt_icon)
icon = alt_icon
if(type)
diff --git a/code/game/objects/effects/decals/remains.dm b/code/game/objects/effects/decals/remains.dm
index 61f14f9d80ebb..55cd7cd98d089 100644
--- a/code/game/objects/effects/decals/remains.dm
+++ b/code/game/objects/effects/decals/remains.dm
@@ -18,18 +18,23 @@
return !istype(here_turf, /obj/structure/closet/crate/grave/filled) && ..()
/obj/effect/decal/remains/human/smokey
- desc = "They look like human remains. They have a strange, smokey aura about them..."
+ name = "remains of Charles Morlbaro"
+ desc = "I guess we figured out what happened to the guy who lives here. You'd best tread lightly around this..."
///Our proximity monitor, for detecting nearby looters.
var/datum/proximity_monitor/proximity_monitor
///The reagent we will release when our remains are disturbed.
var/datum/reagent/that_shit_that_killed_saddam
+ ///A cooldown for how frequently the gas is released when disturbed.
COOLDOWN_DECLARE(gas_cooldown)
+ ///The length of the aforementioned cooldown.
+ var/gas_cooldown_length = (20 SECONDS)
/obj/effect/decal/remains/human/smokey/Initialize(mapload)
. = ..()
- proximity_monitor = new(src, 0)
- that_shit_that_killed_saddam = get_random_reagent_id()
+ proximity_monitor = new(src, 1)
+ var/list/blocked_reagents = subtypesof(/datum/reagent/medicine) + subtypesof(/datum/reagent/consumable) //Boooooriiiiing
+ that_shit_that_killed_saddam = get_random_reagent_id(blacklist = blocked_reagents)
/obj/effect/decal/remains/human/smokey/HasProximity(atom/movable/tomb_raider)
if(!COOLDOWN_FINISHED(src, gas_cooldown))
@@ -37,10 +42,11 @@
if(iscarbon(tomb_raider))
var/mob/living/carbon/nearby_carbon = tomb_raider
- if (nearby_carbon.move_intent != MOVE_INTENT_WALK || prob(15))
+ if(nearby_carbon.move_intent != MOVE_INTENT_WALK || prob(5))
release_smoke(nearby_carbon)
- COOLDOWN_START(src, gas_cooldown, rand(20 SECONDS, 2 MINUTES))
+ COOLDOWN_START(src, gas_cooldown, gas_cooldown_length)
+///Releases a cloud of smoke based on the randomly generated reagent in Initialize().
/obj/effect/decal/remains/human/smokey/proc/release_smoke(mob/living/smoke_releaser)
visible_message(span_warning("[smoke_releaser] disturbs the [src], which releases a huge cloud of gas!"))
var/datum/effect_system/fluid_spread/smoke/chem/cigarette_puff = new()
@@ -49,6 +55,15 @@
cigarette_puff.set_up(range = 2, amount = DIAMOND_AREA(2), holder = src, location = get_turf(src), silent = TRUE)
cigarette_puff.start()
+///Subtype of smokey remains used for rare maintenance spawns.
+/obj/effect/decal/remains/human/smokey/maintenance
+ name = "smokey remains"
+ desc = "They look like human remains. They have a strange, smokey aura about them... You should tread lightly when walking near this."
+
+/obj/effect/decal/remains/human/smokey/maintenance/Initialize(mapload)
+ . = ..()
+ gas_cooldown_length = rand(4 MINUTES, 6 MINUTES)
+
/obj/effect/decal/remains/plasma
icon_state = "remainsplasma"
diff --git a/code/game/objects/effects/particles/gravity.dm b/code/game/objects/effects/particles/gravity.dm
new file mode 100644
index 0000000000000..0d74896e20a7b
--- /dev/null
+++ b/code/game/objects/effects/particles/gravity.dm
@@ -0,0 +1,44 @@
+/particles/grav_field_down
+ icon = 'icons/effects/particles/generic.dmi'
+ icon_state = "cross"
+ width = 100
+ height = 100
+ count = 5
+ spawning = 1
+ lifespan = 0.6 SECONDS
+ fade = 0.5 SECONDS
+ fadein = 0.2 SECONDS
+ position = generator(GEN_CIRCLE, 0, 16, UNIFORM_RAND)
+ gravity = list(0, -0.75)
+ color = "#FF0000"
+
+/particles/grav_field_down/strong
+ gravity = list(0, -1.75)
+
+/particles/grav_field_up
+ icon = 'icons/effects/particles/generic.dmi'
+ icon_state = "cross"
+ width = 100
+ height = 100
+ count = 5
+ spawning = 1
+ lifespan = 0.6 SECONDS
+ fade = 0.5 SECONDS
+ fadein = 0.2 SECONDS
+ position = generator(GEN_CIRCLE, 0, 16, UNIFORM_RAND)
+ gravity = list(0, 0.75)
+ color = "#0077ff"
+
+/particles/grav_field_float
+ icon = 'icons/effects/particles/generic.dmi'
+ icon_state = "cross"
+ width = 100
+ height = 100
+ count = 5
+ spawning = 1
+ lifespan = 0.6 SECONDS
+ fade = 0.5 SECONDS
+ fadein = 0.2 SECONDS
+ position = generator(GEN_CIRCLE, 0, 16, UNIFORM_RAND)
+ velocity = generator(GEN_VECTOR, list(2,0), list(-2,0), UNIFORM_RAND)
+ color = "#FFFF00"
diff --git a/code/game/objects/effects/phased_mob.dm b/code/game/objects/effects/phased_mob.dm
index b1df969b45c92..357e9683072c1 100644
--- a/code/game/objects/effects/phased_mob.dm
+++ b/code/game/objects/effects/phased_mob.dm
@@ -23,6 +23,7 @@
jaunter.forceMove(src)
if(ismob(jaunter))
var/mob/mob_jaunter = jaunter
+ RegisterSignal(mob_jaunter, COMSIG_MOB_STATCHANGE, PROC_REF(on_stat_change))
mob_jaunter.reset_perspective(src)
/obj/effect/dummy/phased_mob/Destroy()
@@ -55,6 +56,7 @@
/obj/effect/dummy/phased_mob/Exited(atom/movable/gone, direction)
. = ..()
if(gone == jaunter)
+ UnregisterSignal(jaunter, COMSIG_MOB_STATCHANGE)
SEND_SIGNAL(src, COMSIG_MOB_EJECTED_FROM_JAUNT, jaunter)
jaunter = null
@@ -98,3 +100,9 @@
newloc = can_z_move(direction, get_turf(src), newloc, ZMOVE_INCAPACITATED_CHECKS | ZMOVE_FEEDBACK | ZMOVE_ALLOW_ANCHORED, user)
return newloc
+
+/// Signal proc for [COMSIG_MOB_STATCHANGE], to throw us out of the jaunt if we lose consciousness.
+/obj/effect/dummy/phased_mob/proc/on_stat_change(mob/living/source, new_stat, old_stat)
+ SIGNAL_HANDLER
+ if(source == jaunter && source.stat != CONSCIOUS)
+ eject_jaunter()
diff --git a/code/game/objects/effects/spawners/message_in_a_bottle.dm b/code/game/objects/effects/spawners/message_in_a_bottle.dm
new file mode 100644
index 0000000000000..c4ac63ad0be22
--- /dev/null
+++ b/code/game/objects/effects/spawners/message_in_a_bottle.dm
@@ -0,0 +1,25 @@
+/obj/effect/spawner/message_in_a_bottle
+ name = "message in a bottle"
+ desc = "Sending out an SOS"
+ icon = 'icons/effects/random_spawners.dmi'
+ icon_state = "message_bottle"
+ var/probability = 100
+
+/obj/effect/spawner/message_in_a_bottle/Initialize(mapload)
+ . = ..()
+ if(!prob(probability))
+ return INITIALIZE_HINT_QDEL
+ if(!SSpersistence.initialized)
+ RegisterSignal(SSpersistence, COMSIG_SUBSYSTEM_POST_INITIALIZE, PROC_REF(on_persistence_init))
+ else
+ SSpersistence.load_message_bottle(loc)
+ return INITIALIZE_HINT_QDEL
+
+/obj/effect/spawner/message_in_a_bottle/proc/on_persistence_init(datum/source)
+ SIGNAL_HANDLER
+ UnregisterSignal(SSpersistence, COMSIG_SUBSYSTEM_POST_INITIALIZE)
+ SSpersistence.load_message_bottle(loc)
+ qdel(src)
+
+/obj/effect/spawner/message_in_a_bottle/low_prob
+ probability = 1.5
diff --git a/code/game/objects/effects/spawners/random/decoration.dm b/code/game/objects/effects/spawners/random/decoration.dm
index 6116d22873317..6d2cf3021ef38 100644
--- a/code/game/objects/effects/spawners/random/decoration.dm
+++ b/code/game/objects/effects/spawners/random/decoration.dm
@@ -114,6 +114,26 @@
/obj/item/flashlight/glowstick/pink,
)
+/obj/effect/spawner/random/decoration/glowstick/on
+ name = "random colored glowstick (on)"
+ icon_state = "glowstick"
+ loot = list(
+ /obj/item/flashlight/glowstick,
+ /obj/item/flashlight/glowstick/red,
+ /obj/item/flashlight/glowstick/blue,
+ /obj/item/flashlight/glowstick/cyan,
+ /obj/item/flashlight/glowstick/orange,
+ /obj/item/flashlight/glowstick/yellow,
+ /obj/item/flashlight/glowstick/pink,
+ )
+
+/obj/effect/spawner/random/decoration/glowstick/on/make_item(spawn_loc, type_path_to_make)
+ . = ..()
+
+ var/obj/item/flashlight/glowstick = .
+
+ glowstick.set_light_on(TRUE)
+
/obj/effect/spawner/random/decoration/paint
name = "paint spawner"
icon_state = "paint"
diff --git a/code/game/objects/effects/spawners/random/exotic.dm b/code/game/objects/effects/spawners/random/exotic.dm
index e802e30056f4f..cb43d6f06ae4f 100644
--- a/code/game/objects/effects/spawners/random/exotic.dm
+++ b/code/game/objects/effects/spawners/random/exotic.dm
@@ -16,8 +16,9 @@
name = "language book spawner"
icon_state = "book"
loot = list( // A single roundstart species language book.
- /obj/item/language_manual/roundstart_species = 100,
+ /obj/item/language_manual/roundstart_species = 96,
/obj/item/book/granter/sign_language = 10,
+ /obj/item/language_manual/piratespeak = 4,
/obj/item/language_manual/roundstart_species/five = 3,
/obj/item/language_manual/roundstart_species/unlimited = 1,
)
diff --git a/code/game/objects/effects/spawners/random/food_or_drink.dm b/code/game/objects/effects/spawners/random/food_or_drink.dm
index 192914b6e3db6..4ff47f08fe994 100644
--- a/code/game/objects/effects/spawners/random/food_or_drink.dm
+++ b/code/game/objects/effects/spawners/random/food_or_drink.dm
@@ -167,6 +167,7 @@
/obj/item/reagent_containers/cup/glass/bottle/lizardwine = 1,
/obj/item/reagent_containers/cup/glass/bottle/vodka/badminka = 1,
/obj/item/reagent_containers/cup/glass/bottle/trappist = 1,
+ /obj/item/reagent_containers/cup/glass/bottle/rum/aged = 1,
)
/obj/effect/spawner/random/food_or_drink/pizzaparty
diff --git a/code/game/objects/effects/spawners/random/structure.dm b/code/game/objects/effects/spawners/random/structure.dm
index 359c147eb4fb5..289a2aba27600 100644
--- a/code/game/objects/effects/spawners/random/structure.dm
+++ b/code/game/objects/effects/spawners/random/structure.dm
@@ -23,6 +23,7 @@
/obj/effect/spawner/random/trash/mess = 30,
/obj/item/kirbyplants/fern = 20,
/obj/structure/closet/crate/decorations = 15,
+ /obj/effect/decal/remains/human/smokey/maintenance = 7,
/obj/structure/destructible/cult/pants_altar = 1,
)
diff --git a/code/game/objects/effects/spawners/random/trash.dm b/code/game/objects/effects/spawners/random/trash.dm
index dfac8e4c0c814..9cf00c20ee3ec 100644
--- a/code/game/objects/effects/spawners/random/trash.dm
+++ b/code/game/objects/effects/spawners/random/trash.dm
@@ -89,7 +89,6 @@
/obj/item/trash/cnds = 1,
/obj/item/trash/syndi_cakes = 1,
/obj/item/trash/shrimp_chips = 1,
- /obj/item/trash/waffles = 1,
/obj/item/trash/tray = 1,
)
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 12adcf15c22f7..d8288801b90fb 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -39,6 +39,12 @@
///The config type to use for greyscaled belt overlays. Both this and greyscale_colors must be assigned to work.
var/greyscale_config_belt
+ /// Greyscale config used when generating digitigrade versions of the sprite.
+ var/digitigrade_greyscale_config_worn
+ /// Greyscale colors used when generating digitigrade versions of the sprite.
+ /// Optional - If not set it will default to normal greyscale colors, or approximate them if those are unset as well
+ var/digitigrade_greyscale_colors
+
/* !!!!!!!!!!!!!!! IMPORTANT !!!!!!!!!!!!!!
IF YOU ADD MORE ICON CRAP TO THIS
@@ -705,7 +711,7 @@
/obj/item/proc/on_equipped(mob/user, slot, initial = FALSE)
SHOULD_NOT_OVERRIDE(TRUE)
equipped(user, slot, initial)
- if(SEND_SIGNAL(src, COMSIG_ITEM_POST_EQUIPPED, user, slot) && COMPONENT_EQUIPPED_FAILED)
+ if(SEND_SIGNAL(src, COMSIG_ITEM_POST_EQUIPPED, user, slot) & COMPONENT_EQUIPPED_FAILED)
return FALSE
return TRUE
@@ -788,7 +794,7 @@
set category = "Object"
set name = "Pick up"
- if(usr.incapacitated() || !Adjacent(usr))
+ if(usr.incapacitated || !Adjacent(usr))
return
if(isliving(usr))
@@ -1075,7 +1081,7 @@
var/timedelay = usr.client.prefs.read_preference(/datum/preference/numeric/tooltip_delay) / 100
tip_timer = addtimer(CALLBACK(src, PROC_REF(openTip), location, control, params, usr), timedelay, TIMER_STOPPABLE)//timer takes delay in deciseconds, but the pref is in milliseconds. dividing by 100 converts it.
if(usr.client.prefs.read_preference(/datum/preference/toggle/item_outlines))
- if(istype(L) && L.incapacitated())
+ if(istype(L) && L.incapacitated)
apply_outline(COLOR_RED_GRAY) //if they're dead or handcuffed, let's show the outline as red to indicate that they can't interact with that right now
else
apply_outline() //if the player's alive and well we send the command with no color set, so it uses the theme's color
@@ -1312,7 +1318,7 @@
* Then, it checks tiny items.
* After all that, it returns TRUE if the item is set to be discovered. Otherwise, it returns FALSE.
*
- * This works similarily to /suicide_act: if you want an item to have a unique interaction, go to that item
+ * This works similarly to /suicide_act: if you want an item to have a unique interaction, go to that item
* and give it an /on_accidental_consumption proc override. For a simple example of this, check out the nuke disk.
*
* Arguments
@@ -1337,7 +1343,7 @@
return
source_item?.reagents?.add_reagent(/datum/reagent/blood, 2)
- else if(custom_materials?.len) //if we've got materials, lets see whats in it
+ else if(custom_materials?.len) //if we've got materials, let's see what's in it
// How many mats have we found? You can only be affected by two material datums by default
var/found_mats = 0
// How much of each material is in it? Used to determine if the glass should break
@@ -1456,8 +1462,8 @@
pickup_animation.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
var/direction = get_dir(source, target)
- var/to_x = target.base_pixel_x
- var/to_y = target.base_pixel_y
+ var/to_x = target.base_pixel_x + target.base_pixel_w
+ var/to_y = target.base_pixel_y + target.base_pixel_z
if(direction & NORTH)
to_y += 32
diff --git a/code/game/objects/items/AI_modules/hacked.dm b/code/game/objects/items/AI_modules/hacked.dm
index 81100d0ed157b..fafde17acb5f3 100644
--- a/code/game/objects/items/AI_modules/hacked.dm
+++ b/code/game/objects/items/AI_modules/hacked.dm
@@ -55,7 +55,7 @@
to_chat(sender, span_warning("You should use [src] on an AI upload console or the AI core itself."))
return
if(malf_candidate.mind?.has_antag_datum(/datum/antagonist/malf_ai)) //Already malf
- to_chat(sender, span_warning("Unknown error occured. Upload process aborted."))
+ to_chat(sender, span_warning("Unknown error occurred. Upload process aborted."))
return
var/datum/antagonist/malf_ai/infected/malf_datum = new (give_objectives = TRUE, new_boss = sender.mind)
diff --git a/code/game/objects/items/airlock_painter.dm b/code/game/objects/items/airlock_painter.dm
index 3365a24650a5b..3124ba9c39196 100644
--- a/code/game/objects/items/airlock_painter.dm
+++ b/code/game/objects/items/airlock_painter.dm
@@ -229,7 +229,7 @@
* Actually add current decal to the floor.
*
* Responsible for actually adding the element to the turf for maximum flexibility.area
- * Can be overriden for different decal behaviors.
+ * Can be overridden for different decal behaviors.
* Arguments:
* * target - The turf being painted to
*/
@@ -298,7 +298,7 @@
.["current_dir"] = stored_dir
.["current_custom_color"] = stored_custom_color
-/obj/item/airlock_painter/decal/ui_act(action, list/params)
+/obj/item/airlock_painter/decal/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/game/objects/items/bear_armor.dm b/code/game/objects/items/bear_armor.dm
index 8cfad42be15a6..140a3d295f11b 100644
--- a/code/game/objects/items/bear_armor.dm
+++ b/code/game/objects/items/bear_armor.dm
@@ -1,7 +1,7 @@
/obj/item/bear_armor
name = "pile of bear armor"
desc = "A scattered pile of various shaped armor pieces fitted for a bear, some duct tape, and a nail filer. Crude instructions \
- are written on the back of one of the plates in russian. This seems like an awful idea."
+ are written on the back of one of the plates in Russian. This seems like an awful idea."
icon = 'icons/obj/tools.dmi'
icon_state = "bear_armor_upgrade"
diff --git a/code/game/objects/items/body_egg.dm b/code/game/objects/items/body_egg.dm
index d244d8c55cc16..d8b48e0789b21 100644
--- a/code/game/objects/items/body_egg.dm
+++ b/code/game/objects/items/body_egg.dm
@@ -15,15 +15,14 @@
if(iscarbon(loc))
Insert(loc)
-/obj/item/organ/internal/body_egg/Insert(mob/living/carbon/egg_owner, special = FALSE, movement_flags = DELETE_IF_REPLACED)
+/obj/item/organ/internal/body_egg/mob_insert(mob/living/carbon/egg_owner, special = FALSE, movement_flags = DELETE_IF_REPLACED)
. = ..()
- if(!.)
- return
+
egg_owner.add_traits(list(TRAIT_XENO_HOST, TRAIT_XENO_IMMUNE), ORGAN_TRAIT)
egg_owner.med_hud_set_status()
INVOKE_ASYNC(src, PROC_REF(AddInfectionImages), egg_owner)
-/obj/item/organ/internal/body_egg/Remove(mob/living/carbon/egg_owner, special, movement_flags)
+/obj/item/organ/internal/body_egg/mob_remove(mob/living/carbon/egg_owner, special, movement_flags)
. = ..()
egg_owner.remove_traits(list(TRAIT_XENO_HOST, TRAIT_XENO_IMMUNE), ORGAN_TRAIT)
egg_owner.med_hud_set_status()
diff --git a/code/game/objects/items/bodybag.dm b/code/game/objects/items/bodybag.dm
index c949f977508f1..4adb8d28b8c8a 100644
--- a/code/game/objects/items/bodybag.dm
+++ b/code/game/objects/items/bodybag.dm
@@ -86,7 +86,7 @@
return item_bag
/obj/item/bodybag/bluespace/container_resist_act(mob/living/user)
- if(user.incapacitated())
+ if(user.incapacitated)
to_chat(user, span_warning("You can't get out while you're restrained like this!"))
return
user.changeNext_move(CLICK_CD_BREAKOUT)
@@ -97,7 +97,7 @@
return
// you are still in the bag? time to go unless you KO'd, honey!
// if they escape during this time and you rebag them the timer is still clocking down and does NOT reset so they can very easily get out.
- if(user.incapacitated())
+ if(user.incapacitated)
to_chat(loc, span_warning("The pressure subsides. It seems that they've stopped resisting..."))
return
loc.visible_message(span_warning("[user] suddenly appears in front of [loc]!"), span_userdanger("[user] breaks free of [src]!"))
diff --git a/code/game/objects/items/cardboard_cutouts.dm b/code/game/objects/items/cardboard_cutouts.dm
index d4508710a8547..b49991b132a4e 100644
--- a/code/game/objects/items/cardboard_cutouts.dm
+++ b/code/game/objects/items/cardboard_cutouts.dm
@@ -149,7 +149,7 @@
/obj/item/cardboard_cutout/proc/check_menu(mob/living/user, obj/item/toy/crayon/crayon)
if(!istype(user))
return FALSE
- if(user.incapacitated())
+ if(user.incapacitated)
return FALSE
if(pushed_over)
to_chat(user, span_warning("Right [src] first!"))
diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm
index 41731cdf31d8f..8490f30f1bb75 100644
--- a/code/game/objects/items/cards_ids.dm
+++ b/code/game/objects/items/cards_ids.dm
@@ -104,6 +104,11 @@
/// Boolean value. If TRUE, the [Intern] tag gets prepended to this ID card when the label is updated.
var/is_intern = FALSE
+ ///If true, the wearer will have bigger arrow when pointing at things. Passed down by trims.
+ var/big_pointer = FALSE
+ ///If set, the arrow will have a different color.
+ var/pointer_color
+
/datum/armor/card_id
fire = 100
acid = 100
@@ -144,6 +149,29 @@
QDEL_NULL(my_store)
return ..()
+/obj/item/card/id/equipped(mob/user, slot)
+ . = ..()
+ if(slot == ITEM_SLOT_ID)
+ RegisterSignal(user, COMSIG_MOVABLE_POINTED, PROC_REF(on_pointed))
+
+/obj/item/card/id/proc/on_pointed(mob/living/user, atom/pointed, obj/effect/temp_visual/point/point)
+ SIGNAL_HANDLER
+ if((!big_pointer && !pointer_color) || HAS_TRAIT(user, TRAIT_UNKNOWN))
+ return
+ if(point.icon_state != /obj/effect/temp_visual/point::icon_state) //it differs from the original icon_state already.
+ return
+ if(big_pointer)
+ point.icon_state = "arrow_large"
+ if(pointer_color)
+ point.icon_state = "[point.icon_state]_white"
+ point.color = pointer_color
+ var/mutable_appearance/highlight = mutable_appearance(point.icon, "[point.icon_state]_highlights", appearance_flags = RESET_COLOR)
+ point.add_overlay(highlight)
+
+/obj/item/card/id/dropped(mob/user)
+ UnregisterSignal(user, COMSIG_MOVABLE_POINTED)
+ return ..()
+
/obj/item/card/id/get_id_examine_strings(mob/user)
. = ..()
. += list("[icon2html(get_cached_flat_icon(), user, extra_classes = "bigicon")]")
@@ -1554,7 +1582,7 @@
return data
-/obj/item/card/id/advanced/chameleon/ui_act(action, list/params)
+/obj/item/card/id/advanced/chameleon/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
@@ -1859,7 +1887,7 @@
/obj/item/card/cardboard/proc/after_input_check(mob/living/user, obj/item/item, input, value)
if(!input || (value && input == value))
return FALSE
- if(QDELETED(user) || QDELETED(item) || QDELETED(src) || user.incapacitated() || !user.is_holding(item) || !user.CanReach(src) || !user.can_write(item))
+ if(QDELETED(user) || QDELETED(item) || QDELETED(src) || user.incapacitated || !user.is_holding(item) || !user.CanReach(src) || !user.can_write(item))
return FALSE
return TRUE
diff --git a/code/game/objects/items/chainsaw.dm b/code/game/objects/items/chainsaw.dm
index 68501057ebf42..5d5de16a4d12a 100644
--- a/code/game/objects/items/chainsaw.dm
+++ b/code/game/objects/items/chainsaw.dm
@@ -80,7 +80,7 @@
/**
* Handles adding components to the chainsaw. Added in Initialize()
*
- * Applies components to the chainsaw. Added as a seperate proc to allow for
+ * Applies components to the chainsaw. Added as a separate proc to allow for
* variance between subtypes
*/
/obj/item/chainsaw/proc/apply_components()
diff --git a/code/game/objects/items/chromosome.dm b/code/game/objects/items/chromosome.dm
index d7fd7b39544be..dcfc7930ebfe2 100644
--- a/code/game/objects/items/chromosome.dm
+++ b/code/game/objects/items/chromosome.dm
@@ -2,7 +2,7 @@
name = "blank chromosome"
icon = 'icons/obj/science/chromosomes.dmi'
icon_state = ""
- desc = "A tube holding chromosomic data."
+ desc = "A tube holding chromosomal data."
force = 0
w_class = WEIGHT_CLASS_SMALL
@@ -16,7 +16,7 @@
/obj/item/chromosome/proc/can_apply(datum/mutation/human/HM)
if(!HM || !(HM.can_chromosome == CHROMOSOME_NONE))
return FALSE
- if((stabilizer_coeff != 1) && (HM.stabilizer_coeff != -1)) //if the chromosome is 1, we dont change anything. If the mutation is -1, we cant change it. sorry
+ if((stabilizer_coeff != 1) && (HM.stabilizer_coeff != -1)) //if the chromosome is 1, we don't change anything. If the mutation is -1, we can't change it. sorry
return TRUE
if((synchronizer_coeff != 1) && (HM.synchronizer_coeff != -1))
return TRUE
diff --git a/code/game/objects/items/cigs_lighters.dm b/code/game/objects/items/cigs_lighters.dm
index fe1f6b7495bda..35f14640278e4 100644
--- a/code/game/objects/items/cigs_lighters.dm
+++ b/code/game/objects/items/cigs_lighters.dm
@@ -129,9 +129,10 @@ CIGARETTE PACKETS ARE IN FANCY.DM
//////////////////
//FINE SMOKABLES//
//////////////////
+
/obj/item/cigarette
name = "cigarette"
- desc = "A roll of tobacco and nicotine."
+ desc = "A roll of tobacco and nicotine. It is not food."
icon = 'icons/obj/cigarettes.dmi'
icon_state = "cigoff"
inhand_icon_state = "cigon" //gets overriden during intialize(), just have it for unit test sanity.
@@ -180,6 +181,8 @@ CIGARETTE PACKETS ARE IN FANCY.DM
VAR_PRIVATE/obj/effect/abstract/particle_holder/mob_smoke
/// How long the current mob has been smoking this cigarette
VAR_FINAL/how_long_have_we_been_smokin = 0 SECONDS
+ /// Which people ate cigarettes and how many
+ var/static/list/cigarette_eaters = list()
/obj/item/cigarette/Initialize(mapload)
. = ..()
@@ -194,12 +197,37 @@ CIGARETTE PACKETS ARE IN FANCY.DM
icon_state = icon_off
inhand_icon_state = inhand_icon_off
+ // "It is called a cigarette"
+ AddComponent(/datum/component/edible,\
+ initial_reagents = list_reagents,\
+ food_flags = null,\
+ foodtypes = JUNKFOOD,\
+ volume = 50,\
+ eat_time = 0 SECONDS,\
+ tastes = list("a never before experienced flavour.", "finally sitting down after standing your entire life"),\
+ eatverbs = list("taste"),\
+ bite_consumption = 50,\
+ junkiness = 0,\
+ reagent_purity = null,\
+ on_consume = CALLBACK(src, PROC_REF(on_consume)),\
+ show_examine = FALSE, \
+ )
+
/obj/item/cigarette/Destroy()
STOP_PROCESSING(SSobj, src)
QDEL_NULL(mob_smoke)
QDEL_NULL(cig_smoke)
return ..()
+/obj/item/cigarette/proc/on_consume(mob/living/eater, mob/living/feeder)
+ if(isnull(eater.client))
+ return
+ var/ckey = eater.client.ckey
+ // We must have more!
+ cigarette_eaters[ckey]++
+ if(cigarette_eaters[ckey] >= 500)
+ eater.client.give_award(/datum/award/achievement/misc/cigarettes)
+
/obj/item/cigarette/equipped(mob/equipee, slot)
. = ..()
if(!(slot & ITEM_SLOT_MASK))
@@ -216,7 +244,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
if(!QDELETED(src) && !QDELETED(dropee) && how_long_have_we_been_smokin >= 4 SECONDS && iscarbon(dropee) && iscarbon(loc))
var/mob/living/carbon/smoker = dropee
// This relies on the fact that dropped is called before slot is nulled
- if(src == smoker.wear_mask && !smoker.incapacitated())
+ if(src == smoker.wear_mask && !smoker.incapacitated)
long_exhale(smoker)
UnregisterSignal(dropee, list(COMSIG_HUMAN_FORCESAY, COMSIG_ATOM_DIR_CHANGE))
diff --git a/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm b/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm
index 64f4ee35f6076..80c71e2b85983 100644
--- a/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm
+++ b/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm
@@ -631,6 +631,7 @@
/obj/machinery/vending/coffee = "Solar's Best Hot Drinks",
/obj/machinery/vending/cola = "Robust Softdrinks",
/obj/machinery/vending/custom = "Custom Vendor",
+ /obj/machinery/vending/cytopro = "CytoPro",
/obj/machinery/vending/dinnerware = "Plasteel Chef's Dinnerware Vendor",
/obj/machinery/vending/drugs = "NanoDrug Plus",
/obj/machinery/vending/engineering = "Robco Tool Maker",
@@ -922,6 +923,9 @@
/obj/item/stack/cable_coil = 1,
/obj/item/stack/sheet/glass = 2)
+/obj/item/circuitboard/machine/sleeper/syndie
+ build_path = /obj/machinery/sleeper/syndie
+
/obj/item/circuitboard/machine/sleeper/fullupgrade
build_path = /obj/machinery/sleeper/syndie/fullupgrade
req_components = list(
@@ -1286,6 +1290,15 @@
/obj/item/stack/sheet/glass = 1)
needs_anchored = FALSE
+/obj/item/circuitboard/machine/hydroponics/fullupgrade
+ build_path = /obj/machinery/hydroponics/constructable/fullupgrade
+ specific_parts = TRUE
+ req_components = list(
+ /datum/stock_part/matter_bin/tier4 = 2,
+ /datum/stock_part/servo/tier4 = 1,
+ /obj/item/stack/sheet/glass = 1
+ )
+
/obj/item/circuitboard/machine/microwave
name = "Microwave"
greyscale_colors = CIRCUIT_COLOR_SERVICE
@@ -1372,6 +1385,10 @@
/datum/stock_part/capacitor = 1)
needs_anchored = FALSE
+/obj/item/circuitboard/machine/fishing_portal_generator/emagged
+ name = "Emagged Fishing Portal Generator"
+ build_path = /obj/machinery/fishing_portal_generator
+
//Supply
/obj/item/circuitboard/machine/ore_redemption
name = "Ore Redemption"
@@ -1681,3 +1698,20 @@
req_components = list(
/obj/item/pipe/trinary/flippable/filter = 1,
)
+
+/obj/item/circuitboard/machine/portagrav
+ name = "Portable Gravity Unit"
+ greyscale_colors = CIRCUIT_COLOR_ENGINEERING
+ build_path = /obj/machinery/power/portagrav
+ req_components = list(
+ /datum/stock_part/capacitor = 2,
+ /datum/stock_part/micro_laser = 2,
+ /obj/item/stack/sheet/glass = 1)
+
+/obj/item/circuitboard/machine/big_manipulator
+ name = "Big Manipulator"
+ greyscale_colors = CIRCUIT_COLOR_ENGINEERING
+ build_path = /obj/machinery/big_manipulator
+ req_components = list(
+ /datum/stock_part/servo = 1,
+ )
diff --git a/code/game/objects/items/clown_items.dm b/code/game/objects/items/clown_items.dm
index 32a81d1f75f9c..6565bcae44f5b 100644
--- a/code/game/objects/items/clown_items.dm
+++ b/code/game/objects/items/clown_items.dm
@@ -74,7 +74,7 @@
/obj/item/soap/nanotrasen/cyborg
/obj/item/soap/deluxe
- desc = "A deluxe Waffle Co. brand bar of soap. Smells of high-class luxury."
+ desc = "A deluxe Waffle Corporation brand bar of soap. Smells of high-class luxury."
grind_results = list(/datum/reagent/consumable/aloejuice = 10, /datum/reagent/lye = 10)
icon_state = "soapdeluxe"
inhand_icon_state = "soapdeluxe"
diff --git a/code/game/objects/items/cosmetics.dm b/code/game/objects/items/cosmetics.dm
index b16cf3a6ef61a..2aa0c927bedc0 100644
--- a/code/game/objects/items/cosmetics.dm
+++ b/code/game/objects/items/cosmetics.dm
@@ -8,6 +8,7 @@
desc = "A generic brand of lipstick."
icon = 'icons/obj/cosmetic.dmi'
icon_state = "lipstick"
+ base_icon_state = "lipstick"
inhand_icon_state = "lipstick"
w_class = WEIGHT_CLASS_TINY
interaction_flags_click = NEED_DEXTERITY|NEED_HANDS|ALLOW_RESTING
@@ -18,6 +19,8 @@
var/style = "lipstick"
/// A trait that's applied while someone has this lipstick applied, and is removed when the lipstick is removed
var/lipstick_trait
+ /// Can this lipstick spawn randomly
+ var/random_spawn = TRUE
/obj/item/lipstick/Initialize(mapload)
. = ..()
@@ -34,8 +37,8 @@
. += "Alt-click to change the style."
/obj/item/lipstick/update_icon_state()
- icon_state = "lipstick[open ? "_uncap" : null]"
- inhand_icon_state = "lipstick[open ? "open" : null]"
+ icon_state = "[base_icon_state][open ? "_uncap" : null]"
+ inhand_icon_state = "[base_icon_state][open ? "open" : null]"
return ..()
/obj/item/lipstick/update_overlays()
@@ -72,7 +75,7 @@
/obj/item/lipstick/proc/check_menu(mob/living/user)
if(!istype(user))
return FALSE
- if(user.incapacitated() || !user.is_holding(src))
+ if(user.incapacitated || !user.is_holding(src))
return FALSE
return TRUE
@@ -104,6 +107,16 @@
name = "\improper Kiss of Death"
desc = "An incredibly potent tube of lipstick made from the venom of the dreaded Yellow Spotted Space Lizard, as deadly as it is chic. Try not to smear it!"
lipstick_trait = TRAIT_KISS_OF_DEATH
+ random_spawn = FALSE
+
+/obj/item/lipstick/syndie
+ name = "syndie lipstick"
+ desc = "Syndicate branded lipstick with a killer dose of kisses. Observe safety regulations!"
+ icon_state = "slipstick"
+ base_icon_state = "slipstick"
+ lipstick_color = COLOR_SYNDIE_RED
+ lipstick_trait = TRAIT_SYNDIE_KISS
+ random_spawn = FALSE
/obj/item/lipstick/random
name = "lipstick"
@@ -116,7 +129,7 @@
if(!possible_colors)
possible_colors = list()
for(var/obj/item/lipstick/lipstick_path as anything in (typesof(/obj/item/lipstick) - src.type))
- if(!initial(lipstick_path.lipstick_color))
+ if(!initial(lipstick_path.lipstick_color) || !initial(lipstick_path.random_spawn))
continue
possible_colors[initial(lipstick_path.lipstick_color)] = initial(lipstick_path.name)
lipstick_color = pick(possible_colors)
@@ -189,7 +202,7 @@
/obj/item/razor/suicide_act(mob/living/carbon/user)
user.visible_message(span_suicide("[user] begins shaving [user.p_them()]self without the razor guard! It looks like [user.p_theyre()] trying to commit suicide!"))
shave(user, BODY_ZONE_PRECISE_MOUTH)
- shave(user, BODY_ZONE_HEAD)//doesnt need to be BODY_ZONE_HEAD specifically, but whatever
+ shave(user, BODY_ZONE_HEAD)//doesn't need to be BODY_ZONE_HEAD specifically, but whatever
return BRUTELOSS
/obj/item/razor/proc/shave(mob/living/carbon/human/skinhead, location = BODY_ZONE_PRECISE_MOUTH)
diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm
index a879571e2b0aa..9b4d17bbb9d64 100644
--- a/code/game/objects/items/crayons.dm
+++ b/code/game/objects/items/crayons.dm
@@ -372,7 +372,7 @@
.["selected_color"] = GLOB.pipe_color_name[paint_color] || paint_color
.["paint_colors"] = GLOB.pipe_paint_colors
-/obj/item/toy/crayon/ui_act(action, list/params)
+/obj/item/toy/crayon/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
@@ -458,6 +458,12 @@
if(RANDOM_ANY)
drawing = pick(all_drawables)
+ if(drawing in graffiti_large_h)
+ paint_mode = PAINT_LARGE_HORIZONTAL
+ text_buffer = ""
+ else
+ paint_mode = PAINT_NORMAL
+
var/istagger = HAS_TRAIT(user, TRAIT_TAGGER)
var/cost = all_drawables[drawing] || CRAYON_COST_DEFAULT
if(istype(target, /obj/item/canvas))
@@ -645,13 +651,38 @@
dye_color = DYE_BLACK
/obj/item/toy/crayon/white
- name = "white crayon"
+ name = "stick of chalk"
+ desc = "A stark-white stick of chalk."
icon_state = "crayonwhite"
paint_color = COLOR_WHITE
crayon_color = "white"
reagent_contents = list(/datum/reagent/consumable/nutriment = 0.5, /datum/reagent/colorful_reagent/powder/white/crayon = 1.5)
dye_color = DYE_WHITE
+/obj/item/toy/crayon/white/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
+ /// Wherein, we draw a chalk body outline vaguely around the dead or "dead" mob
+ if(!ishuman(interacting_with) || user.combat_mode)
+ return ..()
+
+ var/mob/living/carbon/human/pwned_human = interacting_with
+
+ if(!(pwned_human.stat == DEAD || HAS_TRAIT(pwned_human, TRAIT_FAKEDEATH)))
+ balloon_alert_to_viewers("FEEDING TIME")
+ return ..()
+
+ balloon_alert_to_viewers("drawing outline...")
+ if(!do_after(user, DRAW_TIME, target = pwned_human, max_interact_count = 4))
+ return NONE
+ if(!use_charges(user, 1))
+ return NONE
+
+ var/decal_rotation = GET_LYING_ANGLE(pwned_human) - 90
+ var/obj/effect/decal/cleanable/crayon/chalk_line = new(get_turf(pwned_human), paint_color, "body", "chalk outline", decal_rotation, null, "A vaguely [pwned_human] shaped outline of a body.")
+ to_chat(user, span_notice("You draw a chalk outline around [pwned_human]."))
+ chalk_line.pixel_y = (pwned_human.pixel_y + pwned_human.pixel_z) + rand(-2, 2)
+ chalk_line.pixel_x = (pwned_human.pixel_x + pwned_human.pixel_w) + rand(-1, 1)
+ return ITEM_INTERACT_SUCCESS
+
/obj/item/toy/crayon/mime
name = "mime crayon"
icon_state = "crayonmime"
@@ -796,7 +827,6 @@
return (isfloorturf(surface) || iswallturf(surface))
/obj/item/toy/crayon/spraycan/suicide_act(mob/living/user)
- var/mob/living/carbon/human/H = user
var/used = min(charges_left, 10)
if(is_capped || !actually_paints || !use_charges(user, 10, FALSE))
user.visible_message(span_suicide("[user] shakes up [src] with a rattle and lifts it to [user.p_their()] mouth, but nothing happens!"))
@@ -811,7 +841,7 @@
set_painting_tool_color(COLOR_SILVER)
update_appearance()
if(actually_paints)
- H.update_lips("spray_face", paint_color)
+ user.AddComponent(/datum/component/face_decal, "spray", EXTERNAL_ADJACENT, paint_color)
reagents.trans_to(user, used, volume_multiplier, transferred_by = user, methods = VAPOR)
return OXYLOSS
@@ -866,7 +896,7 @@
flash_color(carbon_target, flash_color=paint_color, flash_time=40)
if(ishuman(carbon_target) && actually_paints)
var/mob/living/carbon/human/human_target = carbon_target
- human_target.update_lips("spray_face", paint_color)
+ human_target.AddComponent(/datum/component/face_decal, "spray", EXTERNAL_ADJACENT, paint_color)
use_charges(user, 10, FALSE)
var/fraction = min(1, . / reagents.maximum_volume)
reagents.expose(carbon_target, VAPOR, fraction * volume_multiplier)
diff --git a/code/game/objects/items/debug_items.dm b/code/game/objects/items/debug_items.dm
index 071561d57a095..24f350f37907a 100644
--- a/code/game/objects/items/debug_items.dm
+++ b/code/game/objects/items/debug_items.dm
@@ -46,7 +46,7 @@
/obj/item/debug/omnitool/proc/check_menu(mob/user)
if(!istype(user))
return FALSE
- if(user.incapacitated() || !user.Adjacent(src))
+ if(user.incapacitated || !user.Adjacent(src))
return FALSE
return TRUE
diff --git a/code/game/objects/items/defib.dm b/code/game/objects/items/defib.dm
index 02934d1a03eaa..b1e01e5a6cebc 100644
--- a/code/game/objects/items/defib.dm
+++ b/code/game/objects/items/defib.dm
@@ -137,11 +137,12 @@
return ..()
/obj/item/defibrillator/mouse_drop_dragged(atom/over_object, mob/user, src_location, over_location, params)
- if(ismob(loc))
- var/mob/M = loc
- if(istype(over_object, /atom/movable/screen/inventory/hand))
- var/atom/movable/screen/inventory/hand/H = over_object
- M.putItemFromInventoryInHandIfPossible(src, H.held_index)
+ if(!ismob(loc))
+ return
+ var/mob/living_mob = loc
+ if(!living_mob.incapacitated && istype(over_object, /atom/movable/screen/inventory/hand))
+ var/atom/movable/screen/inventory/hand/hand = over_object
+ living_mob.putItemFromInventoryInHandIfPossible(src, hand.held_index)
/obj/item/defibrillator/screwdriver_act(mob/living/user, obj/item/tool)
if(!cell || !cell_removable)
diff --git a/code/game/objects/items/devices/broadcast_camera.dm b/code/game/objects/items/devices/broadcast_camera.dm
new file mode 100644
index 0000000000000..4f6e3f1f8f475
--- /dev/null
+++ b/code/game/objects/items/devices/broadcast_camera.dm
@@ -0,0 +1,90 @@
+// Unique broadcast camera given to the first Curator
+// Only one should exist ideally, if other types are created they must have different camera_networks
+// Broadcasts its surroundings to entertainment monitors and its audio to entertainment radio channel
+/obj/item/broadcast_camera
+ name = "broadcast camera"
+ desc = "A large camera that streams its live feed and audio to entertainment monitors across the station, allowing everyone to watch the broadcast."
+ desc_controls = "Right-click to change the broadcast name. Alt-click to toggle microphone."
+ icon = 'icons/obj/service/broadcast.dmi'
+ icon_state = "broadcast_cam0"
+ base_icon_state = "broadcast_cam"
+ lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi'
+ force = 8
+ throwforce = 12
+ w_class = WEIGHT_CLASS_NORMAL
+ obj_flags = INDESTRUCTIBLE | EMP_PROTECT_ALL // No fun police
+ slot_flags = NONE
+ light_system = OVERLAY_LIGHT
+ light_color = COLOR_SOFT_RED
+ light_range = 1
+ light_power = 0.3
+ light_on = FALSE
+ /// The name of the broadcast
+ var/broadcast_name = "Curator News"
+ /// The networks it broadcasts to, default is CAMERANET_NETWORK_CURATOR
+ var/list/camera_networks = list(CAMERANET_NETWORK_CURATOR)
+ /// The "virtual" security camera inside of the physical camera
+ var/obj/machinery/camera/internal_camera
+ /// The "virtual" radio inside of the the physical camera, a la microphone
+ var/obj/item/radio/entertainment/microphone/internal_radio
+
+/obj/item/broadcast_camera/Initialize(mapload)
+ . = ..()
+ AddComponent(/datum/component/two_handed, \
+ force_unwielded = 8, \
+ force_wielded = 12, \
+ icon_wielded = "[base_icon_state]1", \
+ wield_callback = CALLBACK(src, PROC_REF(on_wield)), \
+ unwield_callback = CALLBACK(src, PROC_REF(on_unwield)), \
+ )
+
+/obj/item/broadcast_camera/Destroy(force)
+ QDEL_NULL(internal_radio)
+ QDEL_NULL(internal_camera)
+
+ return ..()
+
+/obj/item/broadcast_camera/update_icon_state()
+ icon_state = "[base_icon_state]0"
+ return ..()
+
+/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)
+
+/obj/item/broadcast_camera/examine(mob/user)
+ . = ..()
+ . += span_notice("Broadcast name is [broadcast_name]")
+
+/// When wielding the camera
+/obj/item/broadcast_camera/proc/on_wield()
+ if(!iscarbon(loc))
+ return
+ /// 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.internal_light = FALSE
+ internal_camera.network = camera_networks
+ internal_camera.c_tag = "LIVE: [broadcast_name]"
+ start_broadcasting_network(camera_networks, "[broadcast_name] is now LIVE!")
+
+ // INTERNAL RADIO
+ internal_radio = new(src)
+
+ set_light_on(TRUE)
+ playsound(source = src, soundin = 'sound/machines/terminal_processing.ogg', vol = 20, vary = FALSE, ignore_walls = FALSE)
+ balloon_alert_to_viewers("live!")
+
+/// When unwielding the camera
+/obj/item/broadcast_camera/proc/on_unwield()
+ QDEL_NULL(internal_camera)
+ QDEL_NULL(internal_radio)
+
+ stop_broadcasting_network(camera_networks)
+
+ set_light_on(FALSE)
+ playsound(source = src, soundin = 'sound/machines/terminal_prompt_deny.ogg', vol = 20, vary = FALSE, ignore_walls = FALSE)
+ balloon_alert_to_viewers("offline")
diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm
index 968a2f11f4d4c..8db7652d5a07e 100644
--- a/code/game/objects/items/devices/flashlight.dm
+++ b/code/game/objects/items/devices/flashlight.dm
@@ -694,6 +694,9 @@
color = LIGHT_COLOR_GREEN
light_color = LIGHT_COLOR_GREEN
+/obj/item/flashlight/lantern/jade/on
+ start_on = TRUE
+
/obj/item/flashlight/slime
gender = PLURAL
name = "glowing slime extract"
diff --git a/code/game/objects/items/devices/laserpointer.dm b/code/game/objects/items/devices/laserpointer.dm
index 554db2beb5399..3fe16fdb3fd96 100644
--- a/code/game/objects/items/devices/laserpointer.dm
+++ b/code/game/objects/items/devices/laserpointer.dm
@@ -271,13 +271,13 @@
//catpeople: make any felinid near the target to face the target, chance for felinids to pounce at the light, stepping to the target
for(var/mob/living/carbon/human/target_felinid in view(1, targloc))
- if(!isfelinid(target_felinid) || target_felinid.stat == DEAD || target_felinid.is_blind() || target_felinid.incapacitated())
+ if(!isfelinid(target_felinid) || target_felinid.stat == DEAD || target_felinid.is_blind() || target_felinid.incapacitated)
continue
if(target_felinid.body_position == STANDING_UP)
target_felinid.setDir(get_dir(target_felinid, targloc)) // kitty always looks at the light
if(prob(effectchance * diode.rating))
target_felinid.visible_message(span_warning("[target_felinid] makes a grab for the light!"), span_userdanger("LIGHT!"))
- target_felinid.Move(targloc)
+ target_felinid.Move(targloc, get_dir(target_felinid, targloc))
log_combat(user, target_felinid, "moved with a laser pointer", src)
else
target_felinid.visible_message(span_notice("[target_felinid] looks briefly distracted by the light."), span_warning("You're briefly tempted by the shiny light..."))
diff --git a/code/game/objects/items/devices/lightreplacer.dm b/code/game/objects/items/devices/lightreplacer.dm
index 4039b412ebe78..13821a42de40f 100644
--- a/code/game/objects/items/devices/lightreplacer.dm
+++ b/code/game/objects/items/devices/lightreplacer.dm
@@ -208,7 +208,7 @@
for(var/obj/machinery/light/target in user.loc)
replace_light(target, user)
on_a_light = TRUE
- if(!on_a_light) //So we dont give a ballon alert when we just used replace_light
+ if(!on_a_light) //So we don't give a balloon alert when we just used replace_light
user.balloon_alert(user, "[uses] lights, [bulb_shards]/[BULB_SHARDS_REQUIRED] fragments")
/**
diff --git a/code/game/objects/items/devices/multitool.dm b/code/game/objects/items/devices/multitool.dm
index f6fb14c2f19ba..03ed7f927b0f7 100644
--- a/code/game/objects/items/devices/multitool.dm
+++ b/code/game/objects/items/devices/multitool.dm
@@ -59,7 +59,7 @@
/obj/item/multitool/suicide_act(mob/living/carbon/user)
user.visible_message(span_suicide("[user] puts the [src] to [user.p_their()] chest. It looks like [user.p_theyre()] trying to pulse [user.p_their()] heart off!"))
- return OXYLOSS//theres a reason it wasn't recommended by doctors
+ return OXYLOSS//there's a reason it wasn't recommended by doctors
/**
* Sets the multitool internal object buffer
@@ -142,7 +142,7 @@
if(distance < rangealert) //ai should be able to see us
detect_state = PROXIMITY_ON_SCREEN
break
- if(distance < rangewarning) //ai cant see us but is close
+ if(distance < rangewarning) //ai can't see us but is close
detect_state = PROXIMITY_NEAR
/datum/action/item_action/toggle_multitool
diff --git a/code/game/objects/items/devices/powersink.dm b/code/game/objects/items/devices/powersink.dm
index 1925737143e9d..364550f062aa7 100644
--- a/code/game/objects/items/devices/powersink.dm
+++ b/code/game/objects/items/devices/powersink.dm
@@ -2,9 +2,9 @@
#define CLAMPED_OFF 1
#define OPERATING 2
-#define FRACTION_TO_RELEASE 50
+#define FRACTION_TO_RELEASE 25
#define ALERT 90
-#define MINIMUM_HEAT 10000
+#define MINIMUM_HEAT 20000
// Powersink - used to drain station power
@@ -23,7 +23,7 @@
throw_speed = 1
throw_range = 2
custom_materials = list(/datum/material/iron=SMALL_MATERIAL_AMOUNT* 7.5)
- var/max_heat = 5e7 // Maximum contained heat before exploding. Not actual temperature.
+ var/max_heat = 100 * STANDARD_BATTERY_CHARGE // Maximum contained heat before exploding. Not actual temperature.
var/internal_heat = 0 // Contained heat, goes down every tick.
var/mode = DISCONNECTED // DISCONNECTED, CLAMPED_OFF, OPERATING
var/warning_given = FALSE //! Stop warning spam, only warn the admins/deadchat once that we are about to boom.
@@ -171,7 +171,7 @@
if(istype(terminal.master, /obj/machinery/power/apc))
var/obj/machinery/power/apc/apc = terminal.master
if(apc.operating && apc.cell)
- drained += 0.001 * apc.cell.use(0.05 * STANDARD_CELL_CHARGE, force = TRUE)
+ drained += 0.001 * apc.cell.use(0.1 * STANDARD_BATTERY_CHARGE, force = TRUE)
internal_heat += drained
/obj/item/powersink/process()
diff --git a/code/game/objects/items/devices/radio/electropack.dm b/code/game/objects/items/devices/radio/electropack.dm
index af19c6cd4f5da..b127a650e2d26 100644
--- a/code/game/objects/items/devices/radio/electropack.dm
+++ b/code/game/objects/items/devices/radio/electropack.dm
@@ -104,7 +104,7 @@
data["maxFrequency"] = MAX_FREE_FREQ
return data
-/obj/item/electropack/ui_act(action, params)
+/obj/item/electropack/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/game/objects/items/devices/radio/encryptionkey.dm b/code/game/objects/items/devices/radio/encryptionkey.dm
index 88c9251d5b2bc..2eab06806dd09 100644
--- a/code/game/objects/items/devices/radio/encryptionkey.dm
+++ b/code/game/objects/items/devices/radio/encryptionkey.dm
@@ -4,26 +4,22 @@
icon = 'icons/obj/devices/circuitry_n_data.dmi'
icon_state = "cypherkey_basic"
w_class = WEIGHT_CLASS_TINY
- /// Can this radio key access the binary radio channel?
- var/translate_binary = FALSE
- /// Decrypts Syndicate radio transmissions.
- var/syndie = FALSE
- /// If true, the radio can say/hear on the special CentCom channel.
- var/independent = FALSE
/// What channels does this encryption key grant to the parent headset.
var/list/channels = list()
+ /// Flags for which "special" radio networks should be accessible
+ var/special_channels = NONE
var/datum/language/translated_language
greyscale_config = /datum/greyscale_config/encryptionkey_basic
greyscale_colors = "#820a16#3758c4"
/obj/item/encryptionkey/examine(mob/user)
. = ..()
- if(LAZYLEN(channels) || translate_binary)
+ if(LAZYLEN(channels) || special_channels & RADIO_SPECIAL_BINARY)
var/list/examine_text_list = list()
for(var/i in channels)
examine_text_list += "[GLOB.channel_tokens[i]] - [LOWER_TEXT(i)]"
- if(translate_binary)
+ if(special_channels & RADIO_SPECIAL_BINARY)
examine_text_list += "[GLOB.channel_tokens[MODE_BINARY]] - [MODE_BINARY]"
. += span_notice("It can access the following channels; [jointext(examine_text_list, ", ")].")
@@ -34,14 +30,14 @@
name = "syndicate encryption key"
icon_state = "cypherkey_syndicate"
channels = list(RADIO_CHANNEL_SYNDICATE = 1)
- syndie = TRUE
+ special_channels = RADIO_SPECIAL_SYNDIE
greyscale_config = /datum/greyscale_config/encryptionkey_syndicate
greyscale_colors = "#171717#990000"
/obj/item/encryptionkey/binary
name = "binary translator key"
icon_state = "cypherkey_basic"
- translate_binary = TRUE
+ special_channels = RADIO_SPECIAL_BINARY
translated_language = /datum/language/machine
greyscale_config = /datum/greyscale_config/encryptionkey_basic
greyscale_colors = "#24a157#3758c4"
@@ -102,6 +98,13 @@
greyscale_config = /datum/greyscale_config/encryptionkey_service
greyscale_colors = "#ebebeb#3bca5a"
+/obj/item/encryptionkey/headset_srvent
+ name = "press radio encryption key"
+ icon_state = "cypherkey_service"
+ channels = list(RADIO_CHANNEL_SERVICE = 1, RADIO_CHANNEL_ENTERTAINMENT = 0)
+ greyscale_config = /datum/greyscale_config/encryptionkey_service
+ greyscale_colors = "#83eb8f#3bca5a"
+
/obj/item/encryptionkey/headset_com
name = "command radio encryption key"
icon_state = "cypherkey_cube"
@@ -182,7 +185,7 @@
/obj/item/encryptionkey/headset_cent
name = "\improper CentCom radio encryption key"
icon_state = "cypherkey_centcom"
- independent = TRUE
+ special_channels = RADIO_SPECIAL_CENTCOM
channels = list(RADIO_CHANNEL_CENTCOM = 1)
greyscale_config = /datum/greyscale_config/encryptionkey_centcom
greyscale_colors = "#24a157#dca01b"
@@ -197,6 +200,7 @@
RADIO_CHANNEL_SUPPLY = 1,
RADIO_CHANNEL_SERVICE = 1,
RADIO_CHANNEL_AI_PRIVATE = 1,
+ RADIO_CHANNEL_ENTERTAINMENT = 1,
)
/obj/item/encryptionkey/ai_with_binary
@@ -210,15 +214,16 @@
RADIO_CHANNEL_SUPPLY = 1,
RADIO_CHANNEL_SERVICE = 1,
RADIO_CHANNEL_AI_PRIVATE = 1,
+ RADIO_CHANNEL_ENTERTAINMENT = 1,
)
- translate_binary = TRUE
+ special_channels = RADIO_SPECIAL_BINARY
translated_language = /datum/language/machine
/obj/item/encryptionkey/ai/evil //ported from NT, this goes 'inside' the AI.
name = "syndicate binary encryption key"
icon_state = "cypherkey_syndicate"
channels = list(RADIO_CHANNEL_SYNDICATE = 1)
- syndie = TRUE
+ special_channels = RADIO_SPECIAL_SYNDIE
greyscale_config = /datum/greyscale_config/encryptionkey_syndicate
greyscale_colors = "#171717#990000"
diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm
index edf24b0d942d4..5673afc678a41 100644
--- a/code/game/objects/items/devices/radio/headset.dm
+++ b/code/game/objects/items/devices/radio/headset.dm
@@ -11,7 +11,8 @@ GLOBAL_LIST_INIT(channel_tokens, list(
RADIO_CHANNEL_SUPPLY = RADIO_TOKEN_SUPPLY,
RADIO_CHANNEL_SERVICE = RADIO_TOKEN_SERVICE,
MODE_BINARY = MODE_TOKEN_BINARY,
- RADIO_CHANNEL_AI_PRIVATE = RADIO_TOKEN_AI_PRIVATE
+ RADIO_CHANNEL_AI_PRIVATE = RADIO_TOKEN_AI_PRIVATE,
+ RADIO_CHANNEL_ENTERTAINMENT = RADIO_TOKEN_ENTERTAINMENT,
))
/obj/item/radio/headset
@@ -49,7 +50,7 @@ GLOBAL_LIST_INIT(channel_tokens, list(
if(item_flags & IN_INVENTORY && loc == user)
// construction of frequency description
var/list/avail_chans = list("Use [RADIO_KEY_COMMON] for the currently tuned frequency")
- if(translate_binary)
+ if(special_channels & RADIO_SPECIAL_BINARY)
avail_chans += "use [MODE_TOKEN_BINARY] for [MODE_BINARY]"
if(length(channels))
for(var/i in 1 to length(channels))
@@ -203,6 +204,13 @@ GLOBAL_LIST_INIT(channel_tokens, list(
worn_icon_state = "srv_headset"
keyslot = /obj/item/encryptionkey/headset_srvmed
+/obj/item/radio/headset/headset_srvent
+ name = "press headset"
+ desc = "A headset allowing the wearer to communicate with service and broadcast to entertainment channel."
+ icon_state = "srvent_headset"
+ worn_icon_state = "srv_headset"
+ keyslot = /obj/item/encryptionkey/headset_srvent
+
/obj/item/radio/headset/headset_com
name = "command radio headset"
desc = "A headset with a commanding channel."
@@ -430,12 +438,7 @@ GLOBAL_LIST_INIT(channel_tokens, list(
if(!(ch_name in src.channels))
LAZYSET(channels, ch_name, keyslot2.channels[ch_name])
- if(keyslot2.translate_binary)
- translate_binary = TRUE
- if(keyslot2.syndie)
- syndie = TRUE
- if(keyslot2.independent)
- independent = TRUE
+ special_channels |= keyslot2.special_channels
for(var/ch_name in channels)
secure_radio_connections[ch_name] = add_radio(src, GLOB.radiochannels[ch_name])
@@ -459,6 +462,8 @@ GLOBAL_LIST_INIT(channel_tokens, list(
grant_headset_languages(mob_loc)
/obj/item/radio/headset/click_alt(mob/living/user)
+ if(!istype(user) || !Adjacent(user) || user.incapacitated)
+ return CLICK_ACTION_BLOCKING
if (!command)
return CLICK_ACTION_BLOCKING
use_command = !use_command
diff --git a/code/game/objects/items/devices/radio/intercom.dm b/code/game/objects/items/devices/radio/intercom.dm
index 504f547b5cb78..7a9a85cc66675 100644
--- a/code/game/objects/items/devices/radio/intercom.dm
+++ b/code/game/objects/items/devices/radio/intercom.dm
@@ -118,7 +118,7 @@
return FALSE
if(freq == FREQ_SYNDICATE)
- if(!(syndie))
+ if(!(special_channels &= RADIO_SPECIAL_SYNDIE))
return FALSE//Prevents broadcast of messages over devices lacking the encryption
return TRUE
@@ -219,6 +219,19 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom, 27)
command = TRUE
icon_off = "intercom_command-p"
+/obj/item/radio/intercom/syndicate
+ name = "syndicate intercom"
+ desc = "Talk smack through this."
+ command = TRUE
+ special_channels = RADIO_SPECIAL_SYNDIE
+
+/obj/item/radio/intercom/syndicate/freerange
+ name = "syndicate wide-band intercom"
+ desc = "A custom-made Syndicate-issue intercom used to transmit on all Nanotrasen frequencies. Particularly expensive."
+ freerange = TRUE
+
MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom/prison, 27)
MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom/chapel, 27)
MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom/command, 27)
+MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom/syndicate, 27)
+MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom/syndicate/freerange, 27)
diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm
index 121f0bba965b3..2b7a9bad7602a 100644
--- a/code/game/objects/items/devices/radio/radio.dm
+++ b/code/game/objects/items/devices/radio/radio.dm
@@ -19,7 +19,7 @@
w_class = WEIGHT_CLASS_SMALL
custom_materials = list(/datum/material/iron=SMALL_MATERIAL_AMOUNT * 0.75, /datum/material/glass=SMALL_MATERIAL_AMOUNT * 0.25)
- ///if FALSE, broadcasting and listening dont matter and this radio shouldnt do anything
+ ///if FALSE, broadcasting and listening don't matter and this radio shouldn't do anything
VAR_PRIVATE/on = TRUE
///the "default" radio frequency this radio is set to, listens and transmits to this frequency by default. wont work if the channel is encrypted
VAR_PRIVATE/frequency = FREQ_COMMON
@@ -57,18 +57,16 @@
var/use_command = FALSE
/// If true, use_command can be toggled at will.
var/command = FALSE
+ /// Does it play radio noise?
+ var/radio_noise = TRUE
///makes anyone who is talking through this anonymous.
var/anonymize = FALSE
/// Encryption key handling
var/obj/item/encryptionkey/keyslot
- /// If true, can hear the special binary channel.
- var/translate_binary = FALSE
- /// If true, can say/hear on the special CentCom channel.
- var/independent = FALSE
- /// If true, hears all well-known channels automatically, and can say/hear on the Syndicate channel. Also protects from radio jammers.
- var/syndie = FALSE
+ /// Flags for which "special" radio networks should be accessible
+ var/special_channels = NONE
/// associative list of the encrypted radio channels this radio is currently set to listen/broadcast to, of the form: list(channel name = TRUE or FALSE)
var/list/channels
/// associative list of the encrypted radio channels this radio can listen/broadcast to, of the form: list(channel name = channel frequency)
@@ -81,7 +79,7 @@
/// overlay when mic is on
var/overlay_mic_idle = "m_idle"
- /// overlay when speaking a message (is displayed simultaniously with speaker_active)
+ /// overlay when speaking a message (is displayed simultaneously with speaker_active)
var/overlay_mic_active = "m_active"
/// When set to FALSE, will avoid calling update_icon() in set_broadcasting and co.
@@ -91,6 +89,11 @@
/// If TRUE, will set the icon in initializations.
VAR_PRIVATE/should_update_icon = FALSE
+ /// A very brief cooldown to prevent regular radio sounds from overlapping.
+ COOLDOWN_DECLARE(audio_cooldown)
+ /// A very brief cooldown to prevent "important" radio sounds from overlapping.
+ COOLDOWN_DECLARE(important_audio_cooldown)
+
/obj/item/radio/Initialize(mapload)
set_wires(new /datum/wires/radio(src))
secure_radio_connections = list()
@@ -104,7 +107,7 @@
perform_update_icon = FALSE
set_listening(listening)
set_broadcasting(broadcasting)
- set_frequency(sanitize_frequency(frequency, freerange, syndie))
+ set_frequency(sanitize_frequency(frequency, freerange, (special_channels & RADIO_SPECIAL_SYNDIE)))
set_on(on)
perform_update_icon = TRUE
@@ -149,23 +152,19 @@
if(!(channel_name in channels))
channels[channel_name] = keyslot.channels[channel_name]
- if(keyslot.translate_binary)
- translate_binary = TRUE
- if(keyslot.syndie)
- syndie = TRUE
- if(keyslot.independent)
- independent = TRUE
+ special_channels = keyslot.special_channels
for(var/channel_name in channels)
secure_radio_connections[channel_name] = add_radio(src, GLOB.radiochannels[channel_name])
+ if(!listening)
+ remove_radio_all(src)
+
// Used for cyborg override
/obj/item/radio/proc/resetChannels()
channels = list()
secure_radio_connections = list()
- translate_binary = FALSE
- syndie = FALSE
- independent = FALSE
+ special_channels = NONE
///goes through all radio channels we should be listening for and readds them to the global list
/obj/item/radio/proc/readd_listening_radio_channels()
@@ -177,7 +176,7 @@
/obj/item/radio/proc/make_syndie() // Turns normal radios into Syndicate radios!
qdel(keyslot)
keyslot = new /obj/item/encryptionkey/syndicate()
- syndie = TRUE
+ special_channels |= RADIO_SPECIAL_SYNDIE
recalculateChannels()
/obj/item/radio/interact(mob/user)
@@ -188,7 +187,7 @@
..()
//simple getters only because i NEED to enforce complex setter use for these vars for caching purposes but VAR_PROTECTED requires getter usage as well.
-//if another decorator is made that doesnt require getters feel free to nuke these and change these vars over to that
+//if another decorator is made that doesn't require getters feel free to nuke these and change these vars over to that
///simple getter for the on variable. necessary due to VAR_PROTECTED
/obj/item/radio/proc/is_on()
@@ -243,7 +242,7 @@
if(actual_setting)
should_be_broadcasting = broadcasting
- if(broadcasting && on) //we dont need hearing sensitivity if we arent broadcasting, because talk_into doesnt care about hearing
+ if(broadcasting && on) //we don't need hearing sensitivity if we aren't broadcasting, because talk_into doesn't care about hearing
become_hearing_sensitive(INNATE_TRAIT)
else if(!broadcasting)
lose_hearing_sensitivity(INNATE_TRAIT)
@@ -259,7 +258,7 @@
on = new_on
if(on)
- set_broadcasting(should_be_broadcasting)//set them to whatever theyre supposed to be
+ set_broadcasting(should_be_broadcasting)//set them to whatever they're supposed to be
set_listening(should_be_listening)
else
set_broadcasting(FALSE, actual_setting = FALSE)//fake set them to off
@@ -334,7 +333,7 @@
channel = null
// Nearby active jammers prevent the message from transmitting
- if(is_within_radio_jammer_range(src) && !syndie)
+ if(is_within_radio_jammer_range(src) && !(special_channels & RADIO_SPECIAL_SYNDIE))
return
// Determine the identity information which will be attached to the signal.
@@ -344,7 +343,7 @@
var/datum/signal/subspace/vocal/signal = new(src, freq, speaker, language, radio_message, spans, message_mods)
// Independent radios, on the CentCom frequency, reach all independent radios
- if (independent && (freq == FREQ_CENTCOM || freq == FREQ_CTF_RED || freq == FREQ_CTF_BLUE || freq == FREQ_CTF_GREEN || freq == FREQ_CTF_YELLOW))
+ if (special_channels & RADIO_SPECIAL_CENTCOM && (freq == FREQ_CENTCOM || freq == FREQ_CTF_RED || freq == FREQ_CTF_BLUE || freq == FREQ_CTF_GREEN || freq == FREQ_CTF_YELLOW))
signal.data["compression"] = 0
signal.transmission_method = TRANSMISSION_SUPERSPACE
signal.levels = list(0)
@@ -354,7 +353,7 @@
if(isliving(talking_movable))
var/mob/living/talking_living = talking_movable
- if(talking_living.client?.prefs.read_preference(/datum/preference/toggle/radio_noise))
+ if(radio_noise && !HAS_TRAIT(talking_living, TRAIT_DEAF) && talking_living.client?.prefs.read_preference(/datum/preference/toggle/radio_noise))
SEND_SOUND(talking_living, 'sound/misc/radio_talk.ogg')
// All radios make an attempt to use the subspace system first
@@ -397,12 +396,12 @@
if(message_mods[RADIO_EXTENSION] == MODE_L_HAND || message_mods[RADIO_EXTENSION] == MODE_R_HAND)
// try to avoid being heard double
if (loc == speaker && ismob(speaker))
- var/mob/M = speaker
- var/idx = M.get_held_index_of_item(src)
+ var/mob/mob_speaker = speaker
+ var/idx = mob_speaker.get_held_index_of_item(src)
// left hands are odd slots
if (idx && (idx % 2) == (message_mods[RADIO_EXTENSION] == MODE_L_HAND))
return
- talk_into(speaker, raw_message, , spans, language=message_language, message_mods=filtered_mods)
+ talk_into(speaker, raw_message, spans=spans, language=message_language, message_mods=filtered_mods)
/// Checks if this radio can receive on the given frequency.
/obj/item/radio/proc/can_receive(input_frequency, list/levels)
@@ -412,7 +411,7 @@
if(!position || !(position.z in levels))
return FALSE
- if (input_frequency == FREQ_SYNDICATE && !syndie)
+ if (input_frequency == FREQ_SYNDICATE && !(special_channels & RADIO_SPECIAL_SYNDIE))
return FALSE
// allow checks: are we listening on that frequency?
@@ -420,7 +419,7 @@
return TRUE
for(var/ch_name in channels)
if(channels[ch_name] & FREQ_LISTENING)
- if(GLOB.radiochannels[ch_name] == text2num(input_frequency) || syndie)
+ if(GLOB.radiochannels[ch_name] == text2num(input_frequency) || special_channels & RADIO_SPECIAL_SYNDIE)
return TRUE
return FALSE
@@ -432,12 +431,15 @@
return
var/mob/living/holder = loc
- if(!holder.client?.prefs.read_preference(/datum/preference/toggle/radio_noise))
+ if(!radio_noise || HAS_TRAIT(holder, TRAIT_DEAF) || !holder.client?.prefs.read_preference(/datum/preference/toggle/radio_noise))
return
var/list/spans = data["spans"]
- SEND_SOUND(holder, 'sound/misc/radio_receive.ogg')
- if(SPAN_COMMAND in spans)
+ if(COOLDOWN_FINISHED(src, audio_cooldown))
+ COOLDOWN_START(src, audio_cooldown, 0.5 SECONDS)
+ SEND_SOUND(holder, 'sound/misc/radio_receive.ogg')
+ if((SPAN_COMMAND in spans) && COOLDOWN_FINISHED(src, important_audio_cooldown))
+ COOLDOWN_START(src, important_audio_cooldown, 0.5 SECONDS)
SEND_SOUND(holder, 'sound/misc/radio_important.ogg')
/obj/item/radio/ui_state(mob/user)
@@ -488,7 +490,7 @@
tune = tune * 10
. = TRUE
if(.)
- set_frequency(sanitize_frequency(tune, freerange, syndie))
+ set_frequency(sanitize_frequency(tune, freerange, (special_channels & RADIO_SPECIAL_SYNDIE)))
if("listen")
set_listening(!listening)
. = TRUE
@@ -516,10 +518,6 @@
recalculateChannels()
. = TRUE
-/obj/item/radio/suicide_act(mob/living/user)
- user.visible_message(span_suicide("[user] starts bouncing [src] off [user.p_their()] head! It looks like [user.p_theyre()] trying to commit suicide!"))
- return BRUTELOSS
-
/obj/item/radio/examine(mob/user)
. = ..()
if (frequency && in_range(src, user))
@@ -538,6 +536,11 @@
if(listening && overlay_speaker_idle)
. += overlay_speaker_idle
+/obj/item/radio/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
+ if(user.combat_mode && tool.tool_behaviour == TOOL_SCREWDRIVER)
+ return screwdriver_act(user, tool)
+ return ..()
+
/obj/item/radio/screwdriver_act(mob/living/user, obj/item/tool)
add_fingerprint(user)
unscrewed = !unscrewed
@@ -591,7 +594,7 @@
channels[ch_name] = TRUE
/obj/item/radio/borg/syndicate
- syndie = TRUE
+ special_channels = RADIO_SPECIAL_SYNDIE
keyslot = /obj/item/encryptionkey/syndicate
/obj/item/radio/borg/syndicate/Initialize(mapload)
@@ -639,4 +642,60 @@
. = ..()
set_listening(FALSE)
+// RADIOS USED BY BROADCASTING
+/obj/item/radio/entertainment
+ desc = "You should not hold this."
+ canhear_range = 7
+ freerange = TRUE
+ freqlock = RADIO_FREQENCY_LOCKED
+ radio_noise = FALSE
+
+/obj/item/radio/entertainment/Initialize(mapload)
+ . = ..()
+ set_frequency(FREQ_ENTERTAINMENT)
+
+/obj/item/radio/entertainment/speakers // Used inside of the entertainment monitors, not to be used as a actual item
+ should_be_listening = TRUE
+ should_be_broadcasting = FALSE
+
+/obj/item/radio/entertainment/speakers/Initialize(mapload)
+ . = ..()
+ set_broadcasting(FALSE)
+ set_listening(TRUE)
+ wires?.cut(WIRE_TX)
+
+/obj/item/radio/entertainment/speakers/on_receive_message(list/data)
+ playsound(source = src, soundin = SFX_MUFFLED_SPEECH, vol = 60, extrarange = -4, vary = TRUE, ignore_walls = FALSE)
+
+ return ..()
+
+/obj/item/radio/entertainment/speakers/physical // Can be used as a physical item
+ name = "entertainment radio"
+ desc = "A portable one-way radio permamently tuned into entertainment frequency."
+ icon_state = "radio"
+ inhand_icon_state = "radio"
+ worn_icon_state = "radio"
+ overlay_speaker_idle = "radio_s_idle"
+ overlay_speaker_active = "radio_s_active"
+ overlay_mic_idle = "radio_m_idle"
+ overlay_mic_active = "radio_m_active"
+
+/obj/item/radio/entertainment/microphone // Used inside of a broadcast camera, not to be used as a actual item
+ should_be_listening = FALSE
+ should_be_broadcasting = TRUE
+
+/obj/item/radio/entertainment/microphone/Initialize(mapload)
+ . = ..()
+ set_broadcasting(TRUE)
+ set_listening(FALSE)
+ wires?.cut(WIRE_RX)
+
+/obj/item/radio/entertainment/microphone/physical // Can be used as a physical item
+ name = "microphone"
+ desc = "No comments."
+ icon = 'icons/obj/service/broadcast.dmi'
+ icon_state = "microphone"
+ inhand_icon_state = "microphone"
+ canhear_range = 3
+
#undef FREQ_LISTENING
diff --git a/code/game/objects/items/devices/scanners/health_analyzer.dm b/code/game/objects/items/devices/scanners/health_analyzer.dm
index bebafbdab83b7..26df57683aa26 100644
--- a/code/game/objects/items/devices/scanners/health_analyzer.dm
+++ b/code/game/objects/items/devices/scanners/health_analyzer.dm
@@ -132,7 +132,7 @@
* tochat - Whether to immediately post the result into the chat of the user, otherwise it will return the results.
*/
/proc/healthscan(mob/user, mob/living/target, mode = SCANNER_VERBOSE, advanced = FALSE, tochat = TRUE)
- if(user.incapacitated())
+ if(user.incapacitated)
return
// the final list of strings to render
@@ -409,7 +409,7 @@
return(jointext(render_list, ""))
/proc/chemscan(mob/living/user, mob/living/target)
- if(user.incapacitated())
+ if(user.incapacitated)
return
if(istype(target) && target.reagents)
@@ -495,7 +495,7 @@
/// Displays wounds with extended information on their status vs medscanners
/proc/woundscan(mob/user, mob/living/carbon/patient, obj/item/healthanalyzer/scanner, simple_scan = FALSE)
- if(!istype(patient) || user.incapacitated())
+ if(!istype(patient) || user.incapacitated)
return
var/render_list = ""
@@ -664,7 +664,7 @@
/// Checks the individual for any diseases that are visible to the scanner, and displays the diseases in the attacked to the attacker.
/proc/diseasescan(mob/user, mob/living/carbon/patient, obj/item/healthanalyzer/simple/scanner)
- if(!istype(patient) || user.incapacitated())
+ if(!istype(patient) || user.incapacitated)
return
var/list/render = list()
diff --git a/code/game/objects/items/devices/spyglasses.dm b/code/game/objects/items/devices/spyglasses.dm
index 58c18f87427df..8d70f3de29215 100644
--- a/code/game/objects/items/devices/spyglasses.dm
+++ b/code/game/objects/items/devices/spyglasses.dm
@@ -20,7 +20,7 @@
/obj/item/clothing/glasses/sunglasses/spy/proc/on_screen_clear(client/source, window)
SIGNAL_HANDLER
- linked_bug.cam_screen.hide_from(source.mob)
+ linked_bug.cam_screen.hide_from_client(source)
/obj/item/clothing/glasses/sunglasses/spy/equipped(mob/user, slot)
. = ..()
diff --git a/code/game/objects/items/devices/swapper.dm b/code/game/objects/items/devices/swapper.dm
index dee9198c93296..fc5a9d39f9742 100644
--- a/code/game/objects/items/devices/swapper.dm
+++ b/code/game/objects/items/devices/swapper.dm
@@ -97,7 +97,7 @@
return teleportable
/obj/item/swapper/proc/swap(mob/user)
- if(QDELETED(linked_swapper) || world.time < linked_swapper.cooldown)
+ if(QDELETED(linked_swapper) || isnull(linked_swapper.loc) || world.time < linked_swapper.cooldown)
return
var/atom/movable/A = get_teleportable_container()
diff --git a/code/game/objects/items/devices/taperecorder.dm b/code/game/objects/items/devices/taperecorder.dm
index d30f379197eea..b86489fae9ea7 100644
--- a/code/game/objects/items/devices/taperecorder.dm
+++ b/code/game/objects/items/devices/taperecorder.dm
@@ -122,7 +122,7 @@
/obj/item/taperecorder/proc/can_use(mob/user)
if(user && ismob(user))
- if(!user.incapacitated())
+ if(!user.incapacitated)
return TRUE
return FALSE
diff --git a/code/game/objects/items/devices/traitordevices.dm b/code/game/objects/items/devices/traitordevices.dm
index 0dc69cb9c8117..8327e185ea612 100644
--- a/code/game/objects/items/devices/traitordevices.dm
+++ b/code/game/objects/items/devices/traitordevices.dm
@@ -138,7 +138,7 @@ effective or pretty fucking useless.
data["cooldown"] = DisplayTimeText(get_cooldown())
return data
-/obj/item/healthanalyzer/rad_laser/ui_act(action, params)
+/obj/item/healthanalyzer/rad_laser/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/game/objects/items/devices/transfer_valve.dm b/code/game/objects/items/devices/transfer_valve.dm
index 598c16c9041a8..d17530c801085 100644
--- a/code/game/objects/items/devices/transfer_valve.dm
+++ b/code/game/objects/items/devices/transfer_valve.dm
@@ -291,7 +291,7 @@
data["valve"] = valve_open
return data
-/obj/item/transfer_valve/ui_act(action, params)
+/obj/item/transfer_valve/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/game/objects/items/dice.dm b/code/game/objects/items/dice.dm
index f32b2ee30ec21..64ce9803657bb 100644
--- a/code/game/objects/items/dice.dm
+++ b/code/game/objects/items/dice.dm
@@ -181,7 +181,7 @@
name = "knucklebones rules"
default_raw_text = "How to play knucklebones
\
\
-
- {clientName}
+
+ {show_imprint ? login.IDName : 'Unknown'}
+
On the back, DO NOT GIVE TO THE CLOWN! is printed in large lettering."
+ icon = 'icons/obj/toys/stickers.dmi'
+ icon_state = "stickerpack"
+ illustration = null
+ w_class = WEIGHT_CLASS_TINY
+ var/static/list/pack_labels = list(
+ "smile",
+ "frown",
+ "heart",
+ "silentman",
+ "tider",
+ "star",
+ )
+
+/obj/item/storage/box/stickers/Initialize(mapload)
+ . = ..()
+ atom_storage.max_slots = 8
+ atom_storage.set_holdable(list(/obj/item/sticker))
+ atom_storage.max_specific_storage = WEIGHT_CLASS_TINY
+ if(isnull(illustration))
+ illustration = pick(pack_labels)
+ update_appearance()
/obj/item/storage/box/stickers/proc/generate_non_contraband_stickers_list()
var/list/allowed_stickers = list()
for(var/obj/item/sticker/sticker_type as anything in subtypesof(/obj/item/sticker))
- if(!sticker_type::contraband)
+ if(!sticker_type::exclude_from_random)
allowed_stickers += sticker_type
return allowed_stickers
@@ -247,8 +268,9 @@
new type(src)
/obj/item/storage/box/stickers/googly
- name = "box of googly eye stickers"
+ name = "googly eye sticker pack"
desc = "Turn anything and everything into something vaguely alive!"
+ illustration = "googly-alt"
/obj/item/storage/box/stickers/googly/PopulateContents()
for(var/i in 1 to 6)
diff --git a/code/game/objects/items/storage/holsters.dm b/code/game/objects/items/storage/holsters.dm
index f8dee3afdc7f4..cc8a790c8ef34 100644
--- a/code/game/objects/items/storage/holsters.dm
+++ b/code/game/objects/items/storage/holsters.dm
@@ -113,8 +113,8 @@
/obj/item/storage/belt/holster/detective/full/PopulateContents()
generate_items_inside(list(
- /obj/item/gun/ballistic/revolver/c38/detective = 1,
/obj/item/ammo_box/c38 = 2,
+ /obj/item/gun/ballistic/revolver/c38/detective = 1,
), src)
/obj/item/storage/belt/holster/detective/full/ert
@@ -126,8 +126,8 @@
/obj/item/storage/belt/holster/detective/full/ert/PopulateContents()
generate_items_inside(list(
- /obj/item/gun/ballistic/automatic/pistol/m1911 = 1,
/obj/item/ammo_box/magazine/m45 = 2,
+ /obj/item/gun/ballistic/automatic/pistol/m1911 = 1,
),src)
/obj/item/storage/belt/holster/chameleon
@@ -197,8 +197,8 @@
/obj/item/storage/belt/holster/nukie/cowboy/full/PopulateContents()
generate_items_inside(list(
- /obj/item/gun/ballistic/revolver/syndicate/cowboy/nuclear = 1,
/obj/item/ammo_box/a357 = 2,
+ /obj/item/gun/ballistic/revolver/syndicate/cowboy/nuclear = 1,
), src)
diff --git a/code/game/objects/items/storage/medkit.dm b/code/game/objects/items/storage/medkit.dm
index bee7fdd524f3d..368ef9c0b406a 100644
--- a/code/game/objects/items/storage/medkit.dm
+++ b/code/game/objects/items/storage/medkit.dm
@@ -84,6 +84,7 @@
atom_storage.max_specific_storage = WEIGHT_CLASS_SMALL
atom_storage.open_sound = 'sound/items/medkit_open.ogg'
atom_storage.open_sound_vary = TRUE
+ atom_storage.rustle_sound = 'sound/items/medkit_rustle.ogg'
/obj/item/storage/medkit/regular
icon_state = "medkit"
diff --git a/code/game/objects/items/storage/toolbox.dm b/code/game/objects/items/storage/toolbox.dm
index 905f2e40f47a7..d2bb90e69e445 100644
--- a/code/game/objects/items/storage/toolbox.dm
+++ b/code/game/objects/items/storage/toolbox.dm
@@ -33,7 +33,8 @@
if(prob(1))
latches = "triple_latch"
update_appearance()
-
+ atom_storage.open_sound = 'sound/items/toolbox_open.ogg'
+ atom_storage.rustle_sound = 'sound/items/toolbox_rustle.ogg'
AddElement(/datum/element/falling_hazard, damage = force, wound_bonus = wound_bonus, hardhat_safety = TRUE, crushes = FALSE, impact_sound = hitsound)
/obj/item/storage/toolbox/update_overlays()
diff --git a/code/game/objects/items/storage/uplink_kits.dm b/code/game/objects/items/storage/uplink_kits.dm
index eacd0b4b630d0..05b8a5a0e8ab0 100644
--- a/code/game/objects/items/storage/uplink_kits.dm
+++ b/code/game/objects/items/storage/uplink_kits.dm
@@ -346,6 +346,7 @@
/obj/item/storage/box/syndie_kit/rebarxbowsyndie/PopulateContents()
new /obj/item/book/granter/crafting_recipe/dusting/rebarxbowsyndie_ammo(src)
new /obj/item/gun/ballistic/rifle/rebarxbow/syndie(src)
+ new /obj/item/storage/bag/rebar_quiver/syndicate(src)
/obj/item/storage/box/syndie_kit/origami_bundle
name = "origami kit"
@@ -683,14 +684,7 @@
group.register(i)
desc += " The implants are registered to the \"[group.name]\" group."
-/obj/item/storage/box/syndie_kit/stickers
- name = "sticker kit"
-
-/obj/item/storage/box/syndie_kit/stickers/Initialize(mapload)
- . = ..()
- atom_storage.max_slots = 8
-
-/obj/item/storage/box/syndie_kit/stickers/PopulateContents()
+/obj/item/storage/box/stickers/syndie_kit/PopulateContents()
var/list/types = subtypesof(/obj/item/sticker/syndicate)
for(var/i in 1 to atom_storage.max_slots)
diff --git a/code/game/objects/items/syndie_spraycan.dm b/code/game/objects/items/syndie_spraycan.dm
index 1b7e0d9c4024a..fb6192c6e3990 100644
--- a/code/game/objects/items/syndie_spraycan.dm
+++ b/code/game/objects/items/syndie_spraycan.dm
@@ -143,7 +143,7 @@
user.visible_message(span_suicide("[user] shakes up [src] with a rattle and lifts it to [user.p_their()] mouth, spraying paint across [user.p_their()] teeth!"))
user.say("WITNESS ME!!", forced="spraycan suicide")
playsound(src, 'sound/effects/spray.ogg', 5, TRUE, 5)
- suicider.update_lips("spray_face", paint_color)
+ suicider.AddComponent(/datum/component/face_decal, "spray", EXTERNAL_ADJACENT, paint_color)
return OXYLOSS
/obj/effect/decal/cleanable/traitor_rune
diff --git a/code/game/objects/items/tanks/jetpack.dm b/code/game/objects/items/tanks/jetpack.dm
index cd5a9a1841ead..a7a577c77cf16 100644
--- a/code/game/objects/items/tanks/jetpack.dm
+++ b/code/game/objects/items/tanks/jetpack.dm
@@ -79,7 +79,7 @@
toggle_internals(user)
/obj/item/tank/jetpack/proc/cycle(mob/user)
- if(user.incapacitated())
+ if(user.incapacitated)
return
if(!on)
diff --git a/code/game/objects/items/tanks/tanks.dm b/code/game/objects/items/tanks/tanks.dm
index d89794f420917..9c7138e00dee0 100644
--- a/code/game/objects/items/tanks/tanks.dm
+++ b/code/game/objects/items/tanks/tanks.dm
@@ -256,7 +256,7 @@
if(istype(carbon_user) && (carbon_user.external == src || carbon_user.internal == src))
.["connected"] = TRUE
-/obj/item/tank/ui_act(action, params)
+/obj/item/tank/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/game/objects/items/tanks/watertank.dm b/code/game/objects/items/tanks/watertank.dm
index 8094a9a21c863..15db2a5d3edf2 100644
--- a/code/game/objects/items/tanks/watertank.dm
+++ b/code/game/objects/items/tanks/watertank.dm
@@ -47,7 +47,7 @@
if(user.get_item_by_slot(user.getBackSlot()) != src)
to_chat(user, span_warning("The watertank must be worn properly to use!"))
return
- if(user.incapacitated())
+ if(user.incapacitated)
return
if(QDELETED(noz))
diff --git a/code/game/objects/items/tcg/tcg.dm b/code/game/objects/items/tcg/tcg.dm
index fc2eeba82ff72..23204b4809ff8 100644
--- a/code/game/objects/items/tcg/tcg.dm
+++ b/code/game/objects/items/tcg/tcg.dm
@@ -151,7 +151,7 @@ GLOBAL_LIST_EMPTY(tcgcard_radial_choices)
/obj/item/tcgcard/proc/check_menu(mob/living/user)
if(!istype(user))
return FALSE
- if(user.incapacitated() || !user.Adjacent(src))
+ if(user.incapacitated || !user.Adjacent(src))
return FALSE
return TRUE
@@ -249,7 +249,7 @@ GLOBAL_LIST_EMPTY(tcgcard_radial_choices)
/obj/item/tcgcard_deck/proc/check_menu(mob/living/user)
if(!istype(user))
return FALSE
- if(user.incapacitated() || !user.Adjacent(src))
+ if(user.incapacitated || !user.Adjacent(src))
return FALSE
return TRUE
diff --git a/code/game/objects/items/tcg/tcg_machines.dm b/code/game/objects/items/tcg/tcg_machines.dm
index 78854afdd5b39..77b6891e4c17a 100644
--- a/code/game/objects/items/tcg/tcg_machines.dm
+++ b/code/game/objects/items/tcg/tcg_machines.dm
@@ -105,7 +105,7 @@ GLOBAL_LIST_EMPTY(tcgcard_machine_radial_choices)
/obj/machinery/trading_card_holder/proc/check_menu(mob/living/user)
if(!istype(user))
return FALSE
- if(user.incapacitated() || !user.Adjacent(src))
+ if(user.incapacitated || !user.Adjacent(src))
return FALSE
return TRUE
@@ -356,7 +356,7 @@ GLOBAL_LIST_EMPTY(tcgcard_mana_bar_radial_choices)
/obj/machinery/trading_card_button/proc/check_menu(mob/living/user)
if(!istype(user))
return FALSE
- if(user.incapacitated() || !user.Adjacent(src))
+ if(user.incapacitated || !user.Adjacent(src))
return FALSE
return TRUE
diff --git a/code/game/objects/items/teleportation.dm b/code/game/objects/items/teleportation.dm
index 04f5a0688db82..6fa7e8d23b340 100644
--- a/code/game/objects/items/teleportation.dm
+++ b/code/game/objects/items/teleportation.dm
@@ -190,7 +190,7 @@
var/teleport_location_key = tgui_input_list(user, "Teleporter to lock on", "Hand Teleporter", sort_list(locations))
if (isnull(teleport_location_key))
return
- if(user.get_active_held_item() != src || user.incapacitated())
+ if(user.get_active_held_item() != src || user.incapacitated)
return
// Not always a datum, but needed for IS_WEAKREF_OF to cast properly.
diff --git a/code/game/objects/items/tools/weldingtool.dm b/code/game/objects/items/tools/weldingtool.dm
index fb40a70cbeea0..143b8eab174e6 100644
--- a/code/game/objects/items/tools/weldingtool.dm
+++ b/code/game/objects/items/tools/weldingtool.dm
@@ -153,8 +153,9 @@
if(isnull(affecting) || !IS_ROBOTIC_LIMB(affecting))
return NONE
- if (!affecting.get_damage())
- return
+ if (!affecting.brute_dam)
+ balloon_alert(user, "limb not damaged")
+ return ITEM_INTERACT_BLOCKING
user.visible_message(span_notice("[user] starts to fix some of the dents on [attacked_humanoid == user ? user.p_their() : "[attacked_humanoid]'s"] [affecting.name]."),
span_notice("You start fixing some of the dents on [attacked_humanoid == user ? "your" : "[attacked_humanoid]'s"] [affecting.name]."))
diff --git a/code/game/objects/items/toy_mechs.dm b/code/game/objects/items/toy_mechs.dm
index 1b3367032c190..d08deec62e316 100644
--- a/code/game/objects/items/toy_mechs.dm
+++ b/code/game/objects/items/toy_mechs.dm
@@ -96,7 +96,7 @@
return FALSE
//dead men tell no tales, incapacitated men fight no fights
- if(attacker_controller.incapacitated())
+ if(attacker_controller.incapacitated)
return FALSE
//if the attacker_controller isn't next to the attacking toy (and doesn't have telekinesis), the battle ends
if(!in_range(attacker, attacker_controller) && !(attacker_controller.dna.check_mutation(/datum/mutation/human/telekinesis)))
@@ -106,7 +106,7 @@
//if it's PVP and the opponent is not next to the defending(src) toy (and doesn't have telekinesis), the battle ends
if(opponent)
- if(opponent.incapacitated())
+ if(opponent.incapacitated)
return FALSE
if(!in_range(src, opponent) && !(opponent.dna.check_mutation(/datum/mutation/human/telekinesis)))
opponent.visible_message(span_notice("[opponent.name] separates from [src], ending the battle."), \
diff --git a/code/game/objects/items/trash.dm b/code/game/objects/items/trash.dm
index ff540932f31b7..82636c0ee8514 100644
--- a/code/game/objects/items/trash.dm
+++ b/code/game/objects/items/trash.dm
@@ -85,10 +85,6 @@
desc = "In the Mothic Fleet every individual wrapper is carefully recycled and repurposed into fresh material. Over here they are more commonly dropped directly onto the floor."
icon_state = "moth_ration"
-/obj/item/trash/waffles
- name = "waffles tray"
- icon_state = "waffles"
-
/obj/item/trash/pistachios
name = "pistachios pack"
icon_state = "pistachios_pack"
diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm
index 0d3e3f60d4abf..821f994a1ed6f 100644
--- a/code/game/objects/items/weaponry.dm
+++ b/code/game/objects/items/weaponry.dm
@@ -160,6 +160,14 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
throw_range = 5
armour_penetration = 35
+/obj/item/claymore/cutlass/old
+ name = "old cutlass"
+ desc = parent_type::desc + " This one seems a tad old."
+ force = 24
+ throwforce = 17
+ armour_penetration = 20
+ block_chance = 30
+
/obj/item/claymore/carrot
name = "carrot sword"
desc = "A full-sized carrot sword. Definitely not good for the eyes, not anymore."
@@ -529,11 +537,10 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
AddComponent(/datum/component/two_handed, \
force_unwielded = 10, \
force_wielded = 14, \
- icon_wielded = "[base_icon_state]1", \
)
/obj/item/bambostaff/update_icon_state()
- icon_state = "[base_icon_state]0"
+ icon_state = inhand_icon_state = "[base_icon_state][HAS_TRAIT(src, TRAIT_WIELDED)]"
return ..()
/obj/item/cane
diff --git a/code/game/objects/items_reskin.dm b/code/game/objects/items_reskin.dm
index 9fa3b91d0e198..f8bffa7bf5f63 100644
--- a/code/game/objects/items_reskin.dm
+++ b/code/game/objects/items_reskin.dm
@@ -81,6 +81,6 @@
return FALSE
if(!istype(user))
return FALSE
- if(user.incapacitated())
+ if(user.incapacitated)
return FALSE
return TRUE
diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm
index d07f7ad21c5f5..ceaa0e0beb734 100644
--- a/code/game/objects/obj_defense.dm
+++ b/code/game/objects/obj_defense.dm
@@ -96,7 +96,7 @@
/obj/proc/collision_damage(atom/movable/pusher, force = MOVE_FORCE_DEFAULT, direction)
var/amt = max(0, ((force - (move_resist * MOVE_FORCE_CRUSH_RATIO)) / (move_resist * MOVE_FORCE_CRUSH_RATIO)) * 10)
- take_damage(amt, BRUTE)
+ take_damage(amt, BRUTE, attack_dir = REVERSE_DIR(direction))
/obj/singularity_act()
SSexplosions.high_mov_atom += src
diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm
index f12479c66a444..ef436e24e8c1a 100644
--- a/code/game/objects/objs.dm
+++ b/code/game/objects/objs.dm
@@ -7,7 +7,7 @@
/// Extra examine line to describe controls, such as right-clicking, left-clicking, etc.
var/desc_controls
- /// The context returned when an attack against this object doesnt deal any traditional damage to the object.
+ /// The context returned when an attack against this object doesn't deal any traditional damage to the object.
var/no_damage_feedback = "without leaving a mark"
/// Icon to use as a 32x32 preview in crafting menus and such
var/icon_preview
@@ -24,7 +24,7 @@
/// If this attacks a human with no wound armor on the affected body part, add this to the wound mod. Some attacks may be significantly worse at wounding if there's even a slight layer of armor to absorb some of it vs bare flesh
var/bare_wound_bonus = 0
- /// A multiplier to an objecet's force when used against a stucture, vechicle, machine, or robot.
+ /// A multiplier to an object's force when used against a structure, vehicle, machine, or robot.
var/demolition_mod = 1
/// Custom fire overlay icon, will just use the default overlay if this is null
@@ -32,7 +32,7 @@
/// Particles this obj uses when burning, if any
var/burning_particles
- var/drag_slowdown // Amont of multiplicative slowdown applied if pulled. >1 makes you slower, <1 makes you faster.
+ var/drag_slowdown // Amount of multiplicative slowdown applied if pulled. >1 makes you slower, <1 makes you faster.
/// Map tag for something. Tired of it being used on snowflake items. Moved here for some semblance of a standard.
/// Next pr after the network fix will have me refactor door interactions, so help me god.
@@ -70,7 +70,7 @@ GLOBAL_LIST_EMPTY(objects_by_id_tag)
var/total_force = (attacking_item.force * attacking_item.demolition_mod)
- var/damage = take_damage(total_force, attacking_item.damtype, MELEE, 1)
+ var/damage = take_damage(total_force, attacking_item.damtype, MELEE, 1, get_dir(src, user))
var/damage_verb = "hit"
@@ -190,7 +190,6 @@ GLOBAL_LIST_EMPTY(objects_by_id_tag)
if(obj_flags & UNIQUE_RENAME)
. += span_notice("Use a pen on it to rename it or change its description.")
-
/obj/analyzer_act(mob/living/user, obj/item/analyzer/tool)
if(atmos_scan(user=user, target=src, silent=FALSE))
return TRUE
diff --git a/code/game/objects/structures.dm b/code/game/objects/structures.dm
index ff6e6e171bb06..701c13bfcf755 100644
--- a/code/game/objects/structures.dm
+++ b/code/game/objects/structures.dm
@@ -32,7 +32,7 @@
QUEUE_SMOOTH_NEIGHBORS(src)
return ..()
-/obj/structure/ui_act(action, params)
+/obj/structure/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
add_fingerprint(usr)
return ..()
diff --git a/code/game/objects/structures/beds_chairs/alien_nest.dm b/code/game/objects/structures/beds_chairs/alien_nest.dm
index 77759c9e309b0..365e790ca48f5 100644
--- a/code/game/objects/structures/beds_chairs/alien_nest.dm
+++ b/code/game/objects/structures/beds_chairs/alien_nest.dm
@@ -13,6 +13,7 @@
canSmoothWith = SMOOTH_GROUP_ALIEN_NEST
build_stack_type = null
elevation = 0
+ can_deconstruct = FALSE
var/static/mutable_appearance/nest_overlay = mutable_appearance('icons/mob/nonhuman-player/alien.dmi', "nestoverlay", LYING_MOB_LAYER)
/obj/structure/bed/nest/add_context(atom/source, list/context, obj/item/held_item, mob/living/user)
@@ -21,10 +22,6 @@
return ..()
-/obj/structure/bed/nest/wrench_act_secondary(mob/living/user, obj/item/weapon)
- return ITEM_INTERACT_BLOCKING
-
-
/obj/structure/bed/nest/user_unbuckle_mob(mob/living/captive, mob/living/hero)
if(!length(buckled_mobs))
return
@@ -59,7 +56,7 @@
add_fingerprint(hero)
/obj/structure/bed/nest/user_buckle_mob(mob/living/M, mob/user, check_loc = TRUE)
- if ( !ismob(M) || (get_dist(src, user) > 1) || (M.loc != src.loc) || user.incapacitated() || M.buckled )
+ if ( !ismob(M) || (get_dist(src, user) > 1) || (M.loc != src.loc) || user.incapacitated || M.buckled )
return
if(M.get_organ_by_type(/obj/item/organ/internal/alien/plasmavessel))
diff --git a/code/game/objects/structures/beds_chairs/bed.dm b/code/game/objects/structures/beds_chairs/bed.dm
index 4cfd6355eb0b2..4ade32bdd0e0a 100644
--- a/code/game/objects/structures/beds_chairs/bed.dm
+++ b/code/game/objects/structures/beds_chairs/bed.dm
@@ -15,6 +15,7 @@
anchored = TRUE
can_buckle = TRUE
buckle_lying = 90
+ buckle_dir = SOUTH
resistance_flags = FLAMMABLE
max_integrity = 100
integrity_failure = 0.35
@@ -24,17 +25,21 @@
var/build_stack_amount = 2
/// Mobs standing on it are nudged up by this amount. Also used to align the person back when buckled to it after init.
var/elevation = 8
+ /// If this bed can be deconstructed using a wrench
+ var/can_deconstruct = TRUE
/obj/structure/bed/Initialize(mapload)
. = ..()
AddElement(/datum/element/soft_landing)
if(elevation)
AddElement(/datum/element/elevation, pixel_shift = elevation)
+ update_buckle_vars(dir)
register_context()
/obj/structure/bed/examine(mob/user)
. = ..()
- . += span_notice("It's held together by a couple of bolts.")
+ if (can_deconstruct)
+ . += span_notice("It's held together by a couple of bolts.")
/obj/structure/bed/add_context(atom/source, list/context, obj/item/held_item, mob/living/user)
if(held_item)
@@ -48,6 +53,13 @@
context[SCREENTIP_CONTEXT_LMB] = "Unbuckle"
return CONTEXTUAL_SCREENTIP_SET
+/obj/structure/bed/setDir(newdir)
+ . = ..()
+ update_buckle_vars(newdir)
+
+/obj/structure/bed/proc/update_buckle_vars(newdir)
+ buckle_lying = newdir & NORTHEAST ? 270 : 90
+
/obj/structure/bed/atom_deconstruct(disassembled = TRUE)
if(build_stack_type)
new build_stack_type(loc, build_stack_amount)
@@ -56,6 +68,8 @@
return attack_hand(user, modifiers)
/obj/structure/bed/wrench_act_secondary(mob/living/user, obj/item/weapon)
+ if (!can_deconstruct)
+ return NONE
..()
weapon.play_tool_sound(src)
deconstruct(disassembled = TRUE)
diff --git a/code/game/objects/structures/cannons/cannon.dm b/code/game/objects/structures/cannons/cannon.dm
index 3408ade8283d0..3a10cc17189f8 100644
--- a/code/game/objects/structures/cannons/cannon.dm
+++ b/code/game/objects/structures/cannons/cannon.dm
@@ -140,5 +140,17 @@
new /obj/item/stack/rods(src.loc)
. = ..()
+///A cannon found from the fishing mystery box.
+/obj/structure/cannon/mystery_box
+ icon_state = "mystery_box_cannon" //east facing sprite for the presented item, it'll be changed back to normal on init
+ dir = EAST
+ anchored = FALSE
+
+/obj/structure/cannon/mystery_box/Initialize(mapload)
+ . = ..()
+ icon_state = "falconet_patina"
+ reagents.add_reagent(/datum/reagent/gunpowder, charge_size)
+ loaded_cannonball = new(src)
+
#undef BAD_FUEL_DAMAGE_TAX
#undef BAD_FUEL_EXPLODE_PROBABILTY
diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm
index 4484e3c512ef3..f407dcd82c04f 100644
--- a/code/game/objects/structures/crates_lockers/closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets.dm
@@ -915,6 +915,8 @@ GLOBAL_LIST_EMPTY(roundstart_station_closets)
/obj/structure/closet/mouse_drop_receive(atom/movable/O, mob/living/user, params)
if(!istype(O) || O.anchored || istype(O, /atom/movable/screen))
return
+ if(!istype(user) || user.incapacitated || user.body_position == LYING_DOWN)
+ return
if(user == O) //try to climb onto it
return ..()
if(!opened)
@@ -1193,6 +1195,8 @@ GLOBAL_LIST_EMPTY(roundstart_station_closets)
if(!toggle())
return
if(was_opened)
+ if (!target.Move(get_turf(src), get_dir(target, src)))
+ return
target.forceMove(src)
else
target.Knockdown(SHOVE_KNOCKDOWN_SOLID)
diff --git a/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm b/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm
index f0d1eaa0cc819..2f555ed84dea5 100644
--- a/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm
+++ b/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm
@@ -32,7 +32,7 @@
var/move_delay = FALSE
/obj/structure/closet/cardboard/relaymove(mob/living/user, direction)
- if(opened || move_delay || user.incapacitated() || !isturf(loc) || !has_gravity(loc))
+ if(opened || move_delay || user.incapacitated || !isturf(loc) || !has_gravity(loc))
return
move_delay = TRUE
var/oldloc = loc
@@ -72,7 +72,7 @@
for(var/mob/living/alerted_mob as anything in alerted)
if(alerted_mob.stat != CONSCIOUS || alerted_mob.is_blind())
continue
- if(!alerted_mob.incapacitated(IGNORE_RESTRAINTS))
+ if(!INCAPACITATED_IGNORING(alerted_mob, INCAPABLE_RESTRAINTS))
alerted_mob.face_atom(src)
alerted_mob.do_alert_animation()
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm
index 3dc59fb9ce21a..22dd2bec4b2bb 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm
@@ -18,6 +18,7 @@
new /obj/item/extinguisher/advanced(src)
new /obj/item/storage/photo_album/ce(src)
new /obj/item/storage/box/skillchips/engineering(src)
+ new /obj/item/storage/box/stickers/chief_engineer(src)
/obj/structure/closet/secure_closet/engineering_chief/populate_contents_immediate()
. = ..()
diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm
index 7b64b6569d6cc..cac9fbaf890bb 100644
--- a/code/game/objects/structures/crates_lockers/crates.dm
+++ b/code/game/objects/structures/crates_lockers/crates.dm
@@ -222,6 +222,12 @@
icon_state = "medicalcrate"
base_icon_state = "medicalcrate"
+/obj/structure/closet/crate/deforest
+ name = "deforest medical crate"
+ desc = "A DeFortest brand crate of medical supplies."
+ icon_state = "deforest"
+ base_icon_state = "deforest"
+
/obj/structure/closet/crate/medical/department
icon_state = "medical"
base_icon_state = "medical"
@@ -290,6 +296,24 @@
icon_state = "food"
base_icon_state = "food"
+/obj/structure/closet/crate/freezer/donk
+ name = "donk co. fridge"
+ desc = "A Donk Co. brand fridge, keeps your donkpcokets and foam ammunition fresh!"
+ icon_state = "donkcocrate"
+ base_icon_state = "donkcocrate"
+
+/obj/structure/closet/crate/freezer/interdyne
+ name = "interdyne freezer"
+ desc = "Interdyne Pharmauceutics branded freezer. Might or might not contain cold steel, or fresh organs."
+ icon_state = "interdynefreezer"
+ base_icon_state = "interdynefreezer"
+
+/obj/structure/closet/crate/freezer/blood/interdyne
+ name = "interdyne blood freezer"
+ desc = "Interdyne Pharmauceutics branded freezer. Only freshly harvested- I mean, freshly kept blood inside!"
+ icon_state = "interdynefreezer"
+ base_icon_state = "interdynefreezer"
+
/obj/structure/closet/crate/radiation
desc = "A crate with a radiation sign on it."
name = "radiation crate"
@@ -312,6 +336,12 @@
icon_state = "cargo"
base_icon_state = "cargo"
+/obj/structure/closet/crate/robust
+ name = "robust industries crate"
+ desc = "Robust Inustries LLC. crate. Feels oddly nostalgic."
+ icon_state = "robust"
+ base_icon_state = "robust"
+
/obj/structure/closet/crate/cargo/mining
name = "mining crate"
icon_state = "mining"
@@ -322,6 +352,12 @@
icon_state = "engi_crate"
base_icon_state = "engi_crate"
+/obj/structure/closet/crate/nakamura
+ name = "nakamura engineering crate"
+ desc = "Crate from Nakamura Engineering, most likely containing engineering supplies or MODcores."
+ icon_state = "nakamura"
+ base_icon_state = "nakamura"
+
/obj/structure/closet/crate/engineering/electrical
icon_state = "engi_e_crate"
base_icon_state = "engi_e_crate"
diff --git a/code/game/objects/structures/crates_lockers/crates/secure.dm b/code/game/objects/structures/crates_lockers/crates/secure.dm
index 1a102fdb512fd..e93591f1d596c 100644
--- a/code/game/objects/structures/crates_lockers/crates/secure.dm
+++ b/code/game/objects/structures/crates_lockers/crates/secure.dm
@@ -44,6 +44,17 @@
icon_state = "weaponcrate"
base_icon_state = "weaponcrate"
+/obj/structure/closet/crate/secure/gorlex_weapons
+ desc = "A secure weapons crate of Gorlex Marauders."
+ name = "weapons crate"
+ icon_state = "gorlex_weaponcrate"
+ base_icon_state = "gorlex_weaponcrate"
+
+/obj/structure/closet/crate/secure/gorlex_weapons/jammed
+ desc = "A beaten up, jammed open weapon crate of Gorlex Marauders."
+ name = "jammed weapons crate"
+ locked = FALSE
+
/obj/structure/closet/crate/secure/plasma
desc = "A secure plasma crate."
name = "plasma crate"
@@ -192,3 +203,65 @@
else if(!silent)
to_chat(user, span_warning("[src] is broken!"))
else ..()
+
+/obj/structure/closet/crate/secure/interdyne
+ name = "interdyne crate"
+ desc = "Crate belonging to Interdyne Pharmaceutics. Hopefully doesn't have bioweapons inside..."
+ icon_state = "interdynecrate"
+ base_icon_state = "interdynecrate"
+
+/obj/structure/closet/crate/secure/tiger
+ name = "tiger co-op crate"
+ icon_state = "tigercrate"
+ base_icon_state = "tigercrate"
+
+/obj/structure/closet/crate/secure/self
+ name = "s.e.l.f. crate"
+ desc = "A secure crate locked from the inside with a scanning panel above it and holographic display of lock's status. Sentient Engine Liberation Front engineers are quite the show-offs."
+ icon_state = "selfcrate"
+ base_icon_state = "selfcrate"
+
+/obj/structure/closet/crate/secure/m13
+ name = "mysterious secure crate"
+ desc = "A secure crate. Lacks any obvious logos or even codes for where it arrived from, but looks like taken straight from a spy movie."
+ icon_state = "mithirteencrate"
+ base_icon_state = "mithirteencrate"
+
+/obj/structure/closet/crate/secure/arc
+ name = "animal rights consortium crate"
+ icon_state = "arccrate"
+ base_icon_state = "arccrate"
+
+/obj/structure/closet/crate/secure/cybersun
+ name = "cybersun crate"
+
+/obj/structure/closet/crate/secure/cybersun/dawn
+ desc = "A secure crate from Cybersun Industries. It has distinct orange-green colouring, probably of some departament or division, but you cannot tell what is it."
+ icon_state = "cyber_dawncrate"
+ base_icon_state = "cyber_dawncrate"
+
+/obj/structure/closet/crate/secure/cybersun/noon
+ desc = "A secure crate from Cybersun Industries. It has distinct yellow-orange colouring, probably of some departament or division, but you cannot tell what is it."
+ icon_state = "cyber_nooncrate"
+ base_icon_state = "cyber_nooncrate"
+
+/obj/structure/closet/crate/secure/cybersun/dusk
+ desc = "A secure crate from Cybersun Industries. It has distinct purple-green colouring, probably of some departament or division, but you cannot tell what is it."
+ icon_state = "cyber_duskcrate"
+ base_icon_state = "cyber_duskcrate"
+
+/obj/structure/closet/crate/secure/cybersun/night
+ desc = "A secure crate from Cybersun Industries. This one blatantly adorns syndicate colours. You can only guess it contains equipement for syndicate operatives."
+ icon_state = "cyber_nightcrate"
+ base_icon_state = "cyber_nightcrate"
+
+/obj/structure/closet/crate/secure/wafflecorp
+ name = "wafflecorp crate"
+ desc = "A very outdated model and design of shipment crate with a modern lock strapped on it, how befitting of its brand owner, Waffle Corporation. Golden lettering written in cursive by the logo reads 'bringing you consecutively top five world-wide rated* breakfast since 2055. A much smaller fineprint, also in cursive, clarifies: '*in years 2099-2126'... It's year 2563 now, however."
+ icon_state = "wafflecrate"
+ base_icon_state = "wafflecrate"
+
+/obj/structure/closet/crate/secure/gorlex
+ name = "gorlex marauders crate"
+ icon_state = "gorlexcrate"
+ base_icon_state = "gorlexcrate"
diff --git a/code/game/objects/structures/deployable_turret.dm b/code/game/objects/structures/deployable_turret.dm
index 2b1a90500ccf8..908d2348db4b3 100644
--- a/code/game/objects/structures/deployable_turret.dm
+++ b/code/game/objects/structures/deployable_turret.dm
@@ -85,7 +85,7 @@
STOP_PROCESSING(SSfastprocess, src)
/obj/machinery/deployable_turret/user_buckle_mob(mob/living/M, mob/user, check_loc = TRUE)
- if(user.incapacitated() || !istype(user))
+ if(user.incapacitated || !istype(user))
return
M.forceMove(get_turf(src))
. = ..()
@@ -129,7 +129,7 @@
calculated_projectile_vars = calculate_projectile_angle_and_pixel_offsets(controller, target_turf, modifiers)
/obj/machinery/deployable_turret/proc/direction_track(mob/user, atom/targeted)
- if(user.incapacitated())
+ if(user.incapacitated)
return
setDir(get_dir(src,targeted))
user.setDir(dir)
@@ -169,7 +169,7 @@
/obj/machinery/deployable_turret/proc/checkfire(atom/targeted_atom, mob/user)
target = targeted_atom
- if(target == user || user.incapacitated() || target == get_turf(src))
+ if(target == user || user.incapacitated || target == get_turf(src))
return
if(world.time < cooldown)
if(!warned && world.time > (cooldown - cooldown_duration + rate_of_fire*number_of_shots)) // To capture the window where one is done firing
@@ -187,7 +187,7 @@
addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/machinery/deployable_turret/, fire_helper), user), i*rate_of_fire)
/obj/machinery/deployable_turret/proc/fire_helper(mob/user)
- if(user.incapacitated() || !(user in buckled_mobs))
+ if(user.incapacitated || !(user in buckled_mobs))
return
update_positioning() //REFRESH MOUSE TRACKING!!
var/turf/targets_from = get_turf(src)
diff --git a/code/game/objects/structures/detectiveboard.dm b/code/game/objects/structures/detectiveboard.dm
new file mode 100644
index 0000000000000..94de77563b090
--- /dev/null
+++ b/code/game/objects/structures/detectiveboard.dm
@@ -0,0 +1,303 @@
+#define MAX_ICON_NOTICES 8
+#define MAX_EVIDENCE_Y 3500
+#define MAX_EVIDENCE_X 1180
+
+#define EVIDENCE_TYPE_PHOTO "photo"
+#define EVIDENCE_TYPE_PAPER "paper"
+
+/obj/structure/detectiveboard
+ name = "detective notice board"
+ desc = "A board for linking evidence to crimes."
+ icon = 'icons/obj/wallmounts.dmi'
+ icon_state = "noticeboard"
+ density = FALSE
+ anchored = TRUE
+ max_integrity = 150
+
+ /// When player attaching evidence to board this will become TRUE
+ var/attaching_evidence = FALSE
+ /// Colors for case color
+ var/list/case_colors = list("red", "orange", "yellow", "green", "blue", "violet")
+ /// List of board cases
+ var/list/datum/case/cases = list()
+ /// Index of viewing case in cases array
+ var/current_case = 1
+
+MAPPING_DIRECTIONAL_HELPERS(/obj/structure/detectiveboard, 32)
+
+/obj/structure/detectiveboard/Initialize(mapload)
+ . = ..()
+
+ if(mapload)
+ for(var/obj/item/item in loc)
+ if(istype(item, /obj/item/paper) || istype(item, /obj/item/photo))
+ item.forceMove(src)
+ cases[current_case].notices++
+
+ register_context()
+ find_and_hang_on_wall()
+
+/// Attaching evidences: photo and papers
+
+/obj/structure/detectiveboard/attackby(obj/item/item, mob/user, params)
+ if(istype(item, /obj/item/paper) || istype(item, /obj/item/photo))
+ if(!cases.len)
+ to_chat(user, "There are no cases!")
+ return
+
+ if(attaching_evidence)
+ to_chat(user, "You already attaching evidence!")
+ return
+ attaching_evidence = TRUE
+ var/name = tgui_input_text(user, "Please enter the evidence name", "Detective's Board")
+ if(!name)
+ attaching_evidence = FALSE
+ return
+ var/desc = tgui_input_text(user, "Please enter the evidence description", "Detective's Board")
+ if(!desc)
+ attaching_evidence = FALSE
+ return
+
+ if(!user.transferItemToLoc(item, src))
+ attaching_evidence = FALSE
+ return
+ cases[current_case].notices++
+ var/datum/evidence/evidence = new (name, desc, item)
+ cases[current_case].evidences += evidence
+ to_chat(user, span_notice("You pin the [item] to the detective board."))
+ attaching_evidence = FALSE
+ update_appearance(UPDATE_ICON)
+ return
+ return ..()
+
+/obj/structure/detectiveboard/wrench_act_secondary(mob/living/user, obj/item/tool)
+ . = ..()
+ balloon_alert(user, "[anchored ? "un" : ""]securing...")
+ tool.play_tool_sound(src)
+ if(tool.use_tool(src, user, 6 SECONDS))
+ playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE)
+ balloon_alert(user, "[anchored ? "un" : ""]secured")
+ deconstruct()
+ return TRUE
+
+/obj/structure/detectiveboard/ui_state(mob/user)
+ return GLOB.physical_state
+
+/obj/structure/detectiveboard/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "DetectiveBoard", name, 1200, 800)
+ ui.open()
+
+/obj/structure/detectiveboard/ui_data(mob/user)
+ var/list/data = list()
+ var/list/data_cases = list()
+ for(var/datum/case/case in cases)
+ var/list/data_case = list("ref"=REF(case),"name" = case.name, "color" = case.color)
+ var/list/data_evidences = list()
+ for(var/datum/evidence/evidence in case.evidences)
+ var/list/data_evidence = list("ref" = REF(evidence), "name" = evidence.name, "type" = evidence.evidence_type, "description" = evidence.description, "x"=evidence.x, "y"=evidence.y)
+ var/list/data_connections = list()
+ for(var/datum/evidence/connection in evidence.connections)
+ data_connections += REF(connection) // TODO: create array of strings
+ data_evidence["connections"] = data_connections
+ switch(evidence.evidence_type)
+ if(EVIDENCE_TYPE_PHOTO)
+ var/obj/item/photo/photo = evidence.item
+ var/tmp_picture_name = "evidence_photo[REF(photo)].png"
+ user << browse_rsc(photo.picture.picture_image, tmp_picture_name)
+ data_evidence["photo_url"] = tmp_picture_name
+ if(EVIDENCE_TYPE_PAPER)
+ var/obj/item/paper/paper = evidence.item
+ data_evidence["text"] = ""
+ if(paper.raw_text_inputs && paper.raw_text_inputs.len)
+ data_evidence["text"] = paper.raw_text_inputs[1].raw_text
+ data_evidences += list(data_evidence)
+ data_case["evidences"] = data_evidences
+ var/list/connections = list()
+ for(var/datum/evidence/evidence in case.evidences)
+ for(var/datum/evidence/connection in evidence.connections)
+ var/list/from_pos = get_pin_position(evidence)
+ var/list/to_pos = get_pin_position(connection)
+ var/found_in_connections = FALSE
+ for(var/list/con in connections)
+ if(con["from"]["x"] == to_pos["x"] && con["from"]["y"] == to_pos["y"] && con["to"]["x"] == from_pos["x"] && con["to"]["y"] == from_pos["y"] )
+ found_in_connections = TRUE
+ if(!found_in_connections)
+ var/list/data_connection = list("color" = "red", "from" = from_pos, "to" = to_pos)
+ connections += list(data_connection)
+ data_case["connections"] = connections
+ data_cases += list(data_case)
+
+ data["cases"] = data_cases
+ data["current_case"] = current_case
+ return data
+
+/obj/structure/detectiveboard/proc/get_pin_position(datum/evidence/evidence)
+ return list("x" = evidence.x + 15, "y" = evidence.y + 15)
+
+/obj/structure/detectiveboard/ui_act(action, params, datum/tgui/ui, datum/ui_state/state)
+ . = ..()
+ if(.)
+ return
+ var/mob/user = ui.user
+ switch(action)
+ if("add_case")
+ var/new_case = tgui_input_text(user, "Please enter the case name", "Detective's Board")
+ if(!new_case)
+ return FALSE
+ var/case_color = tgui_input_list(user, "Please choose case color", "Detective's Board", case_colors)
+ if(!case_color)
+ return FALSE
+
+ var/datum/case/case = new (new_case, case_color)
+ cases += case
+ current_case = cases.len
+ update_appearance(UPDATE_ICON)
+ return TRUE
+ if("set_case")
+ if(cases && params["case"] && params["case"] <= cases.len)
+ current_case = params["case"]
+ update_appearance(UPDATE_ICON)
+ return TRUE
+ if("remove_case")
+ var/datum/case/case = locate(params["case_ref"]) in cases
+ for(var/datum/evidence/evidence in case.evidences)
+ remove_item(evidence.item, user)
+ cases -= case
+ current_case = cases.len
+ update_appearance(UPDATE_ICON)
+ return TRUE
+ if("rename_case")
+ var/new_name = tgui_input_text(user, "Please ender the case new name", "Detective's Board")
+ if(new_name)
+ var/datum/case/case = locate(params["case_ref"]) in cases
+ case.name = new_name
+ return TRUE
+ if("look_evidence")
+ var/datum/case/case = locate(params["case_ref"]) in cases
+ var/datum/evidence/evidence = locate(params["evidence_ref"]) in case.evidences
+ if(evidence.evidence_type == EVIDENCE_TYPE_PHOTO)
+ var/obj/item/photo/item = evidence.item
+ item.show(user)
+ return TRUE
+
+ var/obj/item/paper/paper = evidence.item
+ var/paper_text = ""
+ for(var/datum/paper_input/text_input as anything in paper.raw_text_inputs)
+ paper_text += text_input.raw_text
+ user << browse("Anything that is considered to aesthetically obstruct an atmospherics machine (vent, scrubber, port) is listed below. Please re-arrange to accomodate for this.
"
+ results += "Anything that is considered to aesthetically obstruct an atmospherics machine (vent, scrubber, port) is listed below. Please re-arrange to accommodate for this.
"
// Ignore out stuff we see in normal and standard mapping that we don't care about (false alarms). Typically stuff that goes directionally off turfs or other undertile objects that we don't want to care about.
var/list/ignore_list = list(
diff --git a/code/modules/admin/verbs/playsound.dm b/code/modules/admin/verbs/playsound.dm
index c4e4257e84fc7..b70465666f3d0 100644
--- a/code/modules/admin/verbs/playsound.dm
+++ b/code/modules/admin/verbs/playsound.dm
@@ -54,13 +54,13 @@ ADMIN_VERB(play_direct_mob_sound, R_SOUND, "Play Direct Mob Sound", "Play a soun
SEND_SOUND(target, sound)
BLACKBOX_LOG_ADMIN_VERB("Play Direct Mob Sound")
-///Takes an input from either proc/play_web_sound or the request manager and runs it through youtube-dl and prompts the user before playing it to the server.
+///Takes an input from either proc/play_web_sound or the request manager and runs it through yt-dlp and prompts the user before playing it to the server.
/proc/web_sound(mob/user, input, credit)
if(!check_rights(R_SOUND))
return
var/ytdl = CONFIG_GET(string/invoke_youtubedl)
if(!ytdl)
- to_chat(user, span_boldwarning("Youtube-dl was not configured, action unavailable"), confidential = TRUE) //Check config.txt for the INVOKE_YOUTUBEDL value
+ to_chat(user, span_boldwarning("yt-dlp was not configured, action unavailable"), confidential = TRUE) //Check config.txt for the INVOKE_YOUTUBEDL value
return
var/web_sound_url = ""
var/stop_web_sounds = FALSE
@@ -73,14 +73,14 @@ ADMIN_VERB(play_direct_mob_sound, R_SOUND, "Play Direct Mob Sound", "Play a soun
var/stdout = output[SHELLEO_STDOUT]
var/stderr = output[SHELLEO_STDERR]
if(errorlevel)
- to_chat(user, span_boldwarning("Youtube-dl URL retrieval FAILED:"), confidential = TRUE)
+ to_chat(user, span_boldwarning("yt-dlp URL retrieval FAILED:"), confidential = TRUE)
to_chat(user, span_warning("[stderr]"), confidential = TRUE)
return
var/list/data
try
data = json_decode(stdout)
catch(var/exception/e)
- to_chat(user, span_boldwarning("Youtube-dl JSON parsing FAILED:"), confidential = TRUE)
+ to_chat(user, span_boldwarning("yt-dlp JSON parsing FAILED:"), confidential = TRUE)
to_chat(user, span_warning("[e]: [stdout]"), confidential = TRUE)
return
if (data["url"])
diff --git a/code/modules/admin/verbs/secrets.dm b/code/modules/admin/verbs/secrets.dm
index 107d74d9c3975..bcb89379ef40a 100644
--- a/code/modules/admin/verbs/secrets.dm
+++ b/code/modules/admin/verbs/secrets.dm
@@ -41,7 +41,7 @@ ADMIN_VERB(secrets, R_NONE, "Secrets", "Abuse harder than you ever have before w
#define THUNDERDOME_TEMPLATE_FILE "admin_thunderdome.dmm"
#define HIGHLANDER_DELAY_TEXT "40 seconds (crush the hope of a normal shift)"
-/datum/secrets_menu/ui_act(action, params)
+/datum/secrets_menu/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
@@ -526,7 +526,7 @@ ADMIN_VERB(secrets, R_NONE, "Secrets", "Abuse harder than you ever have before w
var/forename = names.len > 1 ? names[2] : names[1]
var/newname = "[forename]-[pick(honorifics["[H.gender]"])]"
H.fully_replace_character_name(H.real_name,newname)
- H.update_mutant_bodyparts()
+ H.update_body_parts()
if(animetype == "Yes")
var/seifuku = pick(typesof(/obj/item/clothing/under/costume/schoolgirl))
var/obj/item/clothing/under/costume/schoolgirl/I = new seifuku
diff --git a/code/modules/admin/verbs/server.dm b/code/modules/admin/verbs/server.dm
index fb7bc16cf24e0..a8389ca0bc155 100644
--- a/code/modules/admin/verbs/server.dm
+++ b/code/modules/admin/verbs/server.dm
@@ -16,10 +16,15 @@ ADMIN_VERB(toggle_hub, R_SERVER, "Toggle Hub", "Toggles the server's visilibilit
SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggled Hub Visibility", "[GLOB.hub_visibility ? "Enabled" : "Disabled"]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc!
+#define REGULAR_RESTART "Regular Restart"
+#define REGULAR_RESTART_DELAYED "Regular Restart (with delay)"
+#define HARD_RESTART "Hard Restart (No Delay/Feedback Reason)"
+#define HARDEST_RESTART "Hardest Restart (No actions, just reboot)"
+#define TGS_RESTART "Server Restart (Kill and restart DD)"
ADMIN_VERB(restart, R_SERVER, "Reboot World", "Restarts the world immediately.", ADMIN_CATEGORY_SERVER)
- var/list/options = list("Regular Restart", "Regular Restart (with delay)", "Hard Restart (No Delay/Feeback Reason)", "Hardest Restart (No actions, just reboot)")
+ var/list/options = list(REGULAR_RESTART, REGULAR_RESTART_DELAYED, HARD_RESTART, HARDEST_RESTART)
if(world.TgsAvailable())
- options += "Server Restart (Kill and restart DD)";
+ options += TGS_RESTART;
if(SSticker.admin_delay_notice)
if(alert(user, "Are you sure? An admin has already delayed the round end for the following reason: [SSticker.admin_delay_notice]", "Confirmation", "Yes", "No") != "Yes")
@@ -32,12 +37,12 @@ ADMIN_VERB(restart, R_SERVER, "Reboot World", "Restarts the world immediately.",
BLACKBOX_LOG_ADMIN_VERB("Reboot World")
var/init_by = "Initiated by [user.holder.fakekey ? "Admin" : user.key]."
switch(result)
- if("Regular Restart")
+ if(REGULAR_RESTART)
if(!user.is_localhost())
if(alert(user, "Are you sure you want to restart the server?","This server is live", "Restart", "Cancel") != "Restart")
return FALSE
SSticker.Reboot(init_by, "admin reboot - by [user.key] [user.holder.fakekey ? "(stealth)" : ""]", 10)
- if("Regular Restart (with delay)")
+ if(REGULAR_RESTART_DELAYED)
var/delay = input("What delay should the restart have (in seconds)?", "Restart Delay", 5) as num|null
if(!delay)
return FALSE
@@ -45,16 +50,22 @@ ADMIN_VERB(restart, R_SERVER, "Reboot World", "Restarts the world immediately.",
if(alert(user,"Are you sure you want to restart the server?","This server is live", "Restart", "Cancel") != "Restart")
return FALSE
SSticker.Reboot(init_by, "admin reboot - by [user.key] [user.holder.fakekey ? "(stealth)" : ""]", delay * 10)
- if("Hard Restart (No Delay, No Feeback Reason)")
+ if(HARD_RESTART)
to_chat(world, "World reboot - [init_by]")
world.Reboot()
- if("Hardest Restart (No actions, just reboot)")
+ if(HARDEST_RESTART)
to_chat(world, "Hard world reboot - [init_by]")
world.Reboot(fast_track = TRUE)
- if("Server Restart (Kill and restart DD)")
+ if(TGS_RESTART)
to_chat(world, "Server restart - [init_by]")
world.TgsEndProcess()
+#undef REGULAR_RESTART
+#undef REGULAR_RESTART_DELAYED
+#undef HARD_RESTART
+#undef HARDEST_RESTART
+#undef TGS_RESTART
+
ADMIN_VERB(end_round, R_SERVER, "End Round", "Forcibly ends the round and allows the server to restart normally.", ADMIN_CATEGORY_SERVER)
var/confirm = tgui_alert(user, "End the round and restart the game world?", "End Round", list("Yes", "Cancel"))
if(confirm != "Yes")
diff --git a/code/modules/admin/view_variables/debug_variables.dm b/code/modules/admin/view_variables/debug_variables.dm
index d9a1b90b0af29..835da1a0b39cb 100644
--- a/code/modules/admin/view_variables/debug_variables.dm
+++ b/code/modules/admin/view_variables/debug_variables.dm
@@ -29,7 +29,7 @@
return "[.][item]"
-// This is split into a seperate proc mostly to make errors that happen not break things too much
+// This is split into a separate proc mostly to make errors that happen not break things too much
/proc/_debug_variable_value(name, value, level, datum/owner, sanitize, display_flags)
if(isappearance(value))
value = get_vv_appearance(value)
@@ -64,11 +64,11 @@
var/datum/datum_value = value
return datum_value.debug_variable_value(name, level, owner, sanitize, display_flags)
- if(islist(value) || (name in GLOB.vv_special_lists)) // Some special lists arent detectable as a list through istype
+ if(islist(value) || (name in GLOB.vv_special_lists)) // Some special lists aren't detectable as a list through istype
var/list/list_value = value
var/list/items = list()
- // This is becuse some lists either dont count as lists or a locate on their ref will return null
+ // This is because some lists either don't count as lists or a locate on their ref will return null
var/link_vars = "Vars=[REF(value)]"
if(name in GLOB.vv_special_lists)
link_vars = "Vars=[REF(owner)];special_varname=[name]"
diff --git a/code/modules/admin/view_variables/filterrific.dm b/code/modules/admin/view_variables/filterrific.dm
index 0bd9f51c114f9..a997d52047743 100644
--- a/code/modules/admin/view_variables/filterrific.dm
+++ b/code/modules/admin/view_variables/filterrific.dm
@@ -24,7 +24,7 @@
data["target_filter_data"] = target.filter_data
return data
-/datum/filter_editor/ui_act(action, list/params)
+/datum/filter_editor/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/admin/view_variables/nobody_wants_to_learn_matrix_math.dm b/code/modules/admin/view_variables/nobody_wants_to_learn_matrix_math.dm
index fa5fde1f20e18..8eb2f1c72f0fb 100644
--- a/code/modules/admin/view_variables/nobody_wants_to_learn_matrix_math.dm
+++ b/code/modules/admin/view_variables/nobody_wants_to_learn_matrix_math.dm
@@ -42,7 +42,7 @@
data["pixelated"] = target.appearance_flags & PIXEL_SCALE
return data
-/datum/nobody_wants_to_learn_matrix_math/ui_act(action, list/params)
+/datum/nobody_wants_to_learn_matrix_math/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
@@ -52,7 +52,7 @@
var/matrix_var_name = params["var_name"]
var/matrix_var_value = params["var_value"]
if(testing_matrix.vv_edit_var(matrix_var_name, matrix_var_value) == FALSE)
- to_chat(src, "Your edit was rejected by the object. This is a bug with the matrix tester, not your fault, so report it on github.", confidential = TRUE)
+ to_chat(src, "Your edit was rejected by the object. This is a bug with the matrix tester, not your fault, so report it on GitHub.", confidential = TRUE)
return
set_transform()
if("scale")
diff --git a/code/modules/antagonists/_common/antag_datum.dm b/code/modules/antagonists/_common/antag_datum.dm
index d51885d51431f..fc8bfa0de8486 100644
--- a/code/modules/antagonists/_common/antag_datum.dm
+++ b/code/modules/antagonists/_common/antag_datum.dm
@@ -128,7 +128,7 @@ GLOBAL_LIST_EMPTY(antagonists)
ui = new(user, src, ui_name, name)
ui.open()
-/datum/antagonist/ui_act(action, params)
+/datum/antagonist/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
@@ -271,6 +271,9 @@ GLOBAL_LIST_EMPTY(antagonists)
if(count_against_dynamic_roll_chance && owner.current.stat != DEAD && owner.current.client)
owner.current.add_to_current_living_antags()
+ for (var/datum/atom_hud/alternate_appearance/basic/antag_hud as anything in GLOB.active_alternate_appearances)
+ antag_hud.apply_to_new_mob(owner.current)
+
SEND_SIGNAL(owner, COMSIG_ANTAGONIST_GAINED, src)
/**
@@ -328,13 +331,8 @@ GLOBAL_LIST_EMPTY(antagonists)
if(team)
team.remove_member(owner)
SEND_SIGNAL(owner, COMSIG_ANTAGONIST_REMOVED, src)
-
- // Remove HUDs that they should no longer see
- var/mob/living/current = owner.current
- for (var/datum/atom_hud/alternate_appearance/basic/has_antagonist/antag_hud as anything in GLOB.has_antagonist_huds)
- if (!antag_hud.mobShouldSee(current))
- antag_hud.hide_from(current)
-
+ if(owner.current)
+ SEND_SIGNAL(owner.current, COMSIG_MOB_ANTAGONIST_REMOVED, src)
qdel(src)
/**
@@ -530,8 +528,7 @@ GLOBAL_LIST_EMPTY(antagonists)
// Add HUDs that they couldn't see before
for (var/datum/atom_hud/alternate_appearance/basic/has_antagonist/antag_hud as anything in GLOB.has_antagonist_huds)
- if (antag_hud.mobShouldSee(owner.current))
- antag_hud.show_to(owner.current)
+ antag_hud.apply_to_new_mob(owner.current)
/// Takes a location, returns an image drawing "on" it that matches this antag datum's hud icon
/datum/antagonist/proc/hud_image_on(mob/hud_loc)
diff --git a/code/modules/antagonists/_common/antag_hud.dm b/code/modules/antagonists/_common/antag_hud.dm
index 863d52ef5ffe4..9933569f9a988 100644
--- a/code/modules/antagonists/_common/antag_hud.dm
+++ b/code/modules/antagonists/_common/antag_hud.dm
@@ -8,8 +8,9 @@ GLOBAL_LIST_EMPTY_TYPED(has_antagonist_huds, /datum/atom_hud/alternate_appearanc
var/datum/weakref/team_ref
/datum/atom_hud/alternate_appearance/basic/has_antagonist/New(key, image/I, antag_datum_type, datum/weakref/team)
- src.antag_datum_type = antag_datum_type
- team_ref = team
+ if(antag_datum_type)
+ src.antag_datum_type = antag_datum_type
+ src.team_ref = team
GLOB.has_antagonist_huds += src
return ..(key, I, NONE)
@@ -18,6 +19,8 @@ GLOBAL_LIST_EMPTY_TYPED(has_antagonist_huds, /datum/atom_hud/alternate_appearanc
return ..()
/datum/atom_hud/alternate_appearance/basic/has_antagonist/mobShouldSee(mob/M)
+ if(add_ghost_version && isobserver(M))
+ return FALSE // use the ghost version instead
var/datum/team/antag_team = team_ref?.resolve()
if(!isnull(antag_team))
return !!(M.mind in antag_team.members)
diff --git a/code/modules/antagonists/_common/antag_spawner.dm b/code/modules/antagonists/_common/antag_spawner.dm
index bbc5c7a7b03ab..5f7a7e579d3ee 100644
--- a/code/modules/antagonists/_common/antag_spawner.dm
+++ b/code/modules/antagonists/_common/antag_spawner.dm
@@ -45,7 +45,7 @@
get_asset_datum(/datum/asset/simple/contracts),
)
-/obj/item/antag_spawner/contract/ui_act(action, list/params)
+/obj/item/antag_spawner/contract/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(used || polling || !ishuman(usr))
return
diff --git a/code/modules/antagonists/abductor/abductor.dm b/code/modules/antagonists/abductor/abductor.dm
index 68cf781db9b05..7fc0c565ab1df 100644
--- a/code/modules/antagonists/abductor/abductor.dm
+++ b/code/modules/antagonists/abductor/abductor.dm
@@ -74,12 +74,13 @@
owner.special_role = ROLE_ABDUCTOR
objectives += team.objectives
finalize_abductor()
- ADD_TRAIT(owner, TRAIT_ABDUCTOR_TRAINING, ABDUCTOR_ANTAGONIST)
+ // We don't want abductors to be converted by other antagonists
+ owner.add_traits(list(TRAIT_ABDUCTOR_TRAINING, TRAIT_UNCONVERTABLE), ABDUCTOR_ANTAGONIST)
return ..()
/datum/antagonist/abductor/on_removal()
owner.special_role = null
- REMOVE_TRAIT(owner, TRAIT_ABDUCTOR_TRAINING, ABDUCTOR_ANTAGONIST)
+ owner.remove_traits(list(TRAIT_ABDUCTOR_TRAINING, TRAIT_UNCONVERTABLE), ABDUCTOR_ANTAGONIST)
return ..()
/datum/antagonist/abductor/greet()
@@ -90,20 +91,20 @@
/datum/antagonist/abductor/proc/finalize_abductor()
//Equip
- var/mob/living/carbon/human/H = owner.current
- H.set_species(/datum/species/abductor)
- var/obj/item/organ/internal/tongue/abductor/T = H.get_organ_slot(ORGAN_SLOT_TONGUE)
- T.mothership = "[team.name]"
+ var/mob/living/carbon/human/new_abductor = owner.current
+ new_abductor.set_species(/datum/species/abductor)
+ var/obj/item/organ/internal/tongue/abductor/abductor_tongue = new_abductor.get_organ_slot(ORGAN_SLOT_TONGUE)
+ abductor_tongue.mothership = "[team.name]"
- H.real_name = "[team.name] [sub_role]"
- H.equipOutfit(outfit)
+ new_abductor.real_name = "[team.name] [sub_role]"
+ new_abductor.equipOutfit(outfit)
// We require that the template be loaded here, so call it in a blocking manner, if its already done loading, this won't block
SSmapping.lazy_load_template(LAZY_TEMPLATE_KEY_ABDUCTOR_SHIPS)
//Teleport to ship
for(var/obj/effect/landmark/abductor/LM in GLOB.landmarks_list)
if(istype(LM, landmark_type) && LM.team_number == team.team_number)
- H.forceMove(LM.loc)
+ new_abductor.forceMove(LM.loc)
break
/datum/antagonist/abductor/scientist/on_gain()
@@ -137,13 +138,13 @@
if(!ishuman(owner.current))
to_chat(admin, span_warning("This only works on humans!"))
return
- var/mob/living/carbon/human/H = owner.current
+ var/mob/living/carbon/human/new_abductor = owner.current
var/gear = tgui_alert(admin,"Agent or Scientist Gear", "Gear", list("Agent", "Scientist"))
if(gear)
if(gear == "Agent")
- H.equipOutfit(/datum/outfit/abductor/agent)
+ new_abductor.equipOutfit(/datum/outfit/abductor/agent)
else
- H.equipOutfit(/datum/outfit/abductor/scientist)
+ new_abductor.equipOutfit(/datum/outfit/abductor/scientist)
/datum/team/abductor_team
member_name = "\improper Abductor"
diff --git a/code/modules/antagonists/abductor/equipment/gear/abductor_clothing.dm b/code/modules/antagonists/abductor/equipment/gear/abductor_clothing.dm
index c54ce6937d86f..e5951473df087 100644
--- a/code/modules/antagonists/abductor/equipment/gear/abductor_clothing.dm
+++ b/code/modules/antagonists/abductor/equipment/gear/abductor_clothing.dm
@@ -103,6 +103,8 @@
/obj/item/clothing/suit/armor/abductor/vest/proc/return_disguise_name(mob/living/carbon/human/source, list/identity)
SIGNAL_HANDLER
+ if(identity[VISIBLE_NAME_FORCED]) // name-forcing overrides disguise
+ return
identity[VISIBLE_NAME_FACE] = disguise.name
identity[VISIBLE_NAME_ID] = ""
diff --git a/code/modules/antagonists/abductor/equipment/gear/abductor_items.dm b/code/modules/antagonists/abductor/equipment/gear/abductor_items.dm
index d3f162f5fb55a..25bbea665777c 100644
--- a/code/modules/antagonists/abductor/equipment/gear/abductor_items.dm
+++ b/code/modules/antagonists/abductor/equipment/gear/abductor_items.dm
@@ -384,7 +384,7 @@ Congratulations! You are now trained for invasive xenobiology research!"}
/obj/item/melee/baton/abductor/proc/SleepAttack(mob/living/target, mob/living/user)
playsound(src, on_stun_sound, 50, TRUE, -1)
- if(target.incapacitated(IGNORE_RESTRAINTS|IGNORE_GRAB))
+ if(INCAPACITATED_IGNORING(target, INCAPABLE_RESTRAINTS|INCAPABLE_GRAB))
if(target.can_block_magic(MAGIC_RESISTANCE_MIND))
to_chat(user, span_warning("The specimen has some kind of mental protection that is interfering with the sleep inducement! It seems you've been foiled."))
target.visible_message(span_danger("[user] tried to induced sleep in [target] with [src], but is unsuccessful!"), \
@@ -689,7 +689,7 @@ Congratulations! You are now trained for invasive xenobiology research!"}
/obj/item/abductor/alien_omnitool/proc/check_menu(mob/user)
if(!istype(user))
return FALSE
- if(user.incapacitated() || !user.Adjacent(src))
+ if(user.incapacitated || !user.Adjacent(src))
return FALSE
return TRUE
diff --git a/code/modules/antagonists/abductor/equipment/gland.dm b/code/modules/antagonists/abductor/equipment/gland.dm
index 29ea5f1e78502..f4fe0fb1875f8 100644
--- a/code/modules/antagonists/abductor/equipment/gland.dm
+++ b/code/modules/antagonists/abductor/equipment/gland.dm
@@ -84,7 +84,7 @@
active_mind_control = FALSE
return TRUE
-/obj/item/organ/internal/heart/gland/Remove(mob/living/carbon/gland_owner, special, movement_flags)
+/obj/item/organ/internal/heart/gland/mob_remove(mob/living/carbon/gland_owner, special, movement_flags)
. = ..()
active = FALSE
if(initial(uses) == 1)
@@ -93,10 +93,8 @@
hud.remove_atom_from_hud(gland_owner)
clear_mind_control()
-/obj/item/organ/internal/heart/gland/Insert(mob/living/carbon/gland_owner, special = FALSE, movement_flags = DELETE_IF_REPLACED)
+/obj/item/organ/internal/heart/gland/mob_insert(mob/living/carbon/gland_owner, special = FALSE, movement_flags = DELETE_IF_REPLACED)
. = ..()
- if(!.)
- return
if(special != 2 && uses) // Special 2 means abductor surgery
Start()
diff --git a/code/modules/antagonists/abductor/equipment/glands/mindshock.dm b/code/modules/antagonists/abductor/equipment/glands/mindshock.dm
index 87870947f17d6..1a3f140c3415d 100644
--- a/code/modules/antagonists/abductor/equipment/glands/mindshock.dm
+++ b/code/modules/antagonists/abductor/equipment/glands/mindshock.dm
@@ -15,7 +15,7 @@
for(var/mob/living/carbon/target in orange(4,owner_turf))
if(target == owner)
continue
- if(HAS_TRAIT(target, TRAIT_MINDSHIELD))
+ if(HAS_MIND_TRAIT(target, TRAIT_MINDSHIELD))
to_chat(target, span_notice("You hear a faint hum fill your ears, which quickly dies down."))
continue
@@ -41,7 +41,7 @@
if(target_human.stat)
continue
- if(HAS_TRAIT(target_human, TRAIT_MINDSHIELD))
+ if(HAS_MIND_TRAIT(target_human, TRAIT_UNCONVERTABLE))
to_chat(target_human, span_notice("You hear a low drone as something foreign attempts to enter your mind, but the noise fades after a few moments."))
continue
diff --git a/code/modules/antagonists/abductor/machinery/console.dm b/code/modules/antagonists/abductor/machinery/console.dm
index ee729de7068b8..3dcdaf5a5b07e 100644
--- a/code/modules/antagonists/abductor/machinery/console.dm
+++ b/code/modules/antagonists/abductor/machinery/console.dm
@@ -118,7 +118,7 @@
data["vest_lock"] = HAS_TRAIT_FROM(vest, TRAIT_NODROP, ABDUCTOR_VEST_TRAIT)
return data
-/obj/machinery/abductor/console/ui_act(action, list/params)
+/obj/machinery/abductor/console/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/antagonists/abductor/machinery/dispenser.dm b/code/modules/antagonists/abductor/machinery/dispenser.dm
index 8d8f9e14b8954..416153c50e58f 100644
--- a/code/modules/antagonists/abductor/machinery/dispenser.dm
+++ b/code/modules/antagonists/abductor/machinery/dispenser.dm
@@ -48,7 +48,7 @@
data["glands"] += list(gland_information)
return data
-/obj/machinery/abductor/gland_dispenser/ui_act(action, list/params)
+/obj/machinery/abductor/gland_dispenser/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/antagonists/abductor/machinery/experiment.dm b/code/modules/antagonists/abductor/machinery/experiment.dm
index a549171b66150..09790f4ba897e 100644
--- a/code/modules/antagonists/abductor/machinery/experiment.dm
+++ b/code/modules/antagonists/abductor/machinery/experiment.dm
@@ -86,7 +86,7 @@
data["occupant_status"] = mob_occupant.stat
return data
-/obj/machinery/abductor/experiment/ui_act(action, list/params)
+/obj/machinery/abductor/experiment/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/antagonists/brother/brother.dm b/code/modules/antagonists/brother/brother.dm
index 5f4622bd910a4..4f535ece8cef0 100644
--- a/code/modules/antagonists/brother/brother.dm
+++ b/code/modules/antagonists/brother/brother.dm
@@ -94,7 +94,7 @@
flashed.balloon_alert(source, "[flashed.p_theyre()] loyal to someone else!")
return
- if (HAS_TRAIT(flashed, TRAIT_MINDSHIELD))
+ if (HAS_TRAIT(flashed, TRAIT_UNCONVERTABLE))
flashed.balloon_alert(source, "[flashed.p_they()] resist!")
return
@@ -221,6 +221,9 @@
return
. = ..()
member.remove_antag_datum(/datum/antagonist/brother)
+ if (!length(members))
+ qdel(src)
+ return
if (isnull(member.current))
return
for (var/datum/mind/brother_mind as anything in members)
diff --git a/code/modules/antagonists/changeling/cellular_emporium.dm b/code/modules/antagonists/changeling/cellular_emporium.dm
index 68e83ea25e668..754d2343d5cd5 100644
--- a/code/modules/antagonists/changeling/cellular_emporium.dm
+++ b/code/modules/antagonists/changeling/cellular_emporium.dm
@@ -69,7 +69,7 @@
return data
-/datum/cellular_emporium/ui_act(action, params)
+/datum/cellular_emporium/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/antagonists/changeling/headslug_eggs.dm b/code/modules/antagonists/changeling/headslug_eggs.dm
index 8f861aec2ec80..75c0881c55167 100644
--- a/code/modules/antagonists/changeling/headslug_eggs.dm
+++ b/code/modules/antagonists/changeling/headslug_eggs.dm
@@ -11,11 +11,11 @@
/// When this egg last got removed from a body. If -1, the egg hasn't been removed from a body.
var/removal_time = -1
-/obj/item/organ/internal/body_egg/changeling_egg/Insert(mob/living/carbon/egg_owner, special = FALSE, movement_flags = DELETE_IF_REPLACED)
+/obj/item/organ/internal/body_egg/changeling_egg/mob_insert(mob/living/carbon/egg_owner, special = FALSE, movement_flags = DELETE_IF_REPLACED)
. = ..()
hatch_time = world.time + (removal_time == -1 ? EGG_INCUBATION_TIME : (hatch_time - removal_time))
-/obj/item/organ/internal/body_egg/changeling_egg/Remove(mob/living/carbon/egg_owner, special, movement_flags)
+/obj/item/organ/internal/body_egg/changeling_egg/mob_remove(mob/living/carbon/egg_owner, special, movement_flags)
. = ..()
removal_time = world.time
diff --git a/code/modules/antagonists/changeling/powers/spiders.dm b/code/modules/antagonists/changeling/powers/spiders.dm
index ce23fc0eb1b57..e184815945b40 100644
--- a/code/modules/antagonists/changeling/powers/spiders.dm
+++ b/code/modules/antagonists/changeling/powers/spiders.dm
@@ -7,6 +7,14 @@
dna_cost = 1
req_absorbs = 3
+// Ensures that you cannot horrifically cheese the game by spawning spiders while in the vents
+/datum/action/changeling/spiders/can_be_used_by(mob/living/user)
+ if (!isopenturf(user.loc))
+ var/turf/user_turf = get_turf(user)
+ user_turf.balloon_alert(user, "not enough space!")
+ return FALSE
+ return ..()
+
//Makes a spider egg cluster. Allows you enable further general havok by introducing spiders to the station.
/datum/action/changeling/spiders/sting_action(mob/user)
..()
diff --git a/code/modules/antagonists/clown_ops/clown_weapons.dm b/code/modules/antagonists/clown_ops/clown_weapons.dm
index 1e566b7d1975e..bd2dfd4b0da01 100644
--- a/code/modules/antagonists/clown_ops/clown_weapons.dm
+++ b/code/modules/antagonists/clown_ops/clown_weapons.dm
@@ -17,6 +17,7 @@
desc = "advanced clown shoes that protect the wearer and render them nearly immune to slipping on their own peels. They also squeak at 100% capacity."
clothing_traits = list(TRAIT_NO_SLIP_WATER)
slowdown = SHOES_SLOWDOWN
+ body_parts_covered = FEET|LEGS
armor_type = /datum/armor/clown_shoes_combat
strip_delay = 70
resistance_flags = NONE
@@ -49,6 +50,7 @@
strip_delay = 70
resistance_flags = NONE
always_noslip = TRUE
+ body_parts_covered = FEET|LEGS
/datum/armor/banana_shoes_combat
melee = 25
diff --git a/code/modules/antagonists/cult/blood_magic.dm b/code/modules/antagonists/cult/blood_magic.dm
index 39cd9b550ae45..4cfa39f3fa654 100644
--- a/code/modules/antagonists/cult/blood_magic.dm
+++ b/code/modules/antagonists/cult/blood_magic.dm
@@ -79,7 +79,7 @@
return
qdel(nullify_spell)
BS = possible_spells[entered_spell_name]
- if(QDELETED(src) || owner.incapacitated() || !BS || (rune && !(locate(/obj/effect/rune/empower) in range(1, owner))) || (length(spells) >= limit))
+ if(QDELETED(src) || owner.incapacitated || !BS || (rune && !(locate(/obj/effect/rune/empower) in range(1, owner))) || (length(spells) >= limit))
return
to_chat(owner,span_warning("You begin to carve unnatural symbols into your flesh!"))
SEND_SOUND(owner, sound('sound/weapons/slice.ogg',0,1,10))
@@ -137,7 +137,7 @@
..()
/datum/action/innate/cult/blood_spell/IsAvailable(feedback = FALSE)
- if(!IS_CULTIST(owner) || owner.incapacitated() || (!charges && deletes_on_empty))
+ if(!IS_CULTIST(owner) || owner.incapacitated || (!charges && deletes_on_empty))
return FALSE
return ..()
@@ -162,14 +162,14 @@
name = "Stun"
desc = "Empowers your hand to stun and mute a victim on contact. Gets weaker depending on how many have joined the Cult."
button_icon_state = "hand"
- magic_path = "/obj/item/melee/blood_magic/stun"
+ magic_path = /obj/item/melee/blood_magic/stun
health_cost = 10
/datum/action/innate/cult/blood_spell/teleport
name = "Teleport"
desc = "Empowers your hand to teleport yourself or another cultist to a teleport rune on contact."
button_icon_state = "tele"
- magic_path = "/obj/item/melee/blood_magic/teleport"
+ magic_path = /obj/item/melee/blood_magic/teleport
health_cost = 7
/datum/action/innate/cult/blood_spell/emp
@@ -194,20 +194,20 @@
desc = "Empowers your hand to start handcuffing victim on contact, and mute them if successful."
button_icon_state = "cuff"
charges = 4
- magic_path = "/obj/item/melee/blood_magic/shackles"
+ magic_path = /obj/item/melee/blood_magic/shackles
/datum/action/innate/cult/blood_spell/construction
name = "Twisted Construction"
desc = "Empowers your hand to corrupt certain metalic objects.
Converts:
Plasteel into runed metal
50 metal into a construct shell
Living cyborgs into constructs after a delay
Cyborg shells into construct shells
Purified soulstones (and any shades inside) into cultist soulstones
Airlocks into brittle runed airlocks after a delay (harm intent)"
button_icon_state = "transmute"
- magic_path = "/obj/item/melee/blood_magic/construction"
+ magic_path = /obj/item/melee/blood_magic/construction
health_cost = 12
/datum/action/innate/cult/blood_spell/equipment
name = "Summon Combat Equipment"
desc = "Empowers your hand to summon combat gear onto a cultist you touch, including cult armor, a cult bola, and a cult sword. Not recommended for use before the blood cult's presence has been revealed."
button_icon_state = "equip"
- magic_path = "/obj/item/melee/blood_magic/armor"
+ magic_path = /obj/item/melee/blood_magic/armor
/datum/action/innate/cult/blood_spell/dagger
name = "Summon Ritual Dagger"
@@ -263,7 +263,7 @@
SEND_SOUND(caller, sound('sound/effects/ghost.ogg', FALSE, TRUE, 50))
var/image/sparkle_image = image('icons/effects/cult.dmi', clicked_on, "bloodsparkles", ABOVE_MOB_LAYER)
- clicked_on.add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/cult, "cult_apoc", sparkle_image, NONE)
+ clicked_on.add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/has_antagonist/cult, "cult_apoc", sparkle_image, NONE)
addtimer(CALLBACK(clicked_on, TYPE_PROC_REF(/atom/, remove_alt_appearance), "cult_apoc", TRUE), 4 MINUTES, TIMER_OVERRIDE|TIMER_UNIQUE)
to_chat(caller, span_cult_bold("[clicked_on] has been cursed with living nightmares!"))
@@ -339,7 +339,7 @@
invocation = "Fel'th Dol Ab'orod!"
button_icon_state = "manip"
charges = 5
- magic_path = "/obj/item/melee/blood_magic/manipulator"
+ magic_path = /obj/item/melee/blood_magic/manipulator
deletes_on_empty = FALSE
// The "magic hand" items
@@ -433,13 +433,15 @@
/obj/item/melee/blood_magic/stun/cast_spell(mob/living/target, mob/living/carbon/user)
if(!istype(target) || IS_CULTIST(target))
return
- var/datum/antagonist/cult/cultist = IS_CULTIST(user)
- var/datum/team/cult/cult_team = cultist.get_team()
+ var/datum/antagonist/cult/cultist = GET_CULTIST(user)
+ var/datum/team/cult/cult_team = cultist?.get_team()
var/effect_coef = 1
- if(cult_team.cult_ascendent)
+ if(cult_team?.cult_ascendent)
effect_coef = 0.1
- else if(cult_team.cult_risen)
+ else if(cult_team?.cult_risen)
effect_coef = 0.4
+ if(IS_CULTIST(user) && isnull(GET_CULTIST(user)))
+ effect_coef = 0.2
user.visible_message(
span_warning("[user] holds up [user.p_their()] hand, which explodes in a flash of red light!"),
span_cult_italic("You attempt to stun [target] with the spell!"),
@@ -513,7 +515,7 @@
to_chat(user, span_warning("You must pick a valid rune!"))
return
var/obj/effect/rune/teleport/actual_selected_rune = potential_runes[input_rune_key] //what rune does that key correspond to?
- if(QDELETED(src) || !user || !user.is_holding(src) || user.incapacitated() || !actual_selected_rune)
+ if(QDELETED(src) || !user || !user.is_holding(src) || user.incapacitated || !actual_selected_rune)
return
var/turf/dest = get_turf(actual_selected_rune)
if(dest.is_blocked_turf(TRUE))
@@ -699,7 +701,7 @@
/obj/item/melee/blood_magic/construction/proc/check_menu(mob/user)
if(!istype(user))
CRASH("The cult construct selection radial menu was accessed by something other than a valid user.")
- if(user.incapacitated() || !user.Adjacent(src))
+ if(user.incapacitated || !user.Adjacent(src))
return FALSE
return TRUE
@@ -965,7 +967,7 @@
/obj/item/melee/blood_magic/manipulator/proc/check_menu(mob/living/user)
if(!istype(user))
CRASH("The Blood Rites manipulator radial menu was accessed by something other than a valid user.")
- if(user.incapacitated() || !user.Adjacent(src))
+ if(user.incapacitated || !user.Adjacent(src))
return FALSE
return TRUE
diff --git a/code/modules/antagonists/cult/cult_comms.dm b/code/modules/antagonists/cult/cult_comms.dm
index a4f3b291f74da..3d5677996502a 100644
--- a/code/modules/antagonists/cult/cult_comms.dm
+++ b/code/modules/antagonists/cult/cult_comms.dm
@@ -120,7 +120,7 @@
if(!team_member.current)
continue
team_member.current.update_mob_action_buttons()
- if(team_member.current.incapacitated())
+ if(team_member.current.incapacitated)
continue
SEND_SOUND(team_member.current, 'sound/hallucinations/im_here1.ogg')
to_chat(team_member.current, span_cult_large("Acolyte [nominee] has asserted that [nominee.p_theyre()] worthy of leading the cult. A vote will be called shortly."))
@@ -129,19 +129,19 @@
///Polls all Cultists on whether the person putting themselves forward should be made the Cult Leader, if they can actually be such.
/proc/poll_cultists_for_leader(mob/living/nominee, datum/team/cult/team)
- if(QDELETED(nominee) || nominee.incapacitated())
+ if(QDELETED(nominee) || nominee.incapacitated)
team.cult_vote_called = FALSE
for(var/datum/mind/team_member as anything in team.members)
if(!team_member.current)
continue
team_member.current.update_mob_action_buttons()
- if(team_member.current.incapacitated())
+ if(team_member.current.incapacitated)
continue
to_chat(team_member.current,span_cult_large("[nominee] has died in the process of attempting to start a vote!"))
return FALSE
var/list/mob/living/asked_cultists = list()
for(var/datum/mind/team_member as anything in team.members)
- if(!team_member.current || team_member.current == nominee || team_member.current.incapacitated())
+ if(!team_member.current || team_member.current == nominee || team_member.current.incapacitated)
continue
SEND_SOUND(team_member.current, 'sound/magic/exit_blood.ogg')
asked_cultists += team_member.current
@@ -161,13 +161,13 @@
chat_text_border_icon = mutable_appearance('icons/effects/effects.dmi', "cult_master_logo")
)
)
- if(QDELETED(nominee) || nominee.incapacitated())
+ if(QDELETED(nominee) || nominee.incapacitated)
team.cult_vote_called = FALSE
for(var/datum/mind/team_member as anything in team.members)
if(!team_member.current)
continue
team_member.current.update_mob_action_buttons()
- if(team_member.current.incapacitated())
+ if(team_member.current.incapacitated)
continue
to_chat(team_member.current,span_cult_large("[nominee] has died in the process of attempting to win the cult's support!"))
return FALSE
@@ -177,7 +177,7 @@
if(!team_member.current)
continue
team_member.current.update_mob_action_buttons()
- if(team_member.current.incapacitated())
+ if(team_member.current.incapacitated)
continue
to_chat(team_member.current,span_cult_large("[nominee] has gone catatonic in the process of attempting to win the cult's support!"))
return FALSE
@@ -187,7 +187,7 @@
if(!team_member.current)
continue
team_member.current.update_mob_action_buttons()
- if(team_member.current.incapacitated())
+ if(team_member.current.incapacitated)
continue
to_chat(team_member.current, span_cult_large("[nominee] could not win the cult's support and shall continue to serve as an acolyte."))
return FALSE
diff --git a/code/modules/antagonists/cult/cult_items.dm b/code/modules/antagonists/cult/cult_items.dm
index 994f98ed099ea..9d386b8f11be7 100644
--- a/code/modules/antagonists/cult/cult_items.dm
+++ b/code/modules/antagonists/cult/cult_items.dm
@@ -19,6 +19,7 @@
inhand_x_dimension = 32
inhand_y_dimension = 32
w_class = WEIGHT_CLASS_SMALL
+ slot_flags = ITEM_SLOT_BELT
force = 15
throwforce = 25
block_chance = 25
@@ -217,7 +218,7 @@ Striking a noncultist, however, will tear their flesh."}
// Get the heretic's new body and antag datum.
trapped_entity = trapped_mind?.current
trapped_entity.key = trapped_mind?.key
- var/datum/antagonist/heretic/heretic_holder = IS_HERETIC(trapped_entity)
+ var/datum/antagonist/heretic/heretic_holder = GET_HERETIC(trapped_entity)
if(!heretic_holder)
stack_trace("[soul_to_bind] in but not a heretic on the heretic soul blade.")
@@ -378,7 +379,7 @@ Striking a noncultist, however, will tear their flesh."}
worn_icon = 'icons/mob/clothing/suits/armor.dmi'
inhand_icon_state = "cultrobes"
body_parts_covered = CHEST|GROIN|LEGS|ARMS
- allowed = list(/obj/item/tome, /obj/item/melee/cultblade)
+ allowed = list(/obj/item/tome, /obj/item/melee/cultblade, /obj/item/melee/sickly_blade/cursed)
armor_type = /datum/armor/hooded_cultrobes
flags_inv = HIDEJUMPSUIT
cold_protection = CHEST|GROIN|LEGS|ARMS
@@ -595,7 +596,6 @@ Striking a noncultist, however, will tear their flesh."}
/obj/item/clothing/suit/hooded/cultrobes/berserker
name = "flagellant's robes"
desc = "Blood-soaked robes infused with dark magic; allows the user to move at inhuman speeds, but at the cost of increased damage. Provides an even greater speed boost if its hood is worn."
- allowed = list(/obj/item/tome, /obj/item/melee/cultblade)
armor_type = /datum/armor/cultrobes_berserker
slowdown = -0.3 //the hood gives an additional -0.3 if you have it flipped up, for a total of -0.6
hoodtype = /obj/item/clothing/head/hooded/cult_hoodie/berserkerhood
@@ -911,7 +911,7 @@ Striking a noncultist, however, will tear their flesh."}
cultists |= cult_mind.current
var/mob/living/cultist_to_receive = tgui_input_list(user, "Who do you wish to call to [src]?", "Followers of the Geometer", (cultists - user))
- if(QDELETED(src) || loc != user || user.incapacitated())
+ if(QDELETED(src) || loc != user || user.incapacitated)
return ITEM_INTERACT_BLOCKING
if(isnull(cultist_to_receive))
to_chat(user, span_cult_italic("You require a destination!"))
@@ -1278,7 +1278,6 @@ Striking a noncultist, however, will tear their flesh."}
return FALSE
/obj/item/shield/mirror/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
- var/turf/impact_turf = get_turf(hit_atom)
if(isliving(hit_atom))
var/mob/living/target = hit_atom
@@ -1291,14 +1290,9 @@ Striking a noncultist, however, will tear their flesh."}
return
if(!..())
target.Paralyze(30)
- var/mob/thrower = throwingdatum?.get_thrower()
- if(thrower)
- for(var/mob/living/Next in orange(2, impact_turf))
- if(!Next.density || IS_CULTIST(Next))
- continue
- throw_at(Next, 3, 1, thrower)
- return
- throw_at(thrower, 7, 1, null)
+ new /obj/effect/temp_visual/cult/sparks(target)
+ playsound(target, 'sound/effects/glassbr3.ogg', 100)
+ qdel(src)
else
..()
diff --git a/code/modules/antagonists/cult/cult_other.dm b/code/modules/antagonists/cult/cult_other.dm
index 9435baedba11a..f9e1462a30efe 100644
--- a/code/modules/antagonists/cult/cult_other.dm
+++ b/code/modules/antagonists/cult/cult_other.dm
@@ -25,8 +25,6 @@
return FALSE
#endif
- if(target.mind.unconvertable)
- return FALSE
if(ishuman(target) && target.mind.holy_role)
return FALSE
if(specific_cult?.is_sacrifice_target(target.mind))
@@ -36,6 +34,6 @@
return FALSE
if(IS_HERETIC_OR_MONSTER(target))
return FALSE
- if(HAS_TRAIT(target, TRAIT_MINDSHIELD) || issilicon(target) || isbot(target) || isdrone(target))
+ if(HAS_MIND_TRAIT(target, TRAIT_UNCONVERTABLE) || issilicon(target) || isbot(target) || isdrone(target))
return FALSE //can't convert machines, shielded, or braindead
return TRUE
diff --git a/code/modules/antagonists/cult/cult_structures.dm b/code/modules/antagonists/cult/cult_structures.dm
index 2cdb2c2e6f468..773f890d25dbb 100644
--- a/code/modules/antagonists/cult/cult_structures.dm
+++ b/code/modules/antagonists/cult/cult_structures.dm
@@ -201,7 +201,7 @@
* Returns TRUE if the user is a living mob that is a cultist and is not incapacitated.
*/
/obj/structure/destructible/cult/item_dispenser/proc/check_menu(mob/user)
- return isliving(user) && is_cultist_check(user) && !user.incapacitated()
+ return isliving(user) && is_cultist_check(user) && !user.incapacitated
// Spooky looking door used in gateways. Or something.
/obj/effect/gateway
diff --git a/code/modules/antagonists/cult/datums/cult_team.dm b/code/modules/antagonists/cult/datums/cult_team.dm
index 72c7df8bf5d14..4d77f65f588df 100644
--- a/code/modules/antagonists/cult/datums/cult_team.dm
+++ b/code/modules/antagonists/cult/datums/cult_team.dm
@@ -65,7 +65,7 @@
for(var/datum/mind/mind as anything in members)
if(mind.current)
SEND_SOUND(mind.current, 'sound/ambience/antag/bloodcult/bloodcult_halos.ogg')
- to_chat(mind.current, span_cult_large(span_warning("Your cult is ascendent and the red harvest approaches - you cannot hide your true nature for much longer!!")))
+ to_chat(mind.current, span_cult_large(span_warning("Your cult is ascendant and the red harvest approaches - you cannot hide your true nature for much longer!!")))
mind.current.AddElement(/datum/element/cult_halo)
cult_ascendent = TRUE
log_game("The blood cult has ascended with [cultplayers] players.")
@@ -134,6 +134,7 @@
return "
")]
I'm sorry I won't sail back home soon,
+
son of a biscuit eater walked the plank with me coffer (or treasure chest as landlubbers call'em),
+
so I got me fishing rod, bottles, waiting to fish the booty back.
+
Luv you hun, I hope this letter find you we-"}
diff --git a/code/modules/bitrunning/netpod/ui.dm b/code/modules/bitrunning/netpod/ui.dm
index 93719fe64ebef..919ba1e174b53 100644
--- a/code/modules/bitrunning/netpod/ui.dm
+++ b/code/modules/bitrunning/netpod/ui.dm
@@ -27,7 +27,7 @@
return data
-/obj/machinery/netpod/ui_act(action, params)
+/obj/machinery/netpod/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return TRUE
diff --git a/code/modules/bitrunning/objects/vendor.dm b/code/modules/bitrunning/objects/vendor.dm
index abd63a9e78430..d44630bc3beed 100644
--- a/code/modules/bitrunning/objects/vendor.dm
+++ b/code/modules/bitrunning/objects/vendor.dm
@@ -62,7 +62,7 @@
/obj/machinery/computer/order_console/bitrunning/retrieve_points(obj/item/card/id/id_card)
return round(id_card.registered_account.bitrunning_points)
-/obj/machinery/computer/order_console/bitrunning/ui_act(action, params)
+/obj/machinery/computer/order_console/bitrunning/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(!.)
flick("vendor_off", src)
diff --git a/code/modules/bitrunning/orders/tech.dm b/code/modules/bitrunning/orders/tech.dm
index 7e987e4818104..0b097127ffb71 100644
--- a/code/modules/bitrunning/orders/tech.dm
+++ b/code/modules/bitrunning/orders/tech.dm
@@ -32,7 +32,7 @@
desc = "This disk contains a program that lets you shapeshift into a lesser ashdrake, or a polar bear."
/datum/orderable_item/bitrunning_tech/flip_skillchip
- item_path = /obj/item/skillchip/matrix_flip
+ item_path = /obj/item/skillchip/matrix_taunt
cost_per_order = 2000
/datum/orderable_item/bitrunning_tech/pka_mod
diff --git a/code/modules/bitrunning/virtual_domain/domains/island_brawl.dm b/code/modules/bitrunning/virtual_domain/domains/island_brawl.dm
index b745a4746aa24..84eb53e026a29 100644
--- a/code/modules/bitrunning/virtual_domain/domains/island_brawl.dm
+++ b/code/modules/bitrunning/virtual_domain/domains/island_brawl.dm
@@ -21,9 +21,17 @@
for(var/obj/effect/mob_spawn/ghost_role/human/virtual_domain/islander/spawner in created_atoms)
custom_spawns += spawner
+ RegisterSignal(spawner, COMSIG_QDELETING, PROC_REF(on_spawner_qdeleted))
RegisterSignals(spawner, list(COMSIG_GHOSTROLE_SPAWNED, COMSIG_BITRUNNER_SPAWNED), PROC_REF(on_spawn))
+/datum/lazy_template/virtual_domain/island_brawl/proc/on_spawner_qdeleted(obj/effect/mob_spawn/ghost_role/human/virtual_domain/islander/source)
+ SIGNAL_HANDLER
+
+ custom_spawns -= source
+ UnregisterSignal(source, COMSIG_QDELETING)
+
+
/// Someone has spawned in, so we check for their death
/datum/lazy_template/virtual_domain/island_brawl/proc/on_spawn(datum/source, mob/living/spawned_mob)
SIGNAL_HANDLER
diff --git a/code/modules/capture_the_flag/ctf_classes.dm b/code/modules/capture_the_flag/ctf_classes.dm
index 0482bd1ec88eb..8f6a03ba7dfc4 100644
--- a/code/modules/capture_the_flag/ctf_classes.dm
+++ b/code/modules/capture_the_flag/ctf_classes.dm
@@ -55,7 +55,7 @@
var/obj/item/radio/headset = human_to_equip.ears
headset.set_frequency(team_radio_freq)
headset.freqlock = RADIO_FREQENCY_LOCKED
- headset.independent = TRUE
+ headset.special_channels |= RADIO_SPECIAL_CENTCOM
human_to_equip.dna.species.stunmod = 0
/datum/outfit/ctf/instagib
diff --git a/code/modules/cards/cardhand.dm b/code/modules/cards/cardhand.dm
index ac14e17fea61b..8fc9b4d0dc70a 100644
--- a/code/modules/cards/cardhand.dm
+++ b/code/modules/cards/cardhand.dm
@@ -67,7 +67,7 @@
qdel(src) // cardhand is empty now so delete it
/obj/item/toy/cards/cardhand/proc/check_menu(mob/living/user)
- return isliving(user) && !user.incapacitated()
+ return isliving(user) && !user.incapacitated
/obj/item/toy/cards/cardhand/attackby(obj/item/weapon, mob/living/user, params, flip_card = FALSE)
var/obj/item/toy/singlecard/card
diff --git a/code/modules/cargo/centcom_podlauncher.dm b/code/modules/cargo/centcom_podlauncher.dm
index dd779c796ce8f..cd86761587680 100644
--- a/code/modules/cargo/centcom_podlauncher.dm
+++ b/code/modules/cargo/centcom_podlauncher.dm
@@ -191,7 +191,7 @@ ADMIN_VERB(centcom_podlauncher, R_ADMIN, "Config/Launch Supplypod", "Configure a
data["soundVolume"] = temp_pod.soundVolume //Admin sound to play when the pod leaves
return data
-/datum/centcom_podlauncher/ui_act(action, params)
+/datum/centcom_podlauncher/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/cargo/expressconsole.dm b/code/modules/cargo/expressconsole.dm
index 4942ea2c06a93..0a2dcfec4b0f0 100644
--- a/code/modules/cargo/expressconsole.dm
+++ b/code/modules/cargo/expressconsole.dm
@@ -128,6 +128,7 @@
if(.)
return
+ var/mob/user = ui.user
switch(action)
if("LZCargo")
usingBeacon = FALSE
@@ -143,7 +144,7 @@
if(D.adjust_money(-BEACON_COST))
cooldown = 10//a ~ten second cooldown for printing beacons to prevent spam
var/obj/item/supplypod_beacon/C = new /obj/item/supplypod_beacon(drop_location())
- C.link_console(src, usr)//rather than in beacon's Initialize(), we can assign the computer to the beacon by reusing this proc)
+ C.link_console(src, user)//rather than in beacon's Initialize(), we can assign the computer to the beacon by reusing this proc)
printed_beacons++//printed_beacons starts at 0, so the first one out will be called beacon # 1
beacon.name = "Supply Pod Beacon #[printed_beacons]"
@@ -159,13 +160,13 @@
CRASH("Unknown supply pack id given by express order console ui. ID: [params["id"]]")
var/name = "*None Provided*"
var/rank = "*None Provided*"
- var/ckey = usr.ckey
- if(ishuman(usr))
- var/mob/living/carbon/human/H = usr
+ var/ckey = user.ckey
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
name = H.get_authentification_name()
rank = H.get_assignment(hand_first = TRUE)
- else if(HAS_SILICON_ACCESS(usr))
- name = usr.real_name
+ else if(HAS_SILICON_ACCESS(user))
+ name = user.real_name
rank = "Silicon"
var/reason = ""
var/list/empty_turfs
diff --git a/code/modules/cargo/goodies.dm b/code/modules/cargo/goodies.dm
index 4751b45aae89b..aa42b5cacde44 100644
--- a/code/modules/cargo/goodies.dm
+++ b/code/modules/cargo/goodies.dm
@@ -221,7 +221,7 @@
/datum/supply_pack/goody/fishing_toolbox
name = "Fishing Toolbox"
- desc = "Complete toolbox set for your fishing adventure. Advanced hooks and lines sold separetely."
+ desc = "Complete toolbox set for your fishing adventure. Contains a valuable tip. Advanced hooks and lines sold separetely."
cost = PAYCHECK_CREW * 2
contains = list(/obj/item/storage/toolbox/fishing)
@@ -321,3 +321,9 @@
cost = PAYCHECK_COMMAND * 18
access_view = ACCESS_WEAPONS
contains = list(/obj/item/gun/ballistic/shotgun/doublebarrel)
+
+/datum/supply_pack/goody/experimental_medication
+ name = "Experimental Medication Single-Pack"
+ desc = "A single bottle of Interdyne brand experimental medication, used for treating people suffering from hereditary manifold disease."
+ cost = PAYCHECK_CREW * 6.5
+ contains = list(/obj/item/storage/pill_bottle/sansufentanyl)
diff --git a/code/modules/cargo/markets/market_item.dm b/code/modules/cargo/markets/market_item.dm
index d7a4dd4c0eef3..faa6c45d795c4 100644
--- a/code/modules/cargo/markets/market_item.dm
+++ b/code/modules/cargo/markets/market_item.dm
@@ -30,6 +30,9 @@
/// Probability for this item to be available. Used by SSmarket on init.
var/availability_prob
+ /// If set, this icon will be shown in the UI.
+ var/html_icon
+
///The identifier for the market item, generated on runtime and used to access them in the market categories.
var/identifier
@@ -51,9 +54,11 @@
//we're replacing the item to sell, and the old item is an instance!
if(ismovable(item))
UnregisterSignal(item, COMSIG_QDELETING)
+ html_icon = null
item = path_or_ref
identifier = "[path_or_ref]"
if(ismovable(path_or_ref))
+ html_icon = icon2base64(getFlatIcon(item, no_anim=TRUE))
RegisterSignal(item, COMSIG_QDELETING, PROC_REF(on_item_del))
identifier = "[REF(src)]"
diff --git a/code/modules/cargo/markets/market_items/local_goods.dm b/code/modules/cargo/markets/market_items/local_goods.dm
new file mode 100644
index 0000000000000..d81c38fec98ba
--- /dev/null
+++ b/code/modules/cargo/markets/market_items/local_goods.dm
@@ -0,0 +1,25 @@
+///A special category for goods placed on the market by station by someone with the LTSRBT.
+/datum/market_item/local_good
+ category = "Local Goods"
+ abstract_path = /datum/market_item/local_good
+ stock = 1
+ availability_prob = 100
+ restockable = FALSE
+ var/datum/bank_account/seller
+
+/datum/market_item/local_good/New(atom/movable/thing, datum/bank_account/seller)
+ ..()
+ set_item(thing)
+ src.seller = seller
+ if(seller)
+ RegisterSignal(seller, COMSIG_QDELETING, PROC_REF(delete_reference))
+
+/datum/market_item/local_good/buy(obj/item/market_uplink/uplink, mob/buyer, shipping_method, legal_status)
+ . = ..()
+ if(. && seller)
+ seller.adjust_money(round(price * (1 - MARKET_WITHHOLDING_TAX)), "Market: Item Sold")
+ QDEL_IN(src, 10 MINUTES) //This category cannot hold more than 40 items at a time, so we need to clear sold items.
+
+/datum/market_item/local_good/proc/delete_reference(datum/source)
+ SIGNAL_HANDLER
+ seller = null
diff --git a/code/modules/cargo/markets/market_items/weapons.dm b/code/modules/cargo/markets/market_items/weapons.dm
index 4f20cf865bc9b..12241450ba59a 100644
--- a/code/modules/cargo/markets/market_items/weapons.dm
+++ b/code/modules/cargo/markets/market_items/weapons.dm
@@ -24,6 +24,16 @@
stock_max = 4
availability_prob = 40
+/datum/market_item/weapon/buckshot
+ name = "Box of Buckshot Shells"
+ desc = "It wasn't easy since buckshot has been made illegal all over this sector of space, but \
+ we managed to find a large cache of it... somewhere. A word of caution, the stuff may be a tad old."
+ stock_max = 3
+ availability_prob = 35
+ item = /obj/item/storage/box/lethalshot/old
+ price_min = CARGO_CRATE_VALUE * 3
+ price_max = CARGO_CRATE_VALUE * 4.5
+
/datum/market_item/weapon/bone_spear
name = "Bone Spear"
desc = "Authentic tribal spear, made from real bones! A steal at any price, especially if you're a caveman."
diff --git a/code/modules/cargo/markets/market_telepad.dm b/code/modules/cargo/markets/market_telepad.dm
index 799395f30d125..53a3d73ee486a 100644
--- a/code/modules/cargo/markets/market_telepad.dm
+++ b/code/modules/cargo/markets/market_telepad.dm
@@ -1,4 +1,5 @@
-#define DEFAULT_RESTOCK_COST 675
+#define DEFAULT_RESTOCK_COST CARGO_CRATE_VALUE * 3.375
+#define PLACE_ON_MARKET_COST PAYCHECK_LOWER * 1.2
/obj/item/circuitboard/machine/ltsrbt
name = "LTSRBT (Machine Board)"
@@ -14,13 +15,14 @@
/obj/machinery/ltsrbt
name = "Long-To-Short-Range-Bluespace-Transceiver"
desc = "The LTSRBT is a compact teleportation machine for receiving and sending items outside the station and inside the station.\nUsing teleportation frequencies stolen from NT it is near undetectable.\nEssential for any illegal market operations on NT stations.\n"
- icon = 'icons/obj/machines/telecomms.dmi'
- icon_state = "exonet_node_idle"
- base_icon_state = "exonet_node"
+ icon = 'icons/obj/machines/ltsrbt.dmi'
+ icon_state = "ltsrbt_idle"
+ base_icon_state = "ltsrbt"
circuit = /obj/item/circuitboard/machine/ltsrbt
density = TRUE
idle_power_usage = BASE_MACHINE_IDLE_CONSUMPTION * 2
+ interaction_flags_atom = INTERACT_ATOM_ATTACK_HAND
/// Divider for energy_usage_per_teleport.
var/power_efficiency = 1
@@ -38,6 +40,12 @@
var/datum/market_purchase/transmitting
/// Queue for purchases that the machine should receive and send.
var/list/datum/market_purchase/queue = list()
+ /// The name of the market item that we've set on the UI
+ var/current_name = ""
+ /// The desc of the market item that we've set on the UI
+ var/current_desc = ""
+ /// The price of the market item that we've set on the UI
+ var/current_price = CARGO_CRATE_VALUE
/**
* Attacking the machinery with enough credits will restock the markets, allowing for more/better items.
* The cost doubles each time this is done.
@@ -48,32 +56,267 @@
. = ..()
register_context()
SSmarket.telepads += src
+ ADD_TRAIT(src, TRAIT_SECLUDED_LOCATION, INNATE_TRAIT) //you cannot sell disky, boss.
+ update_appearance()
/obj/machinery/ltsrbt/Destroy()
SSmarket.telepads -= src
// Bye bye orders.
if(length(SSmarket.telepads))
- for(var/datum/market_purchase/P in queue)
- SSmarket.queue_item(P)
- . = ..()
+ for(var/datum/market_purchase/purchase in queue)
+ SSmarket.queue_item(purchase)
+ if(receiving)
+ SSmarket.queue_item(receiving)
+ queue = null
+ receiving = null
+ transmitting = null
+ return ..()
/obj/machinery/ltsrbt/add_context(atom/source, list/context, obj/item/held_item, mob/user)
- if(held_item && held_item.get_item_credit_value())
- context[SCREENTIP_CONTEXT_LMB] = "Restock"
+ if(held_item)
+ if(state_open)
+ context[SCREENTIP_CONTEXT_LMB] = "Insert"
+ return CONTEXTUAL_SCREENTIP_SET
+ if(held_item.get_item_credit_value() && !(machine_stat & NOPOWER))
+ context[SCREENTIP_CONTEXT_LMB] = "Restock"
+ return CONTEXTUAL_SCREENTIP_SET
+ return NONE
+ if(state_open)
+ context[SCREENTIP_CONTEXT_LMB] = "Close"
return CONTEXTUAL_SCREENTIP_SET
- return NONE
+ context[SCREENTIP_CONTEXT_LMB] = "Open"
+ if(occupant && !(machine_stat & NOPOWER))
+ context[SCREENTIP_CONTEXT_RMB] = "Place on market"
+ return CONTEXTUAL_SCREENTIP_SET
/obj/machinery/ltsrbt/examine(mob/user)
. = ..()
- if(machine_stat & NOPOWER)
- . += span_info("A display reads: \"Current market restock price: [EXAMINE_HINT("[restock_cost] cr")]\".")
+ if(!(machine_stat & NOPOWER))
+ . += span_info("A small display reads:")
+ . += span_tinynoticeital("Current market restock price: [EXAMINE_HINT("[restock_cost] cr")].")
+ . += span_tinynoticeital("Market placement fee: [EXAMINE_HINT("[PLACE_ON_MARKET_COST] cr")].")
+ . += span_tinynoticeital("Withholding tax on local items: [EXAMINE_HINT("[MARKET_WITHHOLDING_TAX * 100]%")].")
/obj/machinery/ltsrbt/update_icon_state()
. = ..()
if(machine_stat & NOPOWER)
icon_state = "[base_icon_state]_off"
else
- icon_state = "[base_icon_state][(receiving || length(queue)) ? "" : "_idle"]"
+ icon_state = "[base_icon_state][(receiving || length(queue) || occupant) ? "" : "_idle"]"
+
+/obj/machinery/ltsrbt/update_overlays()
+ . = ..()
+ if(!state_open)
+ . += "[base_icon_state]_closed"
+ else
+ var/mutable_appearance/overlay = mutable_appearance(icon, "[base_icon_state]_open")
+ overlay.pixel_w -= 2
+ overlay.pixel_z -= 1
+ . += overlay
+
+/obj/machinery/ltsrbt/attack_hand(mob/user, list/modifiers)
+ . = ..()
+ if(.)
+ return
+ if(!state_open)
+ open_machine(density_to_set = TRUE)
+ else
+ close_machine()
+
+/obj/machinery/ltsrbt/open_machine(drop = TRUE, density_to_set = FALSE)
+ . = ..()
+ playsound(src, 'sound/machines/oven/oven_open.ogg', 75, TRUE)
+
+/obj/machinery/ltsrbt/close_machine(atom/movable/target, density_to_set = TRUE)
+ . = ..()
+ playsound(src, 'sound/machines/oven/oven_close.ogg', 75, TRUE)
+
+/obj/machinery/ltsrbt/set_occupant(obj/item/new_occupant)
+ . = ..()
+ if(new_occupant)
+ current_name = new_occupant.name
+ current_desc = new_occupant.desc
+
+/obj/machinery/ltsrbt/can_be_occupant(atom/movable/atom)
+ return isitem(atom) && !atom.anchored
+
+/obj/machinery/ltsrbt/Exited(atom/movable/gone)
+ if(gone == occupant)
+ current_price = initial(current_price)
+ current_name = ""
+ current_desc = ""
+ update_appearance(UPDATE_ICON_STATE)
+ return ..()
+
+/obj/machinery/ltsrbt/attack_hand_secondary(mob/user, list/modifiers)
+ . = ..()
+ if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
+ return
+ if(state_open)
+ balloon_alert(user, "close it first!")
+ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
+ if(!occupant)
+ balloon_alert(user, "nothing loaded!")
+ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
+ if(machine_stat & NOPOWER)
+ balloon_alert(user, "machine unpowered!")
+ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
+ if(!COOLDOWN_FINISHED(src, recharge_cooldown))
+ balloon_alert(user, "on cooldown!")
+ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
+ ui_interact(user)
+ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
+
+/obj/machinery/ltsrbt/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
+ if(user.combat_mode)
+ return NONE
+
+ var/creds_value = tool.get_item_credit_value()
+
+ if(state_open)
+ if(locate(/mob/living) in tool.get_all_contents())
+ say("Living being detected, cannot sell!")
+ playsound(src, 'sound/machines/buzz-sigh.ogg', 40, FALSE)
+ return ITEM_INTERACT_BLOCKING
+ if(!user.transferItemToLoc(tool, src))
+ balloon_alert(user, "stuck to your hands!")
+ return ITEM_INTERACT_BLOCKING
+ balloon_alert(user, "item loaded")
+ close_machine(tool)
+ return ITEM_INTERACT_SUCCESS
+ else if(!creds_value)
+ balloon_alert(user, "open the machine!")
+ return ITEM_INTERACT_BLOCKING
+
+ if(machine_stat & NOPOWER)
+ return
+
+ if(creds_value < restock_cost)
+ say("Insufficient credits!")
+ playsound(src, 'sound/machines/buzz-sigh.ogg', 40, FALSE)
+ return ITEM_INTERACT_BLOCKING
+
+ if(istype(tool, /obj/item/holochip))
+ var/obj/item/holochip/chip = tool
+ chip.spend(restock_cost)
+ else
+ qdel(tool)
+ if(creds_value != restock_cost)
+ var/obj/item/holochip/change = new(loc, creds_value - restock_cost)
+ user.put_in_hands(change)
+
+ SSmarket.restock()
+ restock_cost *= 2
+ return ITEM_INTERACT_SUCCESS
+
+/obj/machinery/ltsrbt/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "LTSRBT", name)
+ ui.open()
+
+/obj/machinery/ltsrbt/ui_state()
+ if(!occupant || !COOLDOWN_FINISHED(src, recharge_cooldown))
+ return GLOB.never_state //close it.
+ else
+ return GLOB.default_state
+
+#define LTSRBT_MIN_PRICE PAYCHECK_LOWER
+#define LTSRBT_MAX_PRICE CARGO_CRATE_VALUE * 50
+
+/obj/machinery/ltsrbt/ui_static_data(mob/user)
+ var/list/data = list()
+ data["loaded_icon"] = icon2base64(getFlatIcon(occupant, no_anim=TRUE))
+ data["min_price"] = LTSRBT_MIN_PRICE
+ data["max_price"] = LTSRBT_MAX_PRICE
+ return data
+
+/obj/machinery/ltsrbt/ui_data(mob/user)
+ var/list/data = list()
+ data["name"] = current_name
+ data["price"] = current_price
+ data["desc"] = current_desc
+ return data
+
+/obj/machinery/ltsrbt/ui_act(action, list/params)
+ . = ..()
+ if(.)
+ return
+ switch(action)
+ if("change_name")
+ var/value = params["value"]
+ if(!CAN_BYPASS_FILTER(usr) && is_ic_filtered_for_pdas(value))
+ return TRUE
+ current_name = trim(value, MAX_NAME_LEN)
+ return TRUE
+ if("change_desc")
+ var/value = params["value"]
+ if(!CAN_BYPASS_FILTER(usr) && is_ic_filtered_for_pdas(value))
+ return TRUE
+ current_desc = trim(value, MAX_DESC_LEN)
+ return TRUE
+ if("change_price")
+ current_price = clamp(params["value"], LTSRBT_MIN_PRICE, LTSRBT_MAX_PRICE)
+ return TRUE
+ if("place_on_market")
+ place_on_market(usr)
+ return TRUE
+
+#undef LTSRBT_MIN_PRICE
+#undef LTSRBT_MAX_PRICE
+
+#define LTSRBT_MAX_MARKET_ITEMS 40
+/obj/machinery/ltsrbt/proc/place_on_market(mob/user)
+ if(QDELETED(occupant))
+ return
+ if(locate(/mob/living) in occupant.get_all_contents())
+ say("Living being detected, cannot sell!")
+ playsound(src, 'sound/machines/buzz-sigh.ogg', 40, FALSE)
+ return
+ var/datum/bank_account/account
+ var/datum/market/our_market = SSmarket.markets[/datum/market/blackmarket]
+ if(!isAdminGhostAI(user))
+ if(!isliving(user))
+ return
+ if(length(our_market.available_items[/datum/market_item/local_good::category]) >= LTSRBT_MAX_MARKET_ITEMS)
+ say("Local market saturated, buy some goods first!")
+ playsound(src, 'sound/machines/buzz-sigh.ogg', 40, FALSE)
+ return
+ var/mob/living/living_user = user
+ var/obj/item/card/id/card = living_user.get_idcard(TRUE)
+ if(!(card?.registered_account))
+ say("No bank account to charge market fees detected!")
+ playsound(src, 'sound/machines/buzz-sigh.ogg', 40, FALSE)
+ return
+ if(!card.registered_account.adjust_money(-PLACE_ON_MARKET_COST, "Market: Placement Fee"))
+ say("Insufficient credits!")
+ playsound(src, 'sound/machines/buzz-sigh.ogg', 40, FALSE)
+ return
+ account = card.registered_account
+
+ var/obj/item/item = occupant //occupant, name, price and desc will be null'd once it exits the machine so we need this.
+ var/name_to_use = current_name || item.name
+ var/desc_to_use = current_desc
+ if(account)
+ desc_to_use += "[current_desc ? " - " : ""]Seller: [account.account_holder]"
+ var/price_to_use = current_price
+ item.moveToNullspace()
+ //Something happened and the item was deleted or relocated as soon as it was moved to nullspace.
+ if(QDELETED(item) || item.loc != null)
+ say("Runtime at market_placement.dm, line 153: item gone!") //metajoke
+ return
+ var/datum/market_item/local_good/new_item = new(item, account)
+ new_item.name = name_to_use
+ new_item.desc = desc_to_use
+ new_item.price = price_to_use
+
+ our_market.add_item(new_item)
+
+ say("Item placed on the market!")
+ playsound(src, 'sound/effects/cashregister.ogg', 40, FALSE)
+ COOLDOWN_START(src, recharge_cooldown, recharge_time * 3)
+
+#undef LTSRBT_MAX_MARKET_ITEMS
/obj/machinery/ltsrbt/RefreshParts()
. = ..()
@@ -81,7 +324,6 @@
// On tier 4 recharge_time should be 20 and by default it is 80 as scanning modules should be tier 1.
for(var/datum/stock_part/scanning_module/scanning_module in component_parts)
recharge_time -= scanning_module.tier * 1 SECONDS
- recharge_cooldown = recharge_time
power_efficiency = 0
for(var/datum/stock_part/micro_laser/laser in component_parts)
@@ -132,43 +374,17 @@
transmitting = receiving
receiving = null
- COOLDOWN_START(src, recharge_cooldown, recharge_time)
return
if(transmitting)
if(transmitting.item.loc == turf)
do_teleport(transmitting.item, get_turf(transmitting.uplink))
use_energy(energy_usage_per_teleport / power_efficiency)
QDEL_NULL(transmitting)
+ COOLDOWN_START(src, recharge_cooldown, recharge_time)
return
if(length(queue))
receiving = pick_n_take(queue)
-/obj/machinery/ltsrbt/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
- var/creds_value = tool.get_item_credit_value()
- if(!creds_value)
- return NONE
-
- . = ITEM_INTERACT_SUCCESS
-
- if(machine_stat & NOPOWER)
- return
-
- if(creds_value < restock_cost)
- say("Insufficient credits!")
- playsound(src, 'sound/machines/buzz-sigh.ogg', 40, FALSE)
- return
-
- if(istype(tool, /obj/item/holochip))
- var/obj/item/holochip/chip = tool
- chip.spend(restock_cost)
- else
- qdel(tool)
- if(creds_value != restock_cost)
- var/obj/item/holochip/change = new(creds_value - restock_cost)
- user.put_in_hands(change)
-
- SSmarket.restock()
- restock_cost *= 2
-
#undef DEFAULT_RESTOCK_COST
+#undef PLACE_ON_MARKET_COST
diff --git a/code/modules/cargo/markets/market_uplink.dm b/code/modules/cargo/markets/market_uplink.dm
index a324a2f0409be..17cad32042668 100644
--- a/code/modules/cargo/markets/market_uplink.dm
+++ b/code/modules/cargo/markets/market_uplink.dm
@@ -80,7 +80,8 @@
"name" = item.name,
"cost" = item.price,
"amount" = item.stock,
- "desc" = item.desc || item.name
+ "desc" = item.desc || item.name,
+ "html_icon" = item.html_icon,
))
return data
@@ -97,7 +98,7 @@
))
return data
-/obj/item/market_uplink/ui_act(action, params)
+/obj/item/market_uplink/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/cargo/order.dm b/code/modules/cargo/order.dm
index c675352d024b2..a10bb3da5c00c 100644
--- a/code/modules/cargo/order.dm
+++ b/code/modules/cargo/order.dm
@@ -10,10 +10,14 @@
#define MANIFEST_ERROR_ITEM (1 << 2)
/obj/item/paper/fluff/jobs/cargo/manifest
+ can_become_message_in_bottle = FALSE //A lot of these are spawned each round, they'd only dilute the pool and make it boring.
var/order_cost = 0
var/order_id = 0
var/errors = 0
+/obj/item/paper/requisition
+ can_become_message_in_bottle = FALSE //A lot of these are spawned each round, they'd only dilute the pool and make it boring.
+
/obj/item/paper/fluff/jobs/cargo/manifest/Initialize(mapload, id, cost, manifest_can_fail = TRUE)
. = ..()
order_id = id
@@ -99,7 +103,7 @@
return round(cost)
/datum/supply_order/proc/generateRequisition(turf/T)
- var/obj/item/paper/requisition_paper = new(T)
+ var/obj/item/paper/requisition/requisition_paper = new(T)
requisition_paper.name = "requisition form - #[id] ([pack.name])"
var/requisition_text = "[station_name()] Supply Requisition
"
diff --git a/code/modules/cargo/orderconsole.dm b/code/modules/cargo/orderconsole.dm
index d835c52f1e859..ae46d9943818b 100644
--- a/code/modules/cargo/orderconsole.dm
+++ b/code/modules/cargo/orderconsole.dm
@@ -329,7 +329,7 @@
else
//create the paper from the SSshuttle.shopping_list
if(length(SSshuttle.shopping_list))
- var/obj/item/paper/requisition_paper = new(get_turf(src))
+ var/obj/item/paper/requisition/requisition_paper = new(get_turf(src))
requisition_paper.name = "requisition form - [station_time_timestamp()]"
var/requisition_text = "[station_name()] Supply Requisition
"
requisition_text += "
"
diff --git a/code/modules/cargo/packs/costumes_toys.dm b/code/modules/cargo/packs/costumes_toys.dm
index de84a263597da..a25c47c5d9f88 100644
--- a/code/modules/cargo/packs/costumes_toys.dm
+++ b/code/modules/cargo/packs/costumes_toys.dm
@@ -90,7 +90,7 @@
/datum/supply_pack/costumes_toys/knucklebones
name = "Knucklebones Game Crate"
desc = "A fun dice game definitely not invented by a cult. Consult your local chaplain regarding \
- approved religious activity. Contains eighteen d6, one white crayon, and instructions on how to play."
+ approved religious activity. Contains eighteen d6, one stick of chalk, and instructions on how to play."
cost = CARGO_CRATE_VALUE * 2
contains = list(/obj/item/dice/d6 = 18,
/obj/item/paper/guides/knucklebone,
diff --git a/code/modules/cargo/packs/engineering.dm b/code/modules/cargo/packs/engineering.dm
index 771cba47df61d..e8255a58e6431 100644
--- a/code/modules/cargo/packs/engineering.dm
+++ b/code/modules/cargo/packs/engineering.dm
@@ -76,7 +76,7 @@
cost = CARGO_CRATE_VALUE * 4
contains = list(/obj/item/inducer/orderable = 2)
crate_name = "inducer crate"
- crate_type = /obj/structure/closet/crate/engineering/electrical
+ crate_type = /obj/structure/closet/crate/nakamura
/datum/supply_pack/engineering/pacman
name = "P.A.C.M.A.N Generator Crate"
@@ -86,7 +86,7 @@
access_view = ACCESS_ENGINEERING
contains = list(/obj/machinery/power/port_gen/pacman)
crate_name = "\improper PACMAN generator crate"
- crate_type = /obj/structure/closet/crate/engineering/electrical
+ crate_type = /obj/structure/closet/crate/nakamura
/datum/supply_pack/engineering/power
name = "Power Cell Crate"
@@ -328,3 +328,12 @@
)
crate_name = "radioactive nebula shielding (IMPORTANT)"
crate_type = /obj/structure/closet/crate/engineering
+
+/datum/supply_pack/engineering/portagrav
+ name = "Portable Gravity Unit Crate"
+ desc = "Contains a portable gravity unit, to make the clown float into the ceiling."
+ cost = CARGO_CRATE_VALUE * 4
+ access_view = ACCESS_ENGINEERING
+ contains = list(/obj/machinery/power/portagrav = 1)
+ crate_name = "portable gravity unit crate"
+ crate_type = /obj/structure/closet/crate/engineering
diff --git a/code/modules/cargo/packs/imports.dm b/code/modules/cargo/packs/imports.dm
index 98fc4d650212c..fc35e473f5ada 100644
--- a/code/modules/cargo/packs/imports.dm
+++ b/code/modules/cargo/packs/imports.dm
@@ -17,6 +17,7 @@
cost = CARGO_CRATE_VALUE * 2
contains = list(/obj/item/gun/ballistic/shotgun/toy = 8)
crate_name = "foam force crate"
+ crate_type = /obj/structure/closet/crate/freezer/donk
discountable = SUPPLY_PACK_STD_DISCOUNTABLE
/datum/supply_pack/imports/foamforce/bonus
@@ -30,6 +31,7 @@
/obj/item/ammo_box/magazine/toy/pistol = 2,
)
crate_name = "foam force crate"
+ crate_type = /obj/structure/closet/crate/freezer/donk
/datum/supply_pack/imports/meatmeatmeatmeat // MEAT MEAT MEAT MEAT
name = "MEAT MEAT MEAT MEAT MEAT"
@@ -141,6 +143,7 @@
/obj/item/gun/ballistic/automatic/wt550 = 2,
/obj/item/ammo_box/magazine/wt550m9 = 2,
)
+ crate_type = /obj/structure/closet/crate/secure/gorlex_weapons/jammed
/datum/supply_pack/imports/wt550ammo
name = "Smuggled WT-550 Ammo Crate"
@@ -153,7 +156,7 @@
/obj/item/ammo_box/magazine/wt550m9/wtic = 2,
)
crate_name = "emergency crate"
- crate_type = /obj/structure/closet/crate/internals
+ crate_type = /obj/structure/closet/crate/secure/gorlex_weapons/jammed
/datum/supply_pack/imports/shocktrooper
name = "Shocktrooper Crate"
@@ -169,6 +172,7 @@
/obj/item/clothing/suit/armor/vest,
/obj/item/clothing/head/helmet,
)
+ crate_type = /obj/structure/closet/crate/secure/gorlex_weapons/jammed
/datum/supply_pack/imports/specialops
name = "Special Ops Crate"
@@ -184,6 +188,7 @@
/obj/item/switchblade,
/obj/item/grenade/mirage = 5,
)
+ crate_type = /obj/structure/closet/crate/secure/gorlex_weapons/jammed
/datum/supply_pack/imports/russian
name = "Russian Surplus Military Gear Crate"
diff --git a/code/modules/cargo/packs/medical.dm b/code/modules/cargo/packs/medical.dm
index 0c626223916af..a112ada0e554f 100644
--- a/code/modules/cargo/packs/medical.dm
+++ b/code/modules/cargo/packs/medical.dm
@@ -29,7 +29,7 @@
/obj/item/reagent_containers/hypospray/medipen/ekit = 3,
/obj/item/reagent_containers/hypospray/medipen/blood_loss = 3)
crate_name = "medipen crate"
- crate_type = /obj/structure/closet/crate/medical
+ crate_type = /obj/structure/closet/crate/deforest
/datum/supply_pack/medical/coroner_crate
name = "Autopsy Kit"
@@ -121,7 +121,7 @@
/datum/supply_pack/medical/experimentalmedicine
name = "Experimental Medicine Crate"
desc = "A crate containing the medication required for living with Hereditary Manifold Sickness, Sansufentanyl."
- cost = CARGO_CRATE_VALUE * 2
+ cost = CARGO_CRATE_VALUE * 3
contains = list(/obj/item/storage/pill_bottle/sansufentanyl = 2)
crate_name = "experimental medicine crate"
crate_type = /obj/structure/closet/crate/medical
@@ -138,6 +138,7 @@
/obj/item/emergency_bed,
)
crate_name = "surgical supplies crate"
+ crate_type = /obj/structure/closet/crate/deforest
/datum/supply_pack/medical/salglucanister
name = "Heavy-Duty Saline Canister"
diff --git a/code/modules/cargo/packs/science.dm b/code/modules/cargo/packs/science.dm
index dfa2a66359336..6b4f38b95a03a 100644
--- a/code/modules/cargo/packs/science.dm
+++ b/code/modules/cargo/packs/science.dm
@@ -189,4 +189,4 @@
access_view = ACCESS_ROBOTICS
contains = list(/obj/item/mod/core/standard = 3)
crate_name = "\improper MOD core crate"
- crate_type = /obj/structure/closet/crate/secure/science/robo
+ crate_type = /obj/structure/closet/crate/nakamura
diff --git a/code/modules/cargo/packs/security.dm b/code/modules/cargo/packs/security.dm
index 05360fe913f0a..1823ef5174f94 100644
--- a/code/modules/cargo/packs/security.dm
+++ b/code/modules/cargo/packs/security.dm
@@ -36,7 +36,7 @@
/datum/supply_pack/security/forensics
name = "Forensics Crate"
desc = "Stay hot on the criminal's heels with Nanotrasen's Detective Essentials™. \
- Contains a forensics scanner, six evidence bags, camera, tape recorder, white crayon, \
+ Contains a forensics scanner, six evidence bags, camera, special board for evidences, tape recorder, stick of chalk, \
and of course, a fedora."
cost = CARGO_CRATE_VALUE * 2.5
access_view = ACCESS_MORGUE
@@ -46,6 +46,7 @@
/obj/item/taperecorder,
/obj/item/toy/crayon/white,
/obj/item/clothing/head/fedora/det_hat,
+ /obj/item/wallframe/detectiveboard
)
crate_name = "forensics crate"
diff --git a/code/modules/cargo/packs/service.dm b/code/modules/cargo/packs/service.dm
index bf6afe107d6c7..26af45f960a5e 100644
--- a/code/modules/cargo/packs/service.dm
+++ b/code/modules/cargo/packs/service.dm
@@ -245,7 +245,7 @@
/obj/item/food/ready_donk/donkhiladas,
)
crate_name = "\improper Ready-Donk crate"
- crate_type = /obj/structure/closet/crate/freezer/food
+ crate_type = /obj/structure/closet/crate/freezer/donk
discountable = SUPPLY_PACK_UNCOMMON_DISCOUNTABLE
/datum/supply_pack/service/randomized/ready_donk/fill(obj/structure/closet/crate/C)
@@ -269,6 +269,7 @@
/obj/item/reagent_containers/cup/bottle/syrup_bottle/caramel, //one extra syrup as a treat
)
crate_name = "coffee equipment crate"
+ crate_type = /obj/structure/closet/crate/robust
discountable = SUPPLY_PACK_UNCOMMON_DISCOUNTABLE
/datum/supply_pack/service/coffeemaker
diff --git a/code/modules/cargo/packs/vending_restock.dm b/code/modules/cargo/packs/vending_restock.dm
index 10ae874d5d6c9..e5ae6f25c9371 100644
--- a/code/modules/cargo/packs/vending_restock.dm
+++ b/code/modules/cargo/packs/vending_restock.dm
@@ -17,7 +17,14 @@
cost = CARGO_CRATE_VALUE * 2
contains = list(/obj/item/vending_refill/cigarette)
crate_name = "cigarette supply crate"
- crate_type = /obj/structure/closet/crate
+ crate_type = /obj/structure/closet/crate/robust
+
+/datum/supply_pack/vending/science/cytopro
+ name = "Cytology Vendor Supply Crate"
+ desc = "For all your vat-growing needs! Contains a CytoPro machine refill."
+ cost = CARGO_CRATE_VALUE * 3
+ contains = list(/obj/item/vending_refill/cytopro)
+ crate_name = "cytopro supply crate"
/datum/supply_pack/vending/dinnerware
name = "Dinnerware Supply Crate"
@@ -106,6 +113,7 @@
cost = CARGO_CRATE_VALUE * 2
contains = list(/obj/item/vending_refill/snack)
crate_name = "snacks supply crate"
+ crate_type = /obj/structure/closet/crate/robust
/datum/supply_pack/vending/cola
name = "Softdrinks Supply Crate"
diff --git a/code/modules/cargo/universal_scanner.dm b/code/modules/cargo/universal_scanner.dm
index 484f4a7a03201..9ce1771421e61 100644
--- a/code/modules/cargo/universal_scanner.dm
+++ b/code/modules/cargo/universal_scanner.dm
@@ -257,7 +257,7 @@
/obj/item/universal_scanner/proc/check_menu(mob/living/user)
if(!istype(user))
return FALSE
- if(user.incapacitated())
+ if(user.incapacitated)
return FALSE
return TRUE
diff --git a/code/modules/client/client_defines.dm b/code/modules/client/client_defines.dm
index 2b60b3bdbb2e4..c8e9e9a64c270 100644
--- a/code/modules/client/client_defines.dm
+++ b/code/modules/client/client_defines.dm
@@ -45,8 +45,6 @@
var/datum/click_intercept = null
///Time when the click was intercepted
var/click_intercept_time = 0
- ///Used for admin AI interaction
- var/AI_Interact = FALSE
///Used to cache this client's bans to save on DB queries
var/ban_cache = null
diff --git a/code/modules/client/preferences/_preference.dm b/code/modules/client/preferences/_preference.dm
index 1ba43cf3d8a63..2ed2405f37687 100644
--- a/code/modules/client/preferences/_preference.dm
+++ b/code/modules/client/preferences/_preference.dm
@@ -111,10 +111,6 @@ GLOBAL_LIST_INIT(preference_entries_by_key, init_preference_entries_by_key())
/// DOES have random body on, will this already be randomized?
var/randomize_by_default = TRUE
- /// If the selected species has this in its /datum/species/mutant_bodyparts,
- /// will show the feature as selectable.
- var/relevant_mutant_bodypart = null
-
/// If the selected species has this in its /datum/species/body_markings,
/// will show the feature as selectable.
var/relevant_body_markings = null
@@ -336,8 +332,7 @@ GLOBAL_LIST_INIT(preference_entries_by_key, init_preference_entries_by_key())
SHOULD_NOT_SLEEP(TRUE)
if ( \
- !isnull(relevant_mutant_bodypart) \
- || !isnull(relevant_inherent_trait) \
+ !isnull(relevant_inherent_trait) \
|| !isnull(relevant_external_organ) \
|| !isnull(relevant_head_flag) \
|| !isnull(relevant_body_markings) \
diff --git a/code/modules/client/preferences/paraplegic.dm b/code/modules/client/preferences/paraplegic.dm
new file mode 100644
index 0000000000000..1ffa704c77d0b
--- /dev/null
+++ b/code/modules/client/preferences/paraplegic.dm
@@ -0,0 +1,20 @@
+/datum/preference/choiced/paraplegic
+ category = PREFERENCE_CATEGORY_MANUALLY_RENDERED
+ savefile_key = "paraplegic"
+ savefile_identifier = PREFERENCE_CHARACTER
+
+/datum/preference/choiced/paraplegic/init_possible_values()
+ return GLOB.paraplegic_choice
+
+/datum/preference/choiced/paraplegic/create_default_value()
+ return "Default"
+
+/datum/preference/choiced/paraplegic/is_accessible(datum/preferences/preferences)
+ . = ..()
+ if (!.)
+ return FALSE
+
+ return "Paraplegic" in preferences.all_quirks
+
+/datum/preference/choiced/paraplegic/apply_to_human(mob/living/carbon/human/target, value)
+ return
diff --git a/code/modules/client/preferences/species_features/felinid.dm b/code/modules/client/preferences/species_features/felinid.dm
index 4c874ea7df750..be90d806323d3 100644
--- a/code/modules/client/preferences/species_features/felinid.dm
+++ b/code/modules/client/preferences/species_features/felinid.dm
@@ -20,7 +20,7 @@
savefile_identifier = PREFERENCE_CHARACTER
category = PREFERENCE_CATEGORY_SECONDARY_FEATURES
can_randomize = FALSE
- relevant_mutant_bodypart = "ears"
+ relevant_external_organ = /obj/item/organ/internal/ears/cat
/datum/preference/choiced/ears/init_possible_values()
return assoc_to_keys_features(SSaccessories.ears_list)
diff --git a/code/modules/client/preferences/species_features/lizard.dm b/code/modules/client/preferences/species_features/lizard.dm
index 66c107153305e..11fefc17b8b9e 100644
--- a/code/modules/client/preferences/species_features/lizard.dm
+++ b/code/modules/client/preferences/species_features/lizard.dm
@@ -93,13 +93,51 @@
savefile_key = "feature_lizard_legs"
savefile_identifier = PREFERENCE_CHARACTER
category = PREFERENCE_CATEGORY_SECONDARY_FEATURES
- relevant_mutant_bodypart = "legs"
/datum/preference/choiced/lizard_legs/init_possible_values()
- return assoc_to_keys_features(SSaccessories.legs_list)
+ return list(NORMAL_LEGS, DIGITIGRADE_LEGS)
/datum/preference/choiced/lizard_legs/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["legs"] = value
+ // Hack to update the dummy in the preference menu
+ // (Because digi legs are ONLY handled on species change)
+ if(!isdummy(target) || target.dna.species.digitigrade_customization == DIGITIGRADE_NEVER)
+ return
+
+ var/list/correct_legs = target.dna.species.bodypart_overrides.Copy() & list(BODY_ZONE_R_LEG, BODY_ZONE_L_LEG)
+
+ if(value == DIGITIGRADE_LEGS)
+ correct_legs[BODY_ZONE_R_LEG] = /obj/item/bodypart/leg/right/digitigrade
+ correct_legs[BODY_ZONE_L_LEG] = /obj/item/bodypart/leg/left/digitigrade
+
+ for(var/obj/item/bodypart/old_part as anything in target.bodyparts)
+ if(old_part.change_exempt_flags & BP_BLOCK_CHANGE_SPECIES)
+ continue
+
+ var/path = correct_legs[old_part.body_zone]
+ if(!path)
+ continue
+ var/obj/item/bodypart/new_part = new path()
+ new_part.replace_limb(target, TRUE)
+ new_part.update_limb(is_creating = TRUE)
+ qdel(old_part)
+
+/datum/preference/choiced/lizard_legs/is_accessible(datum/preferences/preferences)
+ if(!..())
+ return FALSE
+ var/datum/species/species_type = preferences.read_preference(/datum/preference/choiced/species)
+ return initial(species_type.digitigrade_customization) == DIGITIGRADE_OPTIONAL
+
+
+/datum/preference/choiced/lizard_legs/is_accessible(datum/preferences/preferences)
+ . = ..()
+
+ if(!.)
+ return
+
+ var/datum/species/species_type = preferences.read_preference(/datum/preference/choiced/species)
+
+ return initial(species_type.digitigrade_customization) & DIGITIGRADE_OPTIONAL
/datum/preference/choiced/lizard_snout
savefile_key = "feature_lizard_snout"
@@ -121,7 +159,7 @@
savefile_key = "feature_lizard_spines"
savefile_identifier = PREFERENCE_CHARACTER
category = PREFERENCE_CATEGORY_SECONDARY_FEATURES
- relevant_mutant_bodypart = "spines"
+ relevant_external_organ = /obj/item/organ/external/spines
/datum/preference/choiced/lizard_spines/init_possible_values()
return assoc_to_keys_features(SSaccessories.spines_list)
diff --git a/code/modules/client/preferences/species_features/mushperson.dm b/code/modules/client/preferences/species_features/mushperson.dm
index 45bd9c4b72620..4b624e9c02b4f 100644
--- a/code/modules/client/preferences/species_features/mushperson.dm
+++ b/code/modules/client/preferences/species_features/mushperson.dm
@@ -2,7 +2,7 @@
savefile_key = "feature_mushperson_cap"
savefile_identifier = PREFERENCE_CHARACTER
category = PREFERENCE_CATEGORY_SECONDARY_FEATURES
- relevant_mutant_bodypart = "cap"
+ relevant_external_organ = /obj/item/organ/external/mushroom_cap
/datum/preference/choiced/mushroom_cap/init_possible_values()
return assoc_to_keys_features(SSaccessories.caps_list)
diff --git a/code/modules/clothing/chameleon/generic_chameleon_clothing.dm b/code/modules/clothing/chameleon/generic_chameleon_clothing.dm
index 47b6f4db185a5..69800031f73a3 100644
--- a/code/modules/clothing/chameleon/generic_chameleon_clothing.dm
+++ b/code/modules/clothing/chameleon/generic_chameleon_clothing.dm
@@ -107,6 +107,7 @@ do { \
greyscale_colors = null
resistance_flags = NONE
+ body_parts_covered = HANDS|ARMS
armor_type = /datum/armor/gloves_chameleon
actions_types = list(/datum/action/item_action/chameleon/change/gloves)
clothing_traits = list(TRAIT_FAST_CUFFING)
@@ -218,6 +219,7 @@ do { \
desc = "A pair of black shoes."
icon_state = "sneakers"
inhand_icon_state = "sneakers_back"
+ body_parts_covered = FEET|LEGS
greyscale_colors = "#545454#ffffff"
greyscale_config = /datum/greyscale_config/sneakers
greyscale_config_worn = /datum/greyscale_config/sneakers/worn
diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm
index 1998b7abc4db3..d4705aee14c43 100644
--- a/code/modules/clothing/clothing.dm
+++ b/code/modules/clothing/clothing.dm
@@ -528,7 +528,7 @@ BLIND // can't see anything
update_appearance() //most of the time the sprite changes
/obj/item/clothing/proc/can_use(mob/user)
- return istype(user) && !user.incapacitated()
+ return istype(user) && !user.incapacitated
/obj/item/clothing/proc/spawn_shreds()
new /obj/effect/decal/cleanable/shreds(get_turf(src), name)
diff --git a/code/modules/clothing/gloves/punch_mitts.dm b/code/modules/clothing/gloves/punch_mitts.dm
new file mode 100644
index 0000000000000..07d93d5ab021c
--- /dev/null
+++ b/code/modules/clothing/gloves/punch_mitts.dm
@@ -0,0 +1,24 @@
+/obj/item/clothing/gloves/fingerless/punch_mitts
+ name = "punching mitts"
+ desc = "Fingerless gloves with nasty spikes attached. Allows the wearer to utilize the ill-reputed fighting technique known as Hunter Boxing. The style \
+ allows the user to punch wildlife rapidly to death. Supposedly, this is an incredible workout, but few people are insane enough to attempt to \
+ punch every dangerous creature they encounter in the wild to death with their bare hands. Also kinda works against humanoids as well. \
+ Not that you would... right?"
+ icon_state = "punch_mitts"
+ body_parts_covered = HANDS|ARMS
+ resistance_flags = LAVA_PROOF | FIRE_PROOF
+ armor_type = /datum/armor/gloves_mitts
+
+/obj/item/clothing/gloves/fingerless/punch_mitts/Initialize(mapload)
+ . = ..()
+
+ AddComponent(/datum/component/martial_art_giver, /datum/martial_art/boxing/hunter)
+
+/datum/armor/gloves_mitts
+ melee = 25
+ bullet = 5
+ laser = 5
+ energy = 5
+ bomb = 100
+ fire = 100
+ acid = 30
diff --git a/code/modules/clothing/gloves/special.dm b/code/modules/clothing/gloves/special.dm
index d7fb34ae7c7e6..1366a29ac4a6e 100644
--- a/code/modules/clothing/gloves/special.dm
+++ b/code/modules/clothing/gloves/special.dm
@@ -155,3 +155,95 @@
siemens_coefficient = 0.3
clothing_traits = list(TRAIT_QUICKER_CARRY, TRAIT_CHUNKYFINGERS)
clothing_flags = THICKMATERIAL
+
+///A pair of gloves that both allow the user to fish without the need of a held fishing rod and provides athletics experience.
+/obj/item/clothing/gloves/fishing
+ name = "athletic fishing gloves"
+ desc = "A pair of gloves to fish without a fishing rod but your raw athletics strength. It doubles as a good workout device. WARNING: May cause injuries when catching bigger fish."
+ icon_state = "fishing_gloves"
+
+/obj/item/clothing/gloves/fishing/Initialize(mapload)
+ . = ..()
+ AddComponent(/datum/component/profound_fisher, new /obj/item/fishing_rod/mob_fisher/athletic(src))
+
+/obj/item/clothing/gloves/fishing/equipped(mob/user, slot)
+ . = ..()
+ if(slot == ITEM_SLOT_GLOVES)
+ RegisterSignal(user, SIGNAL_ADDTRAIT(TRAIT_ACTIVELY_FISHING), PROC_REF(begin_workout))
+
+/obj/item/clothing/gloves/fishing/dropped(mob/user)
+ UnregisterSignal(user, list(SIGNAL_ADDTRAIT(TRAIT_ACTIVELY_FISHING), SIGNAL_REMOVETRAIT(TRAIT_ACTIVELY_FISHING)))
+ STOP_PROCESSING(SSprocessing, src)
+ return ..()
+
+/obj/item/clothing/gloves/fishing/proc/begin_workout(datum/source)
+ SIGNAL_HANDLER
+ RegisterSignal(source, SIGNAL_REMOVETRAIT(TRAIT_ACTIVELY_FISHING), PROC_REF(stop_workout))
+ if(HAS_TRAIT(source, TRAIT_PROFOUND_FISHER)) //Only begin working out if we're fishing with these gloves and not some other fishing rod..
+ START_PROCESSING(SSprocessing, src)
+
+/obj/item/clothing/gloves/fishing/proc/stop_workout(datum/source)
+ SIGNAL_HANDLER
+ UnregisterSignal(source, SIGNAL_REMOVETRAIT(TRAIT_ACTIVELY_FISHING))
+ STOP_PROCESSING(SSprocessing, src)
+
+/obj/item/clothing/gloves/fishing/process(seconds_per_tick)
+ var/mob/living/wearer = loc
+ var/list/trait_source = GET_TRAIT_SOURCES(wearer, TRAIT_ACTIVELY_FISHING)
+ var/datum/fishing_challenge/challenge = trait_source[1]
+ var/stamina_exhaustion = 2.5 + challenge.difficulty * 0.025
+ var/is_heavy_gravity = wearer.has_gravity() > STANDARD_GRAVITY
+ var/obj/item/organ/internal/cyberimp/chest/spine/potential_spine = wearer.get_organ_slot(ORGAN_SLOT_SPINE)
+ if(istype(potential_spine))
+ stamina_exhaustion *= potential_spine.athletics_boost_multiplier
+ if(HAS_TRAIT(wearer, TRAIT_STRENGTH))
+ stamina_exhaustion *= 0.5
+
+ var/experience = 0.3 + challenge.difficulty * 0.003
+ if(is_heavy_gravity)
+ stamina_exhaustion *= 1.5
+ experience *= 2
+
+ wearer.adjustStaminaLoss(stamina_exhaustion)
+ wearer.mind?.adjust_experience(/datum/skill/athletics, experience)
+ wearer.apply_status_effect(/datum/status_effect/exercised)
+
+///The internal fishing rod of the athletic fishing gloves. The more athletic you're, the easier the minigame will be.
+/obj/item/fishing_rod/mob_fisher/athletic
+ icon = /obj/item/clothing/gloves/fishing::icon
+ icon_state = /obj/item/clothing/gloves/fishing::icon_state
+ line = null
+ bait = null
+ ui_description = "The integrated fishing rod of a pair of athletic fishing gloves"
+
+/obj/item/fishing_rod/mob_fisher/athletic/Initialize(mapload)
+ . = ..()
+ RegisterSignal(src, COMSIG_FISHING_ROD_CAUGHT_FISH, PROC_REF(noodling_is_dangerous))
+
+/obj/item/fishing_rod/mob_fisher/athletic/get_fishing_overlays()
+ return list()
+
+/obj/item/fishing_rod/mob_fisher/athletic/hook_hit(atom/atom_hit_by_hook_projectile, mob/user)
+ difficulty_modifier = -3 * user.mind?.get_skill_level(/datum/skill/athletics)
+ return ..()
+
+/obj/item/fishing_rod/mob_fisher/athletic/proc/noodling_is_dangerous(datum/source, atom/movable/reward, mob/living/user)
+ SIGNAL_HANDLER
+ if(!isfish(reward))
+ return
+ var/damage = 0
+ var/obj/item/fish/fishe = reward
+ switch(fishe.w_class)
+ if(WEIGHT_CLASS_BULKY)
+ damage = 10
+ if(WEIGHT_CLASS_HUGE)
+ damage = 14
+ if(WEIGHT_CLASS_GIGANTIC)
+ damage = 18
+ if(!damage && fishe.weight >= 2000)
+ damage = 5
+ damage = round(damage * fishe.weight * 0.0005)
+ if(damage)
+ var/body_zone = pick(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM)
+ user.apply_damage(damage, BRUTE, body_zone, user.run_armor_check(body_zone, MELEE))
+ playsound(src,'sound/weapons/bite.ogg', damage * 2, TRUE)
diff --git a/code/modules/clothing/head/costume.dm b/code/modules/clothing/head/costume.dm
index 13a6e549b0e91..a1cfd37ec0db0 100644
--- a/code/modules/clothing/head/costume.dm
+++ b/code/modules/clothing/head/costume.dm
@@ -87,6 +87,10 @@
clothing_flags = SNUG_FIT
flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR|HIDESNOUT
+/obj/item/clothing/head/costume/lobsterhat/Initialize(mapload)
+ . = ..()
+ AddComponent(/datum/component/speechmod, replacements = strings("crustacean_replacement.json", "crustacean"))
+
/obj/item/clothing/head/costume/drfreezehat
name = "doctor freeze's wig"
desc = "A cool wig for cool people."
@@ -115,14 +119,10 @@
/obj/item/clothing/head/costume/cardborg/equipped(mob/living/user, slot)
..()
if(ishuman(user) && (slot & ITEM_SLOT_HEAD))
- var/mob/living/carbon/human/H = user
- if(istype(H.wear_suit, /obj/item/clothing/suit/costume/cardborg))
- var/obj/item/clothing/suit/costume/cardborg/CB = H.wear_suit
- CB.disguise(user, src)
-
-/obj/item/clothing/head/costume/cardborg/dropped(mob/living/user)
- ..()
- user.remove_alt_appearance("standard_borg_disguise")
+ var/mob/living/carbon/human/human_user = user
+ if(istype(human_user.wear_suit, /obj/item/clothing/suit/costume/cardborg))
+ var/obj/item/clothing/suit/costume/cardborg/suit = human_user.wear_suit
+ suit.disguise(user, src)
/obj/item/clothing/head/costume/bronze
name = "bronze hat"
diff --git a/code/modules/clothing/head/fedora.dm b/code/modules/clothing/head/fedora.dm
index e4e8d4b54368d..cf0d23ac37f58 100644
--- a/code/modules/clothing/head/fedora.dm
+++ b/code/modules/clothing/head/fedora.dm
@@ -35,3 +35,9 @@
name = "carpskin fedora"
icon_state = "fedora_carpskin"
inhand_icon_state = null
+
+/obj/item/clothing/head/fedora/beige/press
+ name = "press fedora"
+ desc = "An beige fedora with a piece of paper saying \"PRESS\" stuck in its rim."
+ icon_state = "fedora_press"
+ inhand_icon_state = null
diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm
index 76c230ca504d2..2874a27b72b98 100644
--- a/code/modules/clothing/head/helmet.dm
+++ b/code/modules/clothing/head/helmet.dm
@@ -75,6 +75,16 @@
update_appearance()
return CLICK_ACTION_SUCCESS
+/obj/item/clothing/head/helmet/press
+ name = "press helmet"
+ desc = "A blue helmet used to distinguish non-combatant \"PRESS\" members, like if anyone cares."
+ icon_state = "helmet_press"
+
+/obj/item/clothing/head/helmet/press/worn_overlays(mutable_appearance/standing, isinhands, icon_file)
+ . = ..()
+ if(!isinhands)
+ . += emissive_appearance(icon_file, "[icon_state]-emissive", src, alpha = src.alpha)
+
/obj/item/clothing/head/helmet/alt
name = "bulletproof helmet"
desc = "A bulletproof combat helmet that excels in protecting the wearer against traditional projectile weaponry and explosives to a minor extent."
@@ -101,6 +111,7 @@
name = "tactical combat helmet"
desc = "A tactical black helmet, sealed from outside hazards with a plate of glass and not much else."
icon_state = "marine_command"
+ base_icon_state = "marine_command"
inhand_icon_state = "marine_helmet"
armor_type = /datum/armor/helmet_marine
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
@@ -126,14 +137,17 @@
/obj/item/clothing/head/helmet/marine/security
name = "marine heavy helmet"
icon_state = "marine_security"
+ base_icon_state = "marine_security"
/obj/item/clothing/head/helmet/marine/engineer
name = "marine utility helmet"
icon_state = "marine_engineer"
+ base_icon_state = "marine_engineer"
/obj/item/clothing/head/helmet/marine/medic
name = "marine medic helmet"
icon_state = "marine_medic"
+ base_icon_state = "marine_medic"
/obj/item/clothing/head/helmet/marine/pmc
icon_state = "marine"
diff --git a/code/modules/clothing/head/jobs.dm b/code/modules/clothing/head/jobs.dm
index a5041de7fa0a9..5d5fc87d409f4 100644
--- a/code/modules/clothing/head/jobs.dm
+++ b/code/modules/clothing/head/jobs.dm
@@ -54,7 +54,7 @@
/obj/item/clothing/head/utility/chefhat/proc/on_mouse_emote(mob/living/source, key, emote_message, type_override)
SIGNAL_HANDLER
var/mob/living/carbon/wearer = loc
- if(!wearer || wearer.incapacitated(IGNORE_RESTRAINTS))
+ if(!wearer || INCAPACITATED_IGNORING(wearer, INCAPABLE_RESTRAINTS))
return
if (!prob(mouse_control_probability))
return COMPONENT_CANT_EMOTE
@@ -68,7 +68,7 @@
return COMPONENT_MOVABLE_BLOCK_PRE_MOVE // Didn't roll well enough or on cooldown
var/mob/living/carbon/wearer = loc
- if(!wearer || wearer.incapacitated(IGNORE_RESTRAINTS))
+ if(!wearer || INCAPACITATED_IGNORING(wearer, INCAPABLE_RESTRAINTS))
return COMPONENT_MOVABLE_BLOCK_PRE_MOVE // Not worn or can't move
var/move_direction = get_dir(wearer, moved_to)
diff --git a/code/modules/clothing/head/soft_caps.dm b/code/modules/clothing/head/soft_caps.dm
index cb0f9033960c3..f8e7e80532f16 100644
--- a/code/modules/clothing/head/soft_caps.dm
+++ b/code/modules/clothing/head/soft_caps.dm
@@ -33,7 +33,7 @@
/obj/item/clothing/head/soft/proc/flip(mob/user)
- if(!user.incapacitated())
+ if(!user.incapacitated)
flipped = !flipped
if(flipped)
icon_state = "[soft_type][soft_suffix]_flipped"
@@ -173,6 +173,7 @@
/obj/item/clothing/head/soft/fishing_hat/Initialize(mapload)
. = ..()
+ AddComponent(/datum/component/speechmod, replacements = strings("crustacean_replacement.json", "crustacean")) //you asked for this.
AddElement(/datum/element/skill_reward, /datum/skill/fishing)
#define PROPHAT_MOOD "prophat"
diff --git a/code/modules/clothing/masks/gasmask.dm b/code/modules/clothing/masks/gasmask.dm
index cab7a6557e3c4..c5871d23c1859 100644
--- a/code/modules/clothing/masks/gasmask.dm
+++ b/code/modules/clothing/masks/gasmask.dm
@@ -301,14 +301,14 @@ GLOBAL_LIST_INIT(clown_mask_options, list(
AddElement(/datum/element/swabable, CELL_LINE_TABLE_CLOWN, CELL_VIRUS_TABLE_GENERIC, rand(2,3), 0)
/obj/item/clothing/mask/gas/clown_hat/ui_action_click(mob/user)
- if(!istype(user) || user.incapacitated())
+ if(!istype(user) || user.incapacitated)
return
var/choice = show_radial_menu(user,src, clownmask_designs, custom_check = FALSE, radius = 36, require_near = TRUE)
if(!choice)
return FALSE
- if(src && choice && !user.incapacitated() && in_range(user,src))
+ if(src && choice && !user.incapacitated && in_range(user,src))
var/list/options = GLOB.clown_mask_options
icon_state = options[choice]
user.update_worn_mask()
@@ -355,7 +355,7 @@ GLOBAL_LIST_INIT(clown_mask_options, list(
)
/obj/item/clothing/mask/gas/mime/ui_action_click(mob/user)
- if(!istype(user) || user.incapacitated())
+ if(!istype(user) || user.incapacitated)
return
var/list/options = list()
@@ -368,7 +368,7 @@ GLOBAL_LIST_INIT(clown_mask_options, list(
if(!choice)
return FALSE
- if(src && choice && !user.incapacitated() && in_range(user,src))
+ if(src && choice && !user.incapacitated && in_range(user,src))
icon_state = options[choice]
user.update_worn_mask()
update_item_action_buttons()
diff --git a/code/modules/clothing/outfits/ert.dm b/code/modules/clothing/outfits/ert.dm
index 2aa61b0046070..101cedfef88eb 100644
--- a/code/modules/clothing/outfits/ert.dm
+++ b/code/modules/clothing/outfits/ert.dm
@@ -104,6 +104,8 @@
l_pocket = /obj/item/healthanalyzer/advanced
additional_radio = /obj/item/encryptionkey/heads/cmo
+ skillchips = list(/obj/item/skillchip/entrails_reader)
+
/datum/outfit/centcom/ert/medic/alert
name = "ERT Medic - High Alert"
@@ -133,6 +135,9 @@
l_pocket = /obj/item/rcd_ammo/large
additional_radio = /obj/item/encryptionkey/heads/ce
+
+ skillchips = list(/obj/item/skillchip/job/engineer)
+
/datum/outfit/centcom/ert/engineer/alert
name = "ERT Engineer - High Alert"
@@ -520,6 +525,9 @@
glasses = /obj/item/clothing/glasses/hud/health/sunglasses
additional_radio = /obj/item/encryptionkey/heads/cmo
+
+ skillchips = list(/obj/item/skillchip/entrails_reader)
+
/datum/outfit/centcom/ert/marine/engineer
name = "Marine Engineer"
@@ -533,6 +541,8 @@
glasses = /obj/item/clothing/glasses/hud/diagnostic/sunglasses
additional_radio = /obj/item/encryptionkey/heads/ce
+ skillchips = list(/obj/item/skillchip/job/engineer)
+
/datum/outfit/centcom/militia
name = "Militia Man"
diff --git a/code/modules/clothing/shoes/boots.dm b/code/modules/clothing/shoes/boots.dm
index dbfa4f8b3c40d..03f174aa43c31 100644
--- a/code/modules/clothing/shoes/boots.dm
+++ b/code/modules/clothing/shoes/boots.dm
@@ -3,6 +3,7 @@
desc = "High speed, low drag combat boots."
icon_state = "jackboots"
inhand_icon_state = "jackboots"
+ body_parts_covered = FEET|LEGS
armor_type = /datum/armor/shoes_combat
strip_delay = 40
resistance_flags = NONE
@@ -49,6 +50,7 @@
resistance_flags = NONE
armor_type = /datum/armor/shoes_jackboots
can_be_tied = FALSE
+ body_parts_covered = FEET|LEGS
/datum/armor/shoes_jackboots
bio = 90
@@ -108,6 +110,7 @@
strip_delay = 4 SECONDS
equip_delay_other = 4 SECONDS
clothing_flags = THICKMATERIAL
+ body_parts_covered = FEET|LEGS
resistance_flags = NONE
/datum/armor/ice_boots_eva
@@ -177,6 +180,7 @@
strip_delay = 40
resistance_flags = NONE
lace_time = 12 SECONDS
+ body_parts_covered = FEET|LEGS
/datum/armor/shoes_pirate
melee = 25
diff --git a/code/modules/clothing/shoes/cowboy.dm b/code/modules/clothing/shoes/cowboy.dm
index 4295b91cad2f5..ab8ef30c99b60 100644
--- a/code/modules/clothing/shoes/cowboy.dm
+++ b/code/modules/clothing/shoes/cowboy.dm
@@ -109,3 +109,4 @@
desc = "And they sing, oh, ain't you glad you're single? And that song ain't so very far from wrong."
armor_type = /datum/armor/shoes_combat
has_spurs = TRUE
+ body_parts_covered = FEET|LEGS
diff --git a/code/modules/clothing/shoes/cult.dm b/code/modules/clothing/shoes/cult.dm
index 80d03d3a09e25..f1a856b42688b 100644
--- a/code/modules/clothing/shoes/cult.dm
+++ b/code/modules/clothing/shoes/cult.dm
@@ -1,5 +1,5 @@
/obj/item/clothing/shoes/cult
- name = "\improper Nar'Sien invoker boots"
+ name = "\improper Nar'Sian boots"
desc = "A pair of boots worn by the followers of Nar'Sie."
icon_state = "cult"
inhand_icon_state = null
@@ -10,7 +10,7 @@
lace_time = 10 SECONDS
/obj/item/clothing/shoes/cult/alt
- name = "cultist boots"
+ name = "\improper Nar'Sian invoker boots"
icon_state = "cultalt"
/obj/item/clothing/shoes/cult/alt/ghost
diff --git a/code/modules/clothing/shoes/jumpboots.dm b/code/modules/clothing/shoes/jumpboots.dm
index 3446c2e7c7873..dc9dadcea5a53 100644
--- a/code/modules/clothing/shoes/jumpboots.dm
+++ b/code/modules/clothing/shoes/jumpboots.dm
@@ -36,6 +36,7 @@
user.visible_message(span_warning("[usr] dashes forward into the air!"))
recharging_time = world.time + recharging_rate
else
+ REMOVE_TRAIT(user, TRAIT_MOVE_FLOATING, LEAPING_TRAIT)
to_chat(user, span_warning("Something prevents you from dashing forward!"))
/obj/item/clothing/shoes/bhop/rocket
diff --git a/code/modules/clothing/spacesuits/_spacesuits.dm b/code/modules/clothing/spacesuits/_spacesuits.dm
index 703000a1f9133..caf84d9562dcb 100644
--- a/code/modules/clothing/spacesuits/_spacesuits.dm
+++ b/code/modules/clothing/spacesuits/_spacesuits.dm
@@ -24,6 +24,7 @@
flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH | PEPPERPROOF
resistance_flags = NONE
dog_fashion = null
+ slowdown = 0.5
/datum/armor/helmet_space
bio = 100
@@ -47,7 +48,7 @@
/obj/item/tank/internals,
/obj/item/tank/jetpack/oxygen/captain,
)
- slowdown = 1
+ slowdown = 0.5
armor_type = /datum/armor/suit_space
flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
cold_protection = CHEST | GROIN | LEGS | FEET | ARMS | HANDS
diff --git a/code/modules/clothing/spacesuits/pirate.dm b/code/modules/clothing/spacesuits/pirate.dm
index ca041d68d036f..73feec525c548 100644
--- a/code/modules/clothing/spacesuits/pirate.dm
+++ b/code/modules/clothing/spacesuits/pirate.dm
@@ -3,6 +3,7 @@
desc = "A modified helmet to allow space pirates to intimidate their customers whilst staying safe from the void. Comes with some additional protection."
icon_state = "spacepirate"
inhand_icon_state = "space_pirate_helmet"
+ slowdown = 0
armor_type = /datum/armor/space_pirate
strip_delay = 40
equip_delay_other = 20
diff --git a/code/modules/clothing/spacesuits/santa.dm b/code/modules/clothing/spacesuits/santa.dm
index 138f52e046e47..f6bd1657606c5 100644
--- a/code/modules/clothing/spacesuits/santa.dm
+++ b/code/modules/clothing/spacesuits/santa.dm
@@ -7,6 +7,7 @@
inhand_icon_state = "santahat"
flags_cover = HEADCOVERSEYES
dog_fashion = /datum/dog_fashion/head/santa
+ slowdown = 0
/obj/item/clothing/head/helmet/space/santahat/beardless
icon = 'icons/obj/clothing/head/costume.dmi'
@@ -14,6 +15,7 @@
icon_state = "santahatnorm"
inhand_icon_state = "that"
flags_inv = NONE
+ slowdown = 0
/obj/item/clothing/suit/space/santa
name = "Santa's suit"
diff --git a/code/modules/clothing/spacesuits/softsuit.dm b/code/modules/clothing/spacesuits/softsuit.dm
index 510c9e7056f2f..0b644286063ec 100644
--- a/code/modules/clothing/spacesuits/softsuit.dm
+++ b/code/modules/clothing/spacesuits/softsuit.dm
@@ -16,13 +16,14 @@
name = "Engineering Void Helmet"
desc = "A CentCom engineering dark red space suit helmet. While old and dusty, it still gets the job done."
icon_state = "void"
+ slowdown = 2
/obj/item/clothing/suit/space/nasavoid/old
name = "Engineering Voidsuit"
icon_state = "void"
inhand_icon_state = "void_suit"
desc = "A CentCom engineering dark red space suit. Age has degraded the suit making it difficult to move around in."
- slowdown = 4
+ slowdown = 2
allowed = list(/obj/item/flashlight, /obj/item/tank/internals, /obj/item/multitool)
//EVA suit
@@ -72,6 +73,7 @@
inhand_icon_state = "syndicate-helm-orange" //resprite?
armor_type = /datum/armor/space_fragile
strip_delay = 65
+ slowdown = 1
/obj/item/clothing/suit/space/fragile
name = "emergency space suit"
@@ -79,7 +81,7 @@
var/torn = FALSE
icon_state = "syndicate-orange"
inhand_icon_state = "syndicate-orange"
- slowdown = 2
+ slowdown = 1
armor_type = /datum/armor/space_fragile
strip_delay = 65
diff --git a/code/modules/clothing/spacesuits/specialops.dm b/code/modules/clothing/spacesuits/specialops.dm
index cf8fc2a475cc6..caaa32cc24be2 100644
--- a/code/modules/clothing/spacesuits/specialops.dm
+++ b/code/modules/clothing/spacesuits/specialops.dm
@@ -7,6 +7,7 @@
inhand_icon_state = null
greyscale_colors = "#397F3F#FFCE5B"
clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL | SNUG_FIT
+ slowdown = 0
flags_inv = 0
armor_type = /datum/armor/space_beret
strip_delay = 130
diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm
index 3c7fa506b208d..6e56107173c46 100644
--- a/code/modules/clothing/suits/armor.dm
+++ b/code/modules/clothing/suits/armor.dm
@@ -59,6 +59,16 @@
/obj/item/clothing/suit/armor/vest/alt/sec
icon_state = "armor_sec"
+/obj/item/clothing/suit/armor/vest/press
+ name = "press armor vest"
+ desc = "A blue armor vest used to distinguish non-combatant \"PRESS\" members, like if anyone cares."
+ icon_state = "armor_press"
+
+/obj/item/clothing/suit/armor/vest/press/worn_overlays(mutable_appearance/standing, isinhands, icon_file)
+ . = ..()
+ if(!isinhands)
+ . += emissive_appearance(icon_file, "[icon_state]-emissive", src, alpha = src.alpha)
+
/obj/item/clothing/suit/armor/vest/marine
name = "tactical armor vest"
desc = "A set of the finest mass produced, stamped plasteel armor plates, containing an environmental protection unit for all-condition door kicking."
diff --git a/code/modules/clothing/suits/costume.dm b/code/modules/clothing/suits/costume.dm
index 929e8d931d5ca..566ca5557f728 100644
--- a/code/modules/clothing/suits/costume.dm
+++ b/code/modules/clothing/suits/costume.dm
@@ -168,6 +168,7 @@
body_parts_covered = CHEST|GROIN|LEGS
flags_inv = HIDEJUMPSUIT
dog_fashion = /datum/dog_fashion/back
+ var/in_use = FALSE
/obj/item/clothing/suit/costume/cardborg/equipped(mob/living/user, slot)
..()
@@ -176,17 +177,33 @@
/obj/item/clothing/suit/costume/cardborg/dropped(mob/living/user)
..()
+ if (!in_use)
+ return
user.remove_alt_appearance("standard_borg_disguise")
-
-/obj/item/clothing/suit/costume/cardborg/proc/disguise(mob/living/carbon/human/H, obj/item/clothing/head/costume/cardborg/borghead)
- if(istype(H))
- if(!borghead)
- borghead = H.head
- if(istype(borghead, /obj/item/clothing/head/costume/cardborg)) //why is this done this way? because equipped() is called BEFORE THE ITEM IS IN THE SLOT WHYYYY
- var/image/I = image(icon = 'icons/mob/silicon/robots.dmi' , icon_state = "robot", loc = H)
- I.override = 1
- I.add_overlay(mutable_appearance('icons/mob/silicon/robots.dmi', "robot_e")) //gotta look realistic
- add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/silicons, "standard_borg_disguise", I) //you look like a robot to robots! (including yourself because you're totally a robot)
+ in_use = FALSE
+ var/mob/living/carbon/human/human_user = user
+ if (istype(human_user.head, /obj/item/clothing/head/costume/cardborg))
+ UnregisterSignal(human_user.head, COMSIG_ITEM_DROPPED)
+
+/obj/item/clothing/suit/costume/cardborg/proc/disguise(mob/living/carbon/human/human_user, obj/item/clothing/head/costume/cardborg/borghead)
+ if(!istype(human_user))
+ return
+ if(!borghead)
+ borghead = human_user.head
+ if(!istype(borghead, /obj/item/clothing/head/costume/cardborg)) //why is this done this way? because equipped() is called BEFORE THE ITEM IS IN THE SLOT WHYYYY
+ return
+ RegisterSignal(borghead, COMSIG_ITEM_DROPPED, PROC_REF(helmet_drop)) // Don't need to worry about qdeleting since dropped will be called from there
+ in_use = TRUE
+ var/image/override_image = image(icon = 'icons/mob/silicon/robots.dmi' , icon_state = "robot", loc = human_user)
+ override_image.override = TRUE
+ override_image.add_overlay(mutable_appearance('icons/mob/silicon/robots.dmi', "robot_e")) //gotta look realistic
+ add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/silicons, "standard_borg_disguise", override_image) //you look like a robot to robots! (including yourself because you're totally a robot)
+
+/obj/item/clothing/suit/costume/cardborg/proc/helmet_drop(datum/source, mob/living/user)
+ SIGNAL_HANDLER
+ UnregisterSignal(source, COMSIG_ITEM_DROPPED)
+ user.remove_alt_appearance("standard_borg_disguise")
+ in_use = FALSE
/obj/item/clothing/suit/costume/snowman
name = "snowman outfit"
@@ -511,6 +528,14 @@
name = "bronze suit"
desc = "A big and clanky suit made of bronze that offers no protection and looks very unfashionable. Nice."
icon_state = "clockwork_cuirass_old"
+ allowed = list(
+ /obj/item/tank/internals/emergency_oxygen,
+ /obj/item/tank/internals/plasmaman,
+ /obj/item/tank/jetpack/oxygen/captain,
+ /obj/item/storage/belt/holster,
+ //new
+ /obj/item/toy/clockwork_watch,
+ )
armor_type = /datum/armor/costume_bronze
/obj/item/clothing/suit/hooded/mysticrobe
diff --git a/code/modules/clothing/suits/jobs.dm b/code/modules/clothing/suits/jobs.dm
index d211b3cc91edf..7e6bdde01cdfd 100644
--- a/code/modules/clothing/suits/jobs.dm
+++ b/code/modules/clothing/suits/jobs.dm
@@ -191,6 +191,11 @@
if(!isinhands)
. += emissive_appearance(icon_file, "[icon_state]-emissive", src, alpha = src.alpha)
+/obj/item/clothing/suit/hazardvest/press // Variant used by the Curator
+ name = "press hazard vest"
+ desc = "A blue high-visibility vest used to distinguish non-combatant \"PRESS\" members, like if anyone cares."
+ icon_state = "hazard_press"
+
//Lawyer
/obj/item/clothing/suit/toggle/lawyer
name = "blue formal suit jacket"
@@ -225,6 +230,10 @@
blood_overlay_type = "coat"
body_parts_covered = CHEST|ARMS
allowed = list(
+ /obj/item/tank/internals/emergency_oxygen,
+ /obj/item/tank/internals/plasmaman,
+ /obj/item/boxcutter,
+ /obj/item/dest_tagger,
/obj/item/stamp,
/obj/item/storage/bag/mail,
/obj/item/universal_scanner,
diff --git a/code/modules/clothing/under/_under.dm b/code/modules/clothing/under/_under.dm
index 2168177abcba1..6c6f9608e4b76 100644
--- a/code/modules/clothing/under/_under.dm
+++ b/code/modules/clothing/under/_under.dm
@@ -8,6 +8,8 @@
slot_flags = ITEM_SLOT_ICLOTHING
interaction_flags_click = NEED_DEXTERITY
armor_type = /datum/armor/clothing_under
+ supports_variations_flags = CLOTHING_DIGITIGRADE_MASK
+ digitigrade_greyscale_config_worn = /datum/greyscale_config/jumpsuit/worn_digi
equip_sound = 'sound/items/equip/jumpsuit_equip.ogg'
drop_sound = 'sound/items/handling/cloth_drop.ogg'
pickup_sound = 'sound/items/handling/cloth_pickup.ogg'
diff --git a/code/modules/clothing/under/accessories/_accessories.dm b/code/modules/clothing/under/accessories/_accessories.dm
index 91854bc386bf0..5b25418838ab6 100644
--- a/code/modules/clothing/under/accessories/_accessories.dm
+++ b/code/modules/clothing/under/accessories/_accessories.dm
@@ -89,7 +89,7 @@
atom_storage.close_all()
attach_to.clone_storage(atom_storage)
attach_to.atom_storage.set_real_location(src)
- attach_to.atom_storage.rustle_sound = TRUE // it's on the suit now
+ attach_to.atom_storage.do_rustle = TRUE // it's on the suit now
var/num_other_accessories = LAZYLEN(attach_to.attached_accessories)
layer = FLOAT_LAYER + clamp(attach_to.max_number_of_accessories - num_other_accessories, 0, 10)
diff --git a/code/modules/clothing/under/accessories/badges.dm b/code/modules/clothing/under/accessories/badges.dm
index 0ea3922893a76..cc66e9d406a57 100644
--- a/code/modules/clothing/under/accessories/badges.dm
+++ b/code/modules/clothing/under/accessories/badges.dm
@@ -241,3 +241,46 @@
if (ishuman(user))
var/mob/living/carbon/human/human_wearer = user
human_wearer.sec_hud_set_security_status()
+
+/obj/item/clothing/accessory/press_badge
+ name = "press badge"
+ desc = "A blue press badge that clearly identifies the wearer as a member of the media. While it signifies press affiliation, it does not grant any special privileges or rights no matter how much the wearer yells about it."
+ desc_controls = "Click person with it to show them it"
+ icon_state = "press_badge"
+ attachment_slot = NONE // actually NECK but that doesn't make sense
+ /// The name of the person in the badge
+ var/journalist_name
+ /// The name of the press person is working for
+ var/press_name
+
+/obj/item/clothing/accessory/press_badge/examine(mob/user)
+ . = ..()
+ if(!journalist_name || !press_name)
+ . += span_notice("Use it in hand to input information")
+ return
+
+ . += span_notice("It belongs to [journalist_name], [press_name]")
+
+/obj/item/clothing/accessory/press_badge/attack_self(mob/user, modifiers)
+ . = ..()
+ if(!journalist_name)
+ journalist_name = tgui_input_text(user, "What is your name?", "Journalist Name", "[user.name]", MAX_NAME_LEN)
+ if(!press_name)
+ press_name = tgui_input_text(user, "For what organization you work?", "Press Name", "Nanotrasen", MAX_CHARTER_LEN)
+
+/obj/item/clothing/accessory/press_badge/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
+ . = ..()
+ if(!isliving(interacting_with))
+ return
+
+ var/mob/living/interacting_living = interacting_with
+ if(user.combat_mode)
+ playsound(interacting_living, 'sound/weapons/throw.ogg', 30)
+ examine(interacting_living)
+ to_chat(interacting_living, span_userdanger("[user] shoves the [src] up your face!"))
+ user.visible_message(span_warning("[user] have shoved a [src] into [interacting_living] face."))
+ else
+ playsound(interacting_living, 'sound/weapons/throwsoft.ogg', 20)
+ examine(interacting_living)
+ to_chat(interacting_living, span_boldwarning("[user] shows the [src] to you."))
+ user.visible_message(span_notice("[user] shows a [src] to [interacting_living]."))
diff --git a/code/modules/clothing/under/color.dm b/code/modules/clothing/under/color.dm
index 748e697415c54..9ae1c7d63e366 100644
--- a/code/modules/clothing/under/color.dm
+++ b/code/modules/clothing/under/color.dm
@@ -224,6 +224,7 @@
greyscale_config_inhand_left = null
greyscale_config_inhand_right = null
greyscale_config_worn = null
+ digitigrade_greyscale_colors = "#3f3f3f"
can_adjust = FALSE
flags_1 = NONE
diff --git a/code/modules/clothing/under/jobs/civilian/clown_mime.dm b/code/modules/clothing/under/jobs/civilian/clown_mime.dm
index 98571182f2928..55f0da88918b5 100644
--- a/code/modules/clothing/under/jobs/civilian/clown_mime.dm
+++ b/code/modules/clothing/under/jobs/civilian/clown_mime.dm
@@ -31,6 +31,7 @@
inhand_icon_state = "clown"
female_sprite_flags = FEMALE_UNIFORM_TOP_ONLY
can_adjust = FALSE
+ supports_variations_flags = CLOTHING_NO_VARIATION
/obj/item/clothing/under/rank/civilian/clown/Initialize(mapload)
. = ..()
diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm
index 8f1263fa3e2b2..81002bd8a9e2d 100644
--- a/code/modules/clothing/under/miscellaneous.dm
+++ b/code/modules/clothing/under/miscellaneous.dm
@@ -33,6 +33,7 @@
desc = "Groovy!"
icon_state = "psyche"
inhand_icon_state = "p_suit"
+ digitigrade_greyscale_colors = "#3f3f3f"
/obj/item/clothing/under/misc/vice_officer
name = "vice officer's jumpsuit"
diff --git a/code/modules/deathmatch/deathmatch_loadouts.dm b/code/modules/deathmatch/deathmatch_loadouts.dm
index 911e5bf6e1b15..d89fdd383c80f 100644
--- a/code/modules/deathmatch/deathmatch_loadouts.dm
+++ b/code/modules/deathmatch/deathmatch_loadouts.dm
@@ -8,7 +8,9 @@
/// If defined, using this outfit sets the targets species to it
var/datum/species/species_override
/// This outfit will grant these spells if applied
- var/list/granted_spells = list()
+ var/list/spells_to_add = list()
+ /// This outfit will grant these mutations if applied
+ var/list/mutations_to_add = list()
/datum/outfit/deathmatch_loadout/pre_equip(mob/living/carbon/human/user, visualsOnly = FALSE)
. = ..()
@@ -17,15 +19,20 @@
if(!isnull(species_override))
user.set_species(species_override)
+
else if (!isnull(user.dna.species.outfit_important_for_life)) //plasmamen get lit on fire and die
user.set_species(/datum/species/human)
- for(var/datum/action/act as anything in granted_spells)
+
+ for(var/datum/action/act as anything in spells_to_add)
var/datum/action/new_ability = new act(user)
if(istype(new_ability, /datum/action/cooldown/spell))
var/datum/action/cooldown/spell/new_spell = new_ability
- new_spell.spell_requirements = SPELL_REQUIRES_NO_ANTIMAGIC
+ new_spell.spell_requirements = NONE
new_ability.Grant(user)
+ for(var/mutation in mutations_to_add)
+ user.dna.add_mutation(mutation)
+
/datum/outfit/deathmatch_loadout/naked
name = "Deathmatch: Naked"
display_name = "Unarmed, Butt-naked"
@@ -349,7 +356,7 @@
suit = /obj/item/clothing/suit/hooded/explorer
shoes = /obj/item/clothing/shoes/workboots/mining
mask = /obj/item/clothing/mask/gas/explorer
- granted_spells = list(
+ spells_to_add = list(
/datum/action/cooldown/mob_cooldown/dash,
)
@@ -392,10 +399,10 @@
suit = /datum/outfit/wizard::suit
head = /datum/outfit/wizard::head
shoes = /datum/outfit/wizard::shoes
- granted_spells = list(
+ spells_to_add = list(
/datum/action/cooldown/spell/aoe/magic_missile,
/datum/action/cooldown/spell/forcewall,
- /datum/action/cooldown/spell/jaunt/ethereal_jaunt,
+ /datum/action/cooldown/spell/pointed/projectile/fireball,
)
/datum/outfit/deathmatch_loadout/wizard/pyro
@@ -406,7 +413,7 @@
suit = /obj/item/clothing/suit/wizrobe/red
head = /obj/item/clothing/head/wizard/red
mask = /obj/item/cigarette
- granted_spells = list(
+ spells_to_add = list(
/datum/action/cooldown/spell/pointed/projectile/fireball,
/datum/action/cooldown/spell/smoke,
)
@@ -418,7 +425,7 @@
suit = /obj/item/clothing/suit/wizrobe/magusred
head = /obj/item/clothing/head/wizard/magus
- granted_spells = list(
+ spells_to_add = list(
/datum/action/cooldown/spell/pointed/projectile/lightningbolt,
/datum/action/cooldown/spell/charged/beam/tesla,
)
@@ -431,7 +438,7 @@
species_override = /datum/species/skeleton
suit = /obj/item/clothing/suit/wizrobe/black
head = /obj/item/clothing/head/wizard/black
- granted_spells = list(
+ spells_to_add = list(
/datum/action/cooldown/spell/touch/scream_for_me,
/datum/action/cooldown/spell/teleport/radius_turf/blink,
)
@@ -445,7 +452,7 @@
suit = /obj/item/clothing/suit/wizrobe/fake
head = /obj/item/clothing/head/wizard/fake
shoes = /obj/item/clothing/shoes/sandal
- granted_spells = list(
+ spells_to_add = list(
/datum/action/cooldown/spell/conjure_item/spellpacket,
/datum/action/cooldown/spell/aoe/repulse/wizard,
)
@@ -459,7 +466,7 @@
suit = /obj/item/clothing/suit/wizrobe/marisa
head = /obj/item/clothing/head/wizard/marisa
shoes = /obj/item/clothing/shoes/sneakers/marisa
- granted_spells = list(
+ spells_to_add = list(
/datum/action/cooldown/spell/chuuni_invocations,
/datum/action/cooldown/spell/pointed/projectile/spell_cards,
)
@@ -472,7 +479,7 @@
l_hand = /obj/item/mjollnir
suit = /obj/item/clothing/suit/wizrobe/magusblue
head = /obj/item/clothing/head/wizard/magus
- granted_spells = list(
+ spells_to_add = list(
/datum/action/cooldown/spell/summonitem,
)
@@ -482,7 +489,7 @@
desc = "You feel severely under-leveled for this encounter..."
l_hand = null
- granted_spells = list(
+ spells_to_add = list(
/datum/action/cooldown/spell/charge,
)
@@ -495,7 +502,7 @@
suit = /obj/item/clothing/suit/wizrobe/tape
head = /obj/item/clothing/head/wizard/tape
shoes = /obj/item/clothing/shoes/jackboots
- granted_spells = list(
+ spells_to_add = list(
/datum/action/cooldown/spell/conjure_item/infinite_guns/gun,
/datum/action/cooldown/spell/aoe/knock,
)
@@ -510,7 +517,7 @@
suit = /obj/item/clothing/suit/costume/hawaiian
head = /obj/item/clothing/head/wizard/red
shoes = /obj/item/clothing/shoes/sneakers/marisa
- granted_spells = list(
+ spells_to_add = list(
/datum/action/cooldown/spell/rod_form,
/datum/action/cooldown/spell/conjure/the_traps,
)
@@ -527,7 +534,7 @@
mask = /obj/item/clothing/mask/gas/clown_hat
back = /obj/item/storage/backpack/clown
shoes = /obj/item/clothing/shoes/clown_shoes
- granted_spells = null
+ spells_to_add = null
/datum/outfit/deathmatch_loadout/wizard/monkey
name = "Deathmatch: Monkey"
@@ -540,7 +547,7 @@
suit = null
head = /obj/item/clothing/head/wizard
shoes = null
- granted_spells = list(
+ spells_to_add = list(
/datum/action/cooldown/spell/conjure/simian,
)
@@ -716,7 +723,7 @@
/obj/item/food/croissant/throwing = 2,
)
- granted_spells = list(
+ spells_to_add = list(
/datum/action/cooldown/spell/vow_of_silence,
/datum/action/cooldown/spell/conjure_item/invisible_box,
/datum/action/cooldown/spell/conjure/invisible_chair,
@@ -744,3 +751,414 @@
/obj/item/knife/butcher,
/obj/item/sharpener,
)
+
+//species
+
+/datum/outfit/deathmatch_loadout/humanity
+ name = "Deathmatch: Human Species"
+ display_name = "Humanity"
+ desc = "The most ambitious and successful species. Or just the most rapacious, depending on who you ask."
+ species_override = /datum/species/human
+
+ head = /obj/item/clothing/head/soft/black
+ glasses = /obj/item/clothing/glasses/sunglasses
+ ears = /obj/item/radio/headset/headset_com
+ neck = /obj/item/clothing/neck/large_scarf/blue
+ //suit
+ id_trim = /datum/id_trim/job/bridge_assistant // half tider half command
+ id = /obj/item/card/id/advanced/chameleon
+ uniform = /obj/item/clothing/under/trek/command/next
+ l_pocket = /obj/item/gun/energy/e_gun/mini
+ r_pocket = /obj/item/extinguisher/mini
+ gloves = /obj/item/clothing/gloves/fingerless
+ belt = /obj/item/storage/belt/utility/full/inducer
+ shoes = /obj/item/clothing/shoes/sneakers/black
+
+// Lizard: Desert, Soldier, Trash
+
+/datum/outfit/deathmatch_loadout/lizardkind
+ name = "Deathmatch: Lizard Species"
+ display_name = "Lizardfolk"
+ desc = "They may be heavily discrimated against, they may be most often seen doing menial activities, but at least they, uh, uhh..."
+ species_override = /datum/species/lizard
+
+ head = /obj/item/clothing/head/soft/purple
+ id_trim = /datum/id_trim/job/janitor
+ id = /obj/item/card/id/advanced/chameleon
+ uniform = /obj/item/clothing/under/rank/civilian/janitor
+ gloves = /obj/item/clothing/gloves/color/black
+ belt = /obj/item/storage/belt/janitor/full
+ shoes = /obj/item/clothing/shoes/chameleon/noslip
+ r_hand = /obj/item/mop/advanced
+ back = /obj/item/storage/backpack
+ backpack_contents = list(
+ /obj/item/toy/plush/lizard_plushie/green,
+ // reclaiming lizard racism
+ /obj/item/reagent_containers/cup/glass/bottle/lizardwine,
+ /obj/item/tailclub,
+ /obj/item/melee/chainofcommand/tailwhip,
+ /obj/item/reagent_containers/cup/glass/coffee
+ )
+
+/datum/outfit/deathmatch_loadout/mothman
+ name = "Deathmatch: Moth Species"
+ display_name = "Mothmen"
+ desc = "An innocent and fluffy visage hides the combat ability of a particularly hairy kitten."
+ species_override = /datum/species/moth
+
+ head = /obj/item/clothing/head/utility/head_mirror
+ glasses = /obj/item/clothing/glasses/hud/health
+ suit = /obj/item/clothing/suit/hooded/wintercoat/medical
+ suit_store = /obj/item/flashlight/pen/paramedic
+ id_trim = /datum/id_trim/job/medical_doctor
+ id = /obj/item/card/id/advanced/chameleon
+ uniform = /obj/item/clothing/under/rank/medical/scrubs/blue
+ belt = /obj/item/storage/belt/medical/paramedic
+ shoes = /obj/item/clothing/shoes/sneakers/white
+ l_hand = /obj/item/circular_saw
+
+ back = /obj/item/storage/backpack/medic
+
+ backpack_contents = list(
+ /obj/item/toy/plush/moth,
+ /obj/item/storage/medkit/brute,
+ /obj/item/storage/medkit/fire,
+ /obj/item/statuebust/hippocratic
+ )
+
+// Roboticist??
+/datum/outfit/deathmatch_loadout/ethereal
+ name = "Deathmatch: Ethereal Species"
+ display_name = "Etherealkind"
+ desc = "Prepare to be SHOCKED as you are reminded of this species's existence."
+ species_override = /datum/species/ethereal
+
+ head = /obj/item/clothing/head/soft/black
+ id_trim = /datum/id_trim/job/roboticist
+ id = /obj/item/card/id/advanced/chameleon
+ suit = /obj/item/clothing/suit/toggle/labcoat/roboticist
+ suit_store = /datum/id_trim/job/roboticist
+ uniform = /obj/item/clothing/under/rank/rnd/roboticist
+ l_pocket = /obj/item/assembly/flash
+ belt = /obj/item/storage/belt/utility/full
+ shoes = /obj/item/clothing/shoes/sneakers/black
+
+ back = /obj/item/storage/backpack/science
+
+ backpack_contents = list(
+ /obj/item/dnainjector/shock,
+ /obj/item/etherealballdeployer,
+ )
+
+/datum/outfit/deathmatch_loadout/plasmamen
+ name = "Deathmatch: Plasmaman Species"
+ display_name = "Plasmamen"
+ desc = "Burn baby burn!"
+ species_override = /datum/species/plasmaman
+
+ head = /obj/item/clothing/head/helmet/space/plasmaman/atmospherics
+ suit = /obj/item/clothing/suit/hazardvest
+ suit_store = /obj/item/flashlight
+ uniform = /obj/item/clothing/under/plasmaman/atmospherics
+ id_trim = /datum/id_trim/job/atmospheric_technician
+ id = /obj/item/card/id/advanced/chameleon
+ belt = /obj/item/storage/belt/utility/atmostech
+ gloves = /obj/item/clothing/gloves/color/plasmaman/atmos
+ shoes = /obj/item/clothing/shoes/workboots
+ r_pocket = /obj/item/tank/internals/plasmaman/belt/full
+
+ back = /obj/item/storage/backpack/industrial
+
+ backpack_contents = list(
+ /obj/item/toy/plush/plasmamanplushie,
+ /obj/item/tank/internals/plasma,
+ /obj/item/tank/internals/plasmaman,
+ /obj/item/stack/sheet/mineral/uranium/half,
+ /obj/item/stack/sheet/mineral/plasma/thirty,
+ /obj/item/reagent_containers/condiment/milk,
+ /obj/item/storage/medkit/fire,
+ /obj/item/reagent_containers/syringe/plasma
+ )
+
+/datum/outfit/deathmatch_loadout/felinid
+ name = "Deathmatch: Felinid Species"
+ display_name = "Felinids"
+ desc = "Strictly inferior to humans in every way."
+ species_override = /datum/species/human/felinid
+
+ head = /obj/item/clothing/head/soft/rainbow
+ glasses = null
+ ears = /obj/item/radio/headset
+ neck = /obj/item/clothing/neck/petcollar
+ //suit
+ uniform = /obj/item/clothing/under/color/rainbow
+ l_pocket = /obj/item/toy/cattoy
+ r_pocket = /obj/item/restraints/handcuffs/fake
+ gloves = /obj/item/clothing/gloves/color/rainbow
+ belt = /obj/item/melee/curator_whip
+ shoes = /obj/item/clothing/shoes/sneakers/rainbow
+
+//spleef
+
+/datum/outfit/deathmatch_loadout/lattice_battles
+ name = "Deathmatch: Lattice loadout"
+ display_name = "Lattice Battler"
+ desc = "Snip the catwalks under everyone else and win! You're pacifist, so no punching."
+
+ uniform = /obj/item/clothing/under/pants/jeans
+ suit = /obj/item/clothing/suit/costume/wellworn_shirt/graphic
+ back = /obj/item/storage/backpack
+ r_hand = /obj/item/wirecutters
+
+ backpack_contents = list(
+ /obj/item/stack/rods/fifty,
+ /obj/item/stack/rods/fifty,
+ /obj/item/stack/rods/fifty,
+ /obj/item/stack/rods/fifty,
+ )
+
+// We don't want them to just punch each other to death
+
+/datum/outfit/deathmatch_loadout/lattice_battles/pre_equip(mob/living/carbon/human/user, visualsOnly)
+ . = ..()
+ ADD_TRAIT(user, TRAIT_PACIFISM, REF(src))
+
+// Ragnarok: Fight between religions!
+
+/datum/outfit/deathmatch_loadout/cultish/pre_equip(mob/living/carbon/human/user, visualsOnly)
+ . = ..()
+ ADD_TRAIT(user, TRAIT_ACT_AS_CULTIST, REF(src))
+ user.AddElement(/datum/element/cult_halo, initial_delay = 0 SECONDS)
+ user.AddElement(/datum/element/cult_eyes, initial_delay = 0 SECONDS)
+
+// Cultist Invoker, has all the balanced cult gear
+
+/datum/outfit/deathmatch_loadout/cultish/invoker
+ name = "Deathmatch: Cultist Invoker"
+ display_name = "Cultist Invoker"
+ desc = "Prove Nar'sie's superiority with your well-balanced set of equipment."
+ //species_override = /datum/species/plasmaman
+
+ head = /obj/item/clothing/head/hooded/cult_hoodie/cult_shield
+ glasses = /obj/item/clothing/glasses/hud/health/night/cultblind
+ suit = /obj/item/clothing/suit/hooded/cultrobes/cult_shield // the dreaded return!
+ suit_store = /obj/item/melee/cultblade
+ uniform = /obj/item/clothing/under/color/black
+ id_trim = null
+ belt = /obj/item/melee/cultblade/dagger
+ l_pocket = /obj/item/flashlight/flare/culttorch
+ r_pocket = /obj/item/flashlight/flare/culttorch
+ gloves = /obj/item/clothing/gloves/color/black
+ shoes = /obj/item/clothing/shoes/cult/alt
+ l_hand = /obj/item/shield/mirror // the dreaded return!!
+
+ back = /obj/item/storage/backpack/cultpack
+
+ backpack_contents = list(
+ /obj/item/restraints/legcuffs/bola/cult,
+ /obj/item/reagent_containers/cup/beaker/unholywater,
+ )
+
+// Cultist Artificer, gets all the balanced cult magicks
+
+/datum/outfit/deathmatch_loadout/cultish/artificer
+ name = "Deathmatch: Cultist Artificer"
+ display_name = "Cultist Artificer"
+ desc = "Prove Nar'sie's superiority with your well-balanced blood magicks."
+ //species_override = /datum/species/plasmaman
+
+ head = /obj/item/clothing/head/hooded/cult_hoodie/berserkerhood
+ neck = /obj/item/clothing/neck/heretic_focus/crimson_medallion
+ suit = /obj/item/clothing/suit/hooded/cultrobes/berserker
+ suit_store = /obj/item/melee/sickly_blade/cursed
+ uniform = /obj/item/clothing/under/color/red
+ id_trim = null
+ belt = /obj/item/melee/cultblade/dagger
+ l_pocket = /obj/item/flashlight/flare/culttorch
+ r_pocket = /obj/item/flashlight/flare/culttorch
+ gloves = /obj/item/clothing/gloves/color/red
+ shoes = /obj/item/clothing/shoes/cult
+ l_hand = null
+
+ back = /obj/item/storage/backpack/cultpack
+
+ backpack_contents = list(
+ /obj/item/cult_shift,
+ /obj/item/reagent_containers/cup/beaker/unholywater,
+ /obj/item/reagent_containers/cup/beaker/unholywater,
+ /obj/item/reagent_containers/cup/beaker/unholywater,
+ )
+
+ spells_to_add = list(
+ /datum/action/innate/cult/blood_spell/horror,
+ /datum/action/innate/cult/blood_spell/horror,
+ /datum/action/innate/cult/blood_spell/stun,
+ /datum/action/innate/cult/blood_spell/stun,
+ /datum/action/innate/cult/blood_spell/manipulation,
+ )
+
+/datum/outfit/deathmatch_loadout/cultish/artificer/post_equip(mob/living/carbon/human/user, visualsOnly)
+ . = ..()
+ var/datum/action/innate/cult/blood_spell/manipulation/magick = locate() in user
+ magick.charges = 300
+
+/datum/outfit/deathmatch_loadout/heresy
+ /// Grants the effects of these knowledges to the DMer
+ var/list/knowledge_to_grant
+
+/datum/outfit/deathmatch_loadout/heresy/pre_equip(mob/living/carbon/human/user, visualsOnly)
+ . = ..()
+ ADD_TRAIT(user, TRAIT_ACT_AS_HERETIC, REF(src))
+ user.AddElement(/datum/element/leeching_walk)
+
+ // Creates the knowledge as an isolated datum inside the target, allowing passive knowledges to work still.
+ for(var/datum/heretic_knowledge/knowhow as anything in knowledge_to_grant)
+ knowhow = new knowhow(user)
+ knowhow.on_gain(user, null)
+
+// Heretic Warrior
+
+// Has spells of Ash, Blade, and Rust. Overall aggressive
+
+/datum/outfit/deathmatch_loadout/heresy/warrior
+ name = "Deathmatch: Heretic Warrior"
+ display_name = "Heretic Warrior"
+ desc = "Prove the furious strength of the Mansus."
+ //species_override = /datum/species/plasmaman
+
+ head = /obj/item/clothing/head/hooded/cult_hoodie/eldritch
+ neck = /obj/item/clothing/neck/heretic_focus
+ suit = /obj/item/clothing/suit/hooded/cultrobes/eldritch
+ suit_store = /obj/item/melee/sickly_blade/dark
+ uniform = /obj/item/clothing/under/color/darkgreen
+ id_trim = null
+ belt = /obj/item/melee/sickly_blade/ash
+ gloves = null
+ shoes = /obj/item/clothing/shoes/sandal
+ l_pocket = /obj/item/flashlight/lantern/jade/on
+ r_pocket = /obj/item/melee/rune_carver
+ l_hand = null
+
+ back = /obj/item/storage/backpack
+
+ backpack_contents = list(
+ /obj/item/reagent_containers/cup/beaker/eldritch,
+ /obj/item/reagent_containers/cup/beaker/eldritch,
+ /obj/item/eldritch_potion/wounded,
+ /obj/item/eldritch_potion/wounded,
+ )
+
+ // I mean is it really that bad if they don't even know half this stuff is added to them.
+ // It's like, forbidden knowledge. It fits with the mansus theme - great excuse for poor design!
+ knowledge_to_grant = list(
+ /datum/heretic_knowledge/duel_stance,
+ /datum/heretic_knowledge/blade_grasp,
+ /datum/heretic_knowledge/blade_dance,
+ /datum/heretic_knowledge/blade_upgrade/blade,
+ )
+
+ spells_to_add = list(
+ /datum/action/cooldown/spell/touch/mansus_grasp,
+ /datum/action/cooldown/spell/realignment,
+ /datum/action/cooldown/spell/pointed/projectile/furious_steel,
+ /datum/action/cooldown/spell/charged/beam/fire_blast,
+ /datum/action/cooldown/spell/aoe/fiery_rebirth,
+ /datum/action/cooldown/spell/cone/staggered/entropic_plume,
+ /datum/action/cooldown/spell/pointed/rust_construction,
+ )
+
+// Heretic Scribe
+
+// Has spells of Void, Moon, and Cosmos. Overall defensive/mobile
+
+/datum/outfit/deathmatch_loadout/heresy/scribe
+ name = "Deathmatch: Heretic Scribe"
+ display_name = "Heretic Scribe"
+ desc = "Reveal the forgotten knowledge of the Mansus."
+
+ head = /obj/item/clothing/head/helmet/chaplain/witchunter_hat
+ mask = /obj/item/clothing/mask/madness_mask
+ neck = /obj/item/clothing/neck/eldritch_amulet
+ suit = /obj/item/clothing/suit/hooded/cultrobes/void
+ suit_store = /obj/item/melee/sickly_blade
+ uniform = /obj/item/clothing/under/costume/gamberson/military
+ id_trim = null
+ belt = /obj/item/storage/belt/unfathomable_curio
+ gloves = null
+ shoes = /obj/item/clothing/shoes/winterboots/ice_boots
+ l_pocket = /obj/item/ammo_box/strilka310/lionhunter
+ r_pocket = /obj/item/codex_cicatrix
+
+ back = /obj/item/gun/ballistic/rifle/lionhunter // for his neutral b, he wields a gun
+
+ belt_contents = list(
+ /obj/item/heretic_labyrinth_handbook,
+ /obj/item/heretic_labyrinth_handbook,
+ /obj/item/eldritch_potion/crucible_soul,
+ /obj/item/clothing/neck/heretic_focus/moon_amulet = 3,
+ )
+
+ knowledge_to_grant = list(
+ /datum/heretic_knowledge/cosmic_grasp,
+ /datum/heretic_knowledge/moon_grasp,
+ /datum/heretic_knowledge/mark/moon_mark,
+ )
+
+ spells_to_add = list(
+ /datum/action/cooldown/spell/touch/mansus_grasp,
+ /datum/action/cooldown/spell/conjure/cosmic_expansion,
+ /datum/action/cooldown/spell/pointed/projectile/star_blast,
+ /datum/action/cooldown/spell/touch/star_touch,
+ /datum/action/cooldown/spell/cone/staggered/cone_of_cold/void,
+ /datum/action/cooldown/spell/aoe/void_pull,
+ )
+
+// Chaplain! No spells (other than smoke), but strong armor and weapons, and immune to others' spells
+
+/datum/outfit/deathmatch_loadout/holy_crusader
+ name = "Deathmatch: Holy Crusader"
+ display_name = "Holy Crusader"
+ desc = "Smite the heathens!!"
+ //species_override = /datum/species/plasmaman
+
+ head = /obj/item/clothing/head/helmet/chaplain
+ neck = /obj/item/camera/spooky
+ suit = /obj/item/clothing/suit/chaplainsuit/armor/templar
+ suit_store = /obj/item/book/bible/booze
+ uniform = /obj/item/clothing/under/rank/civilian/chaplain
+ id_trim = null
+ belt = /obj/item/nullrod // choose any!
+ gloves = /obj/item/clothing/gloves/plate
+ shoes = /obj/item/clothing/shoes/plate
+ l_pocket = /obj/item/flashlight/lantern/on
+ r_pocket = /obj/item/reagent_containers/cup/glass/bottle/holywater
+ l_hand = /obj/item/shield/buckler
+
+ back = /obj/item/claymore/weak // or don't
+
+ spells_to_add = list(
+ /datum/action/cooldown/spell/smoke/lesser
+ )
+ mutations_to_add = list(
+ /datum/mutation/human/medieval,
+ /datum/mutation/human/lay_on_hands, // useless, but fun
+ )
+
+// Rat'var Apostate
+
+/datum/outfit/deathmatch_loadout/clock_cult
+ name = "Deathmatch: Clock Cultist"
+ display_name = "Rat'var Apostate"
+ desc = "You're in a fight between the servants of gods, and yours is dead. Good luck?"
+ //species_override = /datum/species/plasmaman
+
+ head = /obj/item/clothing/head/costume/bronze
+ suit = /obj/item/clothing/suit/costume/bronze
+ suit_store = /obj/item/toy/clockwork_watch
+ uniform = /obj/item/clothing/under/chameleon
+ id_trim = null
+ belt = /obj/item/brass_spear
+ gloves = /obj/item/clothing/gloves/tinkerer
+ shoes = /obj/item/clothing/shoes/bronze
+ l_pocket = /obj/item/reagent_containers/cup/beaker/synthflesh // they used to turn their dmg into tox with a spell. close enough
+ r_pocket = /obj/item/reagent_containers/cup/beaker/synthflesh
diff --git a/code/modules/deathmatch/deathmatch_mapping.dm b/code/modules/deathmatch/deathmatch_mapping.dm
index 9f006e1524295..b83419490be76 100644
--- a/code/modules/deathmatch/deathmatch_mapping.dm
+++ b/code/modules/deathmatch/deathmatch_mapping.dm
@@ -11,9 +11,6 @@
/obj/effect/landmark/deathmatch_player_spawn
name = "Deathmatch Player Spawner"
-/area/deathmatch/teleport //Prevent access to cross-z teleportation in the map itself (no wands of safety/teleportation scrolls). Cordons should prevent same-z teleportations outside of the arena.
- area_flags = /area/deathmatch::area_flags & ~NOTELEPORT
-
// for the illusion of a moving train
/turf/open/chasm/true/no_smooth/fake_motion_sand
name = "air"
@@ -25,3 +22,12 @@
/turf/open/chasm/true/no_smooth/fake_motion_sand/fast
icon_state = "sandmovingfast"
base_icon_state = "sandmovingfast"
+
+// fakeout
+
+/turf/open/chasm/true/fakeout
+ name = /turf/open/floor/wood::name
+ // desc kept the same
+ icon_state = /turf/open/floor/wood::icon_state
+ base_icon_state = /turf/open/floor/wood::base_icon_state
+ icon = /turf/open/floor/wood::icon
diff --git a/code/modules/deathmatch/deathmatch_maps.dm b/code/modules/deathmatch/deathmatch_maps.dm
index 6a8a245abb795..da08ae0b3114c 100644
--- a/code/modules/deathmatch/deathmatch_maps.dm
+++ b/code/modules/deathmatch/deathmatch_maps.dm
@@ -1,6 +1,7 @@
-/datum/lazy_template/deathmatch //deathmatch maps that have any possibility of the walls being destroyed should use indestructible walls, because baseturf moment
+/datum/lazy_template/deathmatch
map_dir = "_maps/deathmatch"
place_on_top = TRUE
+ turf_reservation_type = /datum/turf_reservation/turf_not_baseturf
/// Map UI Name
var/name
/// Map Description
@@ -16,7 +17,6 @@
/// whether we are currently being loaded by a lobby
var/template_in_use = FALSE
-
/datum/lazy_template/deathmatch/ragecage
name = "Ragecage"
desc = "Fun for the whole family, the classic ragecage."
@@ -204,5 +204,45 @@
map_name = "finaldestination"
key = "finaldestination"
+/datum/lazy_template/deathmatch/species_warfare
+ name = "Species Warfare"
+ desc = "Choose your favorite species and prove its superiority against all the other, lamer species. And also anyone else of your own."
+ max_players = 8
+ allowed_loadouts = list(
+ /datum/outfit/deathmatch_loadout/humanity,
+ /datum/outfit/deathmatch_loadout/lizardkind,
+ /datum/outfit/deathmatch_loadout/mothman,
+ /datum/outfit/deathmatch_loadout/ethereal,
+ /datum/outfit/deathmatch_loadout/plasmamen,
+ /datum/outfit/deathmatch_loadout/felinid,
+ )
+ map_name = "species_warfare"
+ key = "species_warfare"
+
+/datum/lazy_template/deathmatch/lattice_battles
+ name = "Lattice Battles"
+ desc = "Tired of fisticuffs all the time? Just snip the catwalk underneath instead!"
+ max_players = 8
+ allowed_loadouts = list(
+ /datum/outfit/deathmatch_loadout/lattice_battles,
+ )
+ map_name = "lattice_battles"
+ key = "lattice_battles"
+
+/datum/lazy_template/deathmatch/ragnarok
+ name = "Ragnarok"
+ desc = "Cultists, heretics, and chaplains all duking it out in the jungle to retrieve the McGuffin."
+ max_players = 8
+ allowed_loadouts = list(
+ /datum/outfit/deathmatch_loadout/cultish/invoker,
+ /datum/outfit/deathmatch_loadout/cultish/artificer,
+ /datum/outfit/deathmatch_loadout/heresy/warrior,
+ /datum/outfit/deathmatch_loadout/heresy/scribe,
+ /datum/outfit/deathmatch_loadout/holy_crusader,
+ /datum/outfit/deathmatch_loadout/clock_cult,
+ )
+ map_name = "ragnarok"
+ key = "ragnarok"
+
/datum/turf_reservation/indestructible_plating
turf_type = /turf/open/indestructible/plating //a little hacky but i guess it has to be done
diff --git a/code/modules/deathmatch/deathmatch_modifier.dm b/code/modules/deathmatch/deathmatch_modifier.dm
index dadca49d70a4f..9faafa91a48b7 100644
--- a/code/modules/deathmatch/deathmatch_modifier.dm
+++ b/code/modules/deathmatch/deathmatch_modifier.dm
@@ -232,7 +232,7 @@
projectile.ricochets_max += 2
projectile.min_ricochets += 2
projectile.ricochet_incidence_leeway = 0
- ADD_TRAIT(projectile, TRAIT_ALWAYS_HIT_ZONE, DEATHMATCH_TRAIT)
+ projectile.accuracy_falloff = 0
/datum/deathmatch_modifier/stormtrooper
name = "Stormtrooper Aim"
diff --git a/code/modules/events/aurora_caelus.dm b/code/modules/events/aurora_caelus.dm
index 0acb0ad9781a7..875b8c0dcf23a 100644
--- a/code/modules/events/aurora_caelus.dm
+++ b/code/modules/events/aurora_caelus.dm
@@ -17,10 +17,12 @@
start_when = 21
end_when = 80
-/datum/round_event/aurora_caelus/announce()
+/datum/round_event/aurora_caelus/announce(fake)
priority_announce("[station_name()]: A harmless cloud of ions is approaching your station, and will exhaust their energy battering the hull. Nanotrasen has approved a short break for all employees to relax and observe this very rare event. During this time, starlight will be bright but gentle, shifting between quiet green and blue colors. Any staff who would like to view these lights for themselves may proceed to the area nearest to them with viewing ports to open space. We hope you enjoy the lights.",
sound = 'sound/misc/notice2.ogg',
sender_override = "Nanotrasen Meteorology Division")
+ if (fake)
+ return
for(var/V in GLOB.player_list)
var/mob/M = V
if((M.client.prefs.read_preference(/datum/preference/toggle/sound_midi)) && is_station_level(M.z))
@@ -31,6 +33,8 @@
/datum/round_event/aurora_caelus/start()
if(!prob(1) && !check_holidays(APRIL_FOOLS))
return
+
+ var/list/human_blacklist = list()
for(var/area/station/service/kitchen/affected_area in GLOB.areas)
var/obj/machinery/oven/roast_ruiner = locate() in affected_area
if(roast_ruiner)
@@ -40,10 +44,13 @@
message_admins("Aurora Caelus event caused an oven to ignite at [ADMIN_VERBOSEJMP(ruined_roast)].")
log_game("Aurora Caelus event caused an oven to ignite at [loc_name(ruined_roast)].")
announce_to_ghosts(roast_ruiner)
- for(var/mob/living/carbon/human/seymour as anything in GLOB.human_list)
- if(seymour.mind && istype(seymour.mind.assigned_role, /datum/job/cook))
- seymour.say("My roast is ruined!!!", forced = "ruined roast")
- seymour.emote("scream")
+ for(var/mob/living/carbon/human/seymour in viewers(roast_ruiner, 7))
+ if (seymour in human_blacklist)
+ continue
+ human_blacklist += seymour
+ if(seymour.mind && istype(seymour.mind.assigned_role, /datum/job/cook))
+ seymour.say("My roast is ruined!!!", forced = "ruined roast")
+ seymour.emote("scream")
/datum/round_event/aurora_caelus/tick()
if(activeFor % 8 != 0)
diff --git a/code/modules/events/ghost_role/sentience.dm b/code/modules/events/ghost_role/sentience.dm
index 4017361dba51a..092813008458a 100644
--- a/code/modules/events/ghost_role/sentience.dm
+++ b/code/modules/events/ghost_role/sentience.dm
@@ -3,6 +3,7 @@ GLOBAL_LIST_INIT(high_priority_sentience, typecacheof(list(
/mob/living/basic/butterfly,
/mob/living/basic/carp/pet/cayenne,
/mob/living/basic/chicken,
+ /mob/living/basic/crab,
/mob/living/basic/cow,
/mob/living/basic/goat,
/mob/living/basic/lizard,
@@ -18,6 +19,7 @@ GLOBAL_LIST_INIT(high_priority_sentience, typecacheof(list(
/mob/living/simple_animal/bot/secbot/beepsky,
/mob/living/simple_animal/hostile/retaliate/goose/vomit,
/mob/living/basic/bear/snow/misha,
+ /mob/living/basic/mining/lobstrosity/juvenile,
)))
/datum/round_event_control/sentience
diff --git a/code/modules/events/ion_storm.dm b/code/modules/events/ion_storm.dm
index 686adf1e5d3f6..9c9d81d01d73f 100644
--- a/code/modules/events/ion_storm.dm
+++ b/code/modules/events/ion_storm.dm
@@ -34,7 +34,7 @@
//AI laws
for(var/mob/living/silicon/ai/M in GLOB.alive_mob_list)
M.laws_sanity_check()
- if(M.stat != DEAD && !M.incapacitated())
+ if(M.stat != DEAD && !M.incapacitated)
if(prob(replaceLawsetChance))
var/datum/ai_laws/ion_lawset = pick_weighted_lawset()
// pick_weighted_lawset gives us a typepath,
diff --git a/code/modules/events/space_vines/vine_event.dm b/code/modules/events/space_vines/vine_event.dm
index c4c805b1667e2..ce9881c990797 100644
--- a/code/modules/events/space_vines/vine_event.dm
+++ b/code/modules/events/space_vines/vine_event.dm
@@ -39,7 +39,7 @@
for(var/area/station/hallway/area in GLOB.areas)
for(var/turf/open/floor in area.get_turfs_from_all_zlevels())
- if(floor.Enter(vine))
+ if(!isopenspaceturf(floor) && floor.Enter(vine))
turfs += floor
qdel(vine)
@@ -64,7 +64,7 @@
/datum/event_admin_setup/set_location/spacevine/apply_to_event(datum/round_event/spacevine/event)
event.override_turf = chosen_turf
-
+
/datum/event_admin_setup/multiple_choice/spacevine
input_text = "Select starting mutations."
min_choices = 0
@@ -88,7 +88,7 @@
type_choices += text2path(choice)
event.mutations_overridden = TRUE
event.override_mutations = type_choices
-
+
/datum/event_admin_setup/input_number/spacevine_potency
input_text = "Set vine's potency (effects mutation frequency + max severity)"
max_value = 100
diff --git a/code/modules/experisci/experiment/experiments.dm b/code/modules/experisci/experiment/experiments.dm
index 1ec229cd1cd1e..c9f4f1b3d1bd7 100644
--- a/code/modules/experisci/experiment/experiments.dm
+++ b/code/modules/experisci/experiment/experiments.dm
@@ -387,7 +387,7 @@
if (organ.type == target_species.get_mutant_organ_type_for_slot(organ.slot))
continue
else
- if ((organ.type in target_species.mutant_organs) || (organ.type in target_species.external_organs))
+ if ((organ.type in target_species.mutant_organs))
continue
return TRUE
return FALSE
diff --git a/code/modules/experisci/experiment/handlers/experiment_handler.dm b/code/modules/experisci/experiment/handlers/experiment_handler.dm
index 622d84551a285..bb0cc2fb0a5e3 100644
--- a/code/modules/experisci/experiment/handlers/experiment_handler.dm
+++ b/code/modules/experisci/experiment/handlers/experiment_handler.dm
@@ -355,7 +355,7 @@
)
.["experiments"] += list(data)
-/datum/component/experiment_handler/ui_act(action, params)
+/datum/component/experiment_handler/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if (.)
return
diff --git a/code/modules/explorer_drone/control_console.dm b/code/modules/explorer_drone/control_console.dm
index 8cc8854f27dc8..78451dd71a168 100644
--- a/code/modules/explorer_drone/control_console.dm
+++ b/code/modules/explorer_drone/control_console.dm
@@ -97,7 +97,7 @@
icon_screen = initial(icon_screen)
. = ..()
-/obj/machinery/computer/exodrone_control_console/ui_act(action, list/params)
+/obj/machinery/computer/exodrone_control_console/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/explorer_drone/scanner_array.dm b/code/modules/explorer_drone/scanner_array.dm
index 6317ee273bed4..0cbeb684a8c6e 100644
--- a/code/modules/explorer_drone/scanner_array.dm
+++ b/code/modules/explorer_drone/scanner_array.dm
@@ -121,7 +121,7 @@ GLOBAL_LIST_INIT(scan_conditions,init_scan_conditions())
. = ..()
.["all_bands"] = GLOB.exoscanner_bands
-/obj/machinery/computer/exoscanner_control/ui_act(action, list/params)
+/obj/machinery/computer/exoscanner_control/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/fishing/aquarium/aquarium.dm b/code/modules/fishing/aquarium/aquarium.dm
index 5afbf4b72d9a9..0d2cd462128d4 100644
--- a/code/modules/fishing/aquarium/aquarium.dm
+++ b/code/modules/fishing/aquarium/aquarium.dm
@@ -307,14 +307,30 @@
/obj/structure/aquarium/ui_data(mob/user)
. = ..()
- .["fluid_type"] = fluid_type
+ .["fluidType"] = fluid_type
.["temperature"] = fluid_temp
- .["allow_breeding"] = allow_breeding
- .["feeding_interval"] = feeding_interval / (1 MINUTES)
- var/list/content_data = list()
- for(var/atom/movable/fish in contents)
- content_data += list(list("name"=fish.name,"ref"=ref(fish)))
- .["contents"] = content_data
+ .["allowBreeding"] = allow_breeding
+ .["fishData"] = list()
+ .["feedingInterval"] = feeding_interval / (1 MINUTES)
+ .["propData"] = list()
+ for(var/atom/movable/item in contents)
+ if(isfish(item))
+ var/obj/item/fish/fish = item
+ .["fishData"] += list(list(
+ "fish_ref" = REF(fish),
+ "fish_name" = fish.name,
+ "fish_happiness" = fish.get_happiness_value(),
+ "fish_icon" = fish::icon,
+ "fish_icon_state" = fish::icon_state,
+ "fish_health" = fish.health,
+ ))
+ continue
+ .["propData"] += list(list(
+ "prop_ref" = REF(item),
+ "prop_name" = item.name,
+ "prop_icon" = item::icon,
+ "prop_icon_state" = item::icon_state,
+ ))
/obj/structure/aquarium/ui_static_data(mob/user)
. = ..()
@@ -322,8 +338,9 @@
.["minTemperature"] = min_fluid_temp
.["maxTemperature"] = max_fluid_temp
.["fluidTypes"] = fluid_types
+ .["heartIcon"] = 'icons/effects/effects.dmi'
-/obj/structure/aquarium/ui_act(action, params)
+/obj/structure/aquarium/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
@@ -345,14 +362,19 @@
if("feeding_interval")
feeding_interval = params["feeding_interval"] MINUTES
. = TRUE
- if("remove")
- var/atom/movable/inside = locate(params["ref"]) in contents
- if(inside)
- if(isitem(inside))
- user.put_in_hands(inside)
- else
- inside.forceMove(get_turf(src))
- to_chat(user,span_notice("You take out [inside] from [src]."))
+ if("pet_fish")
+ var/obj/item/fish/fish = locate(params["fish_reference"]) in contents
+ fish?.pet_fish(user)
+ if("remove_item")
+ var/atom/movable/item = locate(params["item_reference"]) in contents
+ item?.forceMove(drop_location())
+ to_chat(user, span_notice("You take out [item] from [src]."))
+ if("rename_fish")
+ var/new_name = sanitize_name(params["chosen_name"])
+ if(!new_name)
+ return
+ var/atom/movable/fish = locate(params["fish_reference"]) in contents
+ fish.name = new_name
/obj/structure/aquarium/ui_interact(mob/user, datum/tgui/ui)
. = ..()
@@ -399,9 +421,13 @@
new /obj/item/aquarium_prop/sand(src)
new /obj/item/aquarium_prop/seaweed(src)
- new /obj/item/fish/goldfish/gill(src)
+ if(prob(85))
+ new /obj/item/fish/goldfish/gill(src)
+ reagents.add_reagent(/datum/reagent/consumable/nutriment, 2)
+ else
+ new /obj/item/fish/goldfish/three_eyes/gill(src)
+ reagents.add_reagent(/datum/reagent/toxin/mutagen, 2) //three eyes goldfish feed on mutagen.
- reagents.add_reagent(/datum/reagent/consumable/nutriment, 2)
/obj/structure/aquarium/prefilled
anchored = TRUE
diff --git a/code/modules/fishing/aquarium/aquarium_kit.dm b/code/modules/fishing/aquarium/aquarium_kit.dm
index 1161648f7d15f..3257760f6a439 100644
--- a/code/modules/fishing/aquarium/aquarium_kit.dm
+++ b/code/modules/fishing/aquarium/aquarium_kit.dm
@@ -21,15 +21,15 @@
desc = "A resizable case keeping the fish inside in stasis."
icon = 'icons/obj/storage/case.dmi'
icon_state = "fishbox"
-
+ w_class = WEIGHT_CLASS_SMALL
inhand_icon_state = "syringe_kit"
lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
- storage_type = /datum/storage/fish_case
+ storage_type = /datum/storage/fish_case/adjust_size
/obj/item/storage/fish_case/Initialize(mapload)
- ADD_TRAIT(src, TRAIT_FISH_SAFE_STORAGE, TRAIT_GENERIC) // Before populate so fish instatiates in ready container already
- return ..()
+ . = ..()
+ AddElement(/datum/element/fish_safe_storage)
/obj/item/storage/fish_case/PopulateContents()
var/fish_type = get_fish_type()
@@ -58,7 +58,7 @@
name = "ominous fish case"
/obj/item/storage/fish_case/syndicate/get_fish_type()
- return pick(/obj/item/fish/donkfish, /obj/item/fish/emulsijack, /obj/item/fish/jumpercable)
+ return pick(/obj/item/fish/donkfish, /obj/item/fish/emulsijack, /obj/item/fish/jumpercable, /obj/item/fish/chainsawfish)
/obj/item/storage/fish_case/tiziran
name = "imported fish case"
@@ -91,6 +91,13 @@
for(var/obj/item/fish/fish as anything in contents)
fish.set_status(FISH_DEAD)
+/obj/item/storage/fish_case/bluespace
+ name = "bluespace fish case"
+ icon_state = "fishbox_bluespace"
+ desc = "An improved fish case to keep large fish in stasis in a compact little space."
+ w_class = WEIGHT_CLASS_NORMAL
+ storage_type = /datum/storage/fish_case
+
/obj/item/aquarium_kit
name = "DIY Aquarium Construction Kit"
desc = "Everything you need to build your own aquarium. Raw materials sold separately."
@@ -109,6 +116,7 @@
icon = 'icons/obj/aquarium/supplies.dmi'
w_class = WEIGHT_CLASS_TINY
+ custom_materials = list(/datum/material/plastic = COIN_MATERIAL_AMOUNT)
var/layer_mode = AQUARIUM_LAYER_MODE_BOTTOM
var/beauty = 150
@@ -117,32 +125,37 @@
AddComponent(/datum/component/aquarium_content, icon, beauty = beauty)
/obj/item/aquarium_prop/rocks
- name = "rocks"
+ name = "decorative rocks"
+ desc = "A bunch of tiny plastic rocks for decorating an aquarium. Surely you could have just used real pebbles?"
icon_state = "rocks"
-/obj/item/aquarium_prop/seaweed_top
- name = "dense seaweeds"
- icon_state = "seaweeds_front"
- layer_mode = AQUARIUM_LAYER_MODE_TOP
-
/obj/item/aquarium_prop/seaweed
- name = "seaweeds"
+ name = "fake seaweed"
+ desc = "Little plastic sheets with weighted bottoms, designed to look like underwater foliage. They can be used to spruce up an aquarium."
icon_state = "seaweeds_back"
layer_mode = AQUARIUM_LAYER_MODE_BOTTOM
+/obj/item/aquarium_prop/seaweed/top
+ desc = "A bunch of artificial plants for an aquarium."
+ icon_state = "seaweeds_front"
+ layer_mode = AQUARIUM_LAYER_MODE_TOP
+
/obj/item/aquarium_prop/sand
name = "aquarium sand"
+ desc = "A plastic board for lining the bottom of an aquarium. It's got a bumpy patterned surface vaguely reminiscent of yellow sand."
icon_state = "sand"
layer_mode = AQUARIUM_LAYER_MODE_BEHIND_GLASS
/obj/item/aquarium_prop/treasure
name = "tiny treasure chest"
+ desc = "A very small plastic treaure chest, with nothing inside. You could put this in an aquarium, and it'll look like very small pirates hid treasure in there. Wouldn't that be nice?"
icon_state = "treasure"
layer_mode = AQUARIUM_LAYER_MODE_BOTTOM
/obj/item/storage/box/aquarium_props
name = "aquarium props box"
desc = "All you need to make your aquarium look good."
+ illustration = "fish"
/obj/item/storage/box/aquarium_props/PopulateContents()
for(var/prop_type in subtypesof(/obj/item/aquarium_prop))
diff --git a/code/modules/fishing/aquarium/fish_analyzer.dm b/code/modules/fishing/aquarium/fish_analyzer.dm
index f59f1901b8563..3d01479ef5a2f 100644
--- a/code/modules/fishing/aquarium/fish_analyzer.dm
+++ b/code/modules/fishing/aquarium/fish_analyzer.dm
@@ -65,6 +65,7 @@
if(isfish(target) || istype(target, /obj/structure/aquarium))
scanned_item = WEAKREF(target)
+ SEND_SIGNAL(src, COMSIG_FISH_ANALYZER_ANALYZE_STATUS, target, user)
ui_interact(user)
return ITEM_INTERACT_SUCCESS
diff --git a/code/modules/fishing/bait.dm b/code/modules/fishing/bait.dm
index b67298fab9fea..8eb8911a864ed 100644
--- a/code/modules/fishing/bait.dm
+++ b/code/modules/fishing/bait.dm
@@ -3,13 +3,16 @@
desc = "there's a lot of them in there, getting them out takes a while though"
icon = 'icons/obj/fishing.dmi'
icon_state = "bait_can"
+ base_icon_state = "bait_can"
w_class = WEIGHT_CLASS_SMALL
/// Tracking until we can take out another bait item
COOLDOWN_DECLARE(bait_removal_cooldown)
/// What bait item it produces
- var/bait_type
+ var/obj/item/bait_type = /obj/item/food/bait
/// Time between bait retrievals
- var/cooldown_time = 10 SECONDS
+ var/cooldown_time = 5 SECONDS
+ /// How many uses does it have left.
+ var/uses_left = 20
/obj/item/bait_can/attack_self(mob/user, modifiers)
. = ..()
@@ -17,19 +20,62 @@
if(fresh_bait)
user.put_in_hands(fresh_bait)
+/obj/item/bait_can/examine(mob/user)
+ . = ..()
+ . += span_info("It[uses_left ? " has got [uses_left] [bait_type::name] left" : "'s empty"].")
+
+/obj/item/bait_can/update_icon_state()
+ . = ..()
+ icon_state = base_icon_state
+ if(uses_left <= initial(uses_left))
+ if(!uses_left)
+ icon_state = "[icon_state]_empty"
+ else
+ icon_state = "[icon_state]_open"
+
/obj/item/bait_can/proc/retrieve_bait(mob/user)
+ if(!uses_left)
+ user.balloon_alert(user, "empty")
+ return
if(!COOLDOWN_FINISHED(src, bait_removal_cooldown))
- user.balloon_alert(user, "wait a bit") //I can't think of generic ic reason.
+ user.balloon_alert(user, "wait a bit")
return
COOLDOWN_START(src, bait_removal_cooldown, cooldown_time)
+ update_appearance()
+ uses_left--
return new bait_type(src)
/obj/item/bait_can/worm
name = "can o' worm"
- desc = "this can got worms."
+ desc = "This can got worms."
bait_type = /obj/item/food/bait/worm
/obj/item/bait_can/worm/premium
name = "can o' worm deluxe"
- desc = "this can got fancy worms."
+ desc = "This can got fancy worms."
bait_type = /obj/item/food/bait/worm/premium
+
+/obj/item/bait_can/super_baits
+ name = "can o' super-baits"
+ desc = "This can got the nectar of god."
+ bait_type = /obj/item/food/bait/doughball/synthetic/super
+ uses_left = 12
+
+
+/// Helper proc that checks if a bait matches identifier from fav/disliked bait list
+/proc/is_matching_bait(obj/item/bait, identifier)
+ if(ispath(identifier)) //Just a path
+ return istype(bait, identifier)
+ if(islist(identifier))
+ var/list/special_identifier = identifier
+ switch(special_identifier["Type"])
+ if("Foodtype")
+ var/obj/item/food/food_bait = bait
+ return istype(food_bait) && food_bait.foodtypes & special_identifier["Value"]
+ if("Reagent")
+ return bait.reagents?.has_reagent(special_identifier["Value"], special_identifier["Amount"], check_subtypes = TRUE)
+ else
+ CRASH("Unknown bait identifier in fish favourite/disliked list")
+ else
+ return HAS_TRAIT(bait, identifier)
+
diff --git a/code/modules/fishing/fish/_fish.dm b/code/modules/fishing/fish/_fish.dm
index 19a20a40a816b..ef5ab1572d841 100644
--- a/code/modules/fishing/fish/_fish.dm
+++ b/code/modules/fishing/fish/_fish.dm
@@ -1,39 +1,44 @@
+#define FISH_SAD 0
+#define FISH_NEUTRAL 1
+#define FISH_SATISFIED 2
+#define FISH_HAPPY 3
+#define FISH_VERY_HAPPY 4
+
// Fish path used for autogenerated fish
/obj/item/fish
name = "generic looking aquarium fish"
desc = "very bland"
icon = 'icons/obj/aquarium/fish.dmi'
- icon_state = "bugfish"
lefthand_file = 'icons/mob/inhands/fish_lefthand.dmi'
righthand_file = 'icons/mob/inhands/fish_righthand.dmi'
- inhand_icon_state = "fish_normal"
force = 6
+ throwforce = 6
+ throw_range = 8
attack_verb_continuous = list("slaps", "whacks")
attack_verb_simple = list("slap", "whack")
- hitsound = 'sound/weapons/slap.ogg'
+ hitsound = SFX_DEFAULT_FISH_SLAP
+ drop_sound = 'sound/creatures/fish/fish_drop1.ogg'
+ pickup_sound = SFX_FISH_PICKUP
+ sound_vary = TRUE
///The grind results of the fish. They scale with the weight of the fish.
grind_results = list(/datum/reagent/blood = 5, /datum/reagent/consumable/liquidgibs = 5)
obj_flags = UNIQUE_RENAME
+ item_flags = IMMUTABLE_SLOW|SLOWS_WHILE_IN_HAND
- /// Resulting width of aquarium visual icon - default size of "fish_greyscale" state
- var/sprite_width = 3
- /// Resulting height of aquarium visual icon - default size of "fish_greyscale" state
- var/sprite_height = 3
-
- /// Original width of aquarium visual icon - used to calculate scaledown factor
- var/source_width = 32
- /// Original height of aquarium visual icon - used to calculate scaledown factor
- var/source_height = 32
+ /// width of aquarium visual icon
+ var/sprite_width
+ /// height of aquarium visual icon
+ var/sprite_height
+ ///this icon file will be used for in-aquarium visual for the fish
+ var/dedicated_in_aquarium_icon = 'icons/obj/aquarium/fish.dmi'
/**
- * If present and it also has a dedicated icon state, this icon file will
- * be used for in-aquarium visual for the fish instead of its icon
+ * The icon_state that will be used for in-aquarium visual for the fish
+ * If not set, "[initial(icon_state)]_small" will be used instead
*/
- var/dedicated_in_aquarium_icon
- /// If present this icon will be used for in-aquarium visual for the fish instead of icon_state
var/dedicated_in_aquarium_icon_state
- /// If present aquarium visual will be this color
+ /// If present aquarium visual will be of this color
var/aquarium_vc_color
/// Required fluid type for this fish to live.
@@ -82,12 +87,6 @@
var/list/compatible_types
/// A list of possible evolutions. If set, offsprings may be of a different, new fish type if conditions are met.
var/list/evolution_types
- /// The species' name(s) of the parents of the fish. Shown by the fish analyzer.
- var/progenitors
-
- var/flopping = FALSE
-
- var/in_stasis = FALSE
// Fishing related properties
@@ -97,8 +96,8 @@
*/
var/list/fish_traits = list()
- /// Fishing behaviour
- var/fish_ai_type = FISH_AI_DUMB
+ /// path to datums that dictate how the fish moves during the fishing minigame
+ var/fish_movement_type = /datum/fish_movement
/// Base additive modifier to fishing difficulty
var/fishing_difficulty_modifier = 0
@@ -125,6 +124,9 @@
/// Average weight for this fish type in grams
var/average_weight = 1000
+ ///The general deviation from the average weight and size this fish has in the wild
+ var/weight_size_deviation = 0.2
+
/// When outside of an aquarium, these gases that are checked (as well as pressure and temp) to assert if the environment is safe or not.
var/list/safe_air_limits = list(
/datum/gas/oxygen = list(12, 100),
@@ -145,6 +147,8 @@
/// The beauty this fish provides to the aquarium it's inserted in.
var/beauty = FISH_BEAUTY_GENERIC
+ ///have we recently pet this fish
+ var/recently_petted = FALSE
/obj/item/fish/Initialize(mapload, apply_qualities = TRUE)
. = ..()
@@ -164,7 +168,6 @@
if(apply_qualities)
apply_traits() //Make sure traits are applied before size and weight.
update_size_and_weight()
- progenitors = full_capitalize(name) //default value
register_evolutions()
@@ -190,12 +193,24 @@
/obj/item/fish/examine(mob/user)
. = ..()
- // All spacemen have magic eyes of fish weight perception until fish scale (get it?) is implemented.
- . += span_notice("It's [size] cm long.")
- . += span_notice("It weighs [weight] g.")
+ if(HAS_MIND_TRAIT(user, TRAIT_EXAMINE_DEEPER_FISH))
+ if(status == FISH_DEAD)
+ . += span_deadsay("it's dead.")
+ var/list/warnings = list()
+ if(is_hungry())
+ warnings += "starving"
+ if(!HAS_TRAIT(src, TRAIT_FISH_STASIS) && !proper_environment())
+ warnings += "drowning"
+ if(health < initial(health) * 0.6)
+ warnings += "sick"
+ if(length(warnings))
+ . += span_warning("it's [english_list(warnings)]")
+ if(HAS_MIND_TRAIT(user, TRAIT_EXAMINE_FISH))
+ . += span_notice("It's [size] cm long.")
+ . += span_notice("It weighs [weight] g.")
///Randomizes weight and size.
-/obj/item/fish/proc/randomize_size_and_weight(base_size = average_size, base_weight = average_weight, deviation = 0.2)
+/obj/item/fish/proc/randomize_size_and_weight(base_size = average_size, base_weight = average_weight, deviation = weight_size_deviation)
var/size_deviation = 0.2 * base_size
var/new_size = round(clamp(gaussian(base_size, size_deviation), average_size * 1/MAX_FISH_DEVIATION_COEFF, average_size * MAX_FISH_DEVIATION_COEFF))
@@ -206,38 +221,130 @@
///Updates weight and size, along with weight class, number of fillets you can get and grind results.
/obj/item/fish/proc/update_size_and_weight(new_size = average_size, new_weight = average_weight)
- if(size && fillet_type)
- RemoveElement(/datum/element/processable, TOOL_KNIFE, fillet_type, num_fillets, 0.5 SECONDS, screentip_verb = "Cut")
+ SEND_SIGNAL(src, COMSIG_FISH_UPDATE_SIZE_AND_WEIGHT, new_size, new_weight)
+ if(size)
+ if(fillet_type)
+ RemoveElement(/datum/element/processable, TOOL_KNIFE, fillet_type, num_fillets, 0.5 SECONDS * num_fillets, screentip_verb = "Cut")
+ if(size > FISH_SIZE_TWO_HANDS_REQUIRED)
+ qdel(GetComponent(/datum/component/two_handed))
size = new_size
+ var/init_icon_state = initial(inhand_icon_state)
switch(size)
if(0 to FISH_SIZE_TINY_MAX)
update_weight_class(WEIGHT_CLASS_TINY)
- inhand_icon_state = "fish_small"
+ if(!init_icon_state)
+ inhand_icon_state = "fish_small"
if(FISH_SIZE_TINY_MAX to FISH_SIZE_SMALL_MAX)
- inhand_icon_state = "fish_small"
+ if(!init_icon_state)
+ inhand_icon_state = "fish_small"
update_weight_class(WEIGHT_CLASS_SMALL)
if(FISH_SIZE_SMALL_MAX to FISH_SIZE_NORMAL_MAX)
- inhand_icon_state = "fish_normal"
+ if(!init_icon_state)
+ inhand_icon_state = "fish_normal"
update_weight_class(WEIGHT_CLASS_NORMAL)
if(FISH_SIZE_NORMAL_MAX to FISH_SIZE_BULKY_MAX)
- inhand_icon_state = "fish_bulky"
+ if(!init_icon_state)
+ inhand_icon_state = "fish_bulky"
update_weight_class(WEIGHT_CLASS_BULKY)
- if(FISH_SIZE_BULKY_MAX to INFINITY)
- inhand_icon_state = "fish_huge"
+ if(FISH_SIZE_BULKY_MAX to FISH_SIZE_HUGE_MAX)
+ if(!init_icon_state)
+ inhand_icon_state = "fish_huge"
update_weight_class(WEIGHT_CLASS_HUGE)
+ if(FISH_SIZE_HUGE_MAX to INFINITY)
+ if(!init_icon_state)
+ inhand_icon_state = "fish_huge"
+ update_weight_class(WEIGHT_CLASS_GIGANTIC)
+
+ if(size > FISH_SIZE_TWO_HANDS_REQUIRED)
+ inhand_icon_state = "[inhand_icon_state]_wielded"
+ AddComponent(/datum/component/two_handed, require_twohands = TRUE)
+
if(fillet_type)
var/init_fillets = initial(num_fillets)
var/amount = max(round(init_fillets * size / FISH_FILLET_NUMBER_SIZE_DIVISOR, 1), 1)
num_fillets = amount
- AddElement(/datum/element/processable, TOOL_KNIFE, fillet_type, num_fillets, 0.5 SECONDS, screentip_verb = "Cut")
+ AddElement(/datum/element/processable, TOOL_KNIFE, fillet_type, num_fillets, 0.5 SECONDS * num_fillets, screentip_verb = "Cut")
if(weight)
for(var/reagent_type in grind_results)
grind_results[reagent_type] /= FLOOR(weight/FISH_GRIND_RESULTS_WEIGHT_DIVISOR, 0.1)
weight = new_weight
+
+ if(weight >= FISH_WEIGHT_SLOWDOWN)
+ slowdown = round(((weight/FISH_WEIGHT_SLOWDOWN_DIVISOR)**FISH_WEIGHT_SLOWDOWN_EXPONENT)-1.3, 0.1)
+ drag_slowdown = round(slowdown * 0.5, 1)
+ else
+ slowdown = 0
+ drag_slowdown = 0
+ if(ismob(loc))
+ var/mob/mob = loc
+ mob.update_equipment_speed_mods()
+
for(var/reagent_type in grind_results)
grind_results[reagent_type] *= FLOOR(weight/FISH_GRIND_RESULTS_WEIGHT_DIVISOR, 0.1)
+ update_fish_force()
+
+///Reset weapon-related variables of this items and recalculates those values based on the fish weight and size.
+/obj/item/fish/proc/update_fish_force()
+ if(force >= 15 && hitsound == SFX_ALT_FISH_SLAP)
+ hitsound = SFX_DEFAULT_FISH_SLAP
+ force = initial(force)
+ throwforce = initial(throwforce)
+ throw_range = initial(throw_range)
+ demolition_mod = initial(demolition_mod)
+ attack_verb_continuous = initial(attack_verb_continuous)
+ attack_verb_simple = initial(attack_verb_simple)
+ hitsound = initial(hitsound)
+ damtype = initial(damtype)
+ attack_speed = initial(attack_speed)
+ block_chance = initial(block_chance)
+ armour_penetration = initial(armour_penetration)
+ wound_bonus = initial(wound_bonus)
+ bare_wound_bonus = initial(bare_wound_bonus)
+ toolspeed = initial(toolspeed)
+
+ var/weight_rank = max(round(1 + log(2, weight/FISH_WEIGHT_FORCE_DIVISOR), 1), 1)
+
+ throw_range -= weight_rank
+ get_force_rank()
+
+ var/bonus_malus = weight_rank - w_class
+ if(bonus_malus)
+ calculate_fish_force_bonus(bonus_malus)
+
+ throwforce = force
+
+ SEND_SIGNAL(src, COMSIG_FISH_FORCE_UPDATED, weight_rank, bonus_malus)
+
+ if(force >=15 && hitsound == SFX_DEFAULT_FISH_SLAP) // don't override special attack sounds
+ hitsound = SFX_ALT_FISH_SLAP // do more damage - do heavier slap sound
+
+///A proc that makes the fish slightly stronger or weaker if there's a noticeable discrepancy between size and weight.
+/obj/item/fish/proc/calculate_fish_force_bonus(bonus_malus)
+ demolition_mod += bonus_malus * 0.1
+ attack_speed += bonus_malus * 0.1
+ force = round(force * (1 + bonus_malus * 0.1), 0.1)
+
+/obj/item/fish/proc/get_force_rank()
+ switch(w_class)
+ if(WEIGHT_CLASS_TINY)
+ force -= 3
+ attack_speed -= 0.1 SECONDS
+ if(WEIGHT_CLASS_NORMAL)
+ force += 2
+ if(WEIGHT_CLASS_BULKY)
+ force += 5
+ attack_speed += 0.1 SECONDS
+ if(WEIGHT_CLASS_HUGE)
+ force += 9
+ attack_speed += 0.2 SECONDS
+ demolition_mod += 0.2
+ if(WEIGHT_CLASS_GIGANTIC)
+ force += 13
+ attack_speed += 0.4 SECONDS
+ demolition_mod += 0.4
+
/**
* This proc has fish_traits list populated with fish_traits paths from three different lists:
* traits from x_traits and y_traits are compared, and inserted if conditions are met;
@@ -306,13 +413,13 @@
check_environment()
/obj/item/fish/proc/enter_stasis()
- in_stasis = TRUE
+ ADD_TRAIT(src, TRAIT_FISH_STASIS, INNATE_TRAIT)
// Stop processing until inserted into aquarium again.
stop_flopping()
STOP_PROCESSING(SSobj, src)
/obj/item/fish/proc/exit_stasis()
- in_stasis = FALSE
+ REMOVE_TRAIT(src, TRAIT_FISH_STASIS, INNATE_TRAIT)
if(status != FISH_DEAD)
START_PROCESSING(SSobj, src)
@@ -332,15 +439,9 @@
fed_reagents.remove_reagent(fed_reagent_type, 0.1)
SEND_SIGNAL(src, COMSIG_FISH_FED, fed_reagents, fed_reagent_type)
-/obj/item/fish/proc/check_environment(stasis_check = TRUE)
+/obj/item/fish/proc/check_environment()
if(QDELETED(src)) //we don't care anymore
return
- if(stasis_check)
- // Apply/remove stasis as needed
- if(loc && HAS_TRAIT(loc, TRAIT_FISH_SAFE_STORAGE))
- enter_stasis()
- else if(in_stasis)
- exit_stasis()
if(!do_flop_animation)
return
@@ -348,7 +449,7 @@
// Do additional stuff
var/in_aquarium = isaquarium(loc)
// Start flopping if outside of fish container
- var/should_be_flopping = status == FISH_ALIVE && loc && !HAS_TRAIT(loc,TRAIT_FISH_SAFE_STORAGE) && !in_aquarium
+ var/should_be_flopping = status == FISH_ALIVE && !HAS_TRAIT(src, TRAIT_FISH_STASIS) && !in_aquarium
if(should_be_flopping)
start_flopping()
@@ -356,7 +457,7 @@
stop_flopping()
/obj/item/fish/process(seconds_per_tick)
- if(in_stasis || status != FISH_ALIVE)
+ if(HAS_TRAIT(src, TRAIT_FISH_STASIS) || status != FISH_ALIVE)
return
process_health(seconds_per_tick)
@@ -368,7 +469,7 @@
SEND_SIGNAL(src, COMSIG_FISH_LIFE, seconds_per_tick)
-/obj/item/fish/proc/set_status(new_status)
+/obj/item/fish/proc/set_status(new_status, silent = FALSE)
if(status == new_status)
return
switch(new_status)
@@ -376,20 +477,36 @@
status = FISH_ALIVE
health = initial(health) // since the fishe has been revived
last_feeding = world.time //reset hunger
- check_environment(FALSE)
+ check_environment()
START_PROCESSING(SSobj, src)
if(FISH_DEAD)
status = FISH_DEAD
STOP_PROCESSING(SSobj, src)
stop_flopping()
- var/message = span_notice(replacetext(death_text, "%SRC", "[src]"))
- if(isaquarium(loc))
- loc.visible_message(message)
- else
- visible_message(message)
+ if(!silent)
+ var/message = span_notice(replacetext(death_text, "%SRC", "[src]"))
+ if(isaquarium(loc))
+ loc.visible_message(message)
+ else
+ visible_message(message)
update_appearance()
+ update_fish_force()
SEND_SIGNAL(src, COMSIG_FISH_STATUS_CHANGED)
+/obj/item/fish/expose_reagents(list/reagents, datum/reagents/source, methods = TOUCH, volume_modifier = 1, show_message = TRUE)
+ . = ..()
+ if(. & COMPONENT_NO_EXPOSE_REAGENTS || status != FISH_DEAD)
+ return
+ var/datum/reagent/medicine/strange_reagent/revival = locate() in reagents
+ if(!revival)
+ return
+ if(reagents[revival] >= 2 * w_class)
+ set_status(FISH_ALIVE)
+ else
+ balloon_alert_to_viewers("twitches for a moment!")
+ animate(src, pixel_x = 1, time = 0.1 SECONDS, loop = 2, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL)
+ animate(pixel_x = -1, flags = ANIMATION_RELATIVE)
+
/obj/item/fish/proc/use_lazarus(datum/source, obj/item/lazarus_injector/injector, mob/user)
SIGNAL_HANDLER
if(injector.revive_type != SENTIENCE_ORGANIC)
@@ -460,7 +577,7 @@
return FALSE
if(!being_targeted && length(aquarium.get_fishes()) >= AQUARIUM_MAX_BREEDING_POPULATION)
return FALSE
- return aquarium.allow_breeding && health >= initial(health) * 0.8 && stable_population > 1 && world.time >= breeding_wait
+ return aquarium.allow_breeding && health >= initial(health) * 0.8 && stable_population >= 1 && world.time >= breeding_wait
/obj/item/fish/proc/try_to_reproduce()
var/obj/structure/aquarium/aquarium = loc
@@ -495,36 +612,48 @@
second_fish = other_fish
break
- if(!second_fish && !HAS_TRAIT(src, TRAIT_FISH_SELF_REPRODUCE))
- return FALSE
+ if(!second_fish)
+ if(!HAS_TRAIT(src, TRAIT_FISH_SELF_REPRODUCE))
+ return FALSE
+ if(length(aquarium.tracked_fish_by_type[type]) >= stable_population)
+ return FALSE
+
+ if(PERFORM_ALL_TESTS(fish_breeding) && second_fish && !length(evolution_types))
+ return create_offspring(second_fish.type, second_fish)
var/chosen_type
var/datum/fish_evolution/chosen_evolution
- if(PERFORM_ALL_TESTS(fish_breeding) && second_fish && !length(evolution_types))
- chosen_type = second_fish.type
- else
- var/list/possible_evolutions = list()
- for(var/evolution_type in evolution_types)
+ var/list/possible_evolutions = list()
+ for(var/evolution_type in evolution_types)
+ var/datum/fish_evolution/evolution = GLOB.fish_evolutions[evolution_type]
+ if(evolution.check_conditions(src, second_fish, aquarium))
+ possible_evolutions += evolution
+ if(second_fish?.evolution_types)
+ var/secondary_evolutions = (second_fish.evolution_types - evolution_types)
+ for(var/evolution_type in secondary_evolutions)
var/datum/fish_evolution/evolution = GLOB.fish_evolutions[evolution_type]
- if(evolution.check_conditions(src, second_fish, aquarium))
+ if(evolution.check_conditions(second_fish, src, aquarium))
possible_evolutions += evolution
- if(second_fish?.evolution_types)
- var/secondary_evolutions = (second_fish.evolution_types - evolution_types)
- for(var/evolution_type in secondary_evolutions)
- var/datum/fish_evolution/evolution = GLOB.fish_evolutions[evolution_type]
- if(evolution.check_conditions(second_fish, src, aquarium))
- possible_evolutions += evolution
-
- if(length(possible_evolutions))
- chosen_evolution = pick(possible_evolutions)
- chosen_type = chosen_evolution.new_fish_type
- else if(second_fish)
- if(length(aquarium.tracked_fish_by_type[type]) >= stable_population)
+
+ if(length(possible_evolutions))
+ chosen_evolution = pick(possible_evolutions)
+ chosen_type = chosen_evolution.new_fish_type
+ else if(second_fish)
+ var/recessive = HAS_TRAIT(src, TRAIT_FISH_RECESSIVE)
+ var/recessive_partner = HAS_TRAIT(second_fish, TRAIT_FISH_RECESSIVE)
+ if(length(aquarium.tracked_fish_by_type[type]) >= stable_population)
+ if(recessive_partner && !recessive)
+ return FALSE
+ chosen_type = second_fish.type
+ else
+ if(recessive && !recessive_partner)
chosen_type = second_fish.type
+ else if(recessive_partner && !recessive)
+ chosen_type = type
else
chosen_type = pick(second_fish.type, type)
- else
- chosen_type = type
+ else
+ chosen_type = type
return create_offspring(chosen_type, second_fish, chosen_evolution)
@@ -540,12 +669,6 @@
partner.breeding_wait = world.time + breeding_timeout
else //Make a close of this fish.
new_fish.update_size_and_weight(size, weight, TRUE)
- new_fish.progenitors = initial(name)
- if(partner && type != partner.type)
- var/string = "[initial(name)] - [initial(partner.name)]"
- new_fish.progenitors = full_capitalize(string)
- else
- new_fish.progenitors = full_capitalize(initial(name))
breeding_wait = world.time + breeding_timeout
@@ -594,15 +717,15 @@
/// Starts flopping animation
/obj/item/fish/proc/start_flopping()
- if(flopping) //Requires update_transform/animate_wrappers to be less restrictive.
+ if(HAS_TRAIT(src, TRAIT_FISH_FLOPPING)) //Requires update_transform/animate_wrappers to be less restrictive.
return
- flopping = TRUE
+ ADD_TRAIT(src, TRAIT_FISH_FLOPPING, TRAIT_GENERIC)
flop_animation()
/// Stops flopping animation
/obj/item/fish/proc/stop_flopping()
- if(flopping)
- flopping = FALSE
+ if(HAS_TRAIT(src, TRAIT_FISH_FLOPPING))
+ REMOVE_TRAIT(src, TRAIT_FISH_FLOPPING, TRAIT_GENERIC)
animate(src, transform = matrix()) //stop animation
/// Refreshes flopping animation after temporary animation finishes
@@ -611,7 +734,7 @@
addtimer(CALLBACK(src, PROC_REF(refresh_flopping)), animation_duration)
/obj/item/fish/proc/refresh_flopping()
- if(flopping)
+ if(HAS_TRAIT(src, TRAIT_FISH_FLOPPING))
flop_animation()
/obj/item/fish/proc/try_electrogenesis()
@@ -634,6 +757,31 @@
if(HAS_TRAIT(src, TRAIT_FISH_FROM_CASE)) //Avoid printing money by simply ordering fish and sending it back.
calculated_price *= 0.05
return round(calculated_price)
+/obj/item/fish/proc/get_happiness_value()
+ var/happiness_value = 0
+ if(recently_petted)
+ happiness_value++
+ if(HAS_TRAIT(src, TRAIT_FISH_NO_HUNGER) || min((world.time - last_feeding) / feeding_frequency, 1) < 0.5)
+ happiness_value++
+ var/obj/structure/aquarium/aquarium = loc
+ if(!istype(aquarium))
+ return happiness_value
+ if(compatible_fluid_type(required_fluid_type, aquarium.fluid_type))
+ happiness_value++
+ if(ISINRANGE(aquarium.fluid_temp, required_temperature_min, required_temperature_max))
+ happiness_value++
+ return happiness_value
+
+/obj/item/fish/proc/pet_fish(mob/living/user)
+ if(recently_petted)
+ to_chat(user, span_warning("[src] runs away from your finger as you dip it into the water!"))
+ return
+ if(electrogenesis_power > 15 MEGA JOULES)
+ user.electrocute_act(5, src) //was it all worth it?
+ recently_petted = TRUE
+ SEND_SIGNAL(src, COMSIG_FISH_PETTED)
+ to_chat(user, span_notice("[src] dances around!"))
+ addtimer(VARSET_CALLBACK(src, recently_petted, FALSE), 30 SECONDS)
/// Returns random fish, using random_case_rarity probabilities.
/proc/random_fish_type(required_fluid)
diff --git a/code/modules/fishing/fish/chasm_detritus.dm b/code/modules/fishing/fish/chasm_detritus.dm
index ea9fcb4775770..9595c552e18d2 100644
--- a/code/modules/fishing/fish/chasm_detritus.dm
+++ b/code/modules/fishing/fish/chasm_detritus.dm
@@ -96,7 +96,7 @@ GLOBAL_LIST_INIT_TYPED(chasm_detritus_types, /datum/chasm_detritus, init_chasm_d
/// This also includes all mobs fallen into chasms, regardless of distance
/datum/chasm_detritus/restricted/bodies/get_chasm_contents(turf/fishing_spot)
. = ..()
- . |= GLOB.chasm_fallen_mobs
+ . |= GLOB.chasm_fallen_mobs[get_chasm_category(fishing_spot)]
/// Body detritus is selected in favor of bodies belonging to sentient mobs
/// The first sentient body found in the list of contents is returned, otherwise
diff --git a/code/modules/fishing/fish/fish_evolution.dm b/code/modules/fishing/fish/fish_evolution.dm
index e6e2f1d9570ac..688b0c201c7b4 100644
--- a/code/modules/fishing/fish/fish_evolution.dm
+++ b/code/modules/fishing/fish/fish_evolution.dm
@@ -78,6 +78,7 @@ GLOBAL_LIST_INIT(fish_evolutions, init_subtypes_w_path_keys(/datum/fish_evolutio
/datum/fish_evolution/purple_sludgefish
probability = 5
new_fish_type = /obj/item/fish/sludgefish/purple
+ new_traits = list(/datum/fish_trait/recessive)
removed_traits = list(/datum/fish_trait/no_mating)
/datum/fish_evolution/mastodon
@@ -85,7 +86,7 @@ GLOBAL_LIST_INIT(fish_evolutions, init_subtypes_w_path_keys(/datum/fish_evolutio
probability = 40
new_fish_type = /obj/item/fish/mastodon
new_traits = list(/datum/fish_trait/heavy, /datum/fish_trait/amphibious, /datum/fish_trait/predator, /datum/fish_trait/aggressive)
- conditions_note = "The fish (and its mate) need to be unusually big both in size and weight."
+ conditions_note = "The fish (and its mate) needs to be unusually big both in size and weight."
/datum/fish_evolution/mastodon/check_conditions(obj/item/fish/source, obj/item/fish/mate, obj/structure/aquarium/aquarium)
if((source.size < 120 || source.weight < 3000) || (mate && (mate.size < 120 || mate.weight < 3000)))
@@ -103,3 +104,23 @@ GLOBAL_LIST_INIT(fish_evolutions, init_subtypes_w_path_keys(/datum/fish_evolutio
new_fish_type = /obj/item/fish/chasm_crab/ice
required_temperature_min = MIN_AQUARIUM_TEMP+9
required_temperature_max = MIN_AQUARIUM_TEMP+10
+
+/datum/fish_evolution/three_eyes
+ name = "Three-eyed Goldfish"
+ probability = 3
+ new_fish_type = /obj/item/fish/goldfish/three_eyes
+ new_traits = list(/datum/fish_trait/recessive)
+
+/datum/fish_evolution/chainsawfish
+ name = "Chainsawfish"
+ probability = 30
+ new_fish_type = /obj/item/fish/chainsawfish
+ new_traits = list(/datum/fish_trait/predator, /datum/fish_trait/aggressive)
+ conditions_note = "The fish needs to be unusually big and aggressive"
+
+/datum/fish_evolution/chainsawfish/check_conditions(obj/item/fish/source, obj/item/fish/mate, obj/structure/aquarium/aquarium)
+ var/double_avg_size = /obj/item/fish/goldfish::average_size * 2
+ var/double_avg_weight = /obj/item/fish/goldfish::average_weight * 2
+ if(source.size >= double_avg_size && source.weight >= double_avg_weight && (/datum/fish_trait/aggressive in source.fish_traits))
+ return ..()
+ return FALSE
diff --git a/code/modules/fishing/fish/fish_traits.dm b/code/modules/fishing/fish/fish_traits.dm
index 76b0cc8691c21..3667a038bff49 100644
--- a/code/modules/fishing/fish/fish_traits.dm
+++ b/code/modules/fishing/fish/fish_traits.dm
@@ -37,6 +37,8 @@ GLOBAL_LIST_INIT(spontaneous_fish_traits, populate_spontaneous_fish_traits())
var/list/fish_whitelist
/// Depending on the value, fish with trait will be reported as more or less difficult in the catalog.
var/added_difficulty = 0
+ /// Reagents added to the fish when gained
+ var/list/reagents_to_add
/// Difficulty modifier from this mod, needs to return a list with two values
/datum/fish_trait/proc/difficulty_mod(obj/item/fishing_rod/rod, mob/fisherman)
@@ -54,7 +56,11 @@ GLOBAL_LIST_INIT(spontaneous_fish_traits, populate_spontaneous_fish_traits())
/// Applies some special qualities to the fish that has been spawned
/datum/fish_trait/proc/apply_to_fish(obj/item/fish/fish)
- return
+ SHOULD_CALL_PARENT(TRUE)
+ if(reagents_to_add)
+ for(var/reagent in reagents_to_add)
+ add_to_reagents(fish, reagent, reagents_to_add[reagent])
+ RegisterSignal(fish, COMSIG_ATOM_PROCESSED, PROC_REF(process_reagents))
/// Applies some special qualities to basic mobs generated by fish (i.e. chasm chrab --> young lobstrosity --> lobstrosity).
/datum/fish_trait/proc/apply_to_mob(mob/living/basic/mob)
@@ -79,6 +85,37 @@ GLOBAL_LIST_INIT(spontaneous_fish_traits, populate_spontaneous_fish_traits())
fish.grind_results.Insert(1, reagent_type)
fish.grind_results[reagent_type] = amount
+/// Proc that handles adding reagents from the trait to the fillets from butchered fish.
+/datum/fish_trait/proc/process_reagents(obj/item/fish/source, mob/living/user, obj/item/process_item, list/results)
+ SIGNAL_HANDLER
+ var/results_with_reagents = 0
+ for(var/atom/result as anything in results)
+ if(result.reagents)
+ results_with_reagents++
+ if(!results_with_reagents)
+ return
+ for(var/reagent in reagents_to_add)
+ var/amount = round(source.grind_results[reagent] / results_with_reagents, 0.1)
+ for(var/atom/result as anything in results)
+ result.reagents?.add_reagent(reagent, amount)
+
+/// Proc that adds or changes the venomous when the fish size and/or weight are updated
+/datum/fish_trait/proc/add_venom(obj/item/fish/source, venom_path, new_weight, mult = 0.25)
+ if(source.size)
+ var/old_amount = max(round((source.weight/FISH_GRIND_RESULTS_WEIGHT_DIVISOR) * mult, 0.1), mult)
+ source.RemoveElement(/datum/element/venomous, venom_path, old_amount)
+
+ var/new_amount = max(round((new_weight/FISH_GRIND_RESULTS_WEIGHT_DIVISOR) * mult, 0.1), mult)
+ source.AddElement(/datum/element/venomous, venom_path, new_amount)
+
+/// Proc that changes the venomous element based on if the fish is alive or dead (basically dead fish are weaker).
+/datum/fish_trait/proc/change_venom_on_death(obj/item/fish/source, venom_path, live_mult, dead_mult)
+ var/live_amount = max(round((source.weight/FISH_GRIND_RESULTS_WEIGHT_DIVISOR) * live_mult, 0.1), live_mult)
+ var/dead_amount = max(round((source.weight/FISH_GRIND_RESULTS_WEIGHT_DIVISOR) * dead_mult, 0.1), dead_mult)
+ var/is_dead = source.status == FISH_DEAD
+ source.RemoveElement(/datum/element/venomous, venom_path, is_dead ? live_amount : dead_amount)
+ source.AddElement(/datum/element/venomous, venom_path, is_dead ? dead_amount : live_amount)
+
/datum/fish_trait/wary
name = "Wary"
catalog_description = "This fish will avoid visible fish lines, cloaked line recommended."
@@ -110,7 +147,7 @@ GLOBAL_LIST_INIT(spontaneous_fish_traits, populate_spontaneous_fish_traits())
return
if(HAS_TRAIT(rod.bait, TRAIT_OMNI_BAIT))
return
- if(HAS_TRAIT(rod.bait, TRAIT_GOOD_QUALITY_BAIT) || HAS_TRAIT(rod.bait, TRAIT_GREAT_QUALITY_BAIT))
+ if(!HAS_TRAIT(rod.bait, TRAIT_GOOD_QUALITY_BAIT) && !HAS_TRAIT(rod.bait, TRAIT_GREAT_QUALITY_BAIT))
.[MULTIPLICATIVE_FISHING_MOD] = 0
@@ -126,6 +163,7 @@ GLOBAL_LIST_INIT(spontaneous_fish_traits, populate_spontaneous_fish_traits())
.[MULTIPLICATIVE_FISHING_MOD] = 0
/datum/fish_trait/nocturnal/apply_to_fish(obj/item/fish/fish)
+ . = ..()
RegisterSignal(fish, COMSIG_FISH_LIFE, PROC_REF(check_light))
/datum/fish_trait/nocturnal/proc/check_light(obj/item/fish/source, seconds_per_tick)
@@ -170,7 +208,7 @@ GLOBAL_LIST_INIT(spontaneous_fish_traits, populate_spontaneous_fish_traits())
mob.obj_damage *= 1.3
/datum/fish_trait/heavy/minigame_mod(obj/item/fishing_rod/rod, mob/fisherman, datum/fishing_challenge/minigame)
- minigame.fish_idle_velocity -= 10
+ minigame.mover.fish_idle_velocity -= 10
/datum/fish_trait/carnivore
name = "Carnivore"
@@ -211,6 +249,7 @@ GLOBAL_LIST_INIT(spontaneous_fish_traits, populate_spontaneous_fish_traits())
catalog_description = "This fish emits an invisible toxin that emulsifies other fish for it to feed on."
/datum/fish_trait/emulsijack/apply_to_fish(obj/item/fish/fish)
+ . = ..()
RegisterSignal(fish, COMSIG_FISH_LIFE, PROC_REF(emulsify))
ADD_TRAIT(fish, TRAIT_RESIST_EMULSIFY, FISH_TRAIT_DATUM)
@@ -250,6 +289,7 @@ GLOBAL_LIST_INIT(spontaneous_fish_traits, populate_spontaneous_fish_traits())
incompatible_traits = list(/datum/fish_trait/vegan)
/datum/fish_trait/necrophage/apply_to_fish(obj/item/fish/fish)
+ . = ..()
RegisterSignal(fish, COMSIG_FISH_LIFE, PROC_REF(eat_dead_fishes))
/datum/fish_trait/necrophage/proc/eat_dead_fishes(obj/item/fish/source, seconds_per_tick)
@@ -269,6 +309,7 @@ GLOBAL_LIST_INIT(spontaneous_fish_traits, populate_spontaneous_fish_traits())
diff_traits_inheritability = 25
/datum/fish_trait/parthenogenesis/apply_to_fish(obj/item/fish/fish)
+ . = ..()
ADD_TRAIT(fish, TRAIT_FISH_SELF_REPRODUCE, FISH_TRAIT_DATUM)
/**
@@ -282,8 +323,19 @@ GLOBAL_LIST_INIT(spontaneous_fish_traits, populate_spontaneous_fish_traits())
incompatible_traits = list(/datum/fish_trait/crossbreeder)
/datum/fish_trait/no_mating/apply_to_fish(obj/item/fish/fish)
+ . = ..()
ADD_TRAIT(fish, TRAIT_FISH_NO_MATING, FISH_TRAIT_DATUM)
+///Prevent offsprings of fish with this trait from being of the same type (unless self-mating or the partner also has the trait)
+/datum/fish_trait/recessive
+ name = "Recessive"
+ catalog_description = "If crossbred, offsprings will always be of the mate species, unless it also possess the trait."
+ diff_traits_inheritability = 0
+
+/datum/fish_trait/no_mating/apply_to_fish(obj/item/fish/fish)
+ . = ..()
+ ADD_TRAIT(fish, TRAIT_FISH_RECESSIVE, FISH_TRAIT_DATUM)
+
/datum/fish_trait/revival
diff_traits_inheritability = 15
name = "Self-Revival"
@@ -291,6 +343,7 @@ GLOBAL_LIST_INIT(spontaneous_fish_traits, populate_spontaneous_fish_traits())
spontaneous_manifest_types = list(/obj/item/fish/boned = 100, /obj/item/fish/mastodon = 100)
/datum/fish_trait/revival/apply_to_fish(obj/item/fish/fish)
+ . = ..()
RegisterSignal(fish, COMSIG_FISH_STATUS_CHANGED, PROC_REF(check_status))
/datum/fish_trait/revival/proc/check_status(obj/item/fish/source)
@@ -319,6 +372,7 @@ GLOBAL_LIST_INIT(spontaneous_fish_traits, populate_spontaneous_fish_traits())
incompatible_traits = list(/datum/fish_trait/vegan)
/datum/fish_trait/predator/apply_to_fish(obj/item/fish/fish)
+ . = ..()
RegisterSignal(fish, COMSIG_FISH_LIFE, PROC_REF(eat_fishes))
/datum/fish_trait/predator/proc/eat_fishes(obj/item/fish/source, seconds_per_tick)
@@ -327,7 +381,7 @@ GLOBAL_LIST_INIT(spontaneous_fish_traits, populate_spontaneous_fish_traits())
return
var/obj/structure/aquarium/aquarium = source.loc
for(var/obj/item/fish/victim in aquarium.get_fishes(TRUE, source))
- if(victim.size < source.size * 0.75) // It's a big fish eat small fish world
+ if(victim.size < source.size * 0.7) // It's a big fish eat small fish world
continue
if(victim.status != FISH_ALIVE || victim == source || HAS_TRAIT(victim, TRAIT_YUCKY_FISH) || SPT_PROB(80, seconds_per_tick))
continue
@@ -337,31 +391,35 @@ GLOBAL_LIST_INIT(spontaneous_fish_traits, populate_spontaneous_fish_traits())
/datum/fish_trait/yucky
name = "Yucky"
catalog_description = "This fish tastes so repulsive, other fishes won't try to eat it."
+ reagents_to_add = list(/datum/reagent/yuck = 3)
/datum/fish_trait/yucky/apply_to_fish(obj/item/fish/fish)
- RegisterSignal(fish, COMSIG_ATOM_PROCESSED, PROC_REF(add_yuck))
+ . = ..()
ADD_TRAIT(fish, TRAIT_YUCKY_FISH, FISH_TRAIT_DATUM)
- add_to_reagents(fish, /datum/reagent/yuck, 3)
-
-/datum/fish_trait/yucky/proc/add_yuck(obj/item/fish/source, mob/living/user, obj/item/process_item, list/results)
- var/amount = source.grind_results[/datum/reagent/yuck] / length(results)
- for(var/atom/result as anything in results)
- result.reagents?.add_reagent(/datum/reagent/yuck, amount)
/datum/fish_trait/toxic
name = "Toxic"
- catalog_description = "This fish contains toxins in its liver. Feeding it to predatory fishes or people is not reccomended."
+ catalog_description = "This fish contains toxins. Feeding it to predatory fishes or people is not reccomended."
diff_traits_inheritability = 25
+ reagents_to_add = list(/datum/reagent/toxin/tetrodotoxin = 2.5)
/datum/fish_trait/toxic/apply_to_fish(obj/item/fish/fish)
- RegisterSignal(fish, COMSIG_ATOM_PROCESSED, PROC_REF(add_toxin))
+ . = ..()
+ RegisterSignal(fish, COMSIG_FISH_UPDATE_SIZE_AND_WEIGHT, PROC_REF(make_venomous))
+ RegisterSignal(fish, COMSIG_FISH_STATUS_CHANGED, PROC_REF(on_status_change))
RegisterSignal(fish, COMSIG_FISH_EATEN_BY_OTHER_FISH, PROC_REF(on_eaten))
- add_to_reagents(fish, /datum/reagent/toxin/tetrodotoxin, 2.5)
-/datum/fish_trait/toxic/proc/add_toxin(obj/item/fish/source, mob/living/user, obj/item/process_item, list/results)
- var/amount = source.grind_results[ /datum/reagent/toxin/tetrodotoxin] / length(results)
- for(var/atom/result as anything in results)
- result.reagents?.add_reagent(/datum/reagent/toxin/tetrodotoxin, amount)
+/datum/fish_trait/toxic/proc/make_venomous(obj/item/fish/source, new_size, new_weight)
+ SIGNAL_HANDLER
+ if(!HAS_TRAIT(source, TRAIT_FISH_STINGER))
+ return
+ add_venom(source, /datum/reagent/toxin/tetrodotoxin, new_weight, mult = source.status == FISH_DEAD ? 0.1 : 0.25)
+
+/datum/fish_trait/toxic/proc/on_status_change(obj/item/fish/source)
+ SIGNAL_HANDLER
+ if(!HAS_TRAIT(source, TRAIT_FISH_STINGER))
+ return
+ change_venom_on_death(source, /datum/reagent/toxin/tetrodotoxin, 0.25, 0.1)
/datum/fish_trait/toxic/proc/on_eaten(obj/item/fish/source, obj/item/fish/predator)
if(HAS_TRAIT(predator, TRAIT_FISH_TOXIN_IMMUNE))
@@ -388,6 +446,7 @@ GLOBAL_LIST_INIT(spontaneous_fish_traits, populate_spontaneous_fish_traits())
diff_traits_inheritability = 40
/datum/fish_trait/toxin_immunity/apply_to_fish(obj/item/fish/fish)
+ . = ..()
ADD_TRAIT(fish, TRAIT_FISH_TOXIN_IMMUNE, FISH_TRAIT_DATUM)
/datum/fish_trait/crossbreeder
@@ -398,6 +457,7 @@ GLOBAL_LIST_INIT(spontaneous_fish_traits, populate_spontaneous_fish_traits())
incompatible_traits = list(/datum/fish_trait/no_mating)
/datum/fish_trait/crossbreeder/apply_to_fish(obj/item/fish/fish)
+ . = ..()
ADD_TRAIT(fish, TRAIT_FISH_CROSSBREEDER, FISH_TRAIT_DATUM)
/datum/fish_trait/aggressive
@@ -407,6 +467,7 @@ GLOBAL_LIST_INIT(spontaneous_fish_traits, populate_spontaneous_fish_traits())
catalog_description = "This fish is aggressively territorial, and may attack fish that come close to it."
/datum/fish_trait/aggressive/apply_to_fish(obj/item/fish/fish)
+ . = ..()
RegisterSignal(fish, COMSIG_FISH_LIFE, PROC_REF(try_attack_fish))
/datum/fish_trait/aggressive/proc/try_attack_fish(obj/item/fish/source, seconds_per_tick)
@@ -431,6 +492,7 @@ GLOBAL_LIST_INIT(spontaneous_fish_traits, populate_spontaneous_fish_traits())
added_difficulty = 5
/datum/fish_trait/lubed/apply_to_fish(obj/item/fish/fish)
+ . = ..()
fish.AddComponent(/datum/component/slippery, 8 SECONDS, SLIDE|GALOSHES_DONT_HELP)
/datum/fish_trait/lubed/apply_to_mob(mob/living/basic/mob)
@@ -448,6 +510,7 @@ GLOBAL_LIST_INIT(spontaneous_fish_traits, populate_spontaneous_fish_traits())
catalog_description = "This fish has developed a primitive adaptation to life on both land and water."
/datum/fish_trait/amphibious/apply_to_fish(obj/item/fish/fish)
+ . = ..()
ADD_TRAIT(fish, TRAIT_FISH_AMPHIBIOUS, FISH_TRAIT_DATUM)
if(fish.required_fluid_type == AQUARIUM_FLUID_AIR)
fish.required_fluid_type = AQUARIUM_FLUID_FRESHWATER
@@ -460,6 +523,7 @@ GLOBAL_LIST_INIT(spontaneous_fish_traits, populate_spontaneous_fish_traits())
incompatible_traits = list(/datum/fish_trait/predator, /datum/fish_trait/necrophage)
/datum/fish_trait/mixotroph/apply_to_fish(obj/item/fish/fish)
+ . = ..()
ADD_TRAIT(fish, TRAIT_FISH_NO_HUNGER, FISH_TRAIT_DATUM)
/datum/fish_trait/antigrav
@@ -467,12 +531,13 @@ GLOBAL_LIST_INIT(spontaneous_fish_traits, populate_spontaneous_fish_traits())
inheritability = 75
diff_traits_inheritability = 25
catalog_description = "This fish will invert the gravity of the bait at random. May fall upward outside after being caught."
- added_difficulty = 15
+ added_difficulty = 20
/datum/fish_trait/antigrav/minigame_mod(obj/item/fishing_rod/rod, mob/fisherman, datum/fishing_challenge/minigame)
minigame.special_effects |= FISHING_MINIGAME_RULE_ANTIGRAV
/datum/fish_trait/antigrav/apply_to_fish(obj/item/fish/fish)
+ . = ..()
fish.AddElement(/datum/element/forced_gravity, NEGATIVE_GRAVITY)
/datum/fish_trait/antigrav/apply_to_mob(mob/living/basic/mob)
@@ -489,6 +554,7 @@ GLOBAL_LIST_INIT(spontaneous_fish_traits, populate_spontaneous_fish_traits())
catalog_description = "This fish tends to die of stress when forced to be around too many other fish."
/datum/fish_trait/anxiety/apply_to_fish(obj/item/fish/fish)
+ . = ..()
RegisterSignal(fish, COMSIG_FISH_LIFE, PROC_REF(on_fish_life))
///signal sent when the anxiety fish is fed, killing it if sharing contents with too many fish.
@@ -511,24 +577,18 @@ GLOBAL_LIST_INIT(spontaneous_fish_traits, populate_spontaneous_fish_traits())
catalog_description = "This fish is electroreceptive, and will generate electric fields. Can be harnessed inside a bioelectric generator."
/datum/fish_trait/electrogenesis/apply_to_fish(obj/item/fish/fish)
+ . = ..()
ADD_TRAIT(fish, TRAIT_FISH_ELECTROGENESIS, FISH_TRAIT_DATUM)
- RegisterSignal(fish, COMSIG_ITEM_ATTACK, PROC_REF(on_item_attack))
+ RegisterSignal(fish, COMSIG_FISH_FORCE_UPDATED, PROC_REF(on_force_updated))
-/datum/fish_trait/electrogenesis/proc/on_item_attack(obj/item/fish/fish, mob/living/target, mob/living/user)
+/datum/fish_trait/electrogenesis/proc/on_force_updated(obj/item/fish/fish, weight_rank, bonus_or_malus)
SIGNAL_HANDLER
-
if(fish.status == FISH_ALIVE)
- fish.force = 16
+ fish.force += 10 - fish.w_class
fish.damtype = BURN
fish.attack_verb_continuous = list("shocks", "zaps")
fish.attack_verb_simple = list("shock", "zap")
fish.hitsound = 'sound/effects/sparks4.ogg'
- else
- fish.force = fish::force
- fish.damtype = fish::damtype
- fish.attack_verb_continuous = fish::attack_verb_continuous
- fish.attack_verb_simple = fish::attack_verb_simple
- fish.hitsound = fish::hitsound
/datum/fish_trait/electrogenesis/apply_to_mob(mob/living/basic/mob)
. = ..()
@@ -546,3 +606,44 @@ GLOBAL_LIST_INIT(spontaneous_fish_traits, populate_spontaneous_fish_traits())
/datum/fish_trait/stunted/apply_to_mob(mob/living/basic/mob)
. = ..()
qdel(mob.GetComponent(/datum/component/growth_and_differentiation))
+
+/datum/fish_trait/stinger
+ name = "Stinger"
+ inheritability = 80
+ diff_traits_inheritability = 35
+ catalog_description = "This fish is equipped with a sharp stringer or bill capable of delivering damage and toxins."
+ spontaneous_manifest_types = list(/obj/item/fish/stingray = 100, /obj/item/fish/swordfish = 100, /obj/item/fish/chainsawfish = 100)
+
+/datum/fish_trait/stinger/apply_to_fish(obj/item/fish/fish)
+ . = ..()
+ ADD_TRAIT(fish, TRAIT_FISH_STINGER, FISH_TRAIT_DATUM)
+ RegisterSignal(fish, COMSIG_FISH_FORCE_UPDATED, PROC_REF(on_force_updated))
+
+/datum/fish_trait/stinger/proc/on_force_updated(obj/item/fish/fish, weight_rank, bonus_or_malus)
+ SIGNAL_HANDLER
+ fish.force += 1 + fish.w_class + bonus_or_malus
+
+/datum/fish_trait/toxic_barbs
+ name = "Toxic Barbs"
+ catalog_description = "This fish' stinger, bill or otherwise, is coated with simple, yet effetive venom."
+ spontaneous_manifest_types = list(/obj/item/fish/stingray = 35)
+
+/datum/fish_trait/toxic_barbs/apply_to_fish(obj/item/fish/fish)
+ . = ..()
+ RegisterSignal(fish, COMSIG_FISH_UPDATE_SIZE_AND_WEIGHT, PROC_REF(make_venomous))
+ RegisterSignal(fish, COMSIG_FISH_STATUS_CHANGED, PROC_REF(on_status_change))
+
+/datum/fish_trait/toxic_barbs/proc/make_venomous(obj/item/fish/source, new_size, new_weight)
+ SIGNAL_HANDLER
+ if(!HAS_TRAIT(source, TRAIT_FISH_STINGER))
+ ///Remove the trait from the fish so it doesn't show on the analyzer as it doesn't do anything on stingerless ones.
+ source.fish_traits -= type
+ UnregisterSignal(source, list(COMSIG_FISH_UPDATE_SIZE_AND_WEIGHT, COMSIG_FISH_STATUS_CHANGED))
+ return
+ add_venom(source, /datum/reagent/toxin/venom, new_weight, mult = source.status == FISH_DEAD ? 0.3 : 0.7)
+
+/datum/fish_trait/toxic_barbs/proc/on_status_change(obj/item/fish/source)
+ SIGNAL_HANDLER
+ if(!HAS_TRAIT(source, TRAIT_FISH_STINGER))
+ return
+ change_venom_on_death(source, /datum/reagent/toxin/venom, 0.7, 0.3)
diff --git a/code/modules/fishing/fish/fish_types.dm b/code/modules/fishing/fish/fish_types.dm
index ce9f36f0553d6..81c716cecc2e4 100644
--- a/code/modules/fishing/fish/fish_types.dm
+++ b/code/modules/fishing/fish/fish_types.dm
@@ -5,14 +5,19 @@
desc = "Despite common belief, goldfish do not have three-second memories. \
They can actually remember things that happened up to three months ago."
icon_state = "goldfish"
- sprite_width = 8
- sprite_height = 8
+ dedicated_in_aquarium_icon_state = "fish_greyscale"
+ aquarium_vc_color = "#D8540D"
+ sprite_width = 5
+ sprite_height = 3
stable_population = 3
average_size = 30
average_weight = 500
+ weight_size_deviation = 0.35
favorite_bait = list(/obj/item/food/bait/worm)
required_temperature_min = MIN_AQUARIUM_TEMP+18
required_temperature_max = MIN_AQUARIUM_TEMP+26
+ evolution_types = list(/datum/fish_evolution/three_eyes, /datum/fish_evolution/chainsawfish)
+ compatible_types = list(/obj/item/fish/goldfish/gill, /obj/item/fish/goldfish/three_eyes, /obj/item/fish/goldfish/three_eyes/gill)
/obj/item/fish/goldfish/gill
name = "McGill"
@@ -21,14 +26,43 @@
random_case_rarity = FISH_RARITY_NOPE
show_in_catalog = FALSE
beauty = FISH_BEAUTY_GOOD
+ compatible_types = list(/obj/item/fish/goldfish, /obj/item/fish/goldfish/three_eyes)
+ fish_traits = list(/datum/fish_trait/recessive)
+
+/obj/item/fish/goldfish/three_eyes
+ name = "three-eyed goldfish"
+ desc = "A goldfish with an extra half a pair of eyes. You wonder what it's been feeding on lately..."
+ icon_state = "three_eyes"
+ stable_population = 4
+ fish_traits = list(/datum/fish_trait/recessive, /datum/fish_trait/shiny_lover)
+ compatible_types = list(/obj/item/fish/goldfish, /obj/item/fish/goldfish/gill, /obj/item/fish/goldfish/three_eyes/gill)
+ beauty = FISH_BEAUTY_GOOD
+ fishing_difficulty_modifier = 10
+ random_case_rarity = FISH_RARITY_VERY_RARE
+ food = /datum/reagent/toxin/mutagen
+ favorite_bait = list(
+ list(
+ "Type" = "Reagent",
+ "Value" = /datum/reagent/toxin/mutagen,
+ "Amount" = 3,
+ ),
+ )
+
+/obj/item/fish/goldfish/three_eyes/gill
+ name = "McGill"
+ desc = "A great rubber duck tool for Lawyers who can't get a grasp over their case. It looks kinda different today..."
+ compatible_types = list(/obj/item/fish/goldfish, /obj/item/fish/goldfish/three_eyes)
+ beauty = FISH_BEAUTY_GREAT
+ show_in_catalog = FALSE
+ stable_population = 1
+ random_case_rarity = FISH_RARITY_NOPE
/obj/item/fish/angelfish
name = "angelfish"
desc = "Young Angelfish often live in groups, while adults prefer solitary life. They become territorial and aggressive toward other fish when they reach adulthood."
icon_state = "angelfish"
- dedicated_in_aquarium_icon_state = "bigfish"
+ sprite_width = 4
sprite_height = 7
- source_height = 7
average_size = 30
average_weight = 500
stable_population = 3
@@ -40,10 +74,8 @@
name = "guppy"
desc = "Guppy is also known as rainbow fish because of the brightly colored body and fins."
icon_state = "guppy"
- dedicated_in_aquarium_icon_state = "fish_greyscale"
- aquarium_vc_color = "#91AE64"
- sprite_width = 8
- sprite_height = 5
+ sprite_width = 5
+ sprite_height = 2
average_size = 30
average_weight = 500
stable_population = 6
@@ -54,8 +86,8 @@
name = "plasma tetra"
desc = "Due to their small size, tetras are prey to many predators in their watery world, including eels, crustaceans, and invertebrates."
icon_state = "plastetra"
- dedicated_in_aquarium_icon_state = "fish_greyscale"
- aquarium_vc_color = "#D30EB0"
+ sprite_width = 4
+ sprite_height = 2
average_size = 30
average_weight = 500
stable_population = 3
@@ -63,13 +95,14 @@
required_temperature_max = MIN_AQUARIUM_TEMP+28
/obj/item/fish/catfish
- name = "cory catfish"
+ name = "catfish"
desc = "A catfish has about 100,000 taste buds, and their bodies are covered with them to help detect chemicals present in the water and also to respond to touch."
icon_state = "catfish"
- dedicated_in_aquarium_icon_state = "fish_greyscale"
- aquarium_vc_color = "#907420"
- average_size = 100
- average_weight = 2000
+ sprite_width = 8
+ sprite_height = 4
+ average_size = 80
+ average_weight = 1600
+ weight_size_deviation = 0.35
stable_population = 3
favorite_bait = list(
list(
@@ -85,7 +118,6 @@
name = "tadpole"
desc = "The larval spawn of an amphibian. A very minuscle, round creature with a long tail it uses to swim around."
icon_state = "tadpole"
- dedicated_in_aquarium_icon_state = "tadpole small"
average_size = 3
average_weight = 10
sprite_width = 3
@@ -107,7 +139,7 @@
RegisterSignal(src, COMSIG_FISH_BEFORE_GROWING, PROC_REF(growth_checks))
RegisterSignal(src, COMSIG_FISH_FINISH_GROWING, PROC_REF(on_growth))
-/obj/item/fish/tadpole/set_status(new_status)
+/obj/item/fish/tadpole/set_status(new_status, silent = FALSE)
. = ..()
if(status == FISH_DEAD)
del_timerid = QDEL_IN_STOPPABLE(src, 12 SECONDS)
@@ -136,10 +168,9 @@
name = "clownfish"
desc = "Clownfish catch prey by swimming onto the reef, attracting larger fish, and luring them back to the anemone. The anemone will sting and eat the larger fish, leaving the remains for the clownfish."
icon_state = "clownfish"
- dedicated_in_aquarium_icon_state = "clownfish_small"
required_fluid_type = AQUARIUM_FLUID_SALTWATER
- sprite_width = 8
- sprite_height = 5
+ sprite_width = 7
+ sprite_height = 4
average_size = 30
average_weight = 500
stable_population = 4
@@ -154,19 +185,20 @@
desc = "A clownfish exposed to cherry-flavored lube for far too long. First discovered the days following a cargo incident around the seas of Europa, when thousands of thousands of thousands..."
icon_state = "lubefish"
random_case_rarity = FISH_RARITY_VERY_RARE
- dedicated_in_aquarium_icon_state = "lubefish_small"
fish_traits = list(/datum/fish_trait/picky_eater, /datum/fish_trait/lubed)
evolution_types = null
compatible_types = list(/obj/item/fish/clownfish)
food = /datum/reagent/lube
+ fishing_difficulty_modifier = 5
beauty = FISH_BEAUTY_GREAT
/obj/item/fish/cardinal
name = "cardinalfish"
desc = "Cardinalfish are often found near sea urchins, where the fish hide when threatened."
icon_state = "cardinalfish"
- dedicated_in_aquarium_icon_state = "fish_greyscale"
required_fluid_type = AQUARIUM_FLUID_SALTWATER
+ sprite_width = 6
+ sprite_height = 3
average_size = 30
average_weight = 500
stable_population = 4
@@ -178,9 +210,9 @@
name = "green chromis"
desc = "The Chromis can vary in color from blue to green depending on the lighting and distance from the lights."
icon_state = "greenchromis"
- dedicated_in_aquarium_icon_state = "fish_greyscale"
- aquarium_vc_color = "#00ff00"
required_fluid_type = AQUARIUM_FLUID_SALTWATER
+ sprite_width = 5
+ sprite_height = 3
average_size = 30
average_weight = 500
stable_population = 5
@@ -193,14 +225,14 @@
name = "firefish goby"
desc = "To communicate in the wild, the firefish uses its dorsal fin to alert others of potential danger."
icon_state = "firefish"
- sprite_width = 6
- sprite_height = 5
+ sprite_width = 5
+ sprite_height = 3
required_fluid_type = AQUARIUM_FLUID_SALTWATER
average_size = 30
average_weight = 500
stable_population = 3
disliked_bait = list(/obj/item/food/bait/worm, /obj/item/food/bait/doughball)
- fish_ai_type = FISH_AI_ZIPPY
+ fish_movement_type = /datum/fish_movement/zippy
required_temperature_min = MIN_AQUARIUM_TEMP+23
required_temperature_max = MIN_AQUARIUM_TEMP+28
@@ -210,28 +242,26 @@
icon_state = "pufferfish"
required_fluid_type = AQUARIUM_FLUID_SALTWATER
sprite_width = 8
- sprite_height = 8
+ sprite_height = 6
average_size = 60
average_weight = 1000
stable_population = 3
required_temperature_min = MIN_AQUARIUM_TEMP+23
required_temperature_max = MIN_AQUARIUM_TEMP+28
+ fillet_type = /obj/item/food/fishmeat/quality //Too bad they're poisonous
fish_traits = list(/datum/fish_trait/heavy, /datum/fish_trait/toxic)
beauty = FISH_BEAUTY_GOOD
-
/obj/item/fish/lanternfish
name = "lanternfish"
desc = "Typically found in areas below 6600 feet below the surface of the ocean, they live in complete darkness."
icon_state = "lanternfish"
required_fluid_type = AQUARIUM_FLUID_SALTWATER
random_case_rarity = FISH_RARITY_VERY_RARE
- source_width = 28
- source_height = 21
- sprite_width = 8
- sprite_height = 8
- average_size = 100
- average_weight = 1500
+ sprite_width = 6
+ sprite_height = 5
+ average_size = 50
+ average_weight = 1000
stable_population = 3
fish_traits = list(/datum/fish_trait/nocturnal)
required_temperature_min = MIN_AQUARIUM_TEMP+2 //My source is that the water at a depth 6600 feet is pretty darn cold.
@@ -243,11 +273,13 @@
name = "dwarf moonfish"
desc = "Ordinarily in the wild, the Zagoskian moonfish is around the size of a tuna, however through selective breeding a smaller breed suitable for being kept as an aquarium pet has been created."
icon_state = "dwarf_moonfish"
+ sprite_height = 6
+ sprite_width = 6
required_fluid_type = AQUARIUM_FLUID_SALTWATER
stable_population = 2
fillet_type = /obj/item/food/fishmeat/moonfish
- average_size = 100
- average_weight = 2000
+ average_size = 60
+ average_weight = 1000
required_temperature_min = MIN_AQUARIUM_TEMP+20
required_temperature_max = MIN_AQUARIUM_TEMP+30
beauty = FISH_BEAUTY_GOOD
@@ -256,6 +288,8 @@
name = "gunner jellyfish"
desc = "So called due to their resemblance to an artillery shell, the gunner jellyfish is native to Tizira, where it is enjoyed as a delicacy. Produces a mild hallucinogen that is destroyed by cooking."
icon_state = "gunner_jellyfish"
+ sprite_height = 4
+ sprite_width = 5
required_fluid_type = AQUARIUM_FLUID_SALTWATER
stable_population = 4
fillet_type = /obj/item/food/fishmeat/gunner_jellyfish
@@ -267,10 +301,11 @@
name = "needlefish"
desc = "A tiny, transparent fish which resides in large schools in the oceans of Tizira. A common food for other, larger fish."
icon_state = "needlefish"
- dedicated_in_aquarium_icon_state = "needlefish_small"
+ sprite_height = 3
sprite_width = 7
required_fluid_type = AQUARIUM_FLUID_SALTWATER
stable_population = 12
+ breeding_timeout = 1 MINUTES
fillet_type = null
average_size = 20
average_weight = 300
@@ -282,13 +317,15 @@
name = "armorfish"
desc = "A small shellfish native to Tizira's oceans, known for its exceptionally hard shell. Consumed similarly to prawns."
icon_state = "armorfish"
- dedicated_in_aquarium_icon_state = "armorfish_small"
sprite_height = 5
sprite_width = 6
+ average_size = 25
+ average_weight = 350
required_fluid_type = AQUARIUM_FLUID_SALTWATER
stable_population = 10
+ breeding_timeout = 1.25 MINUTES
fillet_type = /obj/item/food/fishmeat/armorfish
- fish_ai_type = FISH_AI_SLOW
+ fish_movement_type = /datum/fish_movement/slow
required_temperature_min = MIN_AQUARIUM_TEMP+10
required_temperature_max = MIN_AQUARIUM_TEMP+32
@@ -297,7 +334,6 @@
name = "chasm chrab"
desc = "The young of the lobstrosity mature in pools below the earth, eating what falls in until large enough to clamber out. Those found near the station are well-fed."
icon_state = "chrab"
- dedicated_in_aquarium_icon_state = "chrab_small"
sprite_height = 9
sprite_width = 8
stable_population = 4
@@ -390,7 +426,6 @@
name = "arctic chrab"
desc = "A subspecies of chasm chrabs that has adapted to the cold climate and lack of abysmal holes of the icemoon."
icon_state = "arctic_chrab"
- dedicated_in_aquarium_icon_state = "arctic_chrab_small"
required_temperature_min = ICEBOX_MIN_TEMPERATURE-20
required_temperature_max = MIN_AQUARIUM_TEMP+15
evolution_types = list(/datum/fish_evolution/chasm_chrab)
@@ -405,6 +440,8 @@
random_case_rarity = FISH_RARITY_VERY_RARE
required_fluid_type = AQUARIUM_FLUID_FRESHWATER
stable_population = 4
+ sprite_width = 5
+ sprite_height = 4
fillet_type = /obj/item/food/fishmeat/donkfish
fish_traits = list(/datum/fish_trait/yucky)
required_temperature_min = MIN_AQUARIUM_TEMP+15
@@ -418,6 +455,8 @@
random_case_rarity = FISH_RARITY_GOOD_LUCK_FINDING_THIS
required_fluid_type = AQUARIUM_FLUID_ANADROMOUS
stable_population = 3
+ sprite_width = 7
+ sprite_height = 3
fish_traits = list(/datum/fish_trait/emulsijack)
required_temperature_min = MIN_AQUARIUM_TEMP+5
required_temperature_max = MIN_AQUARIUM_TEMP+40
@@ -428,8 +467,7 @@
desc = "A surprisingly useful if nasty looking creation from the syndicate fish labs. Drop one in a tank, and \
watch it self-feed and multiply. Generates more and more power as a growing swarm!"
icon_state = "jumpercable"
- dedicated_in_aquarium_icon_state = "jumpercable_small"
- sprite_width = 17
+ sprite_width = 16
sprite_height = 5
stable_population = 12
average_size = 110
@@ -449,6 +487,8 @@
name = "ratfish"
desc = "A rat exposed to the murky waters of maintenance too long. Any higher power, if it revealed itself, would state that the ratfish's continued existence is extremely unwelcome."
icon_state = "ratfish"
+ sprite_width = 7
+ sprite_height = 5
random_case_rarity = FISH_RARITY_RARE
required_fluid_type = AQUARIUM_FLUID_FRESHWATER
stable_population = 10 //set by New, but this is the default config value
@@ -456,7 +496,7 @@
fish_traits = list(/datum/fish_trait/necrophage)
required_temperature_min = MIN_AQUARIUM_TEMP+15
required_temperature_max = MIN_AQUARIUM_TEMP+35
- fish_ai_type = FISH_AI_ZIPPY
+ fish_movement_type = /datum/fish_movement/zippy
favorite_bait = list(
list(
"Type" = "Foodtype",
@@ -474,7 +514,6 @@
name = "sludgefish"
desc = "A misshapen, fragile, loosely fish-like living goop, the only thing that'd ever thrive in the acidic and claustrophobic cavities of the station's organic waste disposal system."
icon_state = "sludgefish"
- dedicated_in_aquarium_icon_state = "sludgefish_small"
sprite_width = 7
sprite_height = 6
required_fluid_type = AQUARIUM_FLUID_SULPHWATEVER
@@ -493,7 +532,6 @@
name = "purple sludgefish"
desc = "A misshapen, fragile, loosely fish-like living goop. This one has developed sexual reproduction mechanisms, and a purple tint to boot."
icon_state = "sludgefish_purple"
- dedicated_in_aquarium_icon_state = "sludgefish_purple_small"
random_case_rarity = FISH_RARITY_NOPE
fish_traits = list(/datum/fish_trait/parthenogenesis)
@@ -502,7 +540,6 @@
desc = "Kids, this is what happens when a slime overcomes its hydrophobic nature. It goes glug glug."
icon_state = "slimefish"
icon_state_dead = "slimefish_dead"
- dedicated_in_aquarium_icon_state = "slimefish_small"
sprite_width = 7
sprite_height = 7
do_flop_animation = FALSE //it already has a cute bouncy wiggle. :3
@@ -531,10 +568,9 @@
name = "unmarine bonemass"
desc = "What one could mistake for fish remains, is in reality a species that chose to discard its weak flesh a long time ago. A living fossil, in its most literal sense."
icon_state = "bonemass"
- dedicated_in_aquarium_icon_state = "bonemass_small"
sprite_width = 10
sprite_height = 7
- fish_ai_type = FISH_AI_ZIPPY
+ fish_movement_type = /datum/fish_movement/zippy
random_case_rarity = FISH_RARITY_GOOD_LUCK_FINDING_THIS
required_fluid_type = AQUARIUM_FLUID_ANY_WATER
min_pressure = HAZARD_LOW_PRESSURE
@@ -555,24 +591,22 @@
desc = "A monster of exposed muscles and innards, wrapped in a fish-like skeleton. You don't remember ever seeing it on the catalog."
icon = 'icons/obj/aquarium/wide.dmi'
icon_state = "mastodon"
- dedicated_in_aquarium_icon = 'icons/obj/aquarium/fish.dmi'
- dedicated_in_aquarium_icon_state = "mastodon_small"
base_pixel_x = -16
pixel_x = -16
sprite_width = 12
sprite_height = 7
show_in_catalog = FALSE
random_case_rarity = FISH_RARITY_NOPE
- fishing_difficulty_modifier = 5
+ fishing_difficulty_modifier = 30
required_fluid_type = AQUARIUM_FLUID_ANY_WATER
min_pressure = HAZARD_LOW_PRESSURE
health = 300
- stable_population = 2 //This means they can only crossbreed.
+ stable_population = 1 //This means they can only crossbreed.
grind_results = list(/datum/reagent/bone_dust = 5, /datum/reagent/consumable/liquidgibs = 5)
fillet_type = /obj/item/stack/sheet/bone
num_fillets = 2
feeding_frequency = 2 MINUTES
- breeding_timeout = 10 MINUTES
+ breeding_timeout = 5 MINUTES
average_size = 180
average_weight = 5000
death_text = "%SRC stops moving."
@@ -582,14 +616,16 @@
/obj/item/fish/holo
name = "holographic goldfish"
desc = "A holographic representation of a common goldfish, slowly flickering out, removed from its holo-habitat."
- icon_state = "goldfish"
+ icon_state = /obj/item/fish/goldfish::icon_state
show_in_catalog = FALSE
random_case_rarity = FISH_RARITY_NOPE
- sprite_width = 8
- sprite_height = 8
+ dedicated_in_aquarium_icon_state = /obj/item/fish/goldfish::dedicated_in_aquarium_icon_state
+ aquarium_vc_color = /obj/item/fish/goldfish::aquarium_vc_color
+ sprite_width = /obj/item/fish/goldfish::sprite_width
+ sprite_height = /obj/item/fish/goldfish::sprite_height
stable_population = 1
- average_size = 30
- average_weight = 500
+ average_size = /obj/item/fish/goldfish::average_size
+ average_weight = /obj/item/fish/goldfish::average_weight
required_fluid_type = AQUARIUM_FLUID_ANADROMOUS
grind_results = null
fillet_type = null
@@ -605,7 +641,7 @@
return
holo_area.linked.add_to_spawned(src)
-/obj/item/fish/holo/set_status(new_status)
+/obj/item/fish/holo/set_status(new_status, silent = FALSE)
. = ..()
if(status == FISH_DEAD)
animate(src, alpha = 0, 3 SECONDS, easing = SINE_EASING)
@@ -615,7 +651,9 @@
name = "holographic crab"
desc = "A holographic represantion of a soul-crushingly soulless crab, unlike the cuter ones occasionally roaming around. It stares at you, with empty, beady eyes."
icon_state = "crab"
- dedicated_in_aquarium_icon_state = "crab_small"
+ dedicated_in_aquarium_icon_state = null
+ aquarium_vc_color = null
+ average_size = 30
average_weight = 1000
sprite_height = 6
sprite_width = 10
@@ -623,54 +661,68 @@
/obj/item/fish/holo/puffer
name = "holographic pufferfish"
desc ="A holographic representation of 100% safe-to-eat pufferfish... that is, if holographic fishes were even edible."
- icon_state = "pufferfish"
- sprite_width = 8
- sprite_height = 8
- average_size = 60
- average_weight = 1000
+ icon_state = /obj/item/fish/pufferfish::icon_state
+ dedicated_in_aquarium_icon_state = /obj/item/fish/pufferfish::dedicated_in_aquarium_icon_state
+ aquarium_vc_color = /obj/item/fish/pufferfish::aquarium_vc_color
+ average_size = /obj/item/fish/pufferfish::average_size
+ average_weight = /obj/item/fish/pufferfish::average_weight
+ sprite_height = /obj/item/fish/pufferfish::sprite_height
+ sprite_width = /obj/item/fish/pufferfish::sprite_width
beauty = FISH_BEAUTY_GOOD
/obj/item/fish/holo/angel
name = "holographic angelfish"
desc = "A holographic representation of a angelfish. I got nothing snarky to say about this one."
- icon_state = "angelfish"
- dedicated_in_aquarium_icon_state = "bigfish"
- sprite_height = 7
+ icon_state = /obj/item/fish/angelfish::icon_state
+ dedicated_in_aquarium_icon_state = /obj/item/fish/angelfish::dedicated_in_aquarium_icon_state
+ aquarium_vc_color = /obj/item/fish/angelfish::aquarium_vc_color
+ average_size = /obj/item/fish/angelfish::average_size
+ average_weight = /obj/item/fish/angelfish::average_weight
+ sprite_height = /obj/item/fish/angelfish::sprite_height
+ sprite_width = /obj/item/fish/angelfish::sprite_width
/obj/item/fish/holo/clown
name = "holographic clownfish"
icon_state = "holo_clownfish"
desc = "A holographic representation of a clownfish, or at least how they used to look like five centuries ago."
- dedicated_in_aquarium_icon_state = "holo_clownfish_small"
- required_fluid_type = AQUARIUM_FLUID_SALTWATER
- sprite_width = 8
- sprite_height = 5
+ dedicated_in_aquarium_icon_state = null
+ aquarium_vc_color = /obj/item/fish/clownfish::aquarium_vc_color
+ average_size = /obj/item/fish/clownfish::average_size
+ average_weight = /obj/item/fish/clownfish::average_weight
+ sprite_height = /obj/item/fish/clownfish::sprite_height
+ sprite_width = /obj/item/fish/clownfish::sprite_width
/obj/item/fish/holo/checkered
name = "unrendered holographic fish"
desc = "A checkered silhoutte of searing purple and pitch black presents itself before your eyes, like a tear in fabric of reality. It hurts to watch."
icon_state = "checkered" //it's a meta joke, buddy.
- dedicated_in_aquarium_icon_state = "checkered_small"
+ dedicated_in_aquarium_icon_state = null
+ aquarium_vc_color = null
+ average_size = 30
+ average_weight = 500
sprite_width = 4
+ sprite_height = 3
beauty = FISH_BEAUTY_NULL
/obj/item/fish/holo/halffish
name = "holographic half-fish"
desc = "A holographic representation of... a fish reduced to all bones, except for its head. Isn't it supposed to be dead? Ehr, holo-dead?"
icon_state = "half_fish"
- dedicated_in_aquarium_icon_state = "half_fish_small"
+ dedicated_in_aquarium_icon_state = null
+ aquarium_vc_color = null
sprite_height = 4
sprite_width = 10
average_size = 50
+ average_weight = 500
beauty = FISH_BEAUTY_UGLY
/obj/item/fish/starfish
name = "cosmostarfish"
desc = "A peculiar, gravity-defying, echinoderm-looking critter from hyperspace."
icon_state = "starfish"
- dedicated_in_aquarium_icon_state = "starfish_small"
icon_state_dead = "starfish_dead"
sprite_width = 4
+ sprite_height = 3
average_size = 30
average_weight = 300
stable_population = 3
@@ -709,11 +761,10 @@
average_weight = 500
resistance_flags = FIRE_PROOF | LAVA_PROOF
required_fluid_type = AQUARIUM_FLUID_ANY_WATER //if we can survive hot lava and freezing plasrivers, we can survive anything
- fish_ai_type = FISH_AI_ZIPPY
+ fish_movement_type = /datum/fish_movement/zippy
min_pressure = HAZARD_LOW_PRESSURE
required_temperature_min = MIN_AQUARIUM_TEMP+30
required_temperature_max = MIN_AQUARIUM_TEMP+35
- aquarium_vc_color = "#ce7e1d"
fish_traits = list(
/datum/fish_trait/carnivore,
/datum/fish_trait/heavy,
@@ -777,8 +828,8 @@
desc = "A fish overflowing with crippling anxiety and electric potential. Worried about the walls of its tank closing in constantly. Both literally and as a general metaphorical unease about life's direction."
icon_state = "zipzap"
icon_state_dead = "zipzap_dead"
- sprite_width = 8
- sprite_height = 8
+ sprite_width = 6
+ sprite_height = 3
stable_population = 3
average_size = 30
average_weight = 500
@@ -795,3 +846,360 @@
//anxiety naturally limits the amount of zipzaps per tank, so they are stronger alone
electrogenesis_power = 20 MEGA JOULES
beauty = FISH_BEAUTY_GOOD
+
+/obj/item/fish/sockeye_salmon
+ name = "sockeye salmon"
+ desc = "A fairly common and iconic salmon endemic of the Pacific Ocean. At some point imported into outer space, where we're now."
+ icon_state = "sockeye"
+ sprite_width = 6
+ sprite_height = 4
+ stable_population = 6
+ required_temperature_min = MIN_AQUARIUM_TEMP+3
+ required_temperature_max = MIN_AQUARIUM_TEMP+19
+ required_fluid_type = AQUARIUM_FLUID_ANADROMOUS
+ fillet_type = /obj/item/food/fishmeat/salmon
+ beauty = FISH_BEAUTY_GOOD
+
+/obj/item/fish/arctic_char
+ name = "arctic char"
+ desc = "A cold-water anadromous fish widespread around the Northern Hemisphere of Earth, yet it has somehow found a way here."
+ icon_state = "arctic_char"
+ sprite_width = 7
+ sprite_height = 4
+ stable_population = 6
+ average_size = 60
+ average_weight = 1200
+ weight_size_deviation = 0.5 // known for their size dismophism
+ required_temperature_min = MIN_AQUARIUM_TEMP+3
+ required_temperature_max = MIN_AQUARIUM_TEMP+19
+ required_fluid_type = AQUARIUM_FLUID_ANADROMOUS
+
+/obj/item/fish/stingray
+ name = "stingray"
+ desc = "A type of ray, most known for its venomous stinger. Despite that, They're normally docile, if not a bit easily frightened."
+ icon_state = "stingray"
+ stable_population = 4
+ sprite_height = 7
+ sprite_width = 8
+ average_size = 60
+ average_weight = 700
+ beauty = FISH_BEAUTY_GREAT
+ random_case_rarity = FISH_RARITY_RARE
+ required_fluid_type = AQUARIUM_FLUID_SALTWATER //Someone ought to add river rays later I guess.
+ fish_traits = list(/datum/fish_trait/stinger, /datum/fish_trait/toxic_barbs, /datum/fish_trait/wary, /datum/fish_trait/carnivore, /datum/fish_trait/predator)
+
+/obj/item/fish/sand_surfer
+ name = "sand surfer"
+ desc = "A bronze alien \"fish\" living and swimming underneath faraway sandy places."
+ icon_state = "sand_surfer"
+ sprite_height = 6
+ sprite_width = 6
+ stable_population = 5
+ average_size = 65
+ average_weight = 1100
+ weight_size_deviation = 0.35
+ random_case_rarity = FISH_RARITY_RARE
+ required_fluid_type = AQUARIUM_FLUID_AIR
+ required_temperature_min = MIN_AQUARIUM_TEMP+25
+ required_temperature_max = MIN_AQUARIUM_TEMP+60
+ fish_movement_type = /datum/fish_movement/plunger
+ fishing_difficulty_modifier = 5
+ fish_traits = list(/datum/fish_trait/shiny_lover)
+ beauty = FISH_BEAUTY_GOOD
+
+/obj/item/fish/sand_crab
+ name = "burrower crab"
+ desc = "A sand-dwelling crustacean. It looks like a crab and tastes like a crab, but waddles like a fish."
+ icon_state = "crab"
+ sprite_height = 6
+ sprite_width = 10
+ average_size = 60
+ average_weight = 1000
+ weight_size_deviation = 0.1
+ required_fluid_type = AQUARIUM_FLUID_SALTWATER
+ required_temperature_min = MIN_AQUARIUM_TEMP+20
+ required_temperature_max = MIN_AQUARIUM_TEMP+40
+ fillet_type = /obj/item/food/meat/slab/rawcrab
+ fish_traits = list(/datum/fish_trait/amphibious, /datum/fish_trait/shiny_lover, /datum/fish_trait/carnivore)
+ fish_movement_type = /datum/fish_movement/slow
+ favorite_bait = list(
+ list(
+ "Type" = "Foodtype",
+ "Value" = SEAFOOD,
+ ),
+ )
+
+/obj/item/fish/bumpy
+ name = "bump-fish"
+ desc = "An misshapen fish-thing all covered in stubby little tendrils"
+ icon_state = "bumpy"
+ sprite_height = 4
+ sprite_width = 5
+ stable_population = 4
+ required_fluid_type = AQUARIUM_FLUID_ANY_WATER
+ required_temperature_min = MIN_AQUARIUM_TEMP+15
+ required_temperature_max = MIN_AQUARIUM_TEMP+40
+ beauty = FISH_BEAUTY_BAD
+ fish_traits = list(/datum/fish_trait/amphibious, /datum/fish_trait/vegan)
+ favorite_bait = list(
+ list(
+ "Type" = "Foodtype",
+ "Value" = VEGETABLES,
+ ),
+ )
+
+/obj/item/fish/swordfish
+ name = "swordfish"
+ desc = "A large billfish, most famous for its elongated bill, while also fairly popular for cooking, and as a fearsome weapon in the hands of a veteran spess-fisherman."
+ icon = 'icons/obj/aquarium/wide.dmi'
+ icon_state = "swordfish"
+ inhand_icon_state = "swordfish"
+ force = 18
+ sharpness = SHARP_EDGED
+ attack_verb_continuous = list("slashes", "cuts", "pierces")
+ attack_verb_simple = list("slash", "cut", "pierce")
+ block_sound = 'sound/weapons/parry.ogg'
+ hitsound = 'sound/weapons/rapierhit.ogg'
+ demolition_mod = 0.75
+ attack_speed = 1 SECONDS
+ block_chance = 50
+ wound_bonus = 10
+ bare_wound_bonus = 20
+ armour_penetration = 75
+ base_pixel_x = -18
+ pixel_x = -18
+ sprite_width = 13
+ sprite_height = 6
+ stable_population = 3
+ average_size = 140
+ average_weight = 4000
+ breeding_timeout = 4.5 MINUTES
+ feeding_frequency = 4 MINUTES
+ health = 180
+ beauty = FISH_BEAUTY_EXCELLENT
+ random_case_rarity = FISH_RARITY_GOOD_LUCK_FINDING_THIS
+ required_fluid_type = AQUARIUM_FLUID_SALTWATER
+ fish_movement_type = /datum/fish_movement/plunger
+ fishing_difficulty_modifier = 25
+ fillet_type = /obj/item/food/fishmeat/quality
+ favorite_bait = list(
+ list(
+ "Type" = "Foodtype",
+ "Value" = SEAFOOD,
+ ),
+ )
+ fish_traits = list(/datum/fish_trait/carnivore, /datum/fish_trait/predator, /datum/fish_trait/stinger)
+
+/obj/item/fish/swordfish/get_force_rank()
+ switch(w_class)
+ if(WEIGHT_CLASS_TINY)
+ force -= 11
+ attack_speed -= 0.4 SECONDS
+ block_chance -= 45
+ armour_penetration -= 20
+ wound_bonus -= 15
+ bare_wound_bonus -= 20
+ if(WEIGHT_CLASS_SMALL)
+ force -= 8
+ attack_speed -= 0.3 SECONDS
+ block_chance -= 30
+ armour_penetration -= 15
+ wound_bonus -= 10
+ bare_wound_bonus -= 20
+ if(WEIGHT_CLASS_NORMAL)
+ force -= 5
+ attack_speed -= 0.2 SECONDS
+ block_chance -= 20
+ armour_penetration -= 10
+ wound_bonus -= 10
+ bare_wound_bonus -= 15
+ if(WEIGHT_CLASS_BULKY)
+ force -= 3
+ attack_speed -= 0.1 SECONDS
+ block_chance -= 10
+ armour_penetration -= 5
+ wound_bonus -= 5
+ bare_wound_bonus -= 10
+ if(WEIGHT_CLASS_GIGANTIC)
+ force += 5
+ attack_speed += 0.2 SECONDS
+ demolition_mod += 0.15
+ block_chance += 10
+ armour_penetration += 5
+ wound_bonus += 5
+ bare_wound_bonus += 10
+
+ if(status == FISH_DEAD)
+ force -= 4 + w_class
+ block_chance -= 25
+ armour_penetration -= 30
+ wound_bonus -= 10
+ bare_wound_bonus -= 10
+
+/obj/item/fish/swordfish/calculate_fish_force_bonus(bonus_malus)
+ . = ..()
+ armour_penetration += bonus_malus * 5
+ wound_bonus += bonus_malus * 3
+ bare_wound_bonus += bonus_malus * 5
+ block_chance += bonus_malus * 7
+
+/obj/item/fish/chainsawfish
+ name = "chainsawfish"
+ desc = "A very, very angry bioweapon, whose sole purpose is to rip and tear."
+ icon = 'icons/obj/aquarium/wide.dmi'
+ icon_state = "chainsawfish"
+ inhand_icon_state = "chainsawfish"
+ icon_state_dead = "chainsawfish_dead"
+ force = 22
+ demolition_mod = 1.5
+ block_chance = 15
+ attack_verb_continuous = list("saws", "tears", "lacerates", "cuts", "chops", "dices")
+ attack_verb_simple = list("saw", "tear", "lacerate", "cut", "chop", "dice")
+ hitsound = 'sound/weapons/chainsawhit.ogg'
+ sharpness = SHARP_EDGED
+ tool_behaviour = TOOL_SAW
+ toolspeed = 0.5
+ base_pixel_x = -16
+ pixel_x = -16
+ sprite_width = 8
+ sprite_height = 5
+ stable_population = 3
+ average_size = 85
+ average_weight = 2500
+ breeding_timeout = 4.25 MINUTES
+ feeding_frequency = 3 MINUTES
+ health = 180
+ beauty = FISH_BEAUTY_GREAT
+ random_case_rarity = FISH_RARITY_GOOD_LUCK_FINDING_THIS
+ required_fluid_type = AQUARIUM_FLUID_FRESHWATER
+ fish_movement_type = /datum/fish_movement/accelerando
+ fishing_difficulty_modifier = 30
+ favorite_bait = list(
+ list(
+ "Type" = "Foodtype",
+ "Value" = GORE
+ ),
+ )
+ fish_traits = list(/datum/fish_trait/aggressive, /datum/fish_trait/carnivore, /datum/fish_trait/predator, /datum/fish_trait/stinger)
+ required_temperature_min = MIN_AQUARIUM_TEMP+18
+ required_temperature_max = MIN_AQUARIUM_TEMP+26
+
+/obj/item/fish/chainsawfish/Initialize(mapload)
+ . = ..()
+ AddElement(/datum/element/update_icon_updates_onmob)
+
+/obj/item/fish/chainsawfish/update_icon_state()
+ if(status == FISH_DEAD)
+ inhand_icon_state = "chainsawfish_dead"
+ else
+ inhand_icon_state = "chainsawfish"
+ if(HAS_TRAIT(src, TRAIT_WIELDED))
+ inhand_icon_state = "[inhand_icon_state]_wielded"
+ return ..()
+
+/obj/item/fish/chainsawfish/get_force_rank()
+ switch(w_class)
+ if(WEIGHT_CLASS_TINY)
+ force -= 10
+ attack_speed -= 0.2 SECONDS
+ demolition_mod -= 0.4
+ block_chance -= 15
+ armour_penetration -= 10
+ wound_bonus -= 10
+ bare_wound_bonus -= 10
+ toolspeed += 0.6
+ if(WEIGHT_CLASS_SMALL)
+ force -= 8
+ attack_speed -= 0.1 SECONDS
+ demolition_mod -= 0.3
+ block_chance -= 10
+ armour_penetration -= 10
+ wound_bonus -= 10
+ bare_wound_bonus -= 10
+ toolspeed += 0.4
+ if(WEIGHT_CLASS_NORMAL)
+ force -= 5
+ demolition_mod -= 0.15
+ block_chance -= 5
+ armour_penetration -= 5
+ wound_bonus -= 5
+ bare_wound_bonus -= 5
+ toolspeed += 0.2
+ if(WEIGHT_CLASS_HUGE)
+ force += 2
+ attack_speed += 0.2 SECONDS
+ demolition_mod += 0.15
+ armour_penetration += 10
+ block_chance += 10
+ wound_bonus += 10
+ bare_wound_bonus += 5
+ if(WEIGHT_CLASS_GIGANTIC)
+ force += 4
+ attack_speed += 0.4 SECONDS
+ demolition_mod += 0.3
+ block_chance += 20
+ armour_penetration += 20
+ wound_bonus += 15
+ bare_wound_bonus += 10
+ toolspeed -= 0.1
+
+ if(status == FISH_DEAD)
+ force -= 8 + w_class
+ hitsound = SFX_SWING_HIT
+ block_chance -= 25
+ demolition_mod -= 0.3
+ armour_penetration -= 15
+ wound_bonus -= 5
+ bare_wound_bonus -= 5
+ toolspeed += 1
+
+/obj/item/fish/chainsawfish/calculate_fish_force_bonus(bonus_malus)
+ . = ..()
+ armour_penetration += bonus_malus * 3
+ wound_bonus += bonus_malus * 2
+ bare_wound_bonus += bonus_malus * 3
+ block_chance += bonus_malus * 2
+ toolspeed -= bonus_malus * 0.1
+
+/obj/item/fish/soul
+ name = "soulfish"
+ desc = "A distant yet vaguely close critter, like a long lost relative. You feel your soul rejuvenated just from looking at it... Also, what the fuck is this shit?!"
+ icon_state = "soulfish"
+ sprite_width = 7
+ sprite_height = 6
+ average_size = 60
+ average_weight = 1200
+ stable_population = 4
+ show_in_catalog = FALSE
+ beauty = FISH_BEAUTY_EXCELLENT
+ fish_movement_type = /datum/fish_movement/choppy //Glideless legacy movement? in my fishing minigame?
+ favorite_bait = list(
+ list(
+ "Type" = "Foodtype",
+ "Value" = FRIED
+ ),
+ )
+ fillet_type = /obj/item/food/meat/cutlet/plain/human
+ required_temperature_min = MIN_AQUARIUM_TEMP+3
+ required_temperature_max = MIN_AQUARIUM_TEMP+38
+ random_case_rarity = FISH_RARITY_NOPE
+
+/obj/item/fish/skin_crab
+ name = "skin crab"
+ desc = "\"And on the eighth day, a demential mockery of both humanity and crabity was made.\" Fascinating."
+ icon_state = "skin_crab"
+ sprite_width = 7
+ sprite_height = 6
+ average_size = 40
+ average_weight = 750
+ stable_population = 5
+ show_in_catalog = FALSE
+ beauty = FISH_BEAUTY_GREAT
+ favorite_bait = list(
+ list(
+ "Type" = "Foodtype",
+ "Value" = FRIED
+ ),
+ )
+ fillet_type = /obj/item/food/meat/slab/rawcrab
+ random_case_rarity = FISH_RARITY_NOPE
diff --git a/code/modules/fishing/fish_movement.dm b/code/modules/fishing/fish_movement.dm
new file mode 100644
index 0000000000000..a328903617f62
--- /dev/null
+++ b/code/modules/fishing/fish_movement.dm
@@ -0,0 +1,214 @@
+/// Any lower than this, and the target position of the fish is considered null
+#define FISH_TARGET_MIN_DISTANCE 6
+/// The friction applied to fish jumps, so that it decelerates over time
+#define FISH_FRICTION_MULT 0.9
+/// Used to decide whether the fish can jump in a certain direction
+#define FISH_SHORT_JUMP_MIN_DISTANCE 100
+/// The maximum distance for a short jump
+#define FISH_SHORT_JUMP_MAX_DISTANCE 200
+
+///Fish movements are simple datums, generated by the fishing minigame, that represent how the fish moves suring the minigame.
+/datum/fish_movement
+ /// The minigame that spawned us
+ var/datum/fishing_challenge/master
+ /// How many times move_fish() has been called
+ var/times_fired = 0
+ /// How likely the fish is to perform a standard jump, then multiplied by difficulty
+ var/short_jump_chance = 2.25
+ /// How likely the fish is to perform a long jump, then multiplied by difficulty
+ var/long_jump_chance = 0.0625
+ /// The speed limit for the short jump
+ var/short_jump_velocity_limit = 400
+ /// The speed limit for the long jump
+ var/long_jump_velocity_limit = 200
+ /// The current speed limit used
+ var/current_velocity_limit
+ /// The base velocity of the fish, which may affect jump distances and falling speed.
+ var/fish_idle_velocity = 0
+ /// A position on the slider the fish wants to get to
+ var/target_position
+ /// If true, the fish can jump while a target position is set, thus overriding it
+ var/can_interrupt_move = TRUE
+ /// The current speed the fish is moving at
+ var/fish_velocity = 0
+
+/datum/fish_movement/New(datum/fishing_challenge/master)
+ src.master = master
+
+/**
+ * Proc that adjusts movement values to the difficulty of the minigame.
+ * The operations can be a tad complex, but basically it ensures that jump
+ * chances with a probability higher than 1% increase in a smooth curve so that
+ * they still reach 100% prob when the difficulty peakes.
+ */
+/datum/fish_movement/proc/adjust_to_difficulty()
+ var/square_angle_rad = TORADIANS(90)
+ var/zero_one_difficulty = master.difficulty/100
+ if(short_jump_chance > 1)
+ short_jump_chance = (zero_one_difficulty**(square_angle_rad-TORADIANS(arctan(short_jump_chance * 1/square_angle_rad))))*100
+ else
+ short_jump_chance *= master.difficulty
+ if(long_jump_chance > 1)
+ long_jump_chance = (zero_one_difficulty**(square_angle_rad-TORADIANS(arctan(long_jump_chance * 1/square_angle_rad))))*100
+ else
+ long_jump_chance *= master.difficulty
+
+///The main proc, called by minigame every SSfishing tick while it's in the 'active' phase.
+/datum/fish_movement/proc/move_fish(seconds_per_tick)
+ times_fired++
+ /**
+ * The jump chances are meant to run every odd tick (each every decisecond)
+ * We cannot do it every tick because the fish would be jumpier than intended
+ * and we cannot cut the chances in half to fit on each tick, because the maximum probability
+ * would go from 100% to 75%.
+ */
+ var/can_roll = times_fired % 2
+
+ var/long_chance = long_jump_chance * seconds_per_tick * (1/seconds_per_tick)
+ var/short_chance = short_jump_chance * seconds_per_tick * (1/seconds_per_tick)
+
+ // If we have the target but we're close enough, mark as target reached
+ if(abs(target_position - master.fish_position) < FISH_TARGET_MIN_DISTANCE)
+ target_position = null
+
+ // Switching to new long jump target can interrupt any other
+ if(can_roll && (can_interrupt_move || isnull(target_position)) && prob(long_chance))
+ /**
+ * Move at least 0.75 to full of the availible bar in given direction,
+ * and more likely to move in the direction where there's more space
+ */
+ var/distance_from_top = FISHING_MINIGAME_AREA - master.fish_position - master.fish_height
+ var/distance_from_bottom = master.fish_position
+ var/top_chance
+ if(distance_from_top < FISH_SHORT_JUMP_MIN_DISTANCE)
+ top_chance = 0
+ else
+ top_chance = (distance_from_top/max(distance_from_bottom, 1)) * 100
+ var/new_target = master.fish_position
+ if(prob(top_chance))
+ new_target += distance_from_top * rand(75, 100)/100
+ else
+ new_target -= distance_from_bottom * rand(75, 100)/100
+ target_position = round(new_target)
+ current_velocity_limit = long_jump_velocity_limit
+
+ // Move towards target
+ if(!isnull(target_position))
+ var/distance = target_position - master.fish_position
+ // about 5 at diff 15 , 10 at diff 30, 30 at diff 100
+ var/acceleration_mult = get_acceleration(seconds_per_tick)
+ var/target_acceleration = distance * acceleration_mult * seconds_per_tick
+
+ fish_velocity = fish_velocity * FISH_FRICTION_MULT + target_acceleration
+ else if(can_roll && prob(short_chance))
+ var/distance_from_top = FISHING_MINIGAME_AREA - master.fish_position - master.fish_height
+ var/distance_from_bottom = master.fish_position
+ var/jump_length
+ if(distance_from_top >= FISH_SHORT_JUMP_MIN_DISTANCE)
+ jump_length = rand(FISH_SHORT_JUMP_MIN_DISTANCE, FISH_SHORT_JUMP_MAX_DISTANCE)
+ if(distance_from_bottom >= FISH_SHORT_JUMP_MIN_DISTANCE && (!jump_length || prob(50)))
+ jump_length = -rand(FISH_SHORT_JUMP_MIN_DISTANCE, FISH_SHORT_JUMP_MAX_DISTANCE)
+ target_position = clamp(master.fish_position + jump_length, 0, FISHING_MINIGAME_AREA - master.fish_height)
+ current_velocity_limit = short_jump_velocity_limit
+
+ fish_velocity = clamp(fish_velocity + fish_idle_velocity, -current_velocity_limit, current_velocity_limit)
+ set_fish_position(seconds_per_tick)
+
+///Proc that returns the acceleration of the fish during the minigame.
+/datum/fish_movement/proc/get_acceleration(seconds_per_tick)
+ return 0.3 * master.difficulty + 0.5
+
+///Called at the end of move_fish(), for updating the position of the fish in the fishing minigame.
+/datum/fish_movement/proc/set_fish_position(seconds_per_tick)
+ master.fish_position = clamp(master.fish_position + fish_velocity * seconds_per_tick, 0, FISHING_MINIGAME_AREA - master.fish_height)
+
+///Generic fish movement datum that only performs slow, uninterrupted long jumps
+/datum/fish_movement/slow
+ short_jump_chance = 0
+ long_jump_chance = 1.5
+ long_jump_velocity_limit = 150
+ can_interrupt_move = FALSE
+
+///Generic fish movement datum with triple the short jump chance.
+/datum/fish_movement/zippy
+ short_jump_chance = parent_type::short_jump_chance * 3
+
+///fish movement datum that progressively gets faster until acceleration and velocity are double the starting ones.
+/datum/fish_movement/accelerando
+ ///The jump velocity to add each tick
+ var/short_jump_vel_add
+ ///The long jump velocity to add each tick
+ var/long_jump_vel_add
+ ///Time to reach full speed, in seconds.
+ var/accel_time_cap = 30
+
+/datum/fish_movement/accelerando/move_fish(seconds_per_tick)
+ var/seconds_elapsed = (times_fired * seconds_per_tick)
+ if(seconds_elapsed >= accel_time_cap)
+ return ..()
+ if(!times_fired) //First tick, cache the initial jump velocities
+ short_jump_vel_add = short_jump_velocity_limit/accel_time_cap
+ long_jump_vel_add = long_jump_velocity_limit/accel_time_cap
+ return ..()
+
+ if(current_velocity_limit)
+ var/vel_add = current_velocity_limit == short_jump_velocity_limit ? short_jump_vel_add : long_jump_vel_add
+ current_velocity_limit += round(vel_add * seconds_per_tick, 0.01)
+
+ short_jump_velocity_limit += round(short_jump_vel_add * seconds_per_tick, 0.01)
+ long_jump_velocity_limit += round(long_jump_vel_add * seconds_per_tick, 0.01)
+ return ..()
+
+/datum/fish_movement/accelerando/get_acceleration(seconds_per_tick)
+ var/acceleration = ..()
+ return acceleration + min(acceleration, acceleration * times_fired * seconds_per_tick / accel_time_cap)
+
+/datum/fish_movement/accelerando/set_fish_position(seconds_per_tick)
+ fish_velocity = round(fish_velocity)
+ return ..()
+
+///Fish movement datum that updates the fish position twice per second.
+/datum/fish_movement/choppy
+ ///We keep of the theorical fish position to eventually use
+ var/faux_position = 0
+
+/datum/fish_movement/choppy/set_fish_position(seconds_per_tick)
+ faux_position = clamp(faux_position + fish_velocity * seconds_per_tick, 0, FISHING_MINIGAME_AREA - master.fish_height)
+ if(!((times_fired * SSfishing.wait) % (0.5 SECONDS)))
+ master.fish_position = faux_position
+
+///Fish movement datum that weakly pushes the fish up and then down with greater force once it reaches the top of the minigame.
+/datum/fish_movement/plunger
+ ///Is the fish plunging to the bottom of the minigame area, or should it swim up?
+ var/is_plunging = TRUE
+ ///The added idle velocity when plunging
+ var/plunging_speed = -22
+
+/datum/fish_movement/plunger/adjust_to_difficulty()
+ . = ..()
+ //Adjust the fleeing velocity, up to five times the initial value.
+ plunging_speed += round(plunging_speed * master.difficulty * 0.03)
+ fish_idle_velocity += plunging_speed //so it can be safely subtracted if the fish starts at the bottom.
+
+/datum/fish_movement/plunger/move_fish(seconds_per_tick)
+ var/fish_area = FISHING_MINIGAME_AREA - master.fish_height
+ if(is_plunging)
+ if(target_position > master.fish_position) //nothing should stop us from plunging.
+ target_position = null
+ var/dist_bot_percent = master.fish_position/fish_area
+ if(dist_bot_percent <= 0.04)
+ fish_idle_velocity -= plunging_speed
+ is_plunging = FALSE
+ else
+ var/dist_top_percent = (fish_area - master.fish_position)/fish_area
+ if(dist_top_percent <= 0.04)
+ fish_idle_velocity += plunging_speed
+ is_plunging = TRUE
+
+ return ..()
+
+
+#undef FISH_TARGET_MIN_DISTANCE
+#undef FISH_FRICTION_MULT
+#undef FISH_SHORT_JUMP_MIN_DISTANCE
+#undef FISH_SHORT_JUMP_MAX_DISTANCE
diff --git a/code/modules/fishing/fishing_equipment.dm b/code/modules/fishing/fishing_equipment.dm
index f6b49a9b52314..5408e411876b9 100644
--- a/code/modules/fishing/fishing_equipment.dm
+++ b/code/modules/fishing/fishing_equipment.dm
@@ -260,7 +260,6 @@
// Can hold fishing rod despite the size
var/static/list/exception_cache = typecacheof(list(
/obj/item/fishing_rod,
- /obj/item/fishing_line,
))
atom_storage.exception_hold = exception_cache
@@ -269,6 +268,7 @@
new /obj/item/fishing_rod/unslotted(src)
new /obj/item/fishing_hook(src)
new /obj/item/fishing_line(src)
+ new /obj/item/paper/paperslip/fishing_tip(src)
/obj/item/storage/toolbox/fishing/small
name = "compact fishing toolbox"
@@ -285,31 +285,84 @@
new /obj/item/fishing_rod/unslotted(src)
new /obj/item/fishing_hook(src)
new /obj/item/fishing_line(src)
+ new /obj/item/paper/paperslip/fishing_tip(src)
+
+/obj/item/storage/toolbox/fishing/master
+ name = "super fishing toolbox"
+ desc = "Contains EVERYTHING (almost) you need for your fishing trip."
+ icon_state = "gold"
+ inhand_icon_state = "toolbox_gold"
+
+/obj/item/storage/toolbox/fishing/master/PopulateContents()
+ new /obj/item/fishing_rod/telescopic/master(src)
+ new /obj/item/storage/box/fishing_hooks/master(src)
+ new /obj/item/storage/box/fishing_lines/master(src)
+ new /obj/item/bait_can/super_baits(src)
+ new /obj/item/fish_feed(src)
+ new /obj/item/aquarium_kit(src)
+ new /obj/item/fish_analyzer(src)
+ new /obj/item/experi_scanner(src)
/obj/item/storage/box/fishing_hooks
name = "fishing hook set"
+ illustration = "fish"
/obj/item/storage/box/fishing_hooks/PopulateContents()
- . = ..()
new /obj/item/fishing_hook/magnet(src)
new /obj/item/fishing_hook/shiny(src)
new /obj/item/fishing_hook/weighted(src)
+/obj/item/storage/box/fishing_hooks/master
+
+/obj/item/storage/box/fishing_hooks/master/PopulateContents()
+ . = ..()
+ new /obj/item/fishing_hook/stabilized(src)
+ new /obj/item/fishing_hook/jaws(src)
+
/obj/item/storage/box/fishing_lines
name = "fishing line set"
+ illustration = "fish"
/obj/item/storage/box/fishing_lines/PopulateContents()
- . = ..()
new /obj/item/fishing_line/bouncy(src)
new /obj/item/fishing_line/reinforced(src)
new /obj/item/fishing_line/cloaked(src)
+/obj/item/storage/box/fishing_lines/master
+
+/obj/item/storage/box/fishing_lines/master/PopulateContents()
+ . = ..()
+ new /obj/item/fishing_line/auto_reel(src)
+
/obj/item/storage/box/fish_debug
name = "box full of fish"
+ illustration = "fish"
/obj/item/storage/box/fish_debug/PopulateContents()
for(var/fish_type in subtypesof(/obj/item/fish))
new fish_type(src)
+///Used to give the average player info about fishing stuff that's unknown to many.
+/obj/item/paper/paperslip/fishing_tip
+ name = "fishing tip"
+ desc = "A slip of paper containing a pearl of wisdom about fishing within it, though you wish it were an actual pearl."
+
+/obj/item/paper/paperslip/fortune/Initialize(mapload)
+ default_raw_text = pick(GLOB.fishing_tips)
+ return ..()
+
+///From the fishing mystery box. It's basically a lazarus and a few bottles of strange reagents.
+/obj/item/storage/box/fish_revival_kit
+ name = "fish revival kit"
+ desc = "Become a fish doctor today."
+ illustration = "fish"
+
+/obj/item/storage/box/fish_revival_kit/PopulateContents()
+ new /obj/item/lazarus_injector(src)
+ new /obj/item/reagent_containers/cup/bottle/strange_reagent(src)
+ new /obj/item/reagent_containers/cup(src) //to splash the reagents on the fish.
+ new /obj/item/storage/fish_case(src)
+ new /obj/item/storage/fish_case(src)
+
#undef MAGNET_HOOK_BONUS_MULTIPLIER
#undef RESCUE_HOOK_FISH_MULTIPLIER
diff --git a/code/modules/fishing/fishing_minigame.dm b/code/modules/fishing/fishing_minigame.dm
index 9c70d474a62d7..f53437e355953 100644
--- a/code/modules/fishing/fishing_minigame.dm
+++ b/code/modules/fishing/fishing_minigame.dm
@@ -5,16 +5,6 @@
// UI minigame phase
#define MINIGAME_PHASE 3
-/// The height of the minigame slider. Not in pixels, but minigame units.
-#define FISHING_MINIGAME_AREA 1000
-/// Any lower than this, and the target position of the fish is considered null
-#define FISH_TARGET_MIN_DISTANCE 6
-/// The friction applied to fish jumps, so that it decelerates over time
-#define FISH_FRICTION_MULT 0.9
-/// Used to decide whether the fish can jump in a certain direction
-#define FISH_SHORT_JUMP_MIN_DISTANCE 100
-/// The maximum distance for a short jump
-#define FISH_SHORT_JUMP_MAX_DISTANCE 200
// Acceleration mod when bait is over fish
#define FISH_ON_BAIT_ACCELERATION_MULT 0.6
/// The minimum velocity required for the bait to bounce
@@ -47,8 +37,6 @@
var/start_time
/// Is it finished (either by win/lose or window closing)
var/completed = FALSE
- /// Fish AI type to use
- var/fish_ai = FISH_AI_DUMB
/// Rule modifiers (eg weighted bait)
var/special_effects = NONE
/// A list of possible active minigame effects. If not empty, one will be picked from time to time.
@@ -74,7 +62,7 @@
/// Background icon state from fishing_hud.dmi
var/background = "background_default"
/// Fish icon state from fishing_hud.dmi
- var/fish_icon = "fish"
+ var/fish_icon = FISH_ICON_DEF
/// Fishing line visual
var/datum/beam/fishing_line
@@ -93,8 +81,6 @@
var/fish_position = 0
/// The position of the bait on the minigame slider
var/bait_position = 0
- /// The current speed the fish is moving at
- var/fish_velocity = 0
/// The current speed the bait is moving at
var/bait_velocity = 0
@@ -105,22 +91,7 @@
/// How much completion is gained per second when the bait area is intersecting with the fish's
var/completion_gain = 5
- /// How likely the fish is to perform a standard jump, then multiplied by difficulty
- var/short_jump_chance = 2.25
- /// How likely the fish is to perform a long jump, then multiplied by difficulty
- var/long_jump_chance = 0.0625
- /// The speed limit for the short jump
- var/short_jump_velocity_limit = 400
- /// The speed limit for the long jump
- var/long_jump_velocity_limit = 200
- /// The current speed limit used
- var/current_velocity_limit = 200
- /// The base velocity of the fish, which may affect jump distances and falling speed.
- var/fish_idle_velocity = 0
- /// A position on the slider the fish wants to get to
- var/target_position
- /// If true, the fish can jump while a target position is set, thus overriding it
- var/can_interrupt_move = TRUE
+ var/datum/fish_movement/mover
/// Whether the bait is idle or reeling up or down (left and right click)
var/reeling_state = REELING_STATE_IDLE
@@ -144,24 +115,21 @@
RegisterSignal(comp.fish_source, COMSIG_FISHING_SOURCE_INTERRUPT_CHALLENGE, PROC_REF(interrupt_challenge))
comp.fish_source.RegisterSignal(src, COMSIG_FISHING_CHALLENGE_COMPLETED, TYPE_PROC_REF(/datum/fish_source, on_challenge_completed))
background = comp.fish_source.background
+
/// Fish minigame properties
if(ispath(reward_path,/obj/item/fish))
var/obj/item/fish/fish = reward_path
- fish_ai = initial(fish.fish_ai_type)
- switch(fish_ai)
- if(FISH_AI_ZIPPY) // Keeps on jumping
- short_jump_chance *= 3
- if(FISH_AI_SLOW) // Only does long jump, and doesn't change direction until it gets there
- short_jump_chance = 0
- long_jump_chance = 1.5
- long_jump_velocity_limit = 150
- long_jump_velocity_limit = FALSE
+ var/movement_path = initial(fish.fish_movement_type)
+ mover = new movement_path(src)
// Apply fish trait modifiers
var/list/fish_list_properties = collect_fish_properties()
var/list/fish_traits = fish_list_properties[fish][NAMEOF(fish, fish_traits)]
for(var/fish_trait in fish_traits)
var/datum/fish_trait/trait = GLOB.fish_traits[fish_trait]
trait.minigame_mod(rod, user, src)
+ else
+ mover = new /datum/fish_movement(src)
+
/// Enable special parameters
if(rod.line)
completion_gain += 1 // Any fishing line will provide a small boost by default
@@ -196,24 +164,9 @@
completion -= MAX_FISH_COMPLETION_MALUS * (difficulty * 0.01)
if(HAS_MIND_TRAIT(user, TRAIT_REVEAL_FISH))
- fish_icon = GLOB.specific_fish_icons[reward_path] || "fish"
+ fish_icon = GLOB.specific_fish_icons[reward_path] || FISH_ICON_DEF
- /**
- * If the chances are higher than 1% (100% at maximum difficulty), they'll scale
- * less than proportionally (exponent less than 1) instead.
- * This way we ensure fish with high jump chances won't get TOO jumpy until
- * they near the maximum difficulty, at which they hit 100%
- */
- var/square_angle_rad = TORADIANS(90)
- var/zero_one_difficulty = difficulty/100
- if(short_jump_chance > 1)
- short_jump_chance = (zero_one_difficulty**(square_angle_rad-TORADIANS(arctan(short_jump_chance * 1/square_angle_rad))))*100
- else
- short_jump_chance *= difficulty
- if(long_jump_chance > 1)
- long_jump_chance = (zero_one_difficulty**(square_angle_rad-TORADIANS(arctan(long_jump_chance * 1/square_angle_rad))))*100
- else
- long_jump_chance *= difficulty
+ mover.adjust_to_difficulty()
bait_height -= round(difficulty * BAIT_HEIGHT_DIFFICULTY_MALUS)
bait_pixel_height = round(MINIGAME_BAIT_HEIGHT * (bait_height/initial(bait_height)), 1)
@@ -230,6 +183,7 @@
SStgui.close_uis(src)
user = null
used_rod = null
+ QDEL_NULL(mover)
return ..()
/datum/fishing_challenge/proc/send_alert(message)
@@ -242,21 +196,25 @@
interrupt()
/datum/fishing_challenge/proc/interrupt_challenge(datum/source, reason)
+ SIGNAL_HANDLER
if(reason)
send_alert(reason)
interrupt()
/datum/fishing_challenge/proc/start(mob/living/user)
/// Create fishing line visuals
- if(used_rod.display_fishing_line)
- fishing_line = used_rod.create_fishing_line(lure, target_py = 5)
+ if(!used_rod.internal)
+ fishing_line = used_rod.create_fishing_line(lure, user, target_py = 5)
RegisterSignal(fishing_line, COMSIG_QDELETING, PROC_REF(on_line_deleted))
else //if the rod doesnt have a fishing line, then it ends when they move away
- RegisterSignal(user, COMSIG_MOVABLE_MOVED, PROC_REF(on_user_move))
+ RegisterSignal(user, COMSIG_MOVABLE_MOVED, PROC_REF(on_lure_or_user_move))
+ RegisterSignal(lure, COMSIG_MOVABLE_MOVED, PROC_REF(on_lure_or_user_move))
+ RegisterSignal(user, SIGNAL_ADDTRAIT(TRAIT_HANDS_BLOCKED), PROC_REF(on_hands_blocked))
+ RegisterSignal(user, SIGNAL_REMOVETRAIT(TRAIT_PROFOUND_FISHER), PROC_REF(no_longer_fishing))
active_effects = bitfield_to_list(special_effects & FISHING_MINIGAME_ACTIVE_EFFECTS)
// If fishing line breaks los / rod gets dropped / deleted
RegisterSignal(used_rod, COMSIG_ITEM_ATTACK_SELF, PROC_REF(on_attack_self))
- ADD_TRAIT(user, TRAIT_GONE_FISHING, REF(src))
+ ADD_TRAIT(user, TRAIT_GONE_FISHING, WEAKREF(src))
user.add_mood_event("fishing", /datum/mood_event/fishing)
RegisterSignal(user, COMSIG_MOB_CLICKON, PROC_REF(handle_click))
start_baiting_phase()
@@ -270,17 +228,33 @@
user.balloon_alert(user, user.is_holding(used_rod) ? "line snapped" : "rod dropped")
interrupt()
-/datum/fishing_challenge/proc/on_user_move(datum/source)
+/datum/fishing_challenge/proc/on_lure_or_user_move(datum/source)
SIGNAL_HANDLER
- user.balloon_alert(user, "too far!")
+ if(!user.CanReach(lure))
+ user.balloon_alert(user, "too far!")
+ interrupt()
+
+/datum/fishing_challenge/proc/on_hands_blocked(datum/source)
+ SIGNAL_HANDLER
+ if(completed) //the rod was dropped and therefore challenge already completed.
+ return
+ user.balloon_alert(user, "hands blocked!")
+ interrupt()
+
+/datum/fishing_challenge/proc/no_longer_fishing(datum/source)
+ SIGNAL_HANDLER
+ user.balloon_alert(user, "interrupted!")
interrupt()
/datum/fishing_challenge/proc/handle_click(mob/source, atom/target, modifiers)
SIGNAL_HANDLER
- //You need to be holding the rod to use it.
+ if(HAS_TRAIT(source, TRAIT_HANDS_BLOCKED)) //blocked, can't do stuff
+ return
+ //Doing other stuff
if(LAZYACCESS(modifiers, SHIFT_CLICK) || LAZYACCESS(modifiers, CTRL_CLICK) || LAZYACCESS(modifiers, ALT_CLICK))
return
+ //You need to be actively holding on the fishing rod to use it, unless you've the profound_fisher trait.
if(!HAS_TRAIT(source, TRAIT_PROFOUND_FISHER) && source.get_active_held_item() != used_rod)
return
if(phase == WAIT_PHASE)
@@ -313,8 +287,9 @@
completed = TRUE
if(phase == MINIGAME_PHASE)
remove_minigame_hud()
- if(user)
- REMOVE_TRAIT(user, TRAIT_GONE_FISHING, REF(src))
+ if(!QDELETED(user))
+ UnregisterSignal(user, SIGNAL_REMOVETRAIT(TRAIT_GONE_FISHING))
+ user.remove_traits(list(TRAIT_GONE_FISHING, TRAIT_ACTIVELY_FISHING), WEAKREF(src))
if(start_time)
var/seconds_spent = (world.time - start_time) * 0.1
if(!(special_effects & FISHING_MINIGAME_RULE_NO_EXP))
@@ -369,6 +344,16 @@
send_alert("crustacean!!!")
if(FISH_ICON_BONE)
send_alert("bones!!!")
+ if(FISH_ICON_ELECTRIC)
+ send_alert("zappy!!!")
+ if(FISH_ICON_WEAPON)
+ send_alert("weapon!!!")
+ if(FISH_ICON_CRITTER)
+ send_alert("critter!!!")
+ if(FISH_ICON_SEED)
+ send_alert("seed!!!")
+ if(FISH_ICON_BOTTLE)
+ send_alert("bottle!!!")
else
send_alert("!!!")
animate(lure, pixel_y = 3, time = 5, loop = -1, flags = ANIMATION_RELATIVE)
@@ -413,8 +398,13 @@
completion *= 1.2
if(BITING_TIME_WINDOW - 0.5 SECONDS to BITING_TIME_WINDOW)
completion *= 1.4
+ //randomize the position of the fish a little
+ fish_position = rand(0, (FISHING_MINIGAME_AREA - fish_height) * 0.8)
+ var/diff_dist = 100 + difficulty
+ bait_position = clamp(round(fish_position + rand(-diff_dist, diff_dist) - bait_height * 0.5), 0, FISHING_MINIGAME_AREA - bait_height)
if(!prepare_minigame_hud())
return
+ ADD_TRAIT(user, TRAIT_ACTIVELY_FISHING, WEAKREF(src))
phase = MINIGAME_PHASE
deltimer(next_phase_timer)
if((FISHING_MINIGAME_RULE_KILL in special_effects) && ispath(reward_path,/obj/item/fish))
@@ -428,7 +418,7 @@
///Initialize the minigame hud and register some signals to make it work.
/datum/fishing_challenge/proc/prepare_minigame_hud()
- if(!user.client || user.incapacitated())
+ if(!user.client || user.incapacitated)
return FALSE
. = TRUE
fishing_hud = new
@@ -465,7 +455,7 @@
/datum/fishing_challenge/process(seconds_per_tick)
if(length(active_effects) && COOLDOWN_FINISHED(src, active_effect_cd))
select_active_effect()
- move_fish(seconds_per_tick)
+ mover.move_fish(seconds_per_tick)
move_bait(seconds_per_tick)
if(!QDELETED(fishing_hud))
update_visuals()
@@ -501,58 +491,6 @@
fishing_hud.icon_state = background
current_active_effect = null
-///The proc that moves the fish around, just like in the old TGUI, mostly.
-/datum/fishing_challenge/proc/move_fish(seconds_per_tick)
- var/long_chance = long_jump_chance * seconds_per_tick * 10
- var/short_chance = short_jump_chance * seconds_per_tick * 10
-
- // If we have the target but we're close enough, mark as target reached
- if(abs(target_position - fish_position) < FISH_TARGET_MIN_DISTANCE)
- target_position = null
-
- // Switching to new long jump target can interrupt any other
- if((can_interrupt_move || isnull(target_position)) && prob(long_chance))
- /**
- * Move at least 0.75 to full of the availible bar in given direction,
- * and more likely to move in the direction where there's more space
- */
- var/distance_from_top = FISHING_MINIGAME_AREA - fish_position - fish_height
- var/distance_from_bottom = fish_position
- var/top_chance
- if(distance_from_top < FISH_SHORT_JUMP_MIN_DISTANCE)
- top_chance = 0
- else
- top_chance = (distance_from_top/max(distance_from_bottom, 1)) * 100
- var/new_target = fish_position
- if(prob(top_chance))
- new_target += distance_from_top * rand(75, 100)/100
- else
- new_target -= distance_from_bottom * rand(75, 100)/100
- target_position = round(new_target)
- current_velocity_limit = long_jump_velocity_limit
-
- // Move towards target
- if(!isnull(target_position))
- var/distance = target_position - fish_position
- // about 5 at diff 15 , 10 at diff 30, 30 at diff 100
- var/acceleration_mult = 0.3 * difficulty + 0.5
- var/target_acceleration = distance * acceleration_mult * seconds_per_tick
-
- fish_velocity = fish_velocity * FISH_FRICTION_MULT + target_acceleration
- else if(prob(short_chance))
- var/distance_from_top = FISHING_MINIGAME_AREA - fish_position - fish_height
- var/distance_from_bottom = fish_position
- var/jump_length
- if(distance_from_top >= FISH_SHORT_JUMP_MIN_DISTANCE)
- jump_length = rand(FISH_SHORT_JUMP_MIN_DISTANCE, FISH_SHORT_JUMP_MAX_DISTANCE)
- if(distance_from_bottom >= FISH_SHORT_JUMP_MIN_DISTANCE && (!jump_length || prob(50)))
- jump_length = -rand(FISH_SHORT_JUMP_MIN_DISTANCE, FISH_SHORT_JUMP_MAX_DISTANCE)
- target_position = clamp(fish_position + jump_length, 0, FISHING_MINIGAME_AREA - fish_height)
- current_velocity_limit = short_jump_velocity_limit
-
- fish_velocity = clamp(fish_velocity + fish_idle_velocity, -current_velocity_limit, current_velocity_limit)
- fish_position = clamp(fish_position + fish_velocity * seconds_per_tick, 0, FISHING_MINIGAME_AREA - fish_height)
-
///The proc that moves the bait around, just like in the old TGUI, mostly.
/datum/fishing_challenge/proc/move_bait(seconds_per_tick)
var/should_bounce = abs(bait_velocity) > BAIT_MIN_VELOCITY_BOUNCE
@@ -613,9 +551,7 @@
bait_velocity += velocity_change
//check that the fish area is still intersecting the bait now that it has moved
- fish_on_bait = (fish_position + fish_height >= bait_position) && (bait_position + bait_height >= fish_position)
-
- if(fish_on_bait)
+ if(is_fish_on_bait())
completion += completion_gain * seconds_per_tick
if(completion >= 100)
complete(TRUE)
@@ -627,6 +563,10 @@
completion = clamp(completion, 0, 100)
+///Returns TRUE if the fish and the bait are intersecting
+/datum/fishing_challenge/proc/is_fish_on_bait()
+ return (fish_position + fish_height >= bait_position) && (bait_position + bait_height >= fish_position)
+
///update the vertical pixel position of both fish and bait, and the icon state of the completion bar
/datum/fishing_challenge/proc/update_visuals()
var/bait_offset_mult = bait_position/FISHING_MINIGAME_AREA
@@ -726,15 +666,6 @@
#undef BITING_PHASE
#undef MINIGAME_PHASE
-#undef FISHING_MINIGAME_AREA
-#undef FISH_TARGET_MIN_DISTANCE
-#undef FISH_FRICTION_MULT
-#undef FISH_SHORT_JUMP_MIN_DISTANCE
-#undef FISH_SHORT_JUMP_MAX_DISTANCE
-#undef FISH_ON_BAIT_ACCELERATION_MULT
-#undef BAIT_MIN_VELOCITY_BOUNCE
-#undef BAIT_DECELERATION_MULT
-
#undef MINIGAME_SLIDER_HEIGHT
#undef MINIGAME_BAIT_HEIGHT
#undef MINIGAME_FISH_HEIGHT
@@ -745,5 +676,9 @@
#undef REELING_STATE_UP
#undef REELING_STATE_DOWN
+#undef FISH_ON_BAIT_ACCELERATION_MULT
+#undef BAIT_MIN_VELOCITY_BOUNCE
+#undef BAIT_DECELERATION_MULT
+
#undef MAX_FISH_COMPLETION_MALUS
#undef BITING_TIME_WINDOW
diff --git a/code/modules/fishing/fishing_portal_machine.dm b/code/modules/fishing/fishing_portal_machine.dm
index 494b29b4183ee..8b157cbebfff3 100644
--- a/code/modules/fishing/fishing_portal_machine.dm
+++ b/code/modules/fishing/fishing_portal_machine.dm
@@ -100,3 +100,7 @@
if(!choice || !can_interact(user))
return
activate(available_fish_sources[choice])
+
+/obj/machinery/fishing_portal_generator/emagged
+ obj_flags = parent_type::obj_flags | EMAGGED
+ circuit = /obj/item/circuitboard/machine/fishing_portal_generator/emagged
diff --git a/code/modules/fishing/fishing_rod.dm b/code/modules/fishing/fishing_rod.dm
index c36ea48b15c02..1c47b8f7ee39f 100644
--- a/code/modules/fishing/fishing_rod.dm
+++ b/code/modules/fishing/fishing_rod.dm
@@ -36,8 +36,8 @@
/// The default color for the reel overlay if no line is equipped.
var/default_line_color = "gray"
- ///should there be a fishing line?
- var/display_fishing_line = TRUE
+ ///Is this currently being used by the profound fisher component?
+ var/internal = FALSE
///The name of the icon state of the reel overlay
var/reel_overlay = "reel_overlay"
@@ -107,8 +107,19 @@
var/mob/living/caught_mob = reward
if(caught_mob.stat == DEAD)
return
- else if(!isfish(reward))
- return
+ else
+ if(!isfish(reward))
+ return
+ var/obj/item/fish/fish = reward
+ if(HAS_TRAIT(bait, TRAIT_POISONOUS_BAIT) && !HAS_TRAIT(fish, TRAIT_FISH_TOXIN_IMMUNE))
+ var/kill_fish = TRUE
+ for(var/bait_identifer in fish.favorite_bait)
+ if(is_matching_bait(bait, bait_identifer))
+ kill_fish = FALSE
+ break
+ if(kill_fish)
+ fish.set_status(FISH_DEAD, silent = TRUE)
+
QDEL_NULL(bait)
update_icon()
@@ -127,9 +138,10 @@
return
//Try to move it 'till it's under the user's feet, then try to pick it up
if(isitem(currently_hooked))
- step_towards(currently_hooked, get_turf(src))
- if(currently_hooked.loc == user.loc)
- user.put_in_inactive_hand(currently_hooked)
+ var/obj/item/item = currently_hooked
+ step_towards(item, get_turf(src))
+ if(item.loc == user.loc && (item.interaction_flags_item & INTERACT_ITEM_ATTACK_HAND_PICKUP))
+ user.put_in_inactive_hand(item)
QDEL_NULL(fishing_line)
//Not an item, so just delete the line if it's adjacent to the user.
else if(get_dist(currently_hooked,get_turf(src)) > 1)
@@ -147,21 +159,18 @@
ui_interact(user)
/// Generates the fishing line visual from the current user to the target and updates inhands
-/obj/item/fishing_rod/proc/create_fishing_line(atom/movable/target, target_py = null)
- if(!display_fishing_line)
- return null
- var/mob/user = loc
- if(!istype(user))
+/obj/item/fishing_rod/proc/create_fishing_line(atom/movable/target, mob/living/firer, target_py = null)
+ if(internal)
return null
if(fishing_line)
QDEL_NULL(fishing_line)
var/beam_color = line?.line_color || default_line_color
- fishing_line = new(user, target, icon_state = "fishing_line", beam_color = beam_color, emissive = FALSE, override_target_pixel_y = target_py)
- fishing_line.lefthand = user.get_held_index_of_item(src) % 2 == 1
+ fishing_line = new(firer, target, icon_state = "fishing_line", beam_color = beam_color, emissive = FALSE, override_target_pixel_y = target_py)
+ fishing_line.lefthand = firer.get_held_index_of_item(src) % 2 == 1
RegisterSignal(fishing_line, COMSIG_BEAM_BEFORE_DRAW, PROC_REF(check_los))
RegisterSignal(fishing_line, COMSIG_QDELETING, PROC_REF(clear_line))
INVOKE_ASYNC(fishing_line, TYPE_PROC_REF(/datum/beam/, Start))
- user.update_held_items()
+ firer.update_held_items()
return fishing_line
/obj/item/fishing_rod/proc/clear_line(datum/source)
@@ -183,7 +192,7 @@
if(!hook.can_be_hooked(target_atom))
return
currently_hooked = target_atom
- create_fishing_line(target_atom)
+ create_fishing_line(target_atom, user)
hook.hook_attached(target_atom, src)
SEND_SIGNAL(src, COMSIG_FISHING_ROD_HOOKED_ITEM, target_atom, user)
@@ -197,6 +206,9 @@
return BEAM_CANCEL_DRAW
/obj/item/fishing_rod/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
+ //this prevent trying to use telekinesis to fish (which would be broken anyway)
+ if(!user.contains(src))
+ return ..()
return ranged_interact_with_atom(interacting_with, user, modifiers)
/obj/item/fishing_rod/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
@@ -245,9 +257,8 @@
COOLDOWN_START(src, casting_cd, 1 SECONDS)
/// Called by hook projectile when hitting things
-/obj/item/fishing_rod/proc/hook_hit(atom/atom_hit_by_hook_projectile)
- var/mob/user = loc
- if(!hook || !istype(user))
+/obj/item/fishing_rod/proc/hook_hit(atom/atom_hit_by_hook_projectile, mob/user)
+ if(!hook)
return
if(SEND_SIGNAL(atom_hit_by_hook_projectile, COMSIG_FISHING_ROD_CAST, src, user) & FISHING_ROD_CAST_HANDLED)
return
@@ -261,6 +272,12 @@
ui.set_autoupdate(FALSE)
ui.open()
+/obj/item/fishing_rod/ui_state()
+ if(internal)
+ return GLOB.deep_inventory_state
+ else
+ return GLOB.default_state
+
/obj/item/fishing_rod/update_overlays()
. = ..()
. += get_fishing_overlays()
@@ -365,7 +382,7 @@
return FALSE
return TRUE
-/obj/item/fishing_rod/ui_act(action, list/params)
+/obj/item/fishing_rod/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return .
@@ -379,6 +396,8 @@
/// Ideally this will be replaced with generic slotted storage datum + display
/obj/item/fishing_rod/proc/use_slot(slot, mob/user, obj/item/new_item)
+ if(fishing_line || HAS_TRAIT(user, TRAIT_GONE_FISHING))
+ return
var/obj/item/current_item
switch(slot)
if(ROD_SLOT_BAIT)
@@ -585,13 +604,13 @@
transform = transform.Scale(1, -1)
. = ..()
if(!QDELETED(src))
- our_line = owner.create_fishing_line(src)
+ our_line = owner.create_fishing_line(src, firer)
/obj/projectile/fishing_cast/on_hit(atom/target, blocked = 0, pierce_hit)
. = ..()
if(blocked < 100)
QDEL_NULL(our_line) //we need to delete the old beam datum, otherwise it won't let you fish.
- owner.hook_hit(target)
+ owner.hook_hit(target, firer)
/obj/projectile/fishing_cast/Destroy()
QDEL_NULL(our_line)
diff --git a/code/modules/fishing/sources/_fish_source.dm b/code/modules/fishing/sources/_fish_source.dm
index 4a0419f98f55f..5aa03ae8c0c04 100644
--- a/code/modules/fishing/sources/_fish_source.dm
+++ b/code/modules/fishing/sources/_fish_source.dm
@@ -8,30 +8,50 @@ GLOBAL_LIST_INIT(preset_fish_sources, init_subtypes_w_path_keys(/datum/fish_sour
* A lot of the icons here may be a tad inaccurate, but since we're limited to the free font awesome icons we
* have access to, we got to make do.
*/
-GLOBAL_LIST_INIT(specific_fish_icons, zebra_typecacheof(list(
- /mob/living/basic/carp = FISH_ICON_DEF,
- /mob/living/basic/mining = FISH_ICON_HOSTILE,
- /obj/effect/decal/remains = FISH_ICON_BONE,
- /obj/effect/mob_spawn/corpse = FISH_ICON_BONE,
- /obj/item/coin = FISH_ICON_COIN,
- /obj/item/fish = FISH_ICON_DEF,
- /obj/item/fish/armorfish = FISH_ICON_CRAB,
- /obj/item/fish/boned = FISH_ICON_BONE,
- /obj/item/fish/chasm_crab = FISH_ICON_CRAB,
- /obj/item/fish/gunner_jellyfish = FISH_ICON_JELLYFISH,
- /obj/item/fish/holo/crab = FISH_ICON_CRAB,
- /obj/item/fish/holo/puffer = FISH_ICON_CHUNKY,
- /obj/item/fish/mastodon = FISH_ICON_BONE,
- /obj/item/fish/pufferfish = FISH_ICON_CHUNKY,
- /obj/item/fish/slimefish = FISH_ICON_SLIME,
- /obj/item/fish/sludgefish = FISH_ICON_SLIME,
- /obj/item/fish/starfish = FISH_ICON_STAR,
- /obj/item/storage/wallet = FISH_ICON_COIN,
- /obj/item/stack/sheet/bone = FISH_ICON_BONE,
- /obj/item/stack/sheet/mineral = FISH_ICON_GEM,
- /obj/item/stack/ore = FISH_ICON_GEM,
- /obj/structure/closet/crate = FISH_ICON_COIN,
-)))
+GLOBAL_LIST_INIT(specific_fish_icons, generate_specific_fish_icons())
+
+/proc/generate_specific_fish_icons()
+ var/list/return_list = zebra_typecacheof(list(
+ /mob/living/basic/axolotl = FISH_ICON_CRITTER,
+ /mob/living/basic/frog = FISH_ICON_CRITTER,
+ /mob/living/basic/carp = FISH_ICON_DEF,
+ /mob/living/basic/mining = FISH_ICON_HOSTILE,
+ /obj/effect/decal/remains = FISH_ICON_BONE,
+ /obj/effect/mob_spawn/corpse = FISH_ICON_BONE,
+ /obj/effect/spawner/message_in_a_bottle = FISH_ICON_BOTTLE,
+ /obj/item/coin = FISH_ICON_COIN,
+ /obj/item/fish = FISH_ICON_DEF,
+ /obj/item/fish/armorfish = FISH_ICON_CRAB,
+ /obj/item/fish/boned = FISH_ICON_BONE,
+ /obj/item/fish/chainsawfish = FISH_ICON_WEAPON,
+ /obj/item/fish/chasm_crab = FISH_ICON_CRAB,
+ /obj/item/fish/gunner_jellyfish = FISH_ICON_JELLYFISH,
+ /obj/item/fish/holo/crab = FISH_ICON_CRAB,
+ /obj/item/fish/holo/puffer = FISH_ICON_CHUNKY,
+ /obj/item/fish/jumpercable = FISH_ICON_ELECTRIC,
+ /obj/item/fish/lavaloop = FISH_ICON_WEAPON,
+ /obj/item/fish/mastodon = FISH_ICON_BONE,
+ /obj/item/fish/pufferfish = FISH_ICON_CHUNKY,
+ /obj/item/fish/sand_crab = FISH_ICON_CRAB,
+ /obj/item/fish/skin_crab = FISH_ICON_CRAB,
+ /obj/item/fish/slimefish = FISH_ICON_SLIME,
+ /obj/item/fish/sludgefish = FISH_ICON_SLIME,
+ /obj/item/fish/starfish = FISH_ICON_STAR,
+ /obj/item/fish/stingray = FISH_ICON_WEAPON,
+ /obj/item/fish/swordfish = FISH_ICON_WEAPON,
+ /obj/item/fish/zipzap = FISH_ICON_ELECTRIC,
+ /obj/item/seeds/grass = FISH_ICON_SEED,
+ /obj/item/seeds/random = FISH_ICON_SEED,
+ /obj/item/storage/wallet = FISH_ICON_COIN,
+ /obj/item/stack/sheet/bone = FISH_ICON_BONE,
+ /obj/item/stack/sheet/mineral = FISH_ICON_GEM,
+ /obj/item/stack/ore = FISH_ICON_GEM,
+ /obj/structure/closet/crate = FISH_ICON_COIN,
+ /obj/structure/mystery_box = FISH_ICON_COIN,
+ ))
+
+ return_list[FISHING_RANDOM_SEED] = FISH_ICON_SEED
+ return return_list
/**
* Where the fish actually come from - every fishing spot has one assigned but multiple fishing holes
@@ -45,6 +65,10 @@ GLOBAL_LIST_INIT(specific_fish_icons, zebra_typecacheof(list(
var/list/fish_table = list()
/// If a key from fish_table is present here, that fish is availible in limited quantity and is reduced by one on successful fishing
var/list/fish_counts = list()
+ /// Any limited quantity stuff in this list will be readded to the counts after a while
+ var/list/fish_count_regen
+ /// A list of stuff that's currently waiting to be readded to fish_counts
+ var/list/currently_on_regen
/// Text shown as baloon alert when you roll a dud in the table
var/duds = list("it was nothing", "the hook is empty")
/// Baseline difficulty for fishing in this spot
@@ -75,9 +99,12 @@ GLOBAL_LIST_INIT(specific_fish_icons, zebra_typecacheof(list(
return ..()
///Called when src is set as the fish source of a fishing spot component
-/datum/fish_source/proc/on_fishing_spot_init(/datum/component/fishing_spot/spot)
+/datum/fish_source/proc/on_fishing_spot_init(datum/component/fishing_spot/spot)
return
+///Called whenever a fishing spot with this fish source attached is deleted
+/datum/fish_source/proc/on_fishing_spot_del(datum/component/fishing_spot/spot)
+
/// Can we fish in this spot at all. Returns DENIAL_REASON or null if we're good to go
/datum/fish_source/proc/reason_we_cant_fish(obj/item/fishing_rod/rod, mob/fisherman, atom/parent)
return rod.reason_we_cant_fish(src)
@@ -198,16 +225,26 @@ GLOBAL_LIST_INIT(specific_fish_icons, zebra_typecacheof(list(
/datum/fish_source/proc/simple_dispense_reward(reward_path, atom/spawn_location, turf/fishing_spot)
if(isnull(reward_path))
return null
- if((reward_path in fish_counts)) // This is limited count result
+ if(reward_path in fish_counts) // This is limited count result
fish_counts[reward_path] -= 1
- if(!fish_counts[reward_path])
- fish_counts -= reward_path //Ran out of these since rolling (multiple fishermen on same source most likely)
- fish_table -= reward_path
+ var/regen_time = fish_count_regen?[reward_path]
+ if(regen_time)
+ LAZYADDASSOC(currently_on_regen, reward_path, 1)
+ if(currently_on_regen[reward_path] == 1)
+ addtimer(CALLBACK(src, PROC_REF(regen_count), reward_path), regen_time)
var/atom/movable/reward = spawn_reward(reward_path, spawn_location, fishing_spot)
SEND_SIGNAL(src, COMSIG_FISH_SOURCE_REWARD_DISPENSED, reward)
return reward
+/datum/fish_source/proc/regen_count(reward_path, regen_time)
+ fish_counts[reward_path] += 1
+ currently_on_regen[reward_path] -= 1
+ if(!currently_on_regen[reward_path])
+ LAZYREMOVE(currently_on_regen, reward_path)
+ else
+ addtimer(CALLBACK(src, PROC_REF(regen_count), reward_path), regen_time)
+
/// Spawns a reward from a atom path right where the fisherman is. Part of the dispense_reward() logic.
/datum/fish_source/proc/spawn_reward(reward_path, atom/spawn_location, turf/fishing_spot)
if(reward_path == FISHING_DUD)
@@ -239,22 +276,13 @@ GLOBAL_LIST(fishing_property_cache)
GLOB.fishing_property_cache = fish_property_table
return GLOB.fishing_property_cache
-/// Checks if bait matches identifier from fav/disliked bait list
-/datum/fish_source/proc/is_matching_bait(obj/item/bait, identifier)
- if(ispath(identifier)) //Just a path
- return istype(bait, identifier)
- if(islist(identifier))
- var/list/special_identifier = identifier
- switch(special_identifier["Type"])
- if("Foodtype")
- var/obj/item/food/food_bait = bait
- return istype(food_bait) && food_bait.foodtypes & special_identifier["Value"]
- if("Reagent")
- return bait.reagents?.has_reagent(special_identifier["Value"], special_identifier["Amount"], check_subtypes = TRUE)
- else
- CRASH("Unknown bait identifier in fish favourite/disliked list")
- else
- return HAS_TRAIT(bait, identifier)
+/// Returns the fish table, with with the unavailable items from fish_counts removed.
+/datum/fish_source/proc/get_fish_table()
+ var/list/table = fish_table.Copy()
+ for(var/result in table)
+ if(fish_counts[result] == 0)
+ table -= result
+ return table
/// Builds a fish weights table modified by bait/rod/user properties
/datum/fish_source/proc/get_modified_fish_table(obj/item/fishing_rod/rod, mob/fisherman)
@@ -364,13 +392,13 @@ GLOBAL_LIST(fishing_property_cache)
for(var/i in 1 to (severity + 2))
if(!prob((100 + 100 * severity)/i * multiplier))
continue
- var/reward_loot = pick_weight(fish_table)
+ var/reward_loot = pick_weight(get_fish_table())
var/atom/movable/reward = simple_dispense_reward(reward_loot, location, location)
if(isnull(reward))
continue
if(isfish(reward))
var/obj/item/fish/fish = reward
- fish.set_status(FISH_DEAD)
+ fish.set_status(FISH_DEAD, silent = TRUE)
if(isitem(reward))
reward.pixel_x = rand(-9, 9)
reward.pixel_y = rand(-9, 9)
diff --git a/code/modules/fishing/sources/source_types.dm b/code/modules/fishing/sources/source_types.dm
index dd5602b12f99d..52388685687c4 100644
--- a/code/modules/fishing/sources/source_types.dm
+++ b/code/modules/fishing/sources/source_types.dm
@@ -1,17 +1,27 @@
/datum/fish_source/ocean
fish_table = list(
- FISHING_DUD = 15,
- /obj/item/coin/gold = 5,
+ FISHING_DUD = 11,
+ /obj/effect/spawner/message_in_a_bottle = 4,
+ /obj/item/coin/gold = 7,
/obj/item/fish/clownfish = 15,
/obj/item/fish/pufferfish = 15,
/obj/item/fish/cardinal = 15,
/obj/item/fish/greenchromis = 15,
- /obj/item/fish/lanternfish = 5,
- /obj/item/fish/zipzap = 5,
- /obj/item/fish/clownfish/lube = 3,
+ /obj/item/fish/stingray = 10,
+ /obj/item/fish/lanternfish = 7,
+ /obj/item/fish/zipzap = 7,
+ /obj/item/fish/clownfish/lube = 5,
+ /obj/item/fish/swordfish = 5,
+ /obj/structure/mystery_box/fishing = 2,
)
fish_counts = list(
/obj/item/fish/clownfish/lube = 2,
+ /obj/item/fish/swordfish = 2,
+ /obj/structure/mystery_box/fishing = 1,
+ )
+ fish_count_regen = list(
+ /obj/item/fish/clownfish/lube = 3 MINUTES,
+ /obj/item/fish/swordfish = 5 MINUTES,
)
fishing_difficulty = FISHING_DEFAULT_DIFFICULTY + 5
explosive_malus = TRUE
@@ -19,12 +29,63 @@
/datum/fish_source/ocean/beach
catalog_description = "Beach shore water"
+/datum/fish_source/ice_fishing
+ catalog_description = "Ice-covered water"
+ fish_table = list(
+ FISHING_DUD = 4,
+ /obj/item/fish/arctic_char = 5,
+ /obj/item/fish/sockeye_salmon = 5,
+ /obj/item/fish/chasm_crab/ice = 2,
+ /obj/item/fish/boned = 1,
+ )
+ fishing_difficulty = FISHING_DEFAULT_DIFFICULTY + 20
+
+/datum/fish_source/river
+ catalog_description = "River water"
+ fish_table = list(
+ FISHING_DUD = 4,
+ /obj/item/fish/goldfish = 5,
+ /obj/item/fish/guppy = 5,
+ /obj/item/fish/angelfish = 4,
+ /obj/item/fish/catfish = 4,
+ /obj/item/fish/slimefish = 2,
+ /obj/item/fish/sockeye_salmon = 1,
+ /obj/item/fish/arctic_char = 1,
+ /obj/item/fish/goldfish/three_eyes = 1,
+ )
+ fishing_difficulty = FISHING_DEFAULT_DIFFICULTY + 5
+
+/datum/fish_source/sand
+ catalog_description = "Sand"
+ fish_table = list(
+ FISHING_DUD = 8,
+ /obj/item/fish/sand_crab = 10,
+ /obj/item/fish/sand_surfer = 10,
+ /obj/item/fish/bumpy = 10,
+ /obj/item/coin/gold = 3,
+ )
+ fishing_difficulty = FISHING_DEFAULT_DIFFICULTY + 20
+
+/datum/fish_source/cursed_spring
+ catalog_description = null //it's a secret (sorta, I know you're reading this)
+ fish_table = list(
+ FISHING_DUD = 2,
+ /obj/item/fish/soul = 3,
+ /obj/item/fish/skin_crab = 3,
+ /obj/item/fishing_rod/telescopic/master = 1,
+ )
+ fish_counts = list(
+ /obj/item/fishing_rod/telescopic/master = 1,
+ )
+ fishing_difficulty = FISHING_DEFAULT_DIFFICULTY + 25
+
/datum/fish_source/portal
fish_table = list(
FISHING_DUD = 7,
/obj/item/fish/goldfish = 10,
/obj/item/fish/guppy = 10,
/obj/item/fish/angelfish = 10,
+ /obj/item/fish/goldfish/three_eyes = 3,
)
catalog_description = "Aquarium dimension (Fishing portal generator)"
///The name of this option shown in the radial menu on the fishing portal generator
@@ -36,7 +97,8 @@
/datum/fish_source/portal/beach
fish_table = list(
- FISHING_DUD = 10,
+ FISHING_DUD = 7,
+ /obj/effect/spawner/message_in_a_bottle = 3,
/obj/item/fish/clownfish = 10,
/obj/item/fish/pufferfish = 10,
/obj/item/fish/cardinal = 10,
@@ -47,6 +109,12 @@
radial_state = "palm_beach"
overlay_state = "portal_beach"
+/datum/fish_source/portal/beach/on_fishing_spot_init(datum/component/fishing_spot/spot)
+ ADD_TRAIT(spot.parent, TRAIT_MESSAGE_IN_A_BOTTLE_LOCATION, INNATE_TRAIT)
+
+/datum/fish_source/portal/beach/on_fishing_spot_del(datum/component/fishing_spot/spot)
+ REMOVE_TRAIT(spot.parent, TRAIT_MESSAGE_IN_A_BOTTLE_LOCATION, INNATE_TRAIT)
+
/datum/fish_source/portal/chasm
background = "background_lavaland"
fish_table = list(
@@ -63,7 +131,8 @@
/datum/fish_source/portal/ocean
fish_table = list(
- FISHING_DUD = 5,
+ FISHING_DUD = 3,
+ /obj/effect/spawner/message_in_a_bottle = 2,
/obj/item/fish/lanternfish = 5,
/obj/item/fish/firefish = 5,
/obj/item/fish/dwarf_moonfish = 5,
@@ -71,6 +140,14 @@
/obj/item/fish/needlefish = 5,
/obj/item/fish/armorfish = 5,
/obj/item/fish/zipzap = 5,
+ /obj/item/fish/stingray = 4,
+ /obj/item/fish/swordfish = 3,
+ )
+ fish_counts = list(
+ /obj/item/fish/swordfish = 2,
+ )
+ fish_count_regen = list(
+ /obj/item/fish/swordfish = 5 MINUTES,
)
catalog_description = "Ocean dimension (Fishing portal generator)"
fishing_difficulty = FISHING_DEFAULT_DIFFICULTY + 10
@@ -78,6 +155,12 @@
overlay_state = "portal_ocean"
radial_state = "seaboat"
+/datum/fish_source/portal/ocean/on_fishing_spot_init(datum/component/fishing_spot/spot)
+ ADD_TRAIT(spot.parent, TRAIT_MESSAGE_IN_A_BOTTLE_LOCATION, INNATE_TRAIT)
+
+/datum/fish_source/portal/ocean/on_fishing_spot_del(datum/component/fishing_spot/spot)
+ REMOVE_TRAIT(spot.parent, TRAIT_MESSAGE_IN_A_BOTTLE_LOCATION, INNATE_TRAIT)
+
/datum/fish_source/portal/hyperspace
fish_table = list(
FISHING_DUD = 5,
@@ -102,6 +185,13 @@
/obj/item/fish/donkfish = 5,
/obj/item/fish/emulsijack = 5,
/obj/item/fish/jumpercable = 5,
+ /obj/item/fish/chainsawfish = 3,
+ )
+ fish_counts = list(
+ /obj/item/fish/chainsawfish = 1,
+ )
+ fish_count_regen = list(
+ /obj/item/fish/chainsawfish = 7 MINUTES,
)
catalog_description = "Syndicate dimension (Fishing portal generator)"
radial_name = "Syndicate"
@@ -153,8 +243,8 @@
challenge.bait_bounce_mult = clamp(challenge.bait_bounce_mult + (rand(-3, 3) * 0.1), 0.1, 1)
challenge.completion_loss = max(challenge.completion_loss + rand(-2, 2), 0)
challenge.completion_gain = max(challenge.completion_gain + rand(-1, 1), 2)
- challenge.short_jump_velocity_limit += rand(-100, 100)
- challenge.long_jump_velocity_limit += rand(-100, 100)
+ challenge.mover.short_jump_velocity_limit += rand(-100, 100)
+ challenge.mover.long_jump_velocity_limit += rand(-100, 100)
var/static/list/active_effects = bitfield_to_list(FISHING_MINIGAME_ACTIVE_EFFECTS)
for(var/effect in active_effects)
if(prob(30))
@@ -178,7 +268,6 @@
new_traits |= pick_weight(weighted_traits)
caught_fish.inherit_traits(new_traits)
caught_fish.randomize_size_and_weight(deviation = 0.3)
- caught_fish.progenitors = full_capitalize(caught_fish.name)
return caught_fish
@@ -317,16 +406,19 @@
/obj/item/clothing/gloves/bracer = 2,
/obj/effect/decal/remains/human = 2,
/obj/item/fish/mastodon = 1,
+ /obj/item/fishing_rod/telescopic/master = 1,
)
fish_counts = list(
/obj/item/clothing/gloves/bracer = 1,
/obj/effect/decal/remains/human = 1,
/obj/item/fish/mastodon = 1,
+ /obj/item/fishing_rod/telescopic/master = 1,
+ )
+ fish_count_regen = list(
+ /obj/item/fish/mastodon = 8 MINUTES,
)
fishing_difficulty = FISHING_DEFAULT_DIFFICULTY + 15
-#define RANDOM_SEED "Random seed"
-
/datum/fish_source/hydro_tray
catalog_description = "Hydroponics trays"
fish_table = list(
@@ -370,7 +462,7 @@
return ..()
/datum/fish_source/hydro_tray/spawn_reward(reward_path, mob/fisherman, turf/fishing_spot)
- if(reward_path != RANDOM_SEED)
+ if(reward_path != FISHING_RANDOM_SEED)
var/mob/living/created_reward = ..()
if(istype(created_reward))
created_reward.name = "small [created_reward.name]"
@@ -391,5 +483,3 @@
var/picked_path = pick(seeds_to_draw_from)
return new picked_path(get_turf(fishing_spot))
-
-#undef RANDOM_SEED
diff --git a/code/modules/food_and_drinks/machinery/coffeemaker.dm b/code/modules/food_and_drinks/machinery/coffeemaker.dm
index 5fdd296d7fc69..bb532b3162483 100644
--- a/code/modules/food_and_drinks/machinery/coffeemaker.dm
+++ b/code/modules/food_and_drinks/machinery/coffeemaker.dm
@@ -731,7 +731,7 @@
coffeepot.reagents.add_reagent_list(reagent_delta)
qdel(reference_bean)
-
+
// remove the coffee beans from the machine
coffee.Cut(1,2)
coffee_amount--
diff --git a/code/modules/food_and_drinks/machinery/icecream_vat.dm b/code/modules/food_and_drinks/machinery/icecream_vat.dm
index 355601693b9d2..b58af21331eab 100644
--- a/code/modules/food_and_drinks/machinery/icecream_vat.dm
+++ b/code/modules/food_and_drinks/machinery/icecream_vat.dm
@@ -1,5 +1,5 @@
///How many units of a reagent is needed to make a cone.
-#define CONE_REAGENET_NEEDED 1
+#define CONE_REAGENT_NEEDED 1
///The vat is set to dispense ice cream.
#define VAT_MODE_ICECREAM "ice cream"
@@ -242,7 +242,7 @@
///Makes an ice cream cone of the make_type, using ingredients list as reagents used to make it. Puts in user's hand if possible.
/obj/machinery/icecream_vat/proc/make_cone(mob/user, make_type, list/ingredients)
for(var/reagents_needed in ingredients)
- if(!reagents.has_reagent(reagents_needed, CONE_REAGENET_NEEDED))
+ if(!reagents.has_reagent(reagents_needed, CONE_REAGENT_NEEDED))
balloon_alert(user, "not enough ingredients!")
return
var/cone_type = cone_prototypes[make_type].type
@@ -251,7 +251,7 @@
var/obj/item/food/icecream/cone = new cone_type(src)
for(var/reagents_used in ingredients)
- reagents.remove_reagent(reagents_used, CONE_REAGENET_NEEDED)
+ reagents.remove_reagent(reagents_used, CONE_REAGENT_NEEDED)
balloon_alert_to_viewers("cooks up [cone.name]", "cooks up [cone.name]")
try_put_in_hand(cone, user)
@@ -262,14 +262,14 @@
CRASH("[user] was making ice cream of [selected_flavour] but had no flavor datum for it!")
for(var/reagents_needed in flavor.ingredients)
- if(!reagents.has_reagent(reagents_needed, CONE_REAGENET_NEEDED))
+ if(!reagents.has_reagent(reagents_needed, CONE_REAGENT_NEEDED))
balloon_alert(user, "not enough ingredients!")
return
var/should_use_custom_ingredients = (flavor.takes_custom_ingredients && custom_ice_cream_beaker && custom_ice_cream_beaker.reagents.total_volume)
if(flavor.add_flavour(source, should_use_custom_ingredients ? custom_ice_cream_beaker.reagents : null))
for(var/reagents_used in flavor.ingredients)
- reagents.remove_reagent(reagents_used, CONE_REAGENET_NEEDED)
+ reagents.remove_reagent(reagents_used, CONE_REAGENT_NEEDED)
balloon_alert_to_viewers("scoops [selected_flavour]", "scoops [selected_flavour]")
if(istype(cone))
@@ -297,4 +297,4 @@
#undef VAT_MODE_ICECREAM
#undef VAT_MODE_CONES
-#undef CONE_REAGENET_NEEDED
+#undef CONE_REAGENT_NEEDED
diff --git a/code/modules/food_and_drinks/machinery/microwave.dm b/code/modules/food_and_drinks/machinery/microwave.dm
index 2b790306b5ac7..4fa586401ff56 100644
--- a/code/modules/food_and_drinks/machinery/microwave.dm
+++ b/code/modules/food_and_drinks/machinery/microwave.dm
@@ -416,32 +416,7 @@
balloon_alert(user, "max 1 device!")
return ITEM_INTERACT_BLOCKING
- if(istype(item, /obj/item/storage))
- var/obj/item/storage/tray = item
- var/loaded = 0
-
- if(!istype(item, /obj/item/storage/bag/tray))
- // Non-tray dumping requires a do_after
- to_chat(user, span_notice("You start dumping out the contents of [item] into [src]..."))
- if(!do_after(user, 2 SECONDS, target = tray))
- return ITEM_INTERACT_BLOCKING
-
- for(var/obj/tray_item in tray.contents)
- if(!IS_EDIBLE(tray_item))
- continue
- if(ingredients.len >= max_n_of_items)
- balloon_alert(user, "it's full!")
- return ITEM_INTERACT_BLOCKING
- if(tray.atom_storage.attempt_remove(tray_item, src))
- loaded++
- ingredients += tray_item
- if(loaded)
- open(autoclose = 0.6 SECONDS)
- to_chat(user, span_notice("You insert [loaded] items into \the [src]."))
- update_appearance()
- return ITEM_INTERACT_SUCCESS
-
- if(item.w_class <= WEIGHT_CLASS_NORMAL && !user.combat_mode)
+ if(item.w_class <= WEIGHT_CLASS_NORMAL && !user.combat_mode && isnull(item.atom_storage))
if(ingredients.len >= max_n_of_items)
balloon_alert(user, "it's full!")
return ITEM_INTERACT_BLOCKING
@@ -455,6 +430,43 @@
update_appearance()
return ITEM_INTERACT_SUCCESS
+/obj/machinery/microwave/item_interaction_secondary(mob/living/user, obj/item/tool, list/modifiers)
+ if (isnull(tool.atom_storage))
+ return
+ handle_dumping(user, tool)
+ return ITEM_INTERACT_BLOCKING
+
+/obj/machinery/microwave/proc/handle_dumping(mob/living/user, obj/item/tool)
+ if(isnull(tool.atom_storage))
+ return
+
+ var/loaded = 0
+ if(!istype(tool, /obj/item/storage/bag/tray))
+ // Non-tray dumping requires a do_after
+ to_chat(user, span_notice("You start dumping out the contents of [tool] into [src]..."))
+ if(!do_after(user, 2 SECONDS, target = tool))
+ return
+
+ for(var/obj/tray_item in tool.contents)
+ if(!IS_EDIBLE(tray_item))
+ continue
+ if(ingredients.len >= max_n_of_items)
+ balloon_alert(user, "it's full!")
+ return
+ if(tool.atom_storage.attempt_remove(tray_item, src))
+ loaded++
+ ingredients += tray_item
+
+ if(loaded)
+ open(autoclose = 0.6 SECONDS)
+ to_chat(user, span_notice("You insert [loaded] items into \the [src]."))
+ update_appearance()
+
+/obj/machinery/microwave/mouse_drop_receive(obj/item/tool, mob/user, params)
+ if (!istype(tool) || isnull(tool.atom_storage))
+ return
+ handle_dumping(user, tool)
+
/obj/machinery/microwave/attack_hand_secondary(mob/user, list/modifiers)
if(user.can_perform_action(src, ALLOW_SILICON_REACH))
if(!length(ingredients))
diff --git a/code/modules/food_and_drinks/machinery/smartfridge.dm b/code/modules/food_and_drinks/machinery/smartfridge.dm
index 6e115af7df217..1dca29b950422 100644
--- a/code/modules/food_and_drinks/machinery/smartfridge.dm
+++ b/code/modules/food_and_drinks/machinery/smartfridge.dm
@@ -343,7 +343,7 @@
if(ismob(weapon.loc))
var/mob/owner = weapon.loc
if(!owner.transferItemToLoc(weapon, src))
- to_chat(usr, span_warning("\the [weapon] is stuck to your hand, you cannot put it in \the [src]!"))
+ to_chat(owner, span_warning("\the [weapon] is stuck to your hand, you cannot put it in \the [src]!"))
return FALSE
return TRUE
else
@@ -396,42 +396,39 @@
if(. || !ui.user.can_perform_action(src, FORBID_TELEKINESIS_REACH))
return
- . = TRUE
var/mob/living_mob = ui.user
switch(action)
if("Release")
var/amount = text2num(params["amount"])
- var/desired = 1
+ if(isnull(amount) || !isnum(amount))
+ return TRUE
var/dispensed_amount = 0
if(isAI(living_mob))
to_chat(living_mob, span_warning("[src] does not respect your authority!"))
- return
-
- if (amount > 1)
- desired = tgui_input_number(living_mob, "How many items would you like to take out?", "Release", default = min(amount, 50), max_value = min(amount, 50))
- if(!desired)
- return
+ return TRUE
- for(var/obj/item/dispensed_item in src)
- if(desired <= 0)
+ for(var/obj/item/dispensed_item in contents)
+ if(amount <= 0)
break
- if(params["path"] == "[dispensed_item.type]-[dispensed_item.name]")
- if(dispensed_item in component_parts)
- CRASH("Attempted removal of [dispensed_item] component_part from smartfridge via smartfridge interface.")
- //dispense the item
- if(!living_mob.put_in_hands(dispensed_item))
- dispensed_item.forceMove(drop_location())
- adjust_item_drop_location(dispensed_item)
- use_energy(active_power_usage)
- dispensed_amount++
- desired--
+ var/item_name = "[dispensed_item.type]-[replacetext(replacetext(dispensed_item.name, "\proper", ""), "\improper", "")]"
+ if(params["path"] != item_name)
+ continue
+ if(dispensed_item in component_parts)
+ CRASH("Attempted removal of [dispensed_item] component_part from smartfridge via smartfridge interface.")
+ //dispense the item
+ if(!living_mob.put_in_hands(dispensed_item))
+ dispensed_item.forceMove(drop_location())
+ adjust_item_drop_location(dispensed_item)
+ use_energy(active_power_usage)
+ dispensed_amount++
+ amount--
if(dispensed_amount && vend_sound)
playsound(src, vend_sound, 50, TRUE, extrarange = -3)
if (visible_contents)
update_appearance()
- return
+ return TRUE
return FALSE
@@ -479,15 +476,16 @@
.["isdryer"] = TRUE
.["drying"] = drying
-/obj/machinery/smartfridge/drying/ui_act(action, params)
+/obj/machinery/smartfridge/drying/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
update_appearance() // This is to handle a case where the last item is taken out manually instead of through drying pop-out
return
+ var/mob/user = ui.user
switch(action)
if("Dry")
- toggle_drying(FALSE, usr)
+ toggle_drying(FALSE, user)
return TRUE
/obj/machinery/smartfridge/drying/powered()
diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_drink.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_drink.dm
index e5589fcc42d43..5a754361ffb1f 100644
--- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_drink.dm
+++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_drink.dm
@@ -1,6 +1,10 @@
// This is the home of drink related tablecrafting recipes, I have opted to only let players bottle fancy boozes to reduce the number of entries.
+///Abstract types for all drink recipes that use bottles and result in another bottle, so that the message_in_a_bottle item is properly transferred.
+/datum/crafting_recipe/bottled
+ parts = list(/obj/item/reagent_containers/cup/glass/bottle = 1)
+
///////////////// Booze & Bottles ///////////////////
/datum/crafting_recipe/lizardwine
@@ -14,7 +18,7 @@
result = /obj/item/reagent_containers/cup/glass/bottle/lizardwine
category = CAT_DRINK
-/datum/crafting_recipe/moonshinejug
+/datum/crafting_recipe/bottled/moonshinejug
name = "Moonshine Jug"
time = 30
reqs = list(
@@ -24,7 +28,7 @@
result = /obj/item/reagent_containers/cup/glass/bottle/moonshine
category = CAT_DRINK
-/datum/crafting_recipe/hoochbottle
+/datum/crafting_recipe/bottled/hoochbottle
name = "Hooch Bottle"
time = 30
reqs = list(
@@ -35,7 +39,7 @@
result = /obj/item/reagent_containers/cup/glass/bottle/hooch
category = CAT_DRINK
-/datum/crafting_recipe/blazaambottle
+/datum/crafting_recipe/bottled/blazaambottle
name = "Blazaam Bottle"
time = 20
reqs = list(
@@ -45,7 +49,7 @@
result = /obj/item/reagent_containers/cup/glass/bottle/blazaam
category = CAT_DRINK
-/datum/crafting_recipe/champagnebottle
+/datum/crafting_recipe/bottled/champagnebottle
name = "Champagne Bottle"
time = 30
reqs = list(
@@ -55,7 +59,7 @@
result = /obj/item/reagent_containers/cup/glass/bottle/champagne
category = CAT_DRINK
-/datum/crafting_recipe/trappistbottle
+/datum/crafting_recipe/bottled/trappistbottle
name = "Trappist Bottle"
time = 15
reqs = list(
@@ -65,7 +69,7 @@
result = /obj/item/reagent_containers/cup/glass/bottle/trappist
category = CAT_DRINK
-/datum/crafting_recipe/goldschlagerbottle
+/datum/crafting_recipe/bottled/goldschlagerbottle
name = "Goldschlager Bottle"
time = 30
reqs = list(
@@ -75,7 +79,7 @@
result = /obj/item/reagent_containers/cup/glass/bottle/goldschlager
category = CAT_DRINK
-/datum/crafting_recipe/patronbottle
+/datum/crafting_recipe/bottled/patronbottle
name = "Patron Bottle"
time = 30
reqs = list(
@@ -87,7 +91,7 @@
////////////////////// Non-alcoholic recipes ///////////////////
-/datum/crafting_recipe/holybottle
+/datum/crafting_recipe/bottled/holybottle
name = "Holy Water Flask"
time = 30
reqs = list(
@@ -99,7 +103,7 @@
//flask of unholy water is a beaker for some reason, I will try making it a bottle and add it here once the antag freeze is over. t. kryson
-/datum/crafting_recipe/nothingbottle
+/datum/crafting_recipe/bottled/nothingbottle
name = "Nothing Bottle"
time = 30
reqs = list(
@@ -116,7 +120,7 @@
reqs = list(/obj/item/stack/sheet/cardboard = 1)
category = CAT_CONTAINERS
-/datum/crafting_recipe/candycornliquor
+/datum/crafting_recipe/bottled/candycornliquor
name = "candy corn liquor"
result = /obj/item/reagent_containers/cup/glass/bottle/candycornliquor
time = 30
@@ -125,7 +129,7 @@
/obj/item/reagent_containers/cup/glass/bottle = 1)
category = CAT_DRINK
-/datum/crafting_recipe/kong
+/datum/crafting_recipe/bottled/kong
name = "Kong"
result = /obj/item/reagent_containers/cup/glass/bottle/kong
time = 30
diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_egg.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_egg.dm
index ec8eda8d3cfff..7b8c071b3a539 100644
--- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_egg.dm
+++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_egg.dm
@@ -13,7 +13,7 @@
category = CAT_EGG
/datum/crafting_recipe/food/omelette
- name = "Omelette"
+ name = "Omelette du fromage"
reqs = list(
/obj/item/food/egg = 2,
/obj/item/food/cheese/wedge = 2
diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_lizard.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_lizard.dm
index 71716a1ee7c2a..7b253f32ce17d 100644
--- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_lizard.dm
+++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_lizard.dm
@@ -74,7 +74,8 @@
/obj/item/food/grown/garlic = 1,
/datum/reagent/consumable/lemonjuice = 3,
/datum/reagent/consumable/blackpepper = 2,
- /datum/reagent/consumable/nutriment/fat/oil/olive = 3
+ /datum/reagent/consumable/nutriment/fat/oil/olive = 3,
+ /obj/item/reagent_containers/cup/bowl = 1,
)
result = /obj/item/food/lizard_escargot
category = CAT_LIZARD
@@ -94,7 +95,8 @@
reqs = list(
/obj/item/food/fries = 1,
/obj/item/food/meat/cutlet = 2,
- /datum/reagent/consumable/bbqsauce = 5
+ /datum/reagent/consumable/bbqsauce = 5,
+ /obj/item/plate = 1,
)
result = /obj/item/food/lizard_fries
category = CAT_LIZARD
diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_martian.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_martian.dm
index 02bb9ae7bf82c..9048964df1c7c 100644
--- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_martian.dm
+++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_martian.dm
@@ -45,6 +45,7 @@
/obj/item/food/grown/onion = 1,
/datum/reagent/consumable/sugar = 3,
/datum/reagent/consumable/limejuice = 3,
+ /obj/item/reagent_containers/cup/bowl = 1,
)
result = /obj/item/food/sambal
category = CAT_MARTIAN
@@ -78,6 +79,7 @@
/obj/item/food/meat/cutlet = 1,
/obj/item/food/pineappleslice = 1,
/datum/reagent/consumable/soysauce = 3,
+ /obj/item/reagent_containers/cup/bowl = 1,
)
result = /obj/item/food/salad/hurricane_rice
category = CAT_MARTIAN
@@ -91,6 +93,7 @@
/obj/item/food/onion_slice = 1,
/obj/item/food/sausage = 1,
/obj/item/food/grown/chili = 1,
+ /obj/item/reagent_containers/cup/bowl = 1,
)
result = /obj/item/food/salad/ikareis
category = CAT_MARTIAN
@@ -103,7 +106,8 @@
/obj/item/food/grown/bell_pepper = 1,
/obj/item/food/pineappleslice = 1,
/obj/item/food/onion_slice = 1,
- /datum/reagent/consumable/soysauce = 5
+ /datum/reagent/consumable/soysauce = 5,
+ /obj/item/reagent_containers/cup/bowl = 1,
)
result = /obj/item/food/salad/hawaiian_fried_rice
category = CAT_MARTIAN
@@ -118,6 +122,7 @@
/obj/item/food/grown/peas = 1,
/datum/reagent/consumable/ketchup = 5,
/datum/reagent/consumable/worcestershire = 2,
+ /obj/item/reagent_containers/cup/bowl = 1,
)
result = /obj/item/food/salad/ketchup_fried_rice
category = CAT_MARTIAN
@@ -131,6 +136,7 @@
/obj/item/food/cheese/firm_cheese_slice = 1,
/obj/item/food/grown/olive = 1,
/obj/item/food/meatball = 1,
+ /obj/item/reagent_containers/cup/bowl = 1,
)
result = /obj/item/food/salad/mediterranean_fried_rice
category = CAT_MARTIAN
@@ -141,6 +147,7 @@
/obj/item/food/boiledrice = 1,
/obj/item/food/egg = 1,
/datum/reagent/consumable/soysauce = 3,
+ /obj/item/reagent_containers/cup/bowl = 1,
)
result = /obj/item/food/salad/egg_fried_rice
category = CAT_MARTIAN
@@ -154,6 +161,7 @@
/obj/item/food/meat/cutlet = 1,
/obj/item/food/kimchi = 1,
/obj/item/food/egg = 1,
+ /obj/item/reagent_containers/cup/bowl = 1,
)
result = /obj/item/food/salad/bibimbap
category = CAT_MARTIAN
@@ -167,6 +175,7 @@
/obj/item/food/grown/garlic = 1,
/obj/item/food/onion_slice = 1,
/datum/reagent/consumable/nutriment/soup/teriyaki = 4,
+ /obj/item/reagent_containers/cup/bowl = 1,
)
result = /obj/item/food/salad/bulgogi_noodles
category = CAT_MARTIAN
@@ -180,6 +189,7 @@
/obj/item/food/onion_slice = 1,
/obj/item/food/katsu_fillet = 1,
/datum/reagent/consumable/worcestershire = 3,
+ /obj/item/reagent_containers/cup/bowl = 1,
)
result = /obj/item/food/salad/yakisoba_katsu
category = CAT_MARTIAN
@@ -194,6 +204,7 @@
/obj/item/food/egg = 1,
/datum/reagent/consumable/soysauce = 3,
/datum/reagent/consumable/red_bay = 3,
+ /obj/item/reagent_containers/cup/bowl = 1,
)
result = /obj/item/food/salad/martian_fried_noodles
category = CAT_MARTIAN
@@ -203,6 +214,7 @@
reqs = list(
/obj/item/food/spaghetti/boilednoodles = 1,
/datum/reagent/consumable/soysauce = 3,
+ /obj/item/reagent_containers/cup/bowl = 1,
)
result = /obj/item/food/salad/simple_fried_noodles
category = CAT_MARTIAN
@@ -222,6 +234,7 @@
/obj/item/food/grown/onion = 1,
/obj/item/food/grown/carrot = 1,
/obj/item/food/grown/potato = 1,
+ /obj/item/reagent_containers/cup/bowl = 1,
)
result = /obj/item/food/salad/setagaya_curry
category = CAT_MARTIAN
@@ -545,6 +558,7 @@
/obj/item/food/meat/slab/chicken = 1,
/datum/reagent/consumable/coconut_milk = 5,
/datum/reagent/consumable/curry_powder = 3,
+ /obj/item/reagent_containers/cup/bowl = 1,
)
result = /obj/item/food/salad/po_kok_gai
category = CAT_MARTIAN
@@ -579,6 +593,7 @@
/obj/item/food/grown/tomato = 1,
/obj/item/food/uncooked_rice = 1,
/datum/reagent/blood = 5,
+ /obj/item/reagent_containers/cup/bowl = 1,
)
result = /obj/item/food/salad/galinha_de_cabidela
category = CAT_MARTIAN
@@ -589,6 +604,7 @@
/obj/item/food/katsu_fillet = 1,
/obj/item/food/boiledrice = 1,
/datum/reagent/consumable/nutriment/soup/curry_sauce = 5,
+ /obj/item/reagent_containers/cup/bowl = 1,
)
result = /obj/item/food/salad/katsu_curry
category = CAT_MARTIAN
@@ -600,6 +616,7 @@
/obj/item/food/onion_slice = 1,
/obj/item/food/boiledrice = 1,
/datum/reagent/consumable/nutriment/soup/dashi = 5,
+ /obj/item/reagent_containers/cup/bowl = 1,
)
result = /obj/item/food/salad/beef_bowl
category = CAT_MARTIAN
@@ -613,6 +630,7 @@
/obj/item/food/boiledrice = 1,
/datum/reagent/consumable/salt = 2,
/datum/reagent/consumable/nutriment/soup/curry_sauce = 5,
+ /obj/item/reagent_containers/cup/bowl = 1,
)
result = /obj/item/food/salad/salt_chilli_bowl
category = CAT_MARTIAN
@@ -625,6 +643,7 @@
/obj/item/food/grown/onion = 1,
/obj/item/food/boiledrice = 1,
/datum/reagent/consumable/nutriment/soup/dashi = 5,
+ /obj/item/reagent_containers/cup/bowl = 1,
)
result = /obj/item/food/salad/kansai_bowl
category = CAT_MARTIAN
@@ -637,6 +656,7 @@
/obj/item/food/fishmeat = 1,
/obj/item/food/boiledrice = 1,
/datum/reagent/consumable/cafe_latte = 5,
+ /obj/item/reagent_containers/cup/bowl = 1,
)
result = /obj/item/food/salad/eigamudo_curry
category = CAT_MARTIAN
@@ -681,6 +701,7 @@
/datum/reagent/consumable/caramel = 2,
/obj/item/food/icecream = 1,
/datum/reagent/consumable/ethanol/rum = 2,
+ /obj/item/reagent_containers/cup/bowl = 1,
)
result = /obj/item/food/salad/pineapple_foster
category = CAT_MARTIAN
@@ -848,6 +869,7 @@
/obj/item/food/fishmeat = 1,
/obj/item/food/boiledrice = 1,
/datum/reagent/consumable/nutriment/soup/dashi = 5,
+ /obj/item/reagent_containers/cup/bowl = 1,
)
result = /obj/item/food/salad/sprout_bowl
category = CAT_MARTIAN
diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_meat.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_meat.dm
index 98eafb66823df..804956cbeed5b 100644
--- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_meat.dm
+++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_meat.dm
@@ -243,6 +243,7 @@
/obj/item/food/grown/onion = 1,
/obj/item/food/grown/tomato = 1,
/obj/item/food/meat/steak = 1,
+ /obj/item/reagent_containers/cup/bowl = 1,
)
result = /obj/item/food/beef_stroganoff
category = CAT_MEAT
diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_mexican.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_mexican.dm
index 8778ee976ef25..840d3a8c08b1a 100644
--- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_mexican.dm
+++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_mexican.dm
@@ -120,7 +120,8 @@
/obj/item/food/cornchips = 1,
/obj/item/food/grown/chili = 1,
/obj/item/food/grown/onion = 1,
- /obj/item/food/grown/tomato = 1
+ /obj/item/food/grown/tomato = 1,
+ /obj/item/reagent_containers/cup/bowl = 1,
)
result = /obj/item/food/chipsandsalsa
category = CAT_MEXICAN
@@ -198,6 +199,7 @@
/obj/item/food/grown/tomato = 1,
/obj/item/food/grown/onion = 1,
/obj/item/food/grown/chili = 1,
+ /obj/item/reagent_containers/cup/bowl = 1,
)
result = /obj/item/food/pineapple_salsa
category = CAT_MEXICAN
diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_moth.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_moth.dm
index bb20f4ab0b370..aeb27f026b251 100644
--- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_moth.dm
+++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_moth.dm
@@ -2,7 +2,8 @@
name = "Herby cheese"
reqs = list(
/obj/item/food/cheese/curd_cheese = 1,
- /obj/item/food/grown/herbs = 4
+ /obj/item/food/grown/herbs = 4,
+ /obj/item/reagent_containers/cup/bowl = 1,
)
result = /obj/item/food/herby_cheese
category = CAT_MOTH
@@ -187,7 +188,8 @@
reqs = list(
/datum/reagent/consumable/nutriment/soup/rice_porridge = 10,
/obj/item/food/meat/bacon = 1,
- /obj/item/food/friedegg = 2
+ /obj/item/food/friedegg = 2,
+ /obj/item/reagent_containers/cup/bowl = 1,
)
result = /obj/item/food/bowled/hua_mulan_congee
category = CAT_MOTH
@@ -199,7 +201,8 @@
/obj/item/food/grown/eggplant = 1,
/obj/item/food/breadslice/plain = 2,
/obj/item/food/tomato_sauce = 1,
- /obj/item/food/cheese/mozzarella = 1
+ /obj/item/food/cheese/mozzarella = 1,
+ /obj/item/reagent_containers/cup/bowl = 1,
)
result = /obj/item/food/bowled/fried_eggplant_polenta
category = CAT_MOTH
diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm
index 376c1d4f84509..c965526bcb1c6 100644
--- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm
+++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm
@@ -604,6 +604,16 @@
result = /obj/item/food/cherrycupcake/blue
category = CAT_PASTRY
+/datum/crafting_recipe/food/jupitercupcake
+ name = "Jupiter-cup-cake"
+ reqs = list(
+ /obj/item/food/pastrybase = 1,
+ /obj/item/food/grown/mushroom/jupitercup = 1,
+ /datum/reagent/consumable/caramel = 3,
+ )
+ result = /obj/item/food/jupitercupcake
+ category = CAT_PASTRY
+
/datum/crafting_recipe/food/honeybun
name = "Honey bun"
reqs = list(
diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_spaghetti.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_spaghetti.dm
index 589235eacb70c..edf82287373f0 100644
--- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_spaghetti.dm
+++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_spaghetti.dm
@@ -44,7 +44,7 @@
/obj/item/reagent_containers/cup/bowl = 1,
/obj/item/food/spaghetti/boiledspaghetti = 1,
/obj/item/food/meat/cutlet = 2,
- /obj/item/food/grown/cabbage = 1
+ /obj/item/food/grown/cabbage = 1,
)
result = /obj/item/food/spaghetti/beefnoodle
category = CAT_SPAGHETTI
@@ -157,3 +157,15 @@
)
result = /obj/item/food/spaghetti/pad_thai
category = CAT_SPAGHETTI
+
+/datum/crafting_recipe/food/carbonara
+ name = "Spaghetti Carbonara"
+ reqs = list(
+ /obj/item/food/spaghetti/boiledspaghetti = 1,
+ /obj/item/food/cheese/firm_cheese_slice = 1,
+ /obj/item/food/meat/bacon = 1,
+ /obj/item/food/egg = 1,
+ /datum/reagent/consumable/blackpepper = 2,
+ )
+ result = /obj/item/food/spaghetti/carbonara
+ category = CAT_SPAGHETTI
diff --git a/code/modules/holodeck/computer.dm b/code/modules/holodeck/computer.dm
index b98d66f6bd2c7..1107c8c25793a 100644
--- a/code/modules/holodeck/computer.dm
+++ b/code/modules/holodeck/computer.dm
@@ -146,10 +146,10 @@ GLOBAL_LIST_INIT(typecache_holodeck_linked_floorcheck_ok, typecacheof(list(/turf
data["emagged"] = TRUE
data["emag_programs"] = emag_programs
data["program"] = program
- data["can_toggle_safety"] = issilicon(user) || isAdminGhostAI(user)
+ data["can_toggle_safety"] = HAS_SILICON_ACCESS(user)
return data
-/obj/machinery/computer/holodeck/ui_act(action, params)
+/obj/machinery/computer/holodeck/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/hydroponics/biogenerator.dm b/code/modules/hydroponics/biogenerator.dm
index 52df09c29cdf8..3549b3e965f48 100644
--- a/code/modules/hydroponics/biogenerator.dm
+++ b/code/modules/hydroponics/biogenerator.dm
@@ -526,7 +526,7 @@
return data
-/obj/machinery/biogenerator/ui_act(action, list/params)
+/obj/machinery/biogenerator/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/hydroponics/grown/mushrooms.dm b/code/modules/hydroponics/grown/mushrooms.dm
index 9d1d802916bff..9af495f6a6128 100644
--- a/code/modules/hydroponics/grown/mushrooms.dm
+++ b/code/modules/hydroponics/grown/mushrooms.dm
@@ -205,11 +205,11 @@
to_chat(user, span_notice("You hollow up the chanterelle with [I]."))
remove_item_from_storage(user)
- qdel(src)
if(seed.resistance_flags & FIRE_PROOF)
user.put_in_hands(new /obj/item/clothing/head/wizard/chanterelle/fr())
else
user.put_in_hands(new /obj/item/clothing/head/wizard/chanterelle())
+ qdel(src)
//Jupiter Cup
/obj/item/seeds/chanter/jupitercup
diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm
index ed17254fa9b05..041ff97b73cee 100644
--- a/code/modules/hydroponics/hydroponics.dm
+++ b/code/modules/hydroponics/hydroponics.dm
@@ -157,6 +157,11 @@
icon = 'icons/obj/service/hydroponics/equipment.dmi'
icon_state = "hydrotray3"
+/obj/machinery/hydroponics/constructable/fullupgrade
+ name = "deluxe hydroponics tray"
+ desc = "A basin used to grown plants in, packed full of cutting-edge technology."
+ circuit = /obj/item/circuitboard/machine/hydroponics/fullupgrade
+
/obj/machinery/hydroponics/constructable/Initialize(mapload)
. = ..()
AddComponent(/datum/component/simple_rotation)
diff --git a/code/modules/hydroponics/seed_extractor.dm b/code/modules/hydroponics/seed_extractor.dm
index c558cba8b3eab..93d9cc0aea773 100644
--- a/code/modules/hydroponics/seed_extractor.dm
+++ b/code/modules/hydroponics/seed_extractor.dm
@@ -276,7 +276,7 @@
data["trait_db"] += trait_data
return data
-/obj/machinery/seed_extractor/ui_act(action, params)
+/obj/machinery/seed_extractor/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/instruments/items.dm b/code/modules/instruments/items.dm
index 170000eb11557..f0176e6453092 100644
--- a/code/modules/instruments/items.dm
+++ b/code/modules/instruments/items.dm
@@ -27,7 +27,7 @@
if(!ismob(music_player))
return STOP_PLAYING
var/mob/user = music_player
- if(user.incapacitated() || !((loc == user) || (isturf(loc) && Adjacent(user)))) // sorry, no more TK playing.
+ if(user.incapacitated || !((loc == user) || (isturf(loc) && Adjacent(user)))) // sorry, no more TK playing.
return STOP_PLAYING
/obj/item/instrument/suicide_act(mob/living/user)
diff --git a/code/modules/jobs/job_types/bartender.dm b/code/modules/jobs/job_types/bartender.dm
index 13a4162ff3be9..c0f200c82f7b6 100644
--- a/code/modules/jobs/job_types/bartender.dm
+++ b/code/modules/jobs/job_types/bartender.dm
@@ -59,6 +59,8 @@
glasses = /obj/item/clothing/glasses/sunglasses/reagent
shoes = /obj/item/clothing/shoes/laceup
+ skillchips = list(/obj/item/skillchip/drunken_brawler)
+
/datum/outfit/job/bartender/post_equip(mob/living/carbon/human/H, visualsOnly)
. = ..()
diff --git a/code/modules/jobs/job_types/chaplain/chaplain_nullrod.dm b/code/modules/jobs/job_types/chaplain/chaplain_nullrod.dm
index b02dee12cf826..dd7208d170618 100644
--- a/code/modules/jobs/job_types/chaplain/chaplain_nullrod.dm
+++ b/code/modules/jobs/job_types/chaplain/chaplain_nullrod.dm
@@ -586,11 +586,10 @@
AddComponent(/datum/component/two_handed, \
force_unwielded = 14, \
force_wielded = 18, \
- icon_wielded = "[base_icon_state]1", \
)
/obj/item/nullrod/bostaff/update_icon_state()
- icon_state = "[base_icon_state]0"
+ icon_state = inhand_icon_state = "[base_icon_state][HAS_TRAIT(src, TRAIT_WIELDED)]"
return ..()
@@ -706,6 +705,28 @@
hitsound = 'sound/weapons/bladeslice.ogg'
menu_description = "A pointy spear which penetrates armor a little. Can be worn only on the belt."
+// Unholy version of above, since the gamemode is dead in the water
+
+/obj/item/brass_spear
+ name = "dull brass spear"
+ desc = "An ancient spear made of brass. The point seems sharp, but it feels so dull.. you get a feeling brass isn't good nonmagical material for a weapon."
+ icon = 'icons/obj/weapons/spear.dmi'
+ icon_state = "ratvarian_spear"
+ inhand_icon_state = "ratvarian_spear"
+ lefthand_file = 'icons/mob/inhands/antag/clockwork_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/antag/clockwork_righthand.dmi'
+ slot_flags = ITEM_SLOT_BELT
+ force = 15
+ throw_speed = 3
+ throw_range = 7
+ throwforce = 15
+ armour_penetration = 10
+ sharpness = SHARP_POINTY
+ w_class = WEIGHT_CLASS_HUGE
+ attack_verb_continuous = list("stabs", "pokes", "slashes", "clocks")
+ attack_verb_simple = list("stab", "poke", "slash", "clock")
+ hitsound = 'sound/weapons/bladeslice.ogg'
+
// Nullblade - For when you really want to feel like rolling dice during combat
/obj/item/nullrod/nullblade
diff --git a/code/modules/jobs/job_types/chaplain/chaplain_vorpal_scythe.dm b/code/modules/jobs/job_types/chaplain/chaplain_vorpal_scythe.dm
index ec484ebe6ebc5..4b07baaa05890 100644
--- a/code/modules/jobs/job_types/chaplain/chaplain_vorpal_scythe.dm
+++ b/code/modules/jobs/job_types/chaplain/chaplain_vorpal_scythe.dm
@@ -10,7 +10,7 @@ If the scythe isn't empowered when you sheath it, you take a heap of damage and
desc = "This shard seems to be directly linked to some sinister entity. It might be your god! It also gives you a really horrible rash when you hold onto it for too long."
items_to_create = list(/obj/item/vorpalscythe)
-/obj/item/organ/internal/cyberimp/arm/shard/scythe/Insert(mob/living/carbon/receiver, special, movement_flags)
+/obj/item/organ/internal/cyberimp/arm/shard/scythe/mob_insert(mob/living/carbon/receiver, special, movement_flags)
. = ..()
if(receiver.mind)
ADD_TRAIT(receiver.mind, TRAIT_MORBID, ORGAN_TRAIT)
diff --git a/code/modules/jobs/job_types/curator.dm b/code/modules/jobs/job_types/curator.dm
index e2eb35af5497e..93475fdc79e23 100644
--- a/code/modules/jobs/job_types/curator.dm
+++ b/code/modules/jobs/job_types/curator.dm
@@ -47,7 +47,7 @@
/obj/item/choice_beacon/hero = 1,
)
belt = /obj/item/modular_computer/pda/curator
- ears = /obj/item/radio/headset/headset_srv
+ ears = /obj/item/radio/headset/headset_srvent
shoes = /obj/item/clothing/shoes/laceup
l_pocket = /obj/item/laser_pointer/green
r_pocket = /obj/item/key/displaycase
@@ -55,6 +55,18 @@
accessory = /obj/item/clothing/accessory/pocketprotector/full
+/datum/outfit/job/curator/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
+ if(visualsOnly)
+ return ..()
+
+ /// There can be only one cameraman on this station, and no, not that kind
+ var/static/cameraman_choosen = FALSE
+ if(!cameraman_choosen)
+ backpack_contents[/obj/item/broadcast_camera] = 1
+ cameraman_choosen = TRUE
+ return ..()
+
+
/datum/outfit/job/curator/post_equip(mob/living/carbon/human/translator, visualsOnly = FALSE)
..()
diff --git a/code/modules/jobs/job_types/mime.dm b/code/modules/jobs/job_types/mime.dm
index eba86ec2af07a..46090cdbe30ac 100644
--- a/code/modules/jobs/job_types/mime.dm
+++ b/code/modules/jobs/job_types/mime.dm
@@ -131,7 +131,7 @@
return FALSE
if(!user.is_holding(src))
return FALSE
- if(user.incapacitated())
+ if(user.incapacitated)
return FALSE
if(!user.mind)
return FALSE
diff --git a/code/modules/language/_language_manuals.dm b/code/modules/language/_language_manuals.dm
index eb4ca456440d8..7a4298a06b150 100644
--- a/code/modules/language/_language_manuals.dm
+++ b/code/modules/language/_language_manuals.dm
@@ -85,6 +85,14 @@
. = ..()
name = "extended [initial(language.name)] manual"
+/obj/item/language_manual/piratespeak
+ name = "\improper Captain Pete's Guide to Pirate Lingo"
+ icon_state = "book_pirate"
+ desc = "A book containing all the knowledge, jargon and buzzwords to speak like a true old salt."
+ language = /datum/language/piratespeak
+ flavour_text = "Blimey! I feel less of a landlubber now."
+ charges = 5
+
// So drones can teach borgs and AI dronespeak. For best effect, combine with mother drone lawset.
/obj/item/language_manual/dronespeak_manual
name = "dronespeak manual"
diff --git a/code/modules/language/_language_menu.dm b/code/modules/language/_language_menu.dm
index 0bfb7a79977af..905be8169e26a 100644
--- a/code/modules/language/_language_menu.dm
+++ b/code/modules/language/_language_menu.dm
@@ -56,7 +56,7 @@
return data
-/datum/language_menu/ui_act(action, params)
+/datum/language_menu/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/library/bibles.dm b/code/modules/library/bibles.dm
index 5221dc8047422..0c6a1aad71d63 100644
--- a/code/modules/library/bibles.dm
+++ b/code/modules/library/bibles.dm
@@ -186,7 +186,7 @@ GLOBAL_LIST_INIT(bibleitemstates, list(
return FALSE
if(!istype(user) || !user.is_holding(src))
return FALSE
- if(user.incapacitated())
+ if(user.incapacitated)
return FALSE
if(user.mind?.holy_role != HOLY_ROLE_HIGHPRIEST)
return FALSE
diff --git a/code/modules/library/lib_machines.dm b/code/modules/library/lib_machines.dm
index a65159a3f8225..35def980eb922 100644
--- a/code/modules/library/lib_machines.dm
+++ b/code/modules/library/lib_machines.dm
@@ -80,7 +80,7 @@ GLOBAL_VAR_INIT(library_table_modified, 0)
data["params_changed"] = params_changed
return data
-/obj/machinery/computer/libraryconsole/ui_act(action, params)
+/obj/machinery/computer/libraryconsole/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
@@ -424,7 +424,7 @@ GLOBAL_VAR_INIT(library_table_modified, 0)
scanner = WEAKREF(foundya)
return foundya
-/obj/machinery/computer/libraryconsole/bookmanagement/ui_act(action, params)
+/obj/machinery/computer/libraryconsole/bookmanagement/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
//The parent call takes care of stuff like searching, don't forget about that yeah?
. = ..()
if(.)
diff --git a/code/modules/library/skill_learning/generic_skillchips/matrix_flip.dm b/code/modules/library/skill_learning/generic_skillchips/matrix_flip.dm
deleted file mode 100644
index a836442eca052..0000000000000
--- a/code/modules/library/skill_learning/generic_skillchips/matrix_flip.dm
+++ /dev/null
@@ -1,40 +0,0 @@
-#define FLIP_STAMINA_COST 19
-
-/obj/item/skillchip/matrix_flip
- name = "BULLET_DODGER skillchip"
- skill_name = "Flip 2 Dodge"
- skill_description = "At the cost of stamina, your flips can also be used to dodge incoming projectiles."
- skill_icon = FA_ICON_SPINNER
- activate_message = span_notice("You feel the urge to flip scenically as if you are the 'Chosen One'.")
- deactivate_message = span_notice("The urge to flip goes away.")
-
-/obj/item/skillchip/matrix_flip/on_activate(mob/living/carbon/user, silent = FALSE)
- . = ..()
- ADD_TRAIT(user, TRAIT_SLOW_FLIP, SKILLCHIP_TRAIT)
- RegisterSignal(user, COMSIG_MOB_EMOTED("flip"), PROC_REF(on_flip))
- RegisterSignal(user, COMSIG_MOB_PRE_EMOTED, PROC_REF(check_if_we_can_flip))
-
-/obj/item/skillchip/matrix_flip/on_deactivate(mob/living/carbon/user, silent=FALSE)
- REMOVE_TRAIT(user, TRAIT_SLOW_FLIP, SKILLCHIP_TRAIT)
- UnregisterSignal(user, list(COMSIG_MOB_EMOTED("flip"), COMSIG_MOB_PRE_EMOTED))
- return ..()
-
-///Prevent players from stamcritting from INTENTIONAL flips. 1.4s of bullet immunity isn't worth several secs of stun.
-/obj/item/skillchip/matrix_flip/proc/check_if_we_can_flip(mob/living/source, key, params, type_override, intentional, datum/emote/emote)
- SIGNAL_HANDLER
- if(key != "flip" || !intentional)
- return
- if((source.maxHealth - (source.getStaminaLoss() + FLIP_STAMINA_COST)) <= source.crit_threshold)
- source.balloon_alert(source, "too tired!")
- return COMPONENT_CANT_EMOTE
-
-/obj/item/skillchip/matrix_flip/proc/on_flip(mob/living/source)
- SIGNAL_HANDLER
- if(HAS_TRAIT_FROM(source, TRAIT_UNHITTABLE_BY_PROJECTILES, SKILLCHIP_TRAIT))
- return
- playsound(source, 'sound/weapons/fwoosh.ogg', 90, FALSE, frequency = 0.7)
- ADD_TRAIT(source, TRAIT_UNHITTABLE_BY_PROJECTILES, SKILLCHIP_TRAIT)
- source.adjustStaminaLoss(FLIP_STAMINA_COST)
- addtimer(TRAIT_CALLBACK_REMOVE(source, TRAIT_UNHITTABLE_BY_PROJECTILES, SKILLCHIP_TRAIT), FLIP_EMOTE_DURATION * 2)
-
-#undef FLIP_STAMINA_COST
diff --git a/code/modules/library/skill_learning/generic_skillchips/matrix_taunt.dm b/code/modules/library/skill_learning/generic_skillchips/matrix_taunt.dm
new file mode 100644
index 0000000000000..cfe61b08e0c3c
--- /dev/null
+++ b/code/modules/library/skill_learning/generic_skillchips/matrix_taunt.dm
@@ -0,0 +1,37 @@
+#define TAUNT_STAMINA_COST 19
+
+/obj/item/skillchip/matrix_taunt
+ name = "BULLET_DODGER skillchip"
+ skill_name = "Taunt 2 Dodge"
+ skill_description = "At the cost of stamina, your taunts can also be used to dodge incoming projectiles."
+ skill_icon = FA_ICON_SPINNER
+ activate_message = span_notice("You feel the urge to taunt scenically as if you are the 'Chosen One'.")
+ deactivate_message = span_notice("The urge to taunt goes away.")
+
+/obj/item/skillchip/matrix_taunt/on_activate(mob/living/carbon/user, silent = FALSE)
+ . = ..()
+ RegisterSignal(user, COMSIG_MOB_EMOTED("taunt"), PROC_REF(on_taunt))
+ RegisterSignal(user, COMSIG_MOB_PRE_EMOTED, PROC_REF(check_if_we_can_taunt))
+
+/obj/item/skillchip/matrix_taunt/on_deactivate(mob/living/carbon/user, silent=FALSE)
+ UnregisterSignal(user, list(COMSIG_MOB_EMOTED("taunt"), COMSIG_MOB_PRE_EMOTED))
+ return ..()
+
+///Prevent players from stamcritting from INTENTIONAL flips. 1.4s of bullet immunity isn't worth several secs of stun.
+/obj/item/skillchip/matrix_taunt/proc/check_if_we_can_taunt(mob/living/source, key, params, type_override, intentional, datum/emote/emote)
+ SIGNAL_HANDLER
+ if(key != "taunt" || !intentional)
+ return
+ if((source.maxHealth - (source.getStaminaLoss() + TAUNT_STAMINA_COST)) <= source.crit_threshold)
+ source.balloon_alert(source, "too tired!")
+ return COMPONENT_CANT_EMOTE
+
+/obj/item/skillchip/matrix_taunt/proc/on_taunt(mob/living/source)
+ SIGNAL_HANDLER
+ if(HAS_TRAIT_FROM(source, TRAIT_UNHITTABLE_BY_PROJECTILES, SKILLCHIP_TRAIT))
+ return
+ ADD_TRAIT(source, TRAIT_UNHITTABLE_BY_PROJECTILES, SKILLCHIP_TRAIT)
+ source.adjustStaminaLoss(TAUNT_STAMINA_COST)
+ addtimer(TRAIT_CALLBACK_REMOVE(source, TRAIT_UNHITTABLE_BY_PROJECTILES, SKILLCHIP_TRAIT), TAUNT_EMOTE_DURATION * 1.5)
+
+#undef TAUNT_STAMINA_COST
diff --git a/code/modules/library/skill_learning/generic_skillchips/point.dm b/code/modules/library/skill_learning/generic_skillchips/point.dm
new file mode 100644
index 0000000000000..761a482268952
--- /dev/null
+++ b/code/modules/library/skill_learning/generic_skillchips/point.dm
@@ -0,0 +1,99 @@
+/**
+ * A skillchip that gives the user bigger arrows when pointing at things (like some id trims do).
+ * As a bonus, they can costumize the color of the arrow/pointer too.
+ */
+/obj/item/skillchip/big_pointer
+ name = "Kommand skillchip"
+ desc = "A biochip detailing various techniques employed by historical leaders to points at things like a true boss."
+ skill_name = "Enhanced pointing"
+ skill_description = "Learn to point at things in a more noticeable way."
+ skill_icon = FA_ICON_ARROW_DOWN
+ activate_message = span_notice("From \"The Definitive Compendium of Body Language for the Aspiring Leader\", page 164, paragraph 3...")
+ deactivate_message = span_notice("So, uh, yeah, how do I point at things again?")
+
+ ///The action for changing the pointer color
+ var/datum/action/change_pointer_color/action
+
+/obj/item/skillchip/big_pointer/Destroy()
+ action = null
+ return ..()
+
+/obj/item/skillchip/big_pointer/on_activate(mob/living/carbon/user, silent=FALSE)
+ . = ..()
+ RegisterSignal(user, COMSIG_MOVABLE_POINTED, PROC_REF(fancier_pointer))
+ if(!action)
+ action = new(src)
+ action.Grant(user)
+
+/obj/item/skillchip/big_pointer/on_deactivate(mob/living/carbon/user, silent=FALSE)
+ UnregisterSignal(user, COMSIG_MOVABLE_POINTED)
+ action?.arrow_color = null
+ action?.arrow_overlay = null
+ action?.Remove(user)
+ return ..()
+
+/obj/item/skillchip/big_pointer/proc/fancier_pointer(mob/living/user, atom/pointed, obj/effect/temp_visual/point/point)
+ SIGNAL_HANDLER
+ if(HAS_TRAIT(user, TRAIT_UNKNOWN))
+ return
+ point.cut_overlays()
+ if(!action.arrow_color)
+ point.icon_state = "arrow_large"
+ return
+ point.icon_state = "arrow_large_white"
+ point.color = action.arrow_color
+ var/mutable_appearance/highlight = mutable_appearance(point.icon, "arrow_large_white_highlights", appearance_flags = RESET_COLOR)
+ point.add_overlay(highlight)
+
+/datum/action/change_pointer_color
+ name = "Change Pointer Color"
+ desc = "Set your custom pointer color, or reset it to the default."
+ button_icon = /obj/effect/temp_visual/point::icon
+ button_icon_state = "arrow_large_still"
+ check_flags = AB_CHECK_CONSCIOUS
+ ///the color of our arrow
+ var/arrow_color
+ ///the arrow overlay shown on the button
+ var/mutable_appearance/arrow_overlay
+
+/datum/action/change_pointer_color/Destroy()
+ . = ..()
+ arrow_overlay = null
+
+/datum/action/change_pointer_color/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return
+ var/mob/user = owner
+ if(!arrow_color)
+ pick_color(user)
+ return
+ var/choice = tgui_alert(owner, "Reset or update pointer color?","Pointer Color", list("Reset","Update"))
+ if(user != owner || !choice || !IsAvailable(feedback = TRUE))
+ return
+ if(choice == "Update")
+ pick_color(user)
+ else
+ arrow_color = null
+ owner.balloon_alert(owner, "pointer reset")
+ build_all_button_icons(update_flags = UPDATE_BUTTON_ICON, force = TRUE)
+
+/datum/action/change_pointer_color/proc/pick_color(mob/user)
+ var/ncolor = input(owner, "Pick new color", "Pointer Color", arrow_color) as color|null
+ if(user != owner || !IsAvailable(feedback = TRUE))
+ return
+ arrow_color = ncolor
+ owner.balloon_alert(owner, "pointer updated")
+ build_all_button_icons(update_flags = UPDATE_BUTTON_ICON, force = TRUE)
+
+/datum/action/change_pointer_color/apply_button_icon(atom/movable/screen/movable/action_button/current_button, force = FALSE)
+ if(!arrow_color)
+ return ..()
+
+ current_button.icon = current_button.icon_state = null
+ current_button.cut_overlay(arrow_overlay)
+
+ arrow_overlay = mutable_appearance(icon = /obj/effect/temp_visual/point::icon, icon_state = "arrow_large_white_still")
+ arrow_overlay.color = arrow_color
+ arrow_overlay.overlays += mutable_appearance(icon = /obj/effect/temp_visual/point::icon, icon_state = "arrow_large_white_still_highlights", appearance_flags = RESET_COLOR)
+ current_button.add_overlay(arrow_overlay)
diff --git a/code/modules/library/skill_learning/skill_station.dm b/code/modules/library/skill_learning/skill_station.dm
index b376501f758fd..2dec45a6abf77 100644
--- a/code/modules/library/skill_learning/skill_station.dm
+++ b/code/modules/library/skill_learning/skill_station.dm
@@ -252,7 +252,7 @@
current_skills += list(skill_chip.get_chip_data())
.["current"] = current_skills
-/obj/machinery/skill_station/ui_act(action, list/params)
+/obj/machinery/skill_station/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/library/skill_learning/skillchip.dm b/code/modules/library/skill_learning/skillchip.dm
index cc284b91454aa..b8903e5bde09a 100644
--- a/code/modules/library/skill_learning/skillchip.dm
+++ b/code/modules/library/skill_learning/skillchip.dm
@@ -141,6 +141,7 @@
* * silent - Boolean. Whether or not an activation message should be shown to the user.
*/
/obj/item/skillchip/proc/on_activate(mob/living/carbon/user, silent=FALSE)
+ SHOULD_CALL_PARENT(TRUE)
if(!silent && activate_message)
to_chat(user, activate_message)
@@ -175,6 +176,7 @@
* * silent - Boolean. Whether or not a deactivation message should be shown to the user.
*/
/obj/item/skillchip/proc/on_deactivate(mob/living/carbon/user, silent=FALSE)
+ SHOULD_CALL_PARENT(TRUE)
if(!silent && deactivate_message)
to_chat(user, deactivate_message)
@@ -484,9 +486,9 @@
/obj/item/skillchip/master_angler
name = "Mast-Angl-Er skillchip"
- auto_traits = list(TRAIT_REVEAL_FISH, TRAIT_EXAMINE_FISHING_SPOT)
+ auto_traits = list(TRAIT_REVEAL_FISH, TRAIT_EXAMINE_FISHING_SPOT, TRAIT_EXAMINE_FISH, TRAIT_EXAMINE_DEEPER_FISH)
skill_name = "Fisherman's Discernment"
- skill_description = "Lists fishes when examining a fishing spot, and gives a hint of whatever thing's biting the hook."
+ skill_description = "Lists fishes when examining a fishing spot, gives a hint of whatever thing's biting the hook and more."
skill_icon = "fish"
activate_message = span_notice("You feel the knowledge and passion of several sunbaked, seasoned fishermen burn within you.")
deactivate_message = span_notice("You no longer feel like casting a fishing rod by the sunny riverside.")
@@ -499,3 +501,104 @@
skill_icon = FA_ICON_DRUMSTICK_BITE
activate_message = span_notice("You think of your favourite food and realise that you can rotate its flavour in your mind.")
deactivate_message = span_notice("You feel your food-based mind palace crumbling...")
+
+/obj/item/skillchip/drunken_brawler
+ name = "F0RC3 4DD1CT10N skillchip"
+ auto_traits = list(TRAIT_DRUNKEN_BRAWLER)
+ skill_name = "Drunken Unarmed Proficiency"
+ skill_description = "When intoxicated, you gain increased unarmed effectiveness."
+ skill_icon = "wine-bottle"
+ activate_message = span_notice("You honestly could do with a drink. Never know when someone might try and jump you around here.")
+ deactivate_message = span_notice("You suddenly feel a lot safer going around the station sober... ")
+
+/obj/item/skillchip/musical
+ name = "\improper Old Copy of \"Space Station 13: The Musical\""
+ desc = "An old copy of \"Space Station 13: The Musical\", \
+ ran on the station's 100th anniversary...Or maybe it was the 200th?"
+ skill_name = "Memory of a Musical"
+ skill_description = "Allows you to hit that high note, like those that came a century before us."
+ skill_icon = FA_ICON_MUSIC
+ activate_message = span_notice("You feel like you could \u2669 sing a soooong! \u266B")
+ deactivate_message = span_notice("The musical fades from your mind, leaving you with a sense of nostalgia.")
+ custom_premium_price = PAYCHECK_CREW * 4
+
+/obj/item/skillchip/musical/Initialize(mapload, is_removable)
+ . = ..()
+ name = replacetext(name, "Old", round(CURRENT_STATION_YEAR - pick(50, 100, 150, 200, 250), 5))
+
+/obj/item/skillchip/musical/on_activate(mob/living/carbon/user, silent = FALSE)
+ . = ..()
+ RegisterSignal(user, COMSIG_MOB_SAY, PROC_REF(make_music))
+
+/obj/item/skillchip/musical/on_deactivate(mob/living/carbon/user, silent)
+ . = ..()
+ UnregisterSignal(user, COMSIG_MOB_SAY)
+
+/obj/item/skillchip/musical/proc/make_music(mob/living/carbon/source, list/say_args)
+ SIGNAL_HANDLER
+
+ var/raw_message = say_args[SPEECH_MESSAGE]
+ var/list/words = splittext(raw_message, " ")
+ if(length(words) <= 1)
+ say_args[SPEECH_MODS][MODE_SING] = TRUE
+ return
+ var/last_word = words[length(words)]
+ var/num_chars = length_char(last_word)
+ var/last_vowel = ""
+ // find the last vowel present in the word
+ for(var/i in 1 to num_chars)
+ var/char = copytext_char(last_word, i, i + 1)
+ if(char in VOWELS)
+ last_vowel = char
+
+ // now we'll reshape the final word to make it sound like they're singing it
+ var/final_word = ""
+ var/has_ellipsis = copytext(last_word, -3) == "..."
+ for(var/i in 1 to num_chars)
+ var/char = copytext_char(last_word, i, i + 1)
+ // replacing any final periods with exclamation marks (so long as it's not an ellipsis)
+ if(char == "." && i == num_chars && !has_ellipsis)
+ final_word += "!"
+ // or if it's the vowel we found, we're gonna repeat it a few times (holding the note)
+ else if(char == last_vowel)
+ for(var/j in 1 to 4)
+ final_word += char
+ // if we dragged out the last character of the word, just period it
+ if(i == num_chars)
+ final_word += "."
+ // no special handing otherwise
+ else
+ final_word += char
+
+ if(!has_ellipsis)
+ // adding an extra exclamation mark at the end if there's no period
+ var/last_char = copytext_char(final_word, -1)
+ if(last_char != ".")
+ final_word += "!"
+
+ words[length(words)] = final_word
+ // now we siiiiiiing
+ say_args[SPEECH_MESSAGE] = jointext(words, " ")
+ say_args[SPEECH_MODS][MODE_SING] = TRUE
+
+/obj/item/skillchip/musical/examine(mob/user)
+ . = ..()
+ . += span_tinynoticeital("Huh, looks like it'd fit in a skillchip adapter.")
+
+/obj/item/skillchip/musical/examine_more(mob/user)
+ . = ..()
+ var/list/songs = list()
+ songs += "• \"The Ballad of Space Station 13\""
+ songs += "• \"The Captain's Call\""
+ songs += "• \"A Mime's Lament\""
+ songs += "• \"Banned from Cargo\""
+ songs += "• \"Botany Blues\""
+ songs += "• \"Clown Song\""
+ songs += "• \"Elegy to an Engineer\""
+ songs += "• \"Medical Malpractitioner\""
+ songs += "• \"Security Strike\""
+ songs += "• \"Send for the Shuttle\""
+ songs += "• And one song scratched out..."
+
+ . += span_notice("On the back of the chip, you see a list of songs:")
+ . += span_smallnotice("[jointext(songs, "
")]")
diff --git a/code/modules/lootpanel/_lootpanel.dm b/code/modules/lootpanel/_lootpanel.dm
index 45862ebf45542..ab13a7c211677 100644
--- a/code/modules/lootpanel/_lootpanel.dm
+++ b/code/modules/lootpanel/_lootpanel.dm
@@ -56,13 +56,13 @@
/datum/lootpanel/ui_status(mob/user, datum/ui_state/state)
- if(user.incapacitated())
+ if(user.incapacitated)
return UI_DISABLED
return UI_INTERACTIVE
-/datum/lootpanel/ui_act(action, list/params)
+/datum/lootpanel/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/mapfluff/ruins/icemoonruin_code/hotsprings.dm b/code/modules/mapfluff/ruins/icemoonruin_code/hotsprings.dm
index 9e188d4585638..7c674e98e24a1 100644
--- a/code/modules/mapfluff/ruins/icemoonruin_code/hotsprings.dm
+++ b/code/modules/mapfluff/ruins/icemoonruin_code/hotsprings.dm
@@ -14,6 +14,7 @@
baseturfs = /turf/open/water/cursed_spring
planetary_atmos = TRUE
initial_gas_mix = ICEMOON_DEFAULT_ATMOS
+ fishing_datum = /datum/fish_source/cursed_spring
/turf/open/water/cursed_spring/Entered(atom/movable/arrived, atom/old_loc, list/atom/old_locs)
. = ..()
diff --git a/code/modules/mapfluff/ruins/objects_and_mobs/necropolis_gate.dm b/code/modules/mapfluff/ruins/objects_and_mobs/necropolis_gate.dm
index 860eb8c816882..646de6a2186ef 100644
--- a/code/modules/mapfluff/ruins/objects_and_mobs/necropolis_gate.dm
+++ b/code/modules/mapfluff/ruins/objects_and_mobs/necropolis_gate.dm
@@ -161,7 +161,7 @@ GLOBAL_DATUM(necropolis_gate, /obj/structure/necropolis_gate/legion_gate)
/obj/structure/necropolis_gate/legion_gate/attack_hand(mob/user, list/modifiers)
if(!open && !changing_openness)
var/safety = tgui_alert(user, "You think this might be a bad idea...", "Knock on the door?", list("Proceed", "Abort"))
- if(safety == "Abort" || !in_range(src, user) || !src || open || changing_openness || user.incapacitated())
+ if(safety == "Abort" || !in_range(src, user) || !src || open || changing_openness || user.incapacitated)
return
user.visible_message(span_warning("[user] knocks on [src]..."), span_boldannounce("You tentatively knock on [src]..."))
playsound(user.loc, 'sound/effects/shieldbash.ogg', 100, TRUE)
diff --git a/code/modules/mapfluff/ruins/spaceruin_code/TheDerelict.dm b/code/modules/mapfluff/ruins/spaceruin_code/TheDerelict.dm
index ce50fcccc1568..8be91920719c1 100644
--- a/code/modules/mapfluff/ruins/spaceruin_code/TheDerelict.dm
+++ b/code/modules/mapfluff/ruins/spaceruin_code/TheDerelict.dm
@@ -140,7 +140,7 @@
ui = new(user, src, "VaultController", name)
ui.open()
-/obj/machinery/computer/vaultcontroller/ui_act(action, params)
+/obj/machinery/computer/vaultcontroller/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm b/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm
index 21075cea38add..b42618f94ee21 100644
--- a/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm
+++ b/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm
@@ -72,7 +72,7 @@ GLOBAL_VAR_INIT(hhMysteryRoomNumber, rand(1, 999999))
to_chat(target, span_warning("You too far away from \the [src] to enter it!"))
// If the target is incapacitated after selecting a room, they're not allowed to teleport.
- if(target.incapacitated())
+ if(target.incapacitated)
to_chat(target, span_warning("You aren't able to activate \the [src] anymore!"))
// Has the user thrown it away or otherwise disposed of it such that it's no longer in their hands or in some storage connected to them?
@@ -358,7 +358,7 @@ GLOBAL_VAR_INIT(hhMysteryRoomNumber, rand(1, 999999))
to_chat(user, span_warning("Drats! Your vision is too poor to use this!"))
return CLICK_ACTION_BLOCKING
- to_chat(user, span_notice("You peak through the door's bluespace peephole..."))
+ to_chat(user, span_notice("You peek through the door's bluespace peephole..."))
user.reset_perspective(parentSphere)
var/datum/action/peephole_cancel/PHC = new
user.overlay_fullscreen("remote_view", /atom/movable/screen/fullscreen/impaired, 1)
diff --git a/code/modules/mapfluff/ruins/spaceruin_code/oldstation/oldstation_mod.dm b/code/modules/mapfluff/ruins/spaceruin_code/oldstation/oldstation_mod.dm
index ac026045674e8..77b8aa0bbce28 100644
--- a/code/modules/mapfluff/ruins/spaceruin_code/oldstation/oldstation_mod.dm
+++ b/code/modules/mapfluff/ruins/spaceruin_code/oldstation/oldstation_mod.dm
@@ -64,7 +64,7 @@
var/mob/living/carbon/human/human_occupant = occupant
if(!istype(human_occupant))
return
- if(!human_occupant.dropItemToGround(human_occupant.back))
+ if(!isnull(human_occupant.back) && !human_occupant.dropItemToGround(human_occupant.back))
return
if(!human_occupant.equip_to_slot_if_possible(mod_unit, mod_unit.slot_flags, qdel_on_fail = FALSE, disable_warning = TRUE))
return
diff --git a/code/modules/mapping/space_management/space_reservation.dm b/code/modules/mapping/space_management/space_reservation.dm
index 04ba59ab5a459..fe0050d418d23 100644
--- a/code/modules/mapping/space_management/space_reservation.dm
+++ b/code/modules/mapping/space_management/space_reservation.dm
@@ -28,6 +28,9 @@
/// The turf type the reservation is initially made with
var/turf_type = /turf/open/space
+ /// Do we override baseturfs with turf_type?
+ var/turf_type_is_baseturf = TRUE
+
///Distance away from the cordon where we can put a "sort-cordon" and run some extra code (see make_repel). 0 makes nothing happen
var/pre_cordon_distance = 0
@@ -52,6 +55,10 @@
for(var/turf/reserved_turf as anything in release_turfs)
SEND_SIGNAL(reserved_turf, COMSIG_TURF_RESERVATION_RELEASED, src)
+ // immediately disconnect from atmos
+ reserved_turf.blocks_air = TRUE
+ CALCULATE_ADJACENT_TURFS(reserved_turf, KILL_EXCITED)
+
// Makes the linter happy, even tho we don't await this
INVOKE_ASYNC(SSmapping, TYPE_PROC_REF(/datum/controller/subsystem/mapping, reserve_turfs), release_turfs)
@@ -90,7 +97,7 @@
// Its no longer unused, but its also not "used"
cordon_turf.turf_flags &= ~UNUSED_RESERVATION_TURF
- cordon_turf.ChangeTurf(/turf/cordon, /turf/cordon)
+ cordon_turf.empty(/turf/cordon, /turf/cordon)
SSmapping.unused_turfs["[cordon_turf.z]"] -= cordon_turf
// still gets linked to us though
SSmapping.used_turfs[cordon_turf] = src
@@ -138,6 +145,9 @@
if(!HAS_TRAIT(enterer, TRAIT_FREE_HYPERSPACE_SOFTCORDON_MOVEMENT))
space_dump(source, enterer)
+/datum/turf_reservation/turf_not_baseturf
+ turf_type_is_baseturf = FALSE
+
/// Internal proc which handles reserving the area for the reservation.
/datum/turf_reservation/proc/_reserve_area(width, height, zlevel)
src.width = width
@@ -181,7 +191,7 @@
SSmapping.unused_turfs["[T.z]"] -= T
SSmapping.used_turfs[T] = src
T.turf_flags = (T.turf_flags | RESERVATION_TURF) & ~UNUSED_RESERVATION_TURF
- T.ChangeTurf(turf_type, turf_type)
+ T.empty(turf_type, turf_type_is_baseturf ? turf_type : null)
bottom_left_turfs += BL
top_right_turfs += TR
diff --git a/code/modules/mining/aux_base.dm b/code/modules/mining/aux_base.dm
index a1503b7f63420..82cdaffa71468 100644
--- a/code/modules/mining/aux_base.dm
+++ b/code/modules/mining/aux_base.dm
@@ -133,7 +133,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/computer/auxiliary_base, 32)
return FALSE
return TRUE
-/obj/machinery/computer/auxiliary_base/ui_act(action, params)
+/obj/machinery/computer/auxiliary_base/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/mining/boulder_processing/brm.dm b/code/modules/mining/boulder_processing/brm.dm
index 61c5469b45901..9b9186968918b 100644
--- a/code/modules/mining/boulder_processing/brm.dm
+++ b/code/modules/mining/boulder_processing/brm.dm
@@ -153,6 +153,23 @@
playsound(src, MANUAL_TELEPORT_SOUND, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
return TRUE
+/obj/machinery/brm/attack_ai(mob/user)
+ . = ..()
+ if(. || panel_open)
+ return
+ if(!handle_teleport_conditions(user))
+ return
+
+ var/result = pre_collect_boulder()
+ if(result == TURF_BLOCKED_BY_BOULDER)
+ balloon_alert(user, "no space")
+ else if(result)
+ balloon_alert(user, "teleporting")
+
+ COOLDOWN_START(src, manual_teleport_cooldown, TELEPORTATION_TIME)
+
+ return TRUE
+
/obj/machinery/brm/attack_robot(mob/user)
. = ..()
if(. || panel_open)
@@ -206,6 +223,17 @@
end_processing()
update_appearance(UPDATE_ICON_STATE)
+/obj/machinery/brm/attack_ai_secondary(mob/user, list/modifiers)
+ . = ..()
+ if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN || panel_open)
+ return
+ if(!anchored)
+ balloon_alert(user, "anchor first!")
+ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
+
+ toggle_auto_on(user)
+ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
+
/obj/machinery/brm/attack_robot_secondary(mob/user, list/modifiers)
. = ..()
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN || panel_open)
diff --git a/code/modules/mining/equipment/mining_tools.dm b/code/modules/mining/equipment/mining_tools.dm
index abf5ca77e181d..0685dda148dee 100644
--- a/code/modules/mining/equipment/mining_tools.dm
+++ b/code/modules/mining/equipment/mining_tools.dm
@@ -285,7 +285,7 @@
/obj/item/trench_tool/proc/check_menu(mob/user)
if(!istype(user))
return FALSE
- if(user.incapacitated() || !user.Adjacent(src))
+ if(user.incapacitated || !user.Adjacent(src))
return FALSE
return TRUE
diff --git a/code/modules/mining/equipment/monster_organs/monster_organ.dm b/code/modules/mining/equipment/monster_organs/monster_organ.dm
index a854f113740f8..9b6330f3467c3 100644
--- a/code/modules/mining/equipment/monster_organs/monster_organ.dm
+++ b/code/modules/mining/equipment/monster_organs/monster_organ.dm
@@ -36,7 +36,7 @@
icon = 'icons/obj/medical/organs/mining_organs.dmi'
icon_state = "hivelord_core"
actions_types = list(/datum/action/cooldown/monster_core_action)
- visual = FALSE
+
item_flags = NOBLUDGEON
slot = ORGAN_SLOT_MONSTER_CORE
organ_flags = ORGAN_ORGANIC
@@ -66,10 +66,9 @@
deltimer(decay_timer)
return ..()
-/obj/item/organ/internal/monster_core/Insert(mob/living/carbon/target_carbon, special = FALSE, movement_flags)
+/obj/item/organ/internal/monster_core/mob_insert(mob/living/carbon/target_carbon, special = FALSE, movement_flags)
. = ..()
- if(!.)
- return
+
if (inert)
to_chat(target_carbon, span_notice("[src] breaks down as you try to insert it."))
qdel(src)
@@ -80,7 +79,7 @@
target_carbon.visible_message(span_notice("[src] stabilizes as it's inserted."))
return TRUE
-/obj/item/organ/internal/monster_core/Remove(mob/living/carbon/target_carbon, special, movement_flags)
+/obj/item/organ/internal/monster_core/mob_remove(mob/living/carbon/target_carbon, special, movement_flags)
if (!inert && !special)
owner.visible_message(span_notice("[src] rapidly decays as it's removed."))
go_inert()
diff --git a/code/modules/mining/laborcamp/laborstacker.dm b/code/modules/mining/laborcamp/laborstacker.dm
index cd5a60a22f2ae..ee700e3d9774b 100644
--- a/code/modules/mining/laborcamp/laborstacker.dm
+++ b/code/modules/mining/laborcamp/laborstacker.dm
@@ -68,7 +68,7 @@
data["can_go_home"] = can_go_home
return data
-/obj/machinery/mineral/labor_claim_console/ui_act(action, params)
+/obj/machinery/mineral/labor_claim_console/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/mining/lavaland/megafauna_loot.dm b/code/modules/mining/lavaland/megafauna_loot.dm
index 0bbf15352318d..f0270b66d377b 100644
--- a/code/modules/mining/lavaland/megafauna_loot.dm
+++ b/code/modules/mining/lavaland/megafauna_loot.dm
@@ -601,6 +601,10 @@
animate(src)
SpinAnimation(15)
+/obj/item/soulscythe/Destroy(force)
+ soul.ghostize()
+ QDEL_NULL(soul)
+ . = ..()
/mob/living/simple_animal/soulscythe
name = "mysterious spirit"
maxHealth = 200
diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm
index a553415176ea5..f833e15d3f3de 100644
--- a/code/modules/mining/lavaland/necropolis_chests.dm
+++ b/code/modules/mining/lavaland/necropolis_chests.dm
@@ -18,7 +18,7 @@
/obj/structure/closet/crate/necropolis/tendril/attackby(obj/item/item, mob/user, params)
if(!istype(item, /obj/item/skeleton_key) || spawned_loot)
return ..()
- var/loot = rand(1,20)
+ var/loot = rand(1,21)
var/mod
switch(loot)
if(1)
@@ -71,6 +71,9 @@
new /obj/item/bedsheet/cult(src)
if(20)
new /obj/item/clothing/neck/necklace/memento_mori(src)
+ if(21)
+ new /obj/item/clothing/gloves/fingerless/punch_mitts(src)
+ new /obj/item/clothing/head/cowboy(src)
if(!contents.len)
to_chat(user, span_warning("[src] makes a clunking sound as you try to open it. You feel compelled to let the gods know! (Please open an adminhelp and try again!)"))
CRASH("Failed to generate loot. loot number: [loot][mod ? "subloot: [mod]" : null]")
diff --git a/code/modules/mining/lavaland/tendril_loot.dm b/code/modules/mining/lavaland/tendril_loot.dm
index ac3ee0b9b2774..0403e17ad796a 100644
--- a/code/modules/mining/lavaland/tendril_loot.dm
+++ b/code/modules/mining/lavaland/tendril_loot.dm
@@ -557,7 +557,6 @@
var/obj/item/organ/external/wings/functional/wings = get_wing_choice(exposed_human, chest)
wings = new wings()
wings.Insert(exposed_human)
- exposed_human.dna.species.handle_mutant_bodyparts(exposed_human)
playsound(exposed_human.loc, 'sound/items/poster_ripped.ogg', 50, TRUE, -1)
exposed_human.apply_damage(20, def_zone = BODY_ZONE_CHEST, forced = TRUE, wound_bonus = CANT_WOUND)
exposed_human.emote("scream")
@@ -622,6 +621,7 @@
min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT
heat_protection = HANDS
max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT
+ body_parts_covered = HANDS|ARMS
resistance_flags = LAVA_PROOF | FIRE_PROOF //they are from lavaland after all
armor_type = /datum/armor/gloves_gauntlets
diff --git a/code/modules/mining/machine_processing.dm b/code/modules/mining/machine_processing.dm
index 61318f63b92a5..d0c63bd3b7aa8 100644
--- a/code/modules/mining/machine_processing.dm
+++ b/code/modules/mining/machine_processing.dm
@@ -94,7 +94,7 @@
/obj/machinery/mineral/processing_unit_console/ui_data(mob/user)
return processing_machine.ui_data()
-/obj/machinery/mineral/processing_unit_console/ui_act(action, list/params)
+/obj/machinery/mineral/processing_unit_console/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/mining/machine_redemption.dm b/code/modules/mining/machine_redemption.dm
index 14460cffb1b66..312acb6672014 100644
--- a/code/modules/mining/machine_redemption.dm
+++ b/code/modules/mining/machine_redemption.dm
@@ -297,7 +297,7 @@
return data
-/obj/machinery/mineral/ore_redemption/ui_act(action, params)
+/obj/machinery/mineral/ore_redemption/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/mining/machine_silo.dm b/code/modules/mining/machine_silo.dm
index 97c3a90b78eb1..7fe2e9468f186 100644
--- a/code/modules/mining/machine_silo.dm
+++ b/code/modules/mining/machine_silo.dm
@@ -143,7 +143,7 @@
return data
-/obj/machinery/ore_silo/ui_act(action, list/params)
+/obj/machinery/ore_silo/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/mining/machine_stacking.dm b/code/modules/mining/machine_stacking.dm
index c8a58a1d0f493..1c250b578668c 100644
--- a/code/modules/mining/machine_stacking.dm
+++ b/code/modules/mining/machine_stacking.dm
@@ -62,7 +62,7 @@
))
return data
-/obj/machinery/mineral/stacking_unit_console/ui_act(action, list/params)
+/obj/machinery/mineral/stacking_unit_console/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/mining/ores_coins.dm b/code/modules/mining/ores_coins.dm
index 5d9809a01f798..7ad08083df3a8 100644
--- a/code/modules/mining/ores_coins.dm
+++ b/code/modules/mining/ores_coins.dm
@@ -22,6 +22,9 @@
var/list/stack_overlays
var/scan_state = "" //Used by mineral turfs for their scan overlay.
var/spreadChance = 0 //Also used by mineral turfs for spreading veins
+ drop_sound = SFX_STONE_DROP
+ pickup_sound = SFX_STONE_PICKUP
+ sound_vary = TRUE
/obj/item/stack/ore/update_overlays()
. = ..()
@@ -514,7 +517,7 @@ GLOBAL_LIST_INIT(sand_recipes, list(\
playsound(user.loc, 'sound/items/coinflip.ogg', 50, TRUE)
var/oldloc = loc
sleep(1.5 SECONDS)
- if(loc == oldloc && user && !user.incapacitated())
+ if(loc == oldloc && user && !user.incapacitated)
user.visible_message(span_notice("[user] flips [src]. It lands on [coinflip]."), \
span_notice("You flip [src]. It lands on [coinflip]."), \
span_hear("You hear the clattering of loose change."))
@@ -596,7 +599,7 @@ GLOBAL_LIST_INIT(sand_recipes, list(\
playsound(user.loc, 'sound/items/coinflip.ogg', 50, TRUE)
var/oldloc = loc
sleep(1.5 SECONDS)
- if(loc == oldloc && user && !user.incapacitated())
+ if(loc == oldloc && user && !user.incapacitated)
user.visible_message(span_notice("[user] flips [src]. It lands on [coinflip]."), \
span_notice("You flip [src]. It lands on [coinflip]."), \
span_hear("You hear the clattering of loose change."))
diff --git a/code/modules/mining/satchel_ore_box.dm b/code/modules/mining/satchel_ore_box.dm
index b94796b161433..94be35108d0b0 100644
--- a/code/modules/mining/satchel_ore_box.dm
+++ b/code/modules/mining/satchel_ore_box.dm
@@ -95,7 +95,7 @@
return list("materials" = materials)
-/obj/structure/ore_box/ui_act(action, params)
+/obj/structure/ore_box/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/mob/dead/observer/login.dm b/code/modules/mob/dead/observer/login.dm
index c239817a30e14..cf5863163c884 100644
--- a/code/modules/mob/dead/observer/login.dm
+++ b/code/modules/mob/dead/observer/login.dm
@@ -7,9 +7,6 @@
ghost_others = client.prefs.read_preference(/datum/preference/choiced/ghost_others)
var/preferred_form = null
- if(isAdminGhostAI(src))
- has_unlimited_silicon_privilege = TRUE
-
if(client.prefs.unlock_content)
preferred_form = client.prefs.read_preference(/datum/preference/choiced/ghost_form)
ghost_orbit = client.prefs.read_preference(/datum/preference/choiced/ghost_orbit)
diff --git a/code/modules/mob/dead/observer/notificationprefs.dm b/code/modules/mob/dead/observer/notificationprefs.dm
index 802da5e2b8011..5e14f1e5ce9bc 100644
--- a/code/modules/mob/dead/observer/notificationprefs.dm
+++ b/code/modules/mob/dead/observer/notificationprefs.dm
@@ -38,7 +38,7 @@
"desc" = GLOB.poll_ignore_desc[key]
))
-/datum/notificationpanel/ui_act(action, params)
+/datum/notificationpanel/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index bf4411a0d482d..80f7be5e3180e 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -141,11 +141,8 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
add_to_dead_mob_list()
- for(var/v in GLOB.active_alternate_appearances)
- if(!v)
- continue
- var/datum/atom_hud/alternate_appearance/AA = v
- AA.onNewMob(src)
+ for(var/datum/atom_hud/alternate_appearance/alt_hud as anything in GLOB.active_alternate_appearances)
+ alt_hud.apply_to_new_mob(src)
. = ..()
diff --git a/code/modules/mob/emote.dm b/code/modules/mob/emote.dm
index 84b00249a4972..7aba095a944a2 100644
--- a/code/modules/mob/emote.dm
+++ b/code/modules/mob/emote.dm
@@ -83,15 +83,10 @@
/datum/emote/flip/run_emote(mob/user, params , type_override, intentional)
. = ..()
- user.SpinAnimation(HAS_TRAIT(user, TRAIT_SLOW_FLIP) ? FLIP_EMOTE_DURATION * 2 : FLIP_EMOTE_DURATION, 1)
+ user.SpinAnimation(FLIP_EMOTE_DURATION, 1)
/datum/emote/flip/check_cooldown(mob/user, intentional)
- var/slow_flipper = HAS_TRAIT(user, TRAIT_SLOW_FLIP)
- if(slow_flipper)
- cooldown *= 2
. = ..()
- if(slow_flipper)
- cooldown *= 0.5
if(.)
return
if(!can_run_emote(user, intentional=intentional))
@@ -147,3 +142,27 @@
#undef BEYBLADE_DIZZINESS_DURATION
#undef BEYBLADE_CONFUSION_INCREMENT
#undef BEYBLADE_CONFUSION_LIMIT
+
+
+/datum/emote/jump
+ key = "jump"
+ key_third_person = "jumps"
+ message = "jumps!"
+ // Allows ghosts to jump
+ mob_type_ignore_stat_typecache = list(/mob/dead/observer)
+
+/datum/emote/jump/run_emote(mob/user, params, type_override, intentional)
+ . = ..()
+
+ var/original_transform = user.transform
+ animate(user, transform = user.transform.Translate(0, 4), time = 0.1 SECONDS, flags = ANIMATION_PARALLEL)
+ animate(transform = original_transform, time = 0.1 SECONDS)
+
+/datum/emote/jump/get_sound(mob/user)
+ return 'sound/weapons/thudswoosh.ogg'
+
+// Avoids playing sounds if we're a ghost
+/datum/emote/jump/should_play_sound(mob/user, intentional)
+ if ishuman(user)
+ return ..()
+ return FALSE
diff --git a/code/modules/mob/living/basic/basic.dm b/code/modules/mob/living/basic/basic.dm
index 582af27c3161b..9501c4e21d3e9 100644
--- a/code/modules/mob/living/basic/basic.dm
+++ b/code/modules/mob/living/basic/basic.dm
@@ -266,7 +266,7 @@
REMOVE_TRAIT(src, TRAIT_NO_GLIDE, SPEED_TRAIT)
/mob/living/basic/relaymove(mob/living/user, direction)
- if(user.incapacitated())
+ if(user.incapacitated)
return
return relaydrive(user, direction)
diff --git a/code/modules/mob/living/basic/blob_minions/blob_ai.dm b/code/modules/mob/living/basic/blob_minions/blob_ai.dm
index 5aad05d4656ff..5fc90f3dd676b 100644
--- a/code/modules/mob/living/basic/blob_minions/blob_ai.dm
+++ b/code/modules/mob/living/basic/blob_minions/blob_ai.dm
@@ -46,7 +46,7 @@
ai_movement = /datum/ai_movement/jps
idle_behavior = /datum/idle_behavior/idle_random_walk
planning_subtrees = list(
- /datum/ai_planning_subtree/find_and_hunt_target/corpses,
+ /datum/ai_planning_subtree/find_and_hunt_target/corpses/human,
/datum/ai_planning_subtree/travel_to_point/and_clear_target,
/datum/ai_planning_subtree/simple_find_target,
/datum/ai_planning_subtree/attack_obstacle_in_path,
diff --git a/code/modules/mob/living/basic/bots/_bots.dm b/code/modules/mob/living/basic/bots/_bots.dm
index 04b3a7864d21e..cc6ac85c6cbc4 100644
--- a/code/modules/mob/living/basic/bots/_bots.dm
+++ b/code/modules/mob/living/basic/bots/_bots.dm
@@ -26,7 +26,6 @@ GLOBAL_LIST_INIT(command_strings, list(
maximum_survivable_temperature = INFINITY
minimum_survivable_temperature = 0
- has_unlimited_silicon_privilege = TRUE
sentience_type = SENTIENCE_ARTIFICIAL
status_flags = NONE //no default canpush
@@ -59,6 +58,7 @@ GLOBAL_LIST_INIT(command_strings, list(
///All initial access this bot started with.
var/list/initial_access = list()
///Bot-related mode flags on the Bot indicating how they will act. BOT_MODE_ON | BOT_MODE_AUTOPATROL | BOT_MODE_REMOTE_ENABLED | BOT_MODE_CAN_BE_SAPIENT | BOT_MODE_ROUNDSTART_POSSESSION
+ /// DO NOT MODIFY MANUALLY, USE set_bot_mode_flags. If you don't shit breaks BAD
var/bot_mode_flags = BOT_MODE_ON | BOT_MODE_REMOTE_ENABLED | BOT_MODE_CAN_BE_SAPIENT | BOT_MODE_ROUNDSTART_POSSESSION
///Bot-related cover flags on the Bot to deal with what has been done to their cover, including emagging. BOT_COVER_MAINTS_OPEN | BOT_COVER_LOCKED | BOT_COVER_EMAGGED | BOT_COVER_HACKED
var/bot_access_flags = BOT_COVER_LOCKED
@@ -109,6 +109,7 @@ GLOBAL_LIST_INIT(command_strings, list(
/mob/living/basic/bot/Initialize(mapload)
. = ..()
+ add_traits(list(TRAIT_SILICON_ACCESS, TRAIT_REAGENT_SCANNER, TRAIT_UNOBSERVANT), INNATE_TRAIT)
AddElement(/datum/element/ai_retaliate)
RegisterSignal(src, COMSIG_MOVABLE_MOVED, PROC_REF(handle_loop_movement))
RegisterSignal(src, COMSIG_ATOM_WAS_ATTACKED, PROC_REF(after_attacked))
@@ -151,6 +152,11 @@ GLOBAL_LIST_INIT(command_strings, list(
ai_controller.set_blackboard_key(BB_RADIO_CHANNEL, radio_channel)
update_appearance()
+/mob/living/basic/bot/proc/set_mode_flags(mode_flags)
+ SHOULD_CALL_PARENT(TRUE)
+ bot_mode_flags = mode_flags
+ SEND_SIGNAL(src, COMSIG_BOT_MODE_FLAGS_SET, mode_flags)
+
/mob/living/basic/bot/proc/get_mode()
if(client) //Player bots do not have modes, thus the override. Also an easy way for PDA users/AI to know when a bot is a player.
return span_bold("[paicard ? "pAI Controlled" : "Autonomous"]")
@@ -181,7 +187,7 @@ GLOBAL_LIST_INIT(command_strings, list(
/mob/living/basic/bot/proc/turn_on()
if(stat == DEAD)
return FALSE
- bot_mode_flags |= BOT_MODE_ON
+ set_mode_flags(bot_mode_flags | BOT_MODE_ON)
remove_traits(list(TRAIT_INCAPACITATED, TRAIT_IMMOBILIZED, TRAIT_HANDS_BLOCKED), POWER_LACK_TRAIT)
set_light_on(bot_mode_flags & BOT_MODE_ON ? TRUE : FALSE)
update_appearance()
@@ -190,7 +196,7 @@ GLOBAL_LIST_INIT(command_strings, list(
return TRUE
/mob/living/basic/bot/proc/turn_off()
- bot_mode_flags &= ~BOT_MODE_ON
+ set_mode_flags(bot_mode_flags & ~BOT_MODE_ON)
add_traits(on_toggle_traits, POWER_LACK_TRAIT)
set_light_on(bot_mode_flags & BOT_MODE_ON ? TRUE : FALSE)
bot_reset() //Resets an AI's call, should it exist.
@@ -308,7 +314,7 @@ GLOBAL_LIST_INIT(command_strings, list(
return FALSE
bot_access_flags |= BOT_COVER_EMAGGED
bot_access_flags |= BOT_COVER_LOCKED
- bot_mode_flags &= ~BOT_MODE_REMOTE_ENABLED //Manually emagging the bot also locks the AI from controlling it.
+ set_mode_flags(bot_mode_flags & ~BOT_MODE_REMOTE_ENABLED) //Manually emagging the bot also locks the AI from controlling it.
bot_reset()
turn_on() //The bot automatically turns on when emagged, unless recently hit with EMP.
to_chat(src, span_userdanger("(#$*#$^^( OVERRIDE DETECTED"))
@@ -553,9 +559,9 @@ GLOBAL_LIST_INIT(command_strings, list(
switch(command)
if("patroloff")
bot_reset() //HOLD IT!! //OBJECTION!!
- bot_mode_flags &= ~BOT_MODE_AUTOPATROL
+ set_mode_flags(bot_mode_flags & ~BOT_MODE_AUTOPATROL)
if("patrolon")
- bot_mode_flags |= BOT_MODE_AUTOPATROL
+ set_mode_flags(bot_mode_flags | BOT_MODE_AUTOPATROL)
if("summon")
summon_bot(user, user_access = user_access)
if("ejectpai")
@@ -607,10 +613,10 @@ GLOBAL_LIST_INIT(command_strings, list(
if("maintenance")
bot_access_flags ^= BOT_COVER_MAINTS_OPEN
if("patrol")
- bot_mode_flags ^= BOT_MODE_AUTOPATROL
+ set_mode_flags(bot_mode_flags ^ BOT_MODE_AUTOPATROL)
bot_reset()
if("airplane")
- bot_mode_flags ^= BOT_MODE_REMOTE_ENABLED
+ set_mode_flags(bot_mode_flags ^ BOT_MODE_REMOTE_ENABLED)
if("hack")
if(!HAS_SILICON_ACCESS(the_user))
return
diff --git a/code/modules/mob/living/basic/bots/bot_ai.dm b/code/modules/mob/living/basic/bots/bot_ai.dm
index b7cd5dcabd394..a0abbbfd48b40 100644
--- a/code/modules/mob/living/basic/bots/bot_ai.dm
+++ b/code/modules/mob/living/basic/bots/bot_ai.dm
@@ -55,7 +55,15 @@
var/mob/living/basic/bot/bot_pawn = pawn
bot_pawn.bot_reset()
-/datum/ai_controller/basic_controller/bot/able_to_run()
+/datum/ai_controller/basic_controller/bot/setup_able_to_run()
+ . = ..()
+ RegisterSignal(pawn, COMSIG_BOT_MODE_FLAGS_SET, PROC_REF(update_able_to_run))
+
+/datum/ai_controller/basic_controller/bot/clear_able_to_run()
+ UnregisterSignal(pawn, list(COMSIG_BOT_MODE_FLAGS_SET))
+ return ..()
+
+/datum/ai_controller/basic_controller/bot/get_able_to_run()
var/mob/living/basic/bot/bot_pawn = pawn
if(!(bot_pawn.bot_mode_flags & BOT_MODE_ON))
return FALSE
diff --git a/code/modules/mob/living/basic/bots/cleanbot/cleanbot.dm b/code/modules/mob/living/basic/bots/cleanbot/cleanbot.dm
index cd30dd4057d0e..1e2bfdb732b16 100644
--- a/code/modules/mob/living/basic/bots/cleanbot/cleanbot.dm
+++ b/code/modules/mob/living/basic/bots/cleanbot/cleanbot.dm
@@ -239,7 +239,8 @@
// Actions received from TGUI
/mob/living/basic/bot/cleanbot/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
- if(. || (bot_access_flags & BOT_COVER_LOCKED) && !HAS_SILICON_ACCESS(ui.user))
+ var/mob/user = ui.user
+ if(. || (bot_access_flags & BOT_COVER_LOCKED) && !HAS_SILICON_ACCESS(user))
return
switch(action)
diff --git a/code/modules/mob/living/basic/bots/firebot/firebot.dm b/code/modules/mob/living/basic/bots/firebot/firebot.dm
index e6eeaa2031cc6..921909aa8a531 100644
--- a/code/modules/mob/living/basic/bots/firebot/firebot.dm
+++ b/code/modules/mob/living/basic/bots/firebot/firebot.dm
@@ -112,9 +112,10 @@
return data
// Actions received from TGUI
-/mob/living/basic/bot/firebot/ui_act(action, params)
+/mob/living/basic/bot/firebot/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
- if(. || (bot_access_flags & BOT_COVER_LOCKED && !HAS_SILICON_ACCESS(usr)))
+ var/mob/user = ui.user
+ if(. || (bot_access_flags & BOT_COVER_LOCKED && !HAS_SILICON_ACCESS(user)))
return
switch(action)
diff --git a/code/modules/mob/living/basic/bots/honkbots/honkbot.dm b/code/modules/mob/living/basic/bots/honkbots/honkbot.dm
index 7f869995c31a3..38884bec503da 100644
--- a/code/modules/mob/living/basic/bots/honkbots/honkbot.dm
+++ b/code/modules/mob/living/basic/bots/honkbots/honkbot.dm
@@ -88,7 +88,7 @@
/mob/living/basic/bot/honkbot/ui_data(mob/user)
var/list/data = ..()
- if(!(bot_access_flags & BOT_COVER_LOCKED) || issilicon(user) || isAdminGhostAI(user))
+ if(!(bot_access_flags & BOT_COVER_LOCKED) || HAS_SILICON_ACCESS(user))
data["custom_controls"]["slip_people"] = honkbot_flags & HONKBOT_MODE_SLIP
data["custom_controls"]["fake_cuff"] = honkbot_flags & HONKBOT_HANDCUFF_TARGET
data["custom_controls"]["check_ids"] = honkbot_flags & HONKBOT_CHECK_IDS
@@ -97,7 +97,8 @@
/mob/living/basic/bot/honkbot/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
- if(. || !isliving(ui.user) || (bot_access_flags & BOT_COVER_LOCKED) && !(ui.user.has_unlimited_silicon_privilege))
+ var/mob/user = ui.user
+ if(. || !isliving(user) || (bot_access_flags & BOT_COVER_LOCKED) && !HAS_SILICON_ACCESS(user))
return
switch(action)
if("slip_people")
diff --git a/code/modules/mob/living/basic/bots/medbot/medbot.dm b/code/modules/mob/living/basic/bots/medbot/medbot.dm
index 945dd5c709fb6..7b100aa554582 100644
--- a/code/modules/mob/living/basic/bots/medbot/medbot.dm
+++ b/code/modules/mob/living/basic/bots/medbot/medbot.dm
@@ -210,9 +210,9 @@
// Actions received from TGUI
/mob/living/basic/bot/medbot/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
- if(. || !isliving(ui.user) || (bot_access_flags & BOT_COVER_LOCKED) && !HAS_SILICON_ACCESS(ui.user))
+ var/mob/user = ui.user
+ if(. || !isliving(ui.user) || (bot_access_flags & BOT_COVER_LOCKED) && !HAS_SILICON_ACCESS(user))
return
- var/mob/living/our_user = ui.user
switch(action)
if("heal_threshold")
var/adjust_num = round(text2num(params["threshold"]))
@@ -229,7 +229,7 @@
medical_mode_flags ^= MEDBOT_STATIONARY_MODE
if("sync_tech")
if(!linked_techweb)
- to_chat(our_user, span_notice("No research techweb connected."))
+ to_chat(user, span_notice("No research techweb connected."))
return
var/oldheal_amount = heal_amount
var/tech_boosters
diff --git a/code/modules/mob/living/basic/drone/_drone.dm b/code/modules/mob/living/basic/drone/_drone.dm
index 6501e35d51dc2..983ade8de0bcc 100644
--- a/code/modules/mob/living/basic/drone/_drone.dm
+++ b/code/modules/mob/living/basic/drone/_drone.dm
@@ -37,7 +37,6 @@
bubble_icon = "machine"
initial_language_holder = /datum/language_holder/drone
mob_size = MOB_SIZE_SMALL
- has_unlimited_silicon_privilege = TRUE
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, STAMINA = 0, OXY = 0)
hud_possible = list(DIAG_STAT_HUD, DIAG_HUD, ANTAG_HUD)
unique_name = TRUE
@@ -202,7 +201,16 @@
for(var/datum/atom_hud/data/diagnostic/diag_hud in GLOB.huds)
diag_hud.add_atom_to_hud(src)
- add_traits(list(TRAIT_VENTCRAWLER_ALWAYS, TRAIT_NEGATES_GRAVITY, TRAIT_LITERATE, TRAIT_KNOW_ENGI_WIRES, TRAIT_ADVANCEDTOOLUSER), INNATE_TRAIT)
+ add_traits(list(
+ TRAIT_VENTCRAWLER_ALWAYS,
+ TRAIT_NEGATES_GRAVITY,
+ TRAIT_LITERATE,
+ TRAIT_KNOW_ENGI_WIRES,
+ TRAIT_ADVANCEDTOOLUSER,
+ TRAIT_SILICON_ACCESS,
+ TRAIT_REAGENT_SCANNER,
+ TRAIT_UNOBSERVANT,
+ ), INNATE_TRAIT)
listener = new(list(ALARM_ATMOS, ALARM_FIRE, ALARM_POWER), list(z))
RegisterSignal(listener, COMSIG_ALARM_LISTENER_TRIGGERED, PROC_REF(alarm_triggered))
@@ -222,7 +230,7 @@
holder.pixel_y = hud_icon.Height() - world.icon_size
if(stat == DEAD)
holder.icon_state = "huddead2"
- else if(incapacitated())
+ else if(incapacitated)
holder.icon_state = "hudoffline"
else
holder.icon_state = "hudstat"
diff --git a/code/modules/mob/living/basic/drone/drone_tools.dm b/code/modules/mob/living/basic/drone/drone_tools.dm
index 32ec1bb152848..7effefcd7f906 100644
--- a/code/modules/mob/living/basic/drone/drone_tools.dm
+++ b/code/modules/mob/living/basic/drone/drone_tools.dm
@@ -25,7 +25,7 @@
atom_storage.max_total_storage = 40
atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
atom_storage.max_slots = 10
- atom_storage.rustle_sound = FALSE
+ atom_storage.do_rustle = FALSE
atom_storage.set_holdable(drone_builtins)
diff --git a/code/modules/mob/living/basic/drone/visuals_icons.dm b/code/modules/mob/living/basic/drone/visuals_icons.dm
index 7a2122022f81b..32ff97da305a1 100644
--- a/code/modules/mob/living/basic/drone/visuals_icons.dm
+++ b/code/modules/mob/living/basic/drone/visuals_icons.dm
@@ -108,7 +108,7 @@
/mob/living/basic/drone/proc/check_menu()
if(!istype(src))
return FALSE
- if(incapacitated())
+ if(incapacitated)
return FALSE
return TRUE
diff --git a/code/modules/mob/living/basic/guardian/guardian_creator.dm b/code/modules/mob/living/basic/guardian/guardian_creator.dm
index 441a60124a7bf..08a28041cc845 100644
--- a/code/modules/mob/living/basic/guardian/guardian_creator.dm
+++ b/code/modules/mob/living/basic/guardian/guardian_creator.dm
@@ -129,7 +129,7 @@ GLOBAL_LIST_INIT(guardian_radial_images, setup_guardian_radial())
/obj/item/guardian_creator/proc/check_menu(mob/living/user)
if(!istype(user))
return FALSE
- if(user.incapacitated() || !user.is_holding(src) || used)
+ if(user.incapacitated || !user.is_holding(src) || used)
return FALSE
return TRUE
diff --git a/code/modules/mob/living/basic/lavaland/legion/legion.dm b/code/modules/mob/living/basic/lavaland/legion/legion.dm
index 1abd916461bb8..12bf6555d97d4 100644
--- a/code/modules/mob/living/basic/lavaland/legion/legion.dm
+++ b/code/modules/mob/living/basic/lavaland/legion/legion.dm
@@ -10,7 +10,7 @@
icon_living = "legion"
icon_dead = "legion"
icon_gib = "syndicate_gib"
- mob_biotypes = MOB_ORGANIC|MOB_HUMANOID
+ mob_biotypes = MOB_ORGANIC|MOB_SPECIAL|MOB_UNDEAD
basic_mob_flags = DEL_ON_DEATH
speed = 3
maxHealth = 75
diff --git a/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm b/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm
index 7dcbc4ae325b0..8c879d3ab48c8 100644
--- a/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm
+++ b/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm
@@ -45,6 +45,7 @@
AddElement(/datum/element/mob_grabber)
AddElement(/datum/element/footstep, FOOTSTEP_MOB_CLAW)
AddElement(/datum/element/basic_eating, food_types = target_foods)
+ AddComponent(/datum/component/speechmod, replacements = strings("crustacean_replacement.json", "crustacean"))
AddComponent(\
/datum/component/amputating_limbs,\
surgery_time = snip_speed, \
diff --git a/code/modules/mob/living/basic/lavaland/raptor/raptor_ai_controller.dm b/code/modules/mob/living/basic/lavaland/raptor/raptor_ai_controller.dm
index 7ae64e9fb8a5c..a23bcf7801b2e 100644
--- a/code/modules/mob/living/basic/lavaland/raptor/raptor_ai_controller.dm
+++ b/code/modules/mob/living/basic/lavaland/raptor/raptor_ai_controller.dm
@@ -46,9 +46,10 @@
/datum/targeting_strategy/basic/raptor
-//dont attack anyone with the neutral faction.
+//dont attack anyone that shares our factions.
/datum/targeting_strategy/basic/raptor/faction_check(datum/ai_controller/controller, mob/living/living_mob, mob/living/the_target)
- return (the_target.faction.Find(FACTION_NEUTRAL) || the_target.faction.Find(FACTION_RAPTOR))
+ . = ..()
+ return .
/datum/ai_controller/basic_controller/baby_raptor
blackboard = list(
diff --git a/code/modules/mob/living/basic/slime/ai/behaviours.dm b/code/modules/mob/living/basic/slime/ai/behaviours.dm
index 1cd4677994531..35fe1a60c91a1 100644
--- a/code/modules/mob/living/basic/slime/ai/behaviours.dm
+++ b/code/modules/mob/living/basic/slime/ai/behaviours.dm
@@ -30,14 +30,14 @@
/datum/ai_behavior/find_hunt_target/find_slime_food/valid_dinner(mob/living/basic/slime/hunter, mob/living/dinner, radius, datum/ai_controller/controller, seconds_per_tick)
if(REF(dinner) in hunter.faction) //Don't eat our friends...
- return
+ return FALSE
var/static/list/slime_faction = list(FACTION_SLIME)
if(faction_check(slime_faction, dinner.faction)) //Don't try to eat slimy things, no matter how hungry we are. Anyone else can be betrayed.
- return
+ return FALSE
if(!hunter.can_feed_on(dinner, check_adjacent = FALSE)) //Are they tasty to slimes?
- return
+ return FALSE
//If we are retaliating on someone edible, lets eat them instead
if(dinner == controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET])
@@ -57,6 +57,10 @@
/datum/ai_behavior/hunt_target/unarmed_attack_target/slime
/datum/ai_behavior/hunt_target/unarmed_attack_target/slime/target_caught(mob/living/basic/slime/hunter, mob/living/hunted)
+ if (!hunter.can_feed_on(hunted)) // Target is no longer edible
+ hunter.UnarmedAttack(hunted, TRUE)
+ return
+
if((hunted.body_position != STANDING_UP) || prob(20)) //Not standing, or we rolled well? Feed.
hunter.start_feeding(hunted)
return
@@ -69,6 +73,7 @@
/datum/ai_behavior/hunt_target/unarmed_attack_target/slime/finish_action(datum/ai_controller/controller, succeeded, hunting_target_key, hunting_cooldown_key)
. = ..()
- var/mob/living/living_pawn = controller.pawn
- if(living_pawn.buckled)
+ var/mob/living/basic/slime/slime_pawn = controller.pawn
+ var/atom/target = controller.blackboard[hunting_target_key]
+ if(!slime_pawn.can_feed_on(target))
controller.clear_blackboard_key(hunting_target_key)
diff --git a/code/modules/mob/living/basic/slime/ai/subtrees.dm b/code/modules/mob/living/basic/slime/ai/subtrees.dm
index 66c01e6f6c3c6..056befece5d4b 100644
--- a/code/modules/mob/living/basic/slime/ai/subtrees.dm
+++ b/code/modules/mob/living/basic/slime/ai/subtrees.dm
@@ -31,11 +31,11 @@
/datum/ai_planning_subtree/find_and_hunt_target/find_slime_food/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
var/mob/living/living_pawn = controller.pawn
if(living_pawn.buckled)
- return FALSE
+ return
//Slimes don't want to hunt if they are neither rabid, hungry or feeling attack right now
if( (controller.blackboard[BB_SLIME_HUNGER_LEVEL] == SLIME_HUNGER_NONE) && !controller.blackboard[BB_SLIME_RABID] && isnull(controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET]))
- return FALSE
+ return
return ..()
diff --git a/code/modules/mob/living/basic/slime/feeding.dm b/code/modules/mob/living/basic/slime/feeding.dm
index 2c69aad800113..064ec441cb60b 100644
--- a/code/modules/mob/living/basic/slime/feeding.dm
+++ b/code/modules/mob/living/basic/slime/feeding.dm
@@ -20,7 +20,7 @@
if(check_friendship && (REF(meal) in faction))
return FALSE
- if(check_adjacent && !Adjacent(meal))
+ if(check_adjacent && (!Adjacent(meal) || !isturf(loc)))
return FALSE
if(meal.stat == DEAD)
diff --git a/code/modules/mob/living/basic/slime/slime.dm b/code/modules/mob/living/basic/slime/slime.dm
index 352a8149ca616..6adf4e35f3582 100644
--- a/code/modules/mob/living/basic/slime/slime.dm
+++ b/code/modules/mob/living/basic/slime/slime.dm
@@ -286,7 +286,7 @@
/mob/living/basic/slime/proc/on_slime_pre_attack(mob/living/basic/slime/our_slime, atom/target, proximity, modifiers)
SIGNAL_HANDLER
- if(LAZYACCESS(modifiers, RIGHT_CLICK) && isliving(target) && target != src && usr == src)
+ if(LAZYACCESS(modifiers, RIGHT_CLICK) && isliving(target) && target != src)
if(our_slime.can_feed_on(target))
our_slime.start_feeding(target)
return COMPONENT_HOSTILE_NO_ATTACK
diff --git a/code/modules/mob/living/basic/space_fauna/carp/carp.dm b/code/modules/mob/living/basic/space_fauna/carp/carp.dm
index 816bb7cd838e1..1d32b7809a89e 100644
--- a/code/modules/mob/living/basic/space_fauna/carp/carp.dm
+++ b/code/modules/mob/living/basic/space_fauna/carp/carp.dm
@@ -44,6 +44,8 @@
minimum_survivable_temperature = 0
maximum_survivable_temperature = 1500
+ /// If true we will run away from attackers even at full health
+ var/cowardly = FALSE
/// Cytology cells you can swab from this creature
var/cell_line = CELL_LINE_TABLE_CARP
/// What colour is our 'healing' outline?
@@ -88,7 +90,8 @@
if (cell_line)
AddElement(/datum/element/swabable, cell_line, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5)
AddElement(/datum/element/simple_flying)
- AddElement(/datum/element/ai_flee_while_injured)
+ if (!cowardly)
+ AddElement(/datum/element/ai_flee_while_injured)
setup_eating()
AddComponent(/datum/component/aggro_emote, emote_list = string_list(list("gnashes")))
@@ -267,8 +270,8 @@
///Wild carp that just vibe ya know
/mob/living/basic/carp/passive
- name = "passive carp"
- desc = "A timid, sucker-bearing creature that resembles a fish. "
+ name = "false carp"
+ desc = "A close relative of the space carp which is entirely toothless and feeds by stealing its cousin's leftovers."
icon_state = "base_friend"
icon_living = "base_friend"
@@ -278,11 +281,19 @@
attack_verb_continuous = "suckers"
attack_verb_simple = "suck"
- melee_damage_lower = 4
- melee_damage_upper = 4
+ melee_damage_lower = 0
+ melee_damage_upper = 0
+ cowardly = TRUE
ai_controller = /datum/ai_controller/basic_controller/carp/passive
+ gold_core_spawnable = FRIENDLY_SPAWN
/mob/living/basic/carp/passive/Initialize(mapload)
. = ..()
- AddElement(/datum/element/ai_retaliate)
+ AddComponent(/datum/component/ai_retaliate_advanced, CALLBACK(src, PROC_REF(on_attacked)))
AddElement(/datum/element/pet_bonus, "bloops happily!")
+ ADD_TRAIT(src, TRAIT_PACIFISM, INNATE_TRAIT)
+
+/// If someone slaps one of the school, scatter
+/mob/living/basic/carp/passive/proc/on_attacked(mob/living/attacker)
+ for(var/mob/living/basic/carp/passive/schoolmate in oview(src, 9))
+ schoolmate.ai_controller?.insert_blackboard_key_lazylist(BB_BASIC_MOB_RETALIATE_LIST, attacker)
diff --git a/code/modules/mob/living/basic/space_fauna/carp/carp_abilities.dm b/code/modules/mob/living/basic/space_fauna/carp/carp_abilities.dm
index 9a6aea8eff1d2..322d4db193c21 100644
--- a/code/modules/mob/living/basic/space_fauna/carp/carp_abilities.dm
+++ b/code/modules/mob/living/basic/space_fauna/carp/carp_abilities.dm
@@ -28,6 +28,11 @@
projectile_type = pick(permitted_projectiles)
return ..()
+/datum/action/cooldown/mob_cooldown/projectile_attack/magicarp_bolt/InterceptClickOn(mob/living/caller, params, atom/target)
+ if (!caller.combat_mode)
+ return FALSE
+ return ..()
+
/**
* # Lesser Carp Rift
* Teleport a short distance and leave a short-lived portal for people to follow through
diff --git a/code/modules/mob/living/basic/space_fauna/carp/carp_ai_rift_actions.dm b/code/modules/mob/living/basic/space_fauna/carp/carp_ai_rift_actions.dm
index f104d3566b347..260dce64bdc29 100644
--- a/code/modules/mob/living/basic/space_fauna/carp/carp_ai_rift_actions.dm
+++ b/code/modules/mob/living/basic/space_fauna/carp/carp_ai_rift_actions.dm
@@ -7,18 +7,20 @@
var/datum/ai_behavior/rift_behaviour
/// If true we finish planning after this
var/finish_planning = FALSE
+ /// Key to read for flee target
+ var/target_key = BB_BASIC_MOB_CURRENT_TARGET
/datum/ai_planning_subtree/make_carp_rift/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
if (!rift_behaviour)
CRASH("Forgot to specify rift behaviour for [src]")
- if (!controller.blackboard_key_exists(BB_BASIC_MOB_CURRENT_TARGET))
+ if (!controller.blackboard_key_exists(target_key))
return
var/datum/action/cooldown/using_action = controller.blackboard[BB_CARP_RIFT]
if (!using_action?.IsAvailable())
return
- controller.queue_behavior(rift_behaviour, BB_CARP_RIFT, BB_BASIC_MOB_CURRENT_TARGET)
+ controller.queue_behavior(rift_behaviour, BB_CARP_RIFT, target_key)
if (finish_planning)
return SUBTREE_RETURN_FINISH_PLANNING
@@ -31,13 +33,17 @@
finish_planning = TRUE
/datum/ai_planning_subtree/make_carp_rift/panic_teleport/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
- var/atom/movable/fleeing_from = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET]
+ var/atom/movable/fleeing_from = controller.blackboard[target_key]
if(!QDELETED(fleeing_from) && controller.blackboard[BB_CARPS_FEAR_FISHERMAN] && HAS_TRAIT(fleeing_from, TRAIT_SCARY_FISHERMAN))
return ..()
if (controller.blackboard[BB_BASIC_MOB_STOP_FLEEING])
return
return ..()
+/datum/ai_planning_subtree/make_carp_rift/panic_teleport/flee_key
+ target_key = BB_BASIC_MOB_FLEE_TARGET
+
+
/**
* # Make carp rift (aggressive)
* Plan to teleport towards our target so we can fuck them up
@@ -46,7 +52,7 @@
rift_behaviour = /datum/ai_behavior/make_carp_rift/towards/aggressive
/datum/ai_planning_subtree/make_carp_rift/aggressive_teleport/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
- var/atom/movable/target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET]
+ var/atom/movable/target = controller.blackboard[target_key]
if(!QDELETED(target) && controller.blackboard[BB_CARPS_FEAR_FISHERMAN] && HAS_TRAIT(target, TRAIT_SCARY_FISHERMAN))
return
return ..()
diff --git a/code/modules/mob/living/basic/space_fauna/carp/carp_controllers.dm b/code/modules/mob/living/basic/space_fauna/carp/carp_controllers.dm
index 4491ef1149137..ae011f5b14a31 100644
--- a/code/modules/mob/living/basic/space_fauna/carp/carp_controllers.dm
+++ b/code/modules/mob/living/basic/space_fauna/carp/carp_controllers.dm
@@ -106,22 +106,21 @@
*/
/datum/ai_controller/basic_controller/carp/passive
blackboard = list(
- BB_BASIC_MOB_STOP_FLEEING = TRUE,
- BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
+ BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/require_traits,
+ BB_FLEE_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic/not_friends,
- BB_TARGET_PRIORITY_TRAIT = TRAIT_SCARY_FISHERMAN,
BB_CARPS_FEAR_FISHERMAN = TRUE,
+ BB_TARGET_ONLY_WITH_TRAITS = list(TRAIT_SCARY_FISHERMAN),
)
ai_traits = STOP_MOVING_WHEN_PULLED
planning_subtrees = list(
/datum/ai_planning_subtree/pet_planning,
- /datum/ai_planning_subtree/simple_find_nearest_target_to_flee,
- /datum/ai_planning_subtree/make_carp_rift/panic_teleport,
- /datum/ai_planning_subtree/flee_target/from_fisherman,
+ /datum/ai_planning_subtree/simple_find_target/to_flee, // This should only find master fishermen because of the targeting strategy
+ /datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee/from_flee_key,
+ /datum/ai_planning_subtree/make_carp_rift/panic_teleport/flee_key,
+ /datum/ai_planning_subtree/flee_target/from_flee_key,
/datum/ai_planning_subtree/find_food,
- /datum/ai_planning_subtree/attack_obstacle_in_path/carp,
- /datum/ai_planning_subtree/shortcut_to_target_through_carp_rift,
/datum/ai_planning_subtree/make_carp_rift/aggressive_teleport,
- /datum/ai_planning_subtree/basic_melee_attack_subtree/no_fisherman,
+ /datum/ai_planning_subtree/basic_melee_attack_subtree,
/datum/ai_planning_subtree/carp_migration,
)
diff --git a/code/modules/mob/living/basic/space_fauna/netherworld/creature.dm b/code/modules/mob/living/basic/space_fauna/netherworld/creature.dm
index c55376c4fcc8f..15dfcdc29c045 100644
--- a/code/modules/mob/living/basic/space_fauna/netherworld/creature.dm
+++ b/code/modules/mob/living/basic/space_fauna/netherworld/creature.dm
@@ -55,7 +55,7 @@
// This loop will, at most, loop twice.
for(var/atom/check in check_list)
for(var/mob/living/mob_target in oview(src, 7)) // They probably cannot see us if we cannot see them... can they?
- if(mob_target.client && !mob_target.is_blind() && !mob_target.has_unlimited_silicon_privilege)
+ if(mob_target.client && !mob_target.is_blind() && !HAS_TRAIT(mob_target, TRAIT_UNOBSERVANT))
return mob_target
for(var/obj/vehicle/sealed/mecha/mecha_mob_target in oview(src, 7))
for(var/mob/mechamob_target as anything in mecha_mob_target.occupants)
@@ -79,7 +79,7 @@
. = ..()
if (!owner)
return
- observed_blocker = owner.AddComponent(/datum/component/unobserved_actor, unobserved_flags = NO_OBSERVED_ACTIONS)
+ observed_blocker = owner.AddComponent(/datum/component/unobserved_actor, unobserved_flags = NO_OBSERVED_ACTIONS, affected_actions = list(type))
/datum/action/cooldown/spell/jaunt/creature_teleport/Remove(mob/living/remove_from)
QDEL_NULL(observed_blocker)
diff --git a/code/modules/mob/living/basic/space_fauna/spider/spider_abilities/wrap.dm b/code/modules/mob/living/basic/space_fauna/spider/spider_abilities/wrap.dm
index e7771f075a871..088905a5ae2f3 100644
--- a/code/modules/mob/living/basic/space_fauna/spider/spider_abilities/wrap.dm
+++ b/code/modules/mob/living/basic/space_fauna/spider/spider_abilities/wrap.dm
@@ -26,7 +26,7 @@
/datum/action/cooldown/mob_cooldown/wrap/IsAvailable(feedback = FALSE)
. = ..()
- if(!. || owner.incapacitated())
+ if(!. || owner.incapacitated)
return FALSE
if(DOING_INTERACTION(owner, DOAFTER_SOURCE_SPIDER))
if (feedback)
diff --git a/code/modules/mob/living/basic/vermin/crab.dm b/code/modules/mob/living/basic/vermin/crab.dm
index 18a935443a11d..3c1c9146a064d 100644
--- a/code/modules/mob/living/basic/vermin/crab.dm
+++ b/code/modules/mob/living/basic/vermin/crab.dm
@@ -34,6 +34,7 @@
AddElement(/datum/element/tiny_mob_hunter, MOB_SIZE_TINY)
AddElement(/datum/element/ai_retaliate)
AddElement(/datum/element/ai_flee_while_injured)
+ AddComponent(/datum/component/speechmod, replacements = strings("crustacean_replacement.json", "crustacean"))
//COFFEE! SQUEEEEEEEEE!
/mob/living/basic/crab/coffee
@@ -88,7 +89,6 @@
planning_subtrees = list(
/datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee/from_flee_key,
/datum/ai_planning_subtree/flee_target/from_flee_key,
- /datum/ai_planning_subtree/target_retaliate/to_flee,
/datum/ai_planning_subtree/simple_find_target,
/datum/ai_planning_subtree/basic_melee_attack_subtree,
/datum/ai_planning_subtree/random_speech/crab,
diff --git a/code/modules/mob/living/brain/brain_item.dm b/code/modules/mob/living/brain/brain_item.dm
index b4c6f8e682d2d..46419d70e6dee 100644
--- a/code/modules/mob/living/brain/brain_item.dm
+++ b/code/modules/mob/living/brain/brain_item.dm
@@ -437,14 +437,21 @@
/obj/item/organ/internal/brain/lustrous/on_mob_remove(mob/living/carbon/organ_owner, special)
. = ..()
organ_owner.cure_trauma_type(/datum/brain_trauma/special/bluespace_prophet, TRAUMA_RESILIENCE_ABSOLUTE)
+ organ_owner.RemoveElement(/datum/element/tenacious)
/obj/item/organ/internal/brain/lustrous/on_mob_insert(mob/living/carbon/organ_owner, special)
. = ..()
organ_owner.gain_trauma(/datum/brain_trauma/special/bluespace_prophet, TRAUMA_RESILIENCE_ABSOLUTE)
+ organ_owner.AddElement(/datum/element/tenacious)
/obj/item/organ/internal/brain/felinid //A bit smaller than average
brain_size = 0.8
+/obj/item/organ/internal/brain/lizard //A bit smaller than average
+ name = "lizard brain"
+ desc = "This juicy piece of meat has a oversized brain stem and cerebellum, with not much of a limbic system to speak of at all. You would expect it's owner to be pretty cold blooded."
+ organ_traits = list(TRAIT_TACKLING_TAILED_DEFENDER)
+
/obj/item/organ/internal/brain/abductor
name = "grey brain"
desc = "A piece of juicy meat found in an ayy lmao's head."
diff --git a/code/modules/mob/living/carbon/alien/adult/adult.dm b/code/modules/mob/living/carbon/alien/adult/adult.dm
index ad005888178ac..663419ce22cff 100644
--- a/code/modules/mob/living/carbon/alien/adult/adult.dm
+++ b/code/modules/mob/living/carbon/alien/adult/adult.dm
@@ -78,6 +78,7 @@ GLOBAL_LIST_INIT(strippable_alien_humanoid_items, create_strippable_list(list(
SEND_SIGNAL(src, COMSIG_MOVABLE_SET_GRAB_STATE, newstate)
. = grab_state
grab_state = newstate
+ update_incapacitated()
switch(grab_state) // Current state.
if(GRAB_PASSIVE)
REMOVE_TRAIT(pulling, TRAIT_IMMOBILIZED, CHOKEHOLD_TRAIT)
@@ -101,7 +102,7 @@ GLOBAL_LIST_INIT(strippable_alien_humanoid_items, create_strippable_list(list(
/mob/living/carbon/alien/adult/proc/can_consume(atom/movable/poor_soul)
if(!isliving(poor_soul) || pulling != poor_soul)
return FALSE
- if(incapacitated() || grab_state < GRAB_AGGRESSIVE || stat != CONSCIOUS)
+ if(incapacitated || grab_state < GRAB_AGGRESSIVE || stat != CONSCIOUS)
return FALSE
if(get_dir(src, poor_soul) != dir) // Gotta face em 4head
return FALSE
diff --git a/code/modules/mob/living/carbon/alien/alien.dm b/code/modules/mob/living/carbon/alien/alien.dm
index a995eafbb3ac0..f587b9d00160c 100644
--- a/code/modules/mob/living/carbon/alien/alien.dm
+++ b/code/modules/mob/living/carbon/alien/alien.dm
@@ -162,3 +162,6 @@ Des: Removes all infected images from the alien.
/mob/living/carbon/alien/proc/update_alien_speed()
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/alien_speed, multiplicative_slowdown = alien_speed)
+
+/mob/living/carbon/alien/get_footprint_sprite()
+ return FOOTPRINT_SPRITE_CLAWS
diff --git a/code/modules/mob/living/carbon/alien/organs.dm b/code/modules/mob/living/carbon/alien/organs.dm
index 9303cd2347413..3c063aec7e752 100644
--- a/code/modules/mob/living/carbon/alien/organs.dm
+++ b/code/modules/mob/living/carbon/alien/organs.dm
@@ -1,6 +1,5 @@
/obj/item/organ/internal/alien
icon_state = "acid"
- visual = FALSE
food_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/toxin/acid = 10)
/obj/item/organ/internal/alien/plasmavessel
@@ -222,11 +221,11 @@
stomach_contents -= source
UnregisterSignal(source, list(COMSIG_MOVABLE_MOVED, COMSIG_LIVING_DEATH, COMSIG_QDELETING))
-/obj/item/organ/internal/stomach/alien/Insert(mob/living/carbon/stomach_owner, special, movement_flags)
+/obj/item/organ/internal/stomach/alien/mob_insert(mob/living/carbon/stomach_owner, special, movement_flags)
RegisterSignal(stomach_owner, COMSIG_ATOM_RELAYMOVE, PROC_REF(something_moved))
return ..()
-/obj/item/organ/internal/stomach/alien/Remove(mob/living/carbon/stomach_owner, special, movement_flags)
+/obj/item/organ/internal/stomach/alien/mob_remove(mob/living/carbon/stomach_owner, special, movement_flags)
UnregisterSignal(stomach_owner, COMSIG_ATOM_RELAYMOVE)
return ..()
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index 95103340bdae9..a4becbcd0eb60 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -1206,7 +1206,7 @@
return bodyparts.len > 2 && ..()
/mob/living/carbon/proc/hypnosis_vulnerable()
- if(HAS_TRAIT(src, TRAIT_MINDSHIELD))
+ if(HAS_MIND_TRAIT(src, TRAIT_UNCONVERTABLE))
return FALSE
if(has_status_effect(/datum/status_effect/hallucination) || has_status_effect(/datum/status_effect/drugginess))
return TRUE
diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm
index 79af6c802d623..978714e9bf7a3 100644
--- a/code/modules/mob/living/carbon/carbon_defense.dm
+++ b/code/modules/mob/living/carbon/carbon_defense.dm
@@ -395,7 +395,7 @@
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1)
// Shake animation
- if (incapacitated())
+ if (incapacitated)
shake_up_animation()
/mob/proc/shake_up_animation()
@@ -650,6 +650,12 @@
/// Randomise a body part and organ of this mob
/mob/living/carbon/proc/bioscramble(scramble_source)
+ if(!(mob_biotypes & MOB_ORGANIC))
+ return FALSE
+
+ if (HAS_TRAIT(src, TRAIT_GENELESS))
+ return FALSE
+
if (run_armor_check(attack_flag = BIO, absorb_text = "Your armor protects you from [scramble_source]!") >= 100)
return FALSE
diff --git a/code/modules/mob/living/carbon/carbon_update_icons.dm b/code/modules/mob/living/carbon/carbon_update_icons.dm
index 4c98419ef412c..2350788e81f6d 100644
--- a/code/modules/mob/living/carbon/carbon_update_icons.dm
+++ b/code/modules/mob/living/carbon/carbon_update_icons.dm
@@ -53,13 +53,8 @@
overlays_standing[cache_index] = null
SEND_SIGNAL(src, COMSIG_CARBON_REMOVE_OVERLAY, cache_index, I)
-//used when putting/removing clothes that hide certain mutant body parts to just update those and not update the whole body.
-/mob/living/carbon/human/proc/update_mutant_bodyparts()
- dna?.species.handle_mutant_bodyparts(src)
- update_body_parts()
-
/mob/living/carbon/update_body(is_creating = FALSE)
- dna?.species.handle_body(src) //This calls `handle_mutant_bodyparts` which calls `update_mutant_bodyparts()`. Don't double call!
+ dna?.species.handle_body(src)
update_body_parts(is_creating)
/mob/living/carbon/on_changed_z_level(turf/old_turf, turf/new_turf, same_z_layer, notify_contents)
diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm
index 5e1bdf4282686..c2ed9b27866ec 100644
--- a/code/modules/mob/living/carbon/human/_species.dm
+++ b/code/modules/mob/living/carbon/human/_species.dm
@@ -60,16 +60,6 @@ GLOBAL_LIST_EMPTY(features_by_species)
/// Use a [language holder datum][/datum/language_holder] typepath in this var.
/// Should never be null.
var/datum/language_holder/species_language_holder = /datum/language_holder/human_basic
- /**
- * Visible CURRENT bodyparts that are unique to a species.
- * DO NOT USE THIS AS A LIST OF ALL POSSIBLE BODYPARTS AS IT WILL FUCK
- * SHIT UP! Changes to this list for non-species specific bodyparts (ie
- * cat ears and tails) should be assigned at organ level if possible.
- * Assoc values are defaults for given bodyparts, also modified by aforementioned organs.
- * They also allow for faster '[]' list access versus 'in'. Other than that, they are useless right now.
- * Layer hiding is handled by [/datum/species/proc/handle_mutant_bodyparts] below.
- */
- var/list/mutant_bodyparts = list()
///The bodyparts this species uses. assoc of bodypart string - bodypart type. Make sure all the fucking entries are in or I'll skin you alive.
var/list/bodypart_overrides = list(
BODY_ZONE_L_ARM = /obj/item/bodypart/arm/left,
@@ -79,10 +69,8 @@ GLOBAL_LIST_EMPTY(features_by_species)
BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right,
BODY_ZONE_CHEST = /obj/item/bodypart/chest,
)
- ///Internal organs that are unique to this race, like a tail. list(typepath of organ 1, typepath of organ 2)
+ ///Internal organs that are unique to this race, like a tail or other cosmetic organs. list(typepath of organ 1, typepath of organ 2 = "Round").
var/list/mutant_organs = list()
- ///List of external organs to generate like horns, frills, wings, etc. list(typepath of organ = "Round Beautiful BDSM Snout"). Still WIP
- var/list/external_organs = list()
///Replaces default brain with a different organ
var/obj/item/organ/internal/brain/mutantbrain = /obj/item/organ/internal/brain
///Replaces default heart with a different organ
@@ -283,7 +271,10 @@ GLOBAL_LIST_EMPTY(features_by_species)
if(ORGAN_SLOT_STOMACH)
return mutantstomach
else
- CRASH("Invalid organ slot [slot]")
+ // Non-standard organs we might have
+ for(var/obj/item/organ/extra_organ as anything in mutant_organs)
+ if(initial(extra_organ.slot) == slot)
+ return extra_organ
/**
* Corrects organs in a carbon, removing ones it doesn't need and adding ones it does.
@@ -299,46 +290,33 @@ GLOBAL_LIST_EMPTY(features_by_species)
* * visual_only - boolean, only load organs that change how the species looks. Do not use for normal gameplay stuff
*/
/datum/species/proc/regenerate_organs(mob/living/carbon/organ_holder, datum/species/old_species, replace_current = TRUE, list/excluded_zones, visual_only = FALSE)
- //what should be put in if there is no mutantorgan (brains handled separately)
- var/list/organ_slots = list(
- ORGAN_SLOT_BRAIN,
- ORGAN_SLOT_HEART,
- ORGAN_SLOT_LUNGS,
- ORGAN_SLOT_APPENDIX,
- ORGAN_SLOT_EYES,
- ORGAN_SLOT_EARS,
- ORGAN_SLOT_TONGUE,
- ORGAN_SLOT_LIVER,
- ORGAN_SLOT_STOMACH,
- )
-
- for(var/slot in organ_slots)
+ for(var/slot in get_all_slots())
var/obj/item/organ/existing_organ = organ_holder.get_organ_slot(slot)
var/obj/item/organ/new_organ = get_mutant_organ_type_for_slot(slot)
+ var/old_organ_type = old_species?.get_mutant_organ_type_for_slot(slot)
- if(isnull(new_organ)) // if they aren't suppose to have an organ here, remove it
- if(existing_organ)
- existing_organ.Remove(organ_holder, special = TRUE)
+ // if we have an extra organ that before changing that the species didnt have, remove it
+ if(!new_organ)
+ if(existing_organ && (old_organ_type == existing_organ.type || replace_current))
+ existing_organ.Remove(organ_holder)
qdel(existing_organ)
continue
- // we don't want to remove organs that are not the default for this species
- if(!isnull(existing_organ))
- if(!isnull(old_species) && existing_organ.type != old_species.get_mutant_organ_type_for_slot(slot))
- continue
- else if(!replace_current && existing_organ.type != get_mutant_organ_type_for_slot(slot))
+ if(existing_organ)
+ // we dont want to remove organs that were not from the old species (such as from freak surgery or prosthetics)
+ if(existing_organ.type != old_organ_type && !replace_current)
continue
- // at this point we already know new_organ is not null
- if(existing_organ?.type == new_organ)
- continue // we don't want to remove organs that are the same as the new one
+ // we don't want to remove organs that are the same as the new one
+ if(existing_organ.type == new_organ)
+ continue
- if(visual_only && !initial(new_organ.visual))
+ if(visual_only && (!initial(new_organ.bodypart_overlay) && !initial(new_organ.visual)))
continue
var/used_neworgan = FALSE
new_organ = SSwardrobe.provide_type(new_organ)
- var/should_have = new_organ.get_availability(src, organ_holder)
+ var/should_have = new_organ.get_availability(src, organ_holder) && should_visual_organ_apply_to(new_organ, organ_holder)
// Check for an existing organ, and if there is one check to see if we should remove it
var/health_pct = 1
@@ -362,46 +340,6 @@ GLOBAL_LIST_EMPTY(features_by_species)
if(!used_neworgan)
QDEL_NULL(new_organ)
- if(!isnull(old_species))
- for(var/mutant_organ in old_species.mutant_organs)
- if(mutant_organ in mutant_organs)
- continue // need this mutant organ, but we already have it!
-
- var/obj/item/organ/current_organ = organ_holder.get_organ_by_type(mutant_organ)
- if(current_organ)
- current_organ.Remove(organ_holder)
- QDEL_NULL(current_organ)
-
- for(var/obj/item/organ/external/external_organ in organ_holder.organs)
- // External organ checking. We need to check the external organs owned by the carbon itself,
- // because we want to also remove ones not shared by its species.
- // This should be done even if species was not changed.
- if(external_organ in external_organs)
- continue // Don't remove external organs this species is supposed to have.
-
- external_organ.Remove(organ_holder)
- QDEL_NULL(external_organ)
-
- var/list/species_organs = mutant_organs + external_organs
- for(var/organ_path in species_organs)
- var/obj/item/organ/current_organ = organ_holder.get_organ_by_type(organ_path)
- if(ispath(organ_path, /obj/item/organ/external) && !should_external_organ_apply_to(organ_path, organ_holder))
- if(!isnull(current_organ) && replace_current)
- // if we have an organ here and we're replacing organs, remove it
- current_organ.Remove(organ_holder)
- QDEL_NULL(current_organ)
- continue
-
- if(!current_organ || replace_current)
- var/obj/item/organ/replacement = SSwardrobe.provide_type(organ_path)
- // If there's an existing mutant organ, we're technically replacing it.
- // Let's abuse the snowflake proc that skillchips added. Basically retains
- // feature parity with every other organ too.
- if(current_organ)
- current_organ.before_organ_replacement(replacement)
- // organ.Insert will qdel any current organs in that slot, so we don't need to.
- replacement.Insert(organ_holder, special=TRUE, movement_flags = DELETE_IF_REPLACED)
-
/datum/species/proc/worn_items_fit_body_check(mob/living/carbon/wearer)
for(var/obj/item/equipped_item in wearer.get_equipped_items(INCLUDE_POCKETS))
var/equipped_item_slot = wearer.get_slot_by_item(equipped_item)
@@ -443,7 +381,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
if(old_species.type != type)
replace_body(human_who_gained_species, src)
- regenerate_organs(human_who_gained_species, old_species, visual_only = human_who_gained_species.visual_only_organs)
+ regenerate_organs(human_who_gained_species, old_species, replace_current = FALSE, visual_only = human_who_gained_species.visual_only_organs)
// Drop the items the new species can't wear
INVOKE_ASYNC(src, PROC_REF(worn_items_fit_body_check), human_who_gained_species, TRUE)
@@ -459,16 +397,6 @@ GLOBAL_LIST_EMPTY(features_by_species)
//Resets blood if it is excessively high so they don't gib
normalize_blood(human_who_gained_species)
- if(ishuman(human_who_gained_species))
- var/mob/living/carbon/human/human = human_who_gained_species
- for(var/obj/item/organ/external/organ_path as anything in external_organs)
- if(!should_external_organ_apply_to(organ_path, human))
- continue
-
- //Load a persons preferences from DNA
- var/obj/item/organ/external/new_organ = SSwardrobe.provide_type(organ_path)
- new_organ.Insert(human, special=TRUE, movement_flags = DELETE_IF_REPLACED)
-
add_body_markings(human_who_gained_species)
if(length(inherent_traits))
@@ -509,10 +437,6 @@ GLOBAL_LIST_EMPTY(features_by_species)
for(var/X in inherent_traits)
REMOVE_TRAIT(C, X, SPECIES_TRAIT)
- for(var/obj/item/organ/external/organ in C.organs)
- organ.Remove(C)
- qdel(organ)
-
//If their inert mutation is not the same, swap it out
if((inert_mutation != new_species.inert_mutation) && LAZYLEN(C.dna.mutation_index) && (inert_mutation in C.dna.mutation_index))
C.dna.remove_mutation(inert_mutation)
@@ -546,14 +470,13 @@ GLOBAL_LIST_EMPTY(features_by_species)
* Handles the body of a human
*
* Handles lipstick, having no eyes, eye color, undergarnments like underwear, undershirts, and socks, and body layers.
- * Calls [handle_mutant_bodyparts][/datum/species/proc/handle_mutant_bodyparts]
* Arguments:
* * species_human - Human, whoever we're handling the body for
*/
/datum/species/proc/handle_body(mob/living/carbon/human/species_human)
species_human.remove_overlay(BODY_LAYER)
if(HAS_TRAIT(species_human, TRAIT_INVISIBLE_MAN))
- return handle_mutant_bodyparts(species_human)
+ return
var/list/standing = list()
if(!HAS_TRAIT(species_human, TRAIT_HUSK))
@@ -572,7 +495,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
var/mutable_appearance/underwear_overlay
if(underwear)
if(species_human.dna.species.sexes && species_human.physique == FEMALE && (underwear.gender == MALE))
- underwear_overlay = wear_female_version(underwear.icon_state, underwear.icon, BODY_LAYER, FEMALE_UNIFORM_FULL)
+ underwear_overlay = mutable_appearance(wear_female_version(underwear.icon_state, underwear.icon, FEMALE_UNIFORM_FULL), layer = -BODY_LAYER)
else
underwear_overlay = mutable_appearance(underwear.icon, underwear.icon_state, -BODY_LAYER)
if(!underwear.use_static)
@@ -584,9 +507,9 @@ GLOBAL_LIST_EMPTY(features_by_species)
if(undershirt)
var/mutable_appearance/working_shirt
if(species_human.dna.species.sexes && species_human.physique == FEMALE)
- working_shirt = wear_female_version(undershirt.icon_state, undershirt.icon, BODY_LAYER)
+ working_shirt = mutable_appearance(wear_female_version(undershirt.icon_state, undershirt.icon), layer = -BODY_LAYER)
else
- working_shirt = mutable_appearance(undershirt.icon, undershirt.icon_state, -BODY_LAYER)
+ working_shirt = mutable_appearance(undershirt.icon, undershirt.icon_state, layer = -BODY_LAYER)
standing += working_shirt
if(species_human.socks && species_human.num_legs >= 2 && !(species_human.bodyshape & BODYSHAPE_DIGITIGRADE))
@@ -598,103 +521,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
species_human.overlays_standing[BODY_LAYER] = standing
species_human.apply_overlay(BODY_LAYER)
- handle_mutant_bodyparts(species_human)
-
-/**
- * Handles the mutant bodyparts of a human
- *
- * Handles the adding and displaying of, layers, colors, and overlays of mutant bodyparts and accessories.
- * Handles digitigrade leg displaying and squishing.
- * Arguments:
- * * H - Human, whoever we're handling the body for
- * * forced_colour - The forced color of an accessory. Leave null to use mutant color.
- */
-/datum/species/proc/handle_mutant_bodyparts(mob/living/carbon/human/source, forced_colour)
- var/list/bodyparts_to_add = mutant_bodyparts.Copy()
- var/list/relevent_layers = list(BODY_BEHIND_LAYER, BODY_ADJ_LAYER, BODY_FRONT_LAYER)
- var/list/standing = list()
-
- source.remove_overlay(BODY_BEHIND_LAYER)
- source.remove_overlay(BODY_ADJ_LAYER)
- source.remove_overlay(BODY_FRONT_LAYER)
-
- if(!mutant_bodyparts || HAS_TRAIT(source, TRAIT_INVISIBLE_MAN))
- return
-
- var/obj/item/bodypart/head/noggin = source.get_bodypart(BODY_ZONE_HEAD)
-
-
- if(mutant_bodyparts["ears"])
- if(!source.dna.features["ears"] || source.dna.features["ears"] == "None" || source.head && (source.head.flags_inv & HIDEHAIR) || (source.wear_mask && (source.wear_mask.flags_inv & HIDEHAIR)) || !noggin || IS_ROBOTIC_LIMB(noggin))
- bodyparts_to_add -= "ears"
-
- if(!bodyparts_to_add)
- return
-
- var/g = (source.physique == FEMALE) ? "f" : "m"
-
- for(var/layer in relevent_layers)
- var/layertext = mutant_bodyparts_layertext(layer)
-
- for(var/bodypart in bodyparts_to_add)
- var/datum/sprite_accessory/accessory
- switch(bodypart)
- if("ears")
- accessory = SSaccessories.ears_list[source.dna.features["ears"]]
- if("legs")
- accessory = SSaccessories.legs_list[source.dna.features["legs"]]
-
- if(!accessory || accessory.icon_state == "none")
- continue
-
- var/mutable_appearance/accessory_overlay = mutable_appearance(accessory.icon, layer = -layer)
-
- if(accessory.gender_specific)
- accessory_overlay.icon_state = "[g]_[bodypart]_[accessory.icon_state]_[layertext]"
- else
- accessory_overlay.icon_state = "m_[bodypart]_[accessory.icon_state]_[layertext]"
-
- if(accessory.em_block)
- accessory_overlay.overlays += emissive_blocker(accessory_overlay.icon, accessory_overlay.icon_state, source, accessory_overlay.alpha)
-
- if(accessory.center)
- accessory_overlay = center_image(accessory_overlay, accessory.dimension_x, accessory.dimension_y)
-
- if(!(HAS_TRAIT(source, TRAIT_HUSK)))
- if(!forced_colour)
- switch(accessory.color_src)
- if(MUTANT_COLOR)
- accessory_overlay.color = fixed_mut_color || source.dna.features["mcolor"]
- if(HAIR_COLOR)
- accessory_overlay.color = get_fixed_hair_color(source) || source.hair_color
- if(FACIAL_HAIR_COLOR)
- accessory_overlay.color = get_fixed_hair_color(source) || source.facial_hair_color
- if(EYE_COLOR)
- accessory_overlay.color = source.eye_color_left
- else
- accessory_overlay.color = forced_colour
- standing += accessory_overlay
-
- if(accessory.hasinner)
- var/mutable_appearance/inner_accessory_overlay = mutable_appearance(accessory.icon, layer = -layer)
- if(accessory.gender_specific)
- inner_accessory_overlay.icon_state = "[g]_[bodypart]inner_[accessory.icon_state]_[layertext]"
- else
- inner_accessory_overlay.icon_state = "m_[bodypart]inner_[accessory.icon_state]_[layertext]"
-
- if(accessory.center)
- inner_accessory_overlay = center_image(inner_accessory_overlay, accessory.dimension_x, accessory.dimension_y)
-
- standing += inner_accessory_overlay
-
- source.overlays_standing[layer] = standing.Copy()
- standing = list()
-
- source.apply_overlay(BODY_BEHIND_LAYER)
- source.apply_overlay(BODY_ADJ_LAYER)
- source.apply_overlay(BODY_FRONT_LAYER)
-
- update_body_markings(source)
+ update_body_markings(species_human)
//This exists so sprite accessories can still be per-layer without having to include that layer's
//number in their sprite name, which causes issues when those numbers change.
@@ -737,7 +564,9 @@ GLOBAL_LIST_EMPTY(features_by_species)
var/list/new_features = list()
var/static/list/organs_to_randomize = list()
- for(var/obj/item/organ/external/organ_path as anything in external_organs)
+ for(var/obj/item/organ/organ_path as anything in mutant_organs)
+ if(!organ_path.bodypart_overlay)
+ continue
var/overlay_path = initial(organ_path.bodypart_overlay)
var/datum/bodypart_overlay/mutant/sample_overlay = organs_to_randomize[overlay_path]
if(isnull(sample_overlay))
@@ -772,7 +601,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
// Anything that's small or smaller can fit into a pocket by default
if((slot & (ITEM_SLOT_RPOCKET|ITEM_SLOT_LPOCKET)) && I.w_class <= POCKET_WEIGHT_CLASS)
excused = TRUE
- else if(slot & (ITEM_SLOT_SUITSTORE|ITEM_SLOT_BACKPACK|ITEM_SLOT_HANDS))
+ else if(slot & (ITEM_SLOT_SUITSTORE|ITEM_SLOT_BACKPACK|ITEM_SLOT_BELTPACK|ITEM_SLOT_HANDS))
excused = TRUE
if(!excused)
return FALSE
@@ -800,7 +629,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
if(H.num_legs < 2)
return FALSE
if((H.bodyshape & BODYSHAPE_DIGITIGRADE) && !(I.item_flags & IGNORE_DIGITIGRADE))
- if(!(I.supports_variations_flags & (CLOTHING_DIGITIGRADE_VARIATION|CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON)))
+ if(!(I.supports_variations_flags & DIGITIGRADE_VARIATIONS))
if(!disable_warning)
to_chat(H, span_warning("The footwear around here isn't compatible with your feet!"))
return FALSE
@@ -813,6 +642,10 @@ GLOBAL_LIST_EMPTY(features_by_species)
to_chat(H, span_warning("You need a jumpsuit before you can attach this [I.name]!"))
return FALSE
return equip_delay_self_check(I, H, bypass_equip_delay_self)
+ if(ITEM_SLOT_BELTPACK)
+ if(H.belt && H.belt.atom_storage?.can_insert(I, H, messages = TRUE, force = indirect_action ? STORAGE_SOFT_LOCKED : STORAGE_NOT_LOCKED))
+ return TRUE
+ return FALSE
if(ITEM_SLOT_EYES)
if(!H.get_bodypart(BODY_ZONE_HEAD))
return FALSE
@@ -1034,14 +867,32 @@ GLOBAL_LIST_EMPTY(features_by_species)
var/damage = rand(attacking_bodypart.unarmed_damage_low, attacking_bodypart.unarmed_damage_high)
var/limb_accuracy = attacking_bodypart.unarmed_effectiveness
+ // In a brawl, drunkenness can make you swing more wildly and with more force, and thus catch your opponent off guard, but it could also totally throw you off if you're too intoxicated
+ // But god is it going to make you sick moving too much while drunk
+ var/user_drunkenness = user.get_drunk_amount()
+
+ if(user_drunkenness && HAS_TRAIT(user, TRAIT_DRUNKEN_BRAWLER)) // Drunken brawlers only need to be intoxicated, doesn't matter how much
+ limb_accuracy += clamp((user.getFireLoss() + user.getBruteLoss()) * 0.5, 10, 200)
+ damage += damage * clamp((user.getFireLoss() + user.getBruteLoss()) / 100, 0.3, 2) //Basically a multiplier of how much extra damage you get based on how low your health is overall. A floor of about a 30%.
+ var/drunken_martial_descriptor = pick("Drunken", "Intoxicated", "Tipsy", "Inebriated", "Delirious", "Day-Drinker's", "Firegut", "Blackout")
+ atk_verb = "[drunken_martial_descriptor] [atk_verb]"
+
+ else if(user_drunkenness > 30 && user_drunkenness < 60)
+ limb_accuracy *= 1.2
+ user.adjust_disgust(2)
+
+ else if(user_drunkenness >= 60)
+ limb_accuracy = -limb_accuracy // good luck landing a punch now, you drunk fuck
+ user.adjust_disgust(5)
+
var/obj/item/bodypart/affecting = target.get_bodypart(target.get_random_valid_zone(user.zone_selected))
var/miss_chance = 100//calculate the odds that a punch misses entirely. considers stamina and brute damage of the puncher. punches miss by default to prevent weird cases
if(attacking_bodypart.unarmed_damage_low)
- if((target.body_position == LYING_DOWN) || HAS_TRAIT(user, TRAIT_PERFECT_ATTACKER) || staggered) //kicks and attacks against staggered targets never miss (provided your species deals more than 0 damage)
+ if((target.body_position == LYING_DOWN) || HAS_TRAIT(user, TRAIT_PERFECT_ATTACKER) || staggered || user_drunkenness && HAS_TRAIT(user, TRAIT_DRUNKEN_BRAWLER)) //kicks and attacks against staggered targets never miss (provided your species deals more than 0 damage). Drunken brawlers while drunk also don't miss
miss_chance = 0
else
- miss_chance = clamp(UNARMED_MISS_CHANCE_BASE - limb_accuracy + user.getStaminaLoss() + (user.getBruteLoss()*0.5), 0, UNARMED_MISS_CHANCE_MAX) //Limb miss chance + various damage. capped at 80 so there is at least a chance to land a hit.
+ miss_chance = clamp(UNARMED_MISS_CHANCE_BASE - limb_accuracy + (user.getFireLoss()*0.5 + user.getBruteLoss()*0.5), 0, UNARMED_MISS_CHANCE_MAX) //Limb miss chance + various damage. capped at 80 so there is at least a chance to land a hit.
if(!damage || !affecting || prob(miss_chance))//future-proofing for species that have 0 damage/weird cases where no zone is targeted
playsound(target.loc, attacking_bodypart.unarmed_miss_sound, 25, TRUE, -1)
@@ -1053,6 +904,20 @@ GLOBAL_LIST_EMPTY(features_by_species)
var/armor_block = target.run_armor_check(affecting, MELEE)
+ // In a brawl, drunkenness is a boon if you're a bit drunk but not too much. Else you're easier to hit.
+ // But, generally, getting hit while drunk is probably a good way to start throwing up
+ var/target_drunkenness = target.get_drunk_amount()
+ if(target_drunkenness && HAS_TRAIT(target, TRAIT_DRUNKEN_BRAWLER)) // Drunken brawlers only need to be intoxicated, doesn't matter how much
+ armor_block += 20
+
+ else if(target_drunkenness > 30 && target_drunkenness < 60)
+ armor_block += 10
+ target.adjust_disgust(2)
+
+ else if(target_drunkenness >= 60)
+ armor_block *= 0.5
+ target.adjust_disgust(5)
+
playsound(target.loc, attacking_bodypart.unarmed_attack_sound, 25, TRUE, -1)
if(grappled && attacking_bodypart.grappled_attack_verb)
@@ -1080,6 +945,65 @@ GLOBAL_LIST_EMPTY(features_by_species)
target.force_say()
log_combat(user, target, "punched")
+ // If our target is staggered and has sustained enough damage, we can apply a randomly determined status effect to inflict when we punch them.
+ // The effects are based on the punching effectiveness of our attacker. Some effects are not reachable by the average human, and require augmentation to reach or being a species with a heavy punch effectiveness.
+ // Or they're just drunk enough.
+ if(HAS_TRAIT(target, TRAIT_BRAWLING_KNOCKDOWN_BLOCKED) || target.stat == DEAD) //If our target is dead or has specailized armor, there is no way to inflict these effects.
+ return
+
+ // If our target is staggered, the target's armor, minus our limb effectiveness sets the minimum necessary amount of damage sustained to cause an effect. Minimum 40, max 200 for sanity reasons
+ if(staggered && (target.getFireLoss()*0.5 + target.getBruteLoss()*0.5) >= min(armor_block - limb_accuracy, 40, 200))
+ stagger_combo(user, target, atk_verb, limb_accuracy, armor_block)
+
+/// Handles the stagger combo effect of our punch. Follows the same logic as the above proc, target is our owner, user is our attacker.
+/datum/species/proc/stagger_combo(mob/living/carbon/human/user, mob/living/carbon/human/target, atk_verb = "hit", limb_accuracy = 0, armor_block = 0)
+ // Randomly determines the effects of our punch. Limb accuracy is a bonus, armor block is a defense
+ var/roll_them_bones = rand(-20, 20) + limb_accuracy - armor_block
+
+ switch(roll_them_bones)
+ if (-INFINITY to 0) //Mostly a gimmie, this one just keeps them staggered briefly
+ target.adjust_staggered_up_to(1 SECONDS, 10 SECONDS)
+ target.visible_message(span_warning("[user]'s [atk_verb] briefly winds [target]!"), \
+ span_warning("You are briefly winded by [user]'s [atk_verb]!"), span_hear("You hear a thud!"), COMBAT_MESSAGE_RANGE, user)
+ to_chat(user, span_warning("Your [atk_verb] briefly winds [target]!"))
+
+ if (1 to 10)
+ target.adjust_eye_blur_up_to(5 SECONDS, 10 SECONDS)
+ target.visible_message(span_warning("[user]'s [atk_verb] hits [target] so hard, their eyes water! Ouch!"), \
+ span_warning("You are hit viciously by [user]'s [atk_verb], and your eyes begin to water!"), span_hear("You hear a thud!"), COMBAT_MESSAGE_RANGE, user)
+ to_chat(user, span_warning("Your [atk_verb] causes [target] to tear up!"))
+
+ if (11 to 30)
+ target.adjust_dizzy_up_to(5 SECONDS, 10 SECONDS)
+ target.adjust_eye_blur_up_to(5 SECONDS, 10 SECONDS)
+ target.adjust_confusion_up_to(5 SECONDS, 10 SECONDS)
+ target.visible_message(span_warning("[user]'s [atk_verb] hits [target] so hard, they are sent reeling in agony! Damn!"), \
+ span_warning("You are hit viciously by [user]'s [atk_verb], and everything becomes a dizzying blur!"), span_hear("You hear a thud!"), COMBAT_MESSAGE_RANGE, user)
+ to_chat(user, span_warning("Your [atk_verb] causes [target] to go stumbling about in a confuzed daze!"))
+
+ if(31 to 40)
+ target.adjust_dizzy_up_to(5 SECONDS, 10 SECONDS)
+ target.adjust_confusion_up_to(5 SECONDS, 10 SECONDS)
+ target.adjust_temp_blindness_up_to(5 SECONDS, 10 SECONDS)
+ target.visible_message(span_warning("[user]'s [atk_verb] hits [target] so hard, they are sent reeling blindly in agony! Goddamn!"), \
+ span_warning("You are hit viciously by [user]'s [atk_verb], and everything becomes a dizzying, blinding blur!"), span_hear("You hear a thud!"), COMBAT_MESSAGE_RANGE, user)
+ to_chat(user, span_warning("Your [atk_verb] causes [target] to go stumbling about in a confuzed, blind daze!"))
+
+ if (41 to 45)
+ target.apply_effect(4 SECONDS, EFFECT_KNOCKDOWN, armor_block)
+ target.visible_message(span_warning("[user]'s [atk_verb] hits [target] so hard, you knock them off their feet! Holy shit!"), \
+ span_warning("You are hit viciously by [user]'s [atk_verb] and sent toppling head over heels!"), span_hear("You hear a sickening thud!"), COMBAT_MESSAGE_RANGE, user)
+ to_chat(user, span_warning("Your [atk_verb] lands, and you send [target] sailing off their feet!"))
+
+ if (46 to INFINITY)
+ target.apply_effect(4 SECONDS, EFFECT_KNOCKDOWN, armor_block)
+ var/obj/item/bodypart/affecting = target.get_bodypart(target.get_random_valid_zone(user.zone_selected))
+ target.apply_damage(5, BRUTE, affecting, armor_block, wound_bonus = limb_accuracy * 2) //Mostly for the crunchy wounding effect than actually doing damage
+ target.visible_message(span_warning("[user]'s [atk_verb] hits [target] so hard, you hit them off their feet with a loud crunch! Fucking hell!"), \
+ span_warning("You are hit viciously by [user]'s [atk_verb], and suddenly feel an overwhelming pain as you topple head over heels!"), span_hear("You hear a sickening crack and a loud thud!"), COMBAT_MESSAGE_RANGE, user)
+ to_chat(user, span_warning("Your [atk_verb] lands, and [target] is sent crashing to the floor with the immense force! Good god!"))
+
+
/datum/species/proc/disarm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
if(user.body_position != STANDING_UP)
return FALSE
@@ -1484,15 +1408,14 @@ GLOBAL_LIST_EMPTY(features_by_species)
var/datum/preference/preference = GLOB.preference_entries[preference_type]
if ( \
- (preference.relevant_mutant_bodypart in mutant_bodyparts) \
- || (preference.relevant_inherent_trait in inherent_traits) \
- || (preference.relevant_external_organ in external_organs) \
+ (preference.relevant_inherent_trait in inherent_traits) \
+ || (preference.relevant_external_organ in mutant_organs) \
|| (preference.relevant_head_flag && check_head_flags(preference.relevant_head_flag)) \
|| (preference.relevant_body_markings in body_markings) \
)
features += preference.savefile_key
- for (var/obj/item/organ/external/organ_type as anything in external_organs)
+ for (var/obj/item/organ/organ_type as anything in mutant_organs)
var/preference = initial(organ_type.preference)
if (!isnull(preference))
features += preference
@@ -1537,7 +1460,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
/datum/species/proc/get_types_to_preload()
var/list/to_store = list()
to_store += mutant_organs
- for(var/obj/item/organ/external/horny as anything in external_organs)
+ for(var/obj/item/organ/horny as anything in mutant_organs)
to_store += horny //Haha get it?
//Don't preload brains, cause reuse becomes a horrible headache
@@ -2123,6 +2046,10 @@ GLOBAL_LIST_EMPTY(features_by_species)
/// Update the overlays if necessary
/datum/species/proc/update_body_markings(mob/living/carbon/human/hooman)
+ if(HAS_TRAIT(hooman, TRAIT_INVISIBLE_MAN))
+ remove_body_markings(hooman)
+ return
+
var/needs_update = FALSE
for(var/datum/bodypart_overlay/simple/body_marking/marking as anything in body_markings)
if(initial(marking.dna_feature_key) == body_markings[marking]) // dna is same as our species (sort of mini-cache), so no update needed
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 9816012218225..cf73704600c7f 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -909,7 +909,7 @@
return ishuman(target) && target.body_position == LYING_DOWN
/mob/living/carbon/human/proc/fireman_carry(mob/living/carbon/target)
- if(!can_be_firemanned(target) || incapacitated(IGNORE_GRAB))
+ if(!can_be_firemanned(target) || INCAPACITATED_IGNORING(src, INCAPABLE_GRAB))
to_chat(src, span_warning("You can't fireman carry [target] while [target.p_they()] [target.p_are()] standing!"))
return
@@ -940,7 +940,7 @@
return
//Second check to make sure they're still valid to be carried
- if(!can_be_firemanned(target) || incapacitated(IGNORE_GRAB) || target.buckled)
+ if(!can_be_firemanned(target) || INCAPACITATED_IGNORING(src, INCAPABLE_GRAB) || target.buckled)
visible_message(span_warning("[src] fails to fireman carry [target]!"))
return
@@ -956,7 +956,7 @@
visible_message(span_warning("[target] fails to climb onto [src]!"))
return
- if(target.incapacitated(IGNORE_GRAB) || incapacitated(IGNORE_GRAB))
+ if(INCAPACITATED_IGNORING(target, INCAPABLE_GRAB) || INCAPACITATED_IGNORING(src, INCAPABLE_GRAB))
target.visible_message(span_warning("[target] can't hang onto [src]!"))
return
diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm
index 3a9004618470f..c561ca28999f1 100644
--- a/code/modules/mob/living/carbon/human/human_helpers.dm
+++ b/code/modules/mob/living/carbon/human/human_helpers.dm
@@ -58,10 +58,13 @@
//repurposed proc. Now it combines get_id_name() and get_face_name() to determine a mob's name variable. Made into a separate proc as it'll be useful elsewhere
/mob/living/carbon/human/get_visible_name(add_id_name = TRUE, force_real_name = FALSE)
- var/list/identity = list(null, null)
+ var/list/identity = list(null, null, null)
SEND_SIGNAL(src, COMSIG_HUMAN_GET_VISIBLE_NAME, identity)
var/signal_face = LAZYACCESS(identity, VISIBLE_NAME_FACE)
var/signal_id = LAZYACCESS(identity, VISIBLE_NAME_ID)
+ var/force_set = LAZYACCESS(identity, VISIBLE_NAME_FORCED)
+ if(force_set) // our name is overriden by something
+ return signal_face // no need to null-check, because force_set will always set a signal_face
var/face_name = !isnull(signal_face) ? signal_face : get_face_name("")
var/id_name = !isnull(signal_id) ? signal_id : get_id_name("")
if (force_real_name)
@@ -107,6 +110,11 @@
var/obj/item/card/id/id = wear_id
if(HAS_TRAIT(src, TRAIT_UNKNOWN))
. = if_no_id //You get NOTHING, no id name, good day sir
+ var/list/identity = list(null, null, null)
+ SEND_SIGNAL(src, COMSIG_HUMAN_GET_FORCED_NAME, identity)
+ if(identity[VISIBLE_NAME_FORCED])
+ . = identity[VISIBLE_NAME_FACE] // to return forced names when unknown, instead of ID
+ return
if(istype(wallet))
id = wallet.front_id
if(istype(id))
diff --git a/code/modules/mob/living/carbon/human/human_say.dm b/code/modules/mob/living/carbon/human/human_say.dm
index 0ce34ffa27205..8edeeb8088403 100644
--- a/code/modules/mob/living/carbon/human/human_say.dm
+++ b/code/modules/mob/living/carbon/human/human_say.dm
@@ -73,7 +73,7 @@
var/area/our_area = get_area(src)
if(our_area.area_flags & BINARY_JAMMING)
return FALSE
- return dongle.translate_binary
+ return (dongle.special_channels & RADIO_SPECIAL_BINARY)
/mob/living/carbon/human/radio(message, list/message_mods = list(), list/spans, language) //Poly has a copy of this, lazy bastard
. = ..()
diff --git a/code/modules/mob/living/carbon/human/human_update_icons.dm b/code/modules/mob/living/carbon/human/human_update_icons.dm
index fe5817eab2780..77b73cae9bc4d 100644
--- a/code/modules/mob/living/carbon/human/human_update_icons.dm
+++ b/code/modules/mob/living/carbon/human/human_update_icons.dm
@@ -133,9 +133,9 @@ There are several things that need to be remembered:
var/obj/item/bodypart/chest/my_chest = get_bodypart(BODY_ZONE_CHEST)
my_chest?.worn_uniform_offset?.apply_offset(uniform_overlay)
overlays_standing[UNIFORM_LAYER] = uniform_overlay
- apply_overlay(UNIFORM_LAYER)
- update_mutant_bodyparts()
+ update_body_parts()
+ apply_overlay(UNIFORM_LAYER)
/mob/living/carbon/human/update_worn_id(update_obscured = TRUE)
remove_overlay(ID_LAYER)
@@ -434,12 +434,10 @@ There are several things that need to be remembered:
var/obj/item/bodypart/chest/my_chest = get_bodypart(BODY_ZONE_CHEST)
my_chest?.worn_suit_offset?.apply_offset(suit_overlay)
overlays_standing[SUIT_LAYER] = suit_overlay
- update_body_parts()
- update_mutant_bodyparts()
+ update_body_parts()
apply_overlay(SUIT_LAYER)
-
/mob/living/carbon/human/update_pockets()
if(client && hud_used)
var/atom/movable/screen/inventory/inv
@@ -489,7 +487,7 @@ There are several things that need to be remembered:
overlays_standing[FACEMASK_LAYER] = mask_overlay
apply_overlay(FACEMASK_LAYER)
- update_mutant_bodyparts() //e.g. upgate needed because mask now hides lizard snout
+ update_body_parts() //e.g. upgate needed because mask now hides lizard snout
/mob/living/carbon/human/update_worn_back(update_obscured = TRUE)
remove_overlay(BACK_LAYER)
@@ -548,12 +546,72 @@ There are several things that need to be remembered:
hands += hand_overlay
return hands
-/proc/wear_female_version(t_color, icon, layer, type, greyscale_colors)
- var/index = "[t_color]-[greyscale_colors]"
- var/icon/female_clothing_icon = GLOB.female_clothing_icons[index]
- if(!female_clothing_icon) //Create standing/laying icons if they don't exist
- generate_female_clothing(index, t_color, icon, type)
- return mutable_appearance(GLOB.female_clothing_icons[index], layer = -layer)
+/// Modifies a sprite slightly to conform to female body shapes
+/proc/wear_female_version(icon_state, icon, type, greyscale_colors)
+ var/index = "[icon_state]-[greyscale_colors]"
+ var/static/list/female_clothing_icons = list()
+ var/icon/female_clothing_icon = female_clothing_icons[index]
+ if(!female_clothing_icon) //Create standing/laying icons if they don't exist
+ var/female_icon_state = "female[type == FEMALE_UNIFORM_FULL ? "_full" : ((!type || type & FEMALE_UNIFORM_TOP_ONLY) ? "_top" : "")][type & FEMALE_UNIFORM_NO_BREASTS ? "_no_breasts" : ""]"
+ var/icon/female_cropping_mask = icon('icons/mob/clothing/under/masking_helpers.dmi', female_icon_state)
+ female_clothing_icon = icon(icon, icon_state)
+ female_clothing_icon.Blend(female_cropping_mask, ICON_MULTIPLY)
+ female_clothing_icon = fcopy_rsc(female_clothing_icon)
+ female_clothing_icons[index] = female_clothing_icon
+
+ return icon(female_clothing_icon)
+
+// These coordonates point to roughly somewhere in the middle of the left leg
+// Used in approximating what color the pants of clothing should be
+#define LEG_SAMPLE_X_LOWER 13
+#define LEG_SAMPLE_X_UPPER 14
+
+#define LEG_SAMPLE_Y_LOWER 8
+#define LEG_SAMPLE_Y_UPPER 9
+
+/// Modifies a sprite to conform to digitigrade body shapes
+/proc/wear_digi_version(icon/base_icon, key, greyscale_config = /datum/greyscale_config/jumpsuit/worn_digi, greyscale_colors)
+ ASSERT(key, "wear_digi_version: no key passed")
+ ASSERT(ispath(greyscale_config, /datum/greyscale_config), "wear_digi_version: greyscale_config is not a valid path (got: [greyscale_config])")
+ // items with greyscale colors containing multiple colors are invalid
+ if(isnull(greyscale_colors) || length(SSgreyscale.ParseColorString(greyscale_colors)) > 1)
+ var/pant_color
+ // approximates the color of the pants by sampling a few pixels in the middle of the left leg
+ for(var/x in LEG_SAMPLE_X_LOWER to LEG_SAMPLE_X_UPPER)
+ for(var/y in LEG_SAMPLE_Y_LOWER to LEG_SAMPLE_Y_UPPER)
+ var/xy_color = base_icon.GetPixel(x, y)
+ pant_color = pant_color ? BlendRGB(pant_color, xy_color, 0.5) : xy_color
+
+ greyscale_colors = pant_color || "#1d1d1d" // black pants always look good
+
+ var/index = "[key]-[greyscale_config]-[greyscale_colors]"
+ var/static/list/digitigrade_clothing_icons = list()
+ var/icon/digitigrade_clothing_icon = digitigrade_clothing_icons[index]
+ if(!digitigrade_clothing_icon)
+ var/static/icon/torso_mask
+ if(!torso_mask)
+ torso_mask = icon('icons/mob/clothing/under/masking_helpers.dmi', "digi_torso_mask")
+ var/static/icon/leg_mask
+ if(!leg_mask)
+ leg_mask = icon('icons/mob/clothing/under/masking_helpers.dmi', "digi_leg_mask")
+
+ base_icon.Blend(leg_mask, ICON_SUBTRACT) // cuts the legs off
+
+ var/icon/leg_icon = SSgreyscale.GetColoredIconByType(greyscale_config, greyscale_colors)
+ leg_icon.Blend(torso_mask, ICON_SUBTRACT) // cuts the torso off
+
+ base_icon.Blend(leg_icon, ICON_OVERLAY) // puts the new legs on
+
+ digitigrade_clothing_icon = fcopy_rsc(base_icon)
+ digitigrade_clothing_icons[index] = digitigrade_clothing_icon
+
+ return icon(digitigrade_clothing_icon)
+
+#undef LEG_SAMPLE_X_LOWER
+#undef LEG_SAMPLE_X_UPPER
+
+#undef LEG_SAMPLE_Y_LOWER
+#undef LEG_SAMPLE_Y_UPPER
/mob/living/carbon/human/proc/get_overlays_copy(list/unwantedLayers)
var/list/out = new
@@ -689,11 +747,30 @@ generate/load female uniform sprites matching all previously decided variables
//Find a valid layer from variables+arguments
var/layer2use = alternate_worn_layer || default_layer
- var/mutable_appearance/standing
+ var/mob/living/carbon/wearer = loc
+ var/is_digi = istype(wearer) && (wearer.bodyshape & BODYSHAPE_DIGITIGRADE) && !wearer.is_digitigrade_squished()
+
+ var/mutable_appearance/standing // this is the actual resulting MA
+ var/icon/building_icon // used to construct an icon across multiple procs before converting it to MA
if(female_uniform)
- standing = wear_female_version(t_state, file2use, layer2use, female_uniform, greyscale_colors) //should layer2use be in sync with the adjusted value below? needs testing - shiz
- if(!standing)
- standing = mutable_appearance(file2use, t_state, -layer2use)
+ building_icon = wear_female_version(
+ icon_state = t_state,
+ icon = file2use,
+ type = female_uniform,
+ greyscale_colors = greyscale_colors,
+ )
+ if(!isinhands && is_digi && (supports_variations_flags & CLOTHING_DIGITIGRADE_MASK))
+ building_icon = wear_digi_version(
+ base_icon = building_icon || icon(file2use, t_state),
+ key = "[t_state]-[file2use]-[female_uniform]",
+ greyscale_config = digitigrade_greyscale_config_worn || greyscale_config_worn,
+ greyscale_colors = digitigrade_greyscale_colors || greyscale_colors || color,
+ )
+ if(building_icon)
+ standing = mutable_appearance(building_icon, layer = -layer2use)
+
+ // no special handling done, default it
+ standing ||= mutable_appearance(file2use, t_state, layer = -layer2use)
//Get the overlays for this item when it's being worn
//eg: ammo counters, primed grenade flashes, etc.
diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm
index a24e9cd070d86..d2ad1ad89ae2d 100644
--- a/code/modules/mob/living/carbon/human/inventory.dm
+++ b/code/modules/mob/living/carbon/human/inventory.dm
@@ -52,6 +52,9 @@
if(looking_for == belt)
return ITEM_SLOT_BELT
+ if(belt && (looking_for in belt))
+ return ITEM_SLOT_BELTPACK
+
if(looking_for == wear_id)
return ITEM_SLOT_ID
@@ -197,6 +200,9 @@
return
s_store = equipping
update_suit_storage()
+ if(ITEM_SLOT_BELTPACK)
+ if(!belt || !belt.atom_storage?.attempt_insert(equipping, src, override = TRUE, force = indirect_action ? STORAGE_SOFT_LOCKED : STORAGE_NOT_LOCKED))
+ not_handled = TRUE
else
to_chat(src, span_danger("You are trying to equip this item to an unsupported inventory slot. Report this to a coder!"))
@@ -368,7 +374,7 @@
/// take the most recent item out of a slot or place held item in a slot
/mob/living/carbon/human/proc/smart_equip_targeted(slot_type = ITEM_SLOT_BELT, slot_item_name = "belt")
- if(incapacitated())
+ if(incapacitated)
return
var/obj/item/thing = get_active_held_item()
var/obj/item/equipped_item = get_item_by_slot(slot_type)
diff --git a/code/modules/mob/living/carbon/human/species_types/dullahan.dm b/code/modules/mob/living/carbon/human/species_types/dullahan.dm
index 1d7c328f88232..d4dea2abfcc6a 100644
--- a/code/modules/mob/living/carbon/human/species_types/dullahan.dm
+++ b/code/modules/mob/living/carbon/human/species_types/dullahan.dm
@@ -19,7 +19,6 @@
BODY_ZONE_CHEST = /obj/item/bodypart/chest,
)
inherent_biotypes = MOB_UNDEAD|MOB_HUMANOID
- mutant_bodyparts = list("wings" = "None")
mutantbrain = /obj/item/organ/internal/brain/dullahan
mutanteyes = /obj/item/organ/internal/eyes/dullahan
mutanttongue = /obj/item/organ/internal/tongue/dullahan
diff --git a/code/modules/mob/living/carbon/human/species_types/ethereal.dm b/code/modules/mob/living/carbon/human/species_types/ethereal.dm
index 4c307107f153d..669b4f6b18dbc 100644
--- a/code/modules/mob/living/carbon/human/species_types/ethereal.dm
+++ b/code/modules/mob/living/carbon/human/species_types/ethereal.dm
@@ -11,10 +11,8 @@
siemens_coeff = 0.5 //They thrive on energy
payday_modifier = 1.0
inherent_traits = list(
- TRAIT_NO_UNDERWEAR,
TRAIT_MUTANT_COLORS,
TRAIT_FIXED_MUTANT_COLORS,
- TRAIT_FIXED_HAIRCOLOR,
TRAIT_AGENDER,
)
changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC | RACE_SWAP | ERT_SPAWN | SLIME_EXTRACT
@@ -247,12 +245,9 @@
mutantbrain = /obj/item/organ/internal/brain/lustrous
changesource_flags = MIRROR_BADMIN | MIRROR_MAGIC | RACE_SWAP | ERT_SPAWN
inherent_traits = list(
- TRAIT_NO_UNDERWEAR,
TRAIT_MUTANT_COLORS,
TRAIT_FIXED_MUTANT_COLORS,
- TRAIT_FIXED_HAIRCOLOR,
TRAIT_AGENDER,
- TRAIT_TENACIOUS, // this doesn't work. tenacity is an element
TRAIT_NOBREATH,
TRAIT_RESISTHIGHPRESSURE,
TRAIT_RESISTLOWPRESSURE,
diff --git a/code/modules/mob/living/carbon/human/species_types/felinid.dm b/code/modules/mob/living/carbon/human/species_types/felinid.dm
index b26bd476b4bc4..8a040425a9747 100644
--- a/code/modules/mob/living/carbon/human/species_types/felinid.dm
+++ b/code/modules/mob/living/carbon/human/species_types/felinid.dm
@@ -3,11 +3,10 @@
name = "Felinid"
id = SPECIES_FELINE
examine_limb_id = SPECIES_HUMAN
- mutant_bodyparts = list("ears" = "Cat", "wings" = "None")
mutantbrain = /obj/item/organ/internal/brain/felinid
mutanttongue = /obj/item/organ/internal/tongue/cat
mutantears = /obj/item/organ/internal/ears/cat
- external_organs = list(
+ mutant_organs = list(
/obj/item/organ/external/tail/cat = "Cat",
)
inherent_traits = list(
@@ -151,7 +150,7 @@
// stored_feature_id is only set once (the first time an organ is inserted), so this should be safe.
var/obj/item/organ/internal/ears/cat/kitty_ears = new
kitty_ears.Insert(soon_to_be_felinid, special = TRUE, movement_flags = DELETE_IF_REPLACED)
- if(should_external_organ_apply_to(/obj/item/organ/external/tail/cat, soon_to_be_felinid)) //only give them a tail if they actually have sprites for it / are a compatible subspecies.
+ if(should_visual_organ_apply_to(/obj/item/organ/external/tail/cat, soon_to_be_felinid)) //only give them a tail if they actually have sprites for it / are a compatible subspecies.
var/obj/item/organ/external/tail/cat/kitty_tail = new
kitty_tail.Insert(soon_to_be_felinid, special = TRUE, movement_flags = DELETE_IF_REPLACED)
@@ -174,8 +173,8 @@
old_tail.Remove(purrbated_human, special = TRUE)
qdel(old_tail)
// Locate does not work on assoc lists, so we do it by hand
- for(var/external_organ in target_species.external_organs)
- if(!should_external_organ_apply_to(external_organ, purrbated_human))
+ for(var/external_organ in target_species.mutant_organs)
+ if(!should_visual_organ_apply_to(external_organ, purrbated_human))
continue
if(ispath(external_organ, /obj/item/organ/external/tail))
var/obj/item/organ/external/tail/new_tail = new external_organ()
diff --git a/code/modules/mob/living/carbon/human/species_types/flypeople.dm b/code/modules/mob/living/carbon/human/species_types/flypeople.dm
index 44e8981c55315..0f2072b777353 100644
--- a/code/modules/mob/living/carbon/human/species_types/flypeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/flypeople.dm
@@ -2,10 +2,6 @@
name = "Flyperson"
plural_form = "Flypeople"
id = SPECIES_FLYPERSON
- inherent_traits = list(
- TRAIT_TACKLING_FRAIL_ATTACKER,
- TRAIT_ANTENNAE,
- )
inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_BUG
meat = /obj/item/food/meat/slab/human/mutant/fly
mutanteyes = /obj/item/organ/internal/eyes/fly
diff --git a/code/modules/mob/living/carbon/human/species_types/humans.dm b/code/modules/mob/living/carbon/human/species_types/humans.dm
index ef8140c7d82ef..be6357f6b4f21 100644
--- a/code/modules/mob/living/carbon/human/species_types/humans.dm
+++ b/code/modules/mob/living/carbon/human/species_types/humans.dm
@@ -4,7 +4,6 @@
inherent_traits = list(
TRAIT_USES_SKINTONES,
)
- mutant_bodyparts = list("wings" = "None")
skinned_type = /obj/item/stack/sheet/animalhide/human
changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | ERT_SPAWN | RACE_SWAP | SLIME_EXTRACT
payday_modifier = 1.1
diff --git a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
index 276d4a0fa7a5f..811ae45ea8cb3 100644
--- a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
@@ -412,7 +412,7 @@
return data
-/datum/action/innate/swap_body/ui_act(action, params)
+/datum/action/innate/swap_body/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
index 6b71a234d9b61..65945467f5eb1 100644
--- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
@@ -5,12 +5,10 @@
id = SPECIES_LIZARD
inherent_traits = list(
TRAIT_MUTANT_COLORS,
- TRAIT_TACKLING_TAILED_DEFENDER,
)
inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_REPTILE
- mutant_bodyparts = list("legs" = "Normal Legs")
body_markings = list(/datum/bodypart_overlay/simple/body_marking/lizard = "None")
- external_organs = list(
+ mutant_organs = list(
/obj/item/organ/external/horns = "None",
/obj/item/organ/external/frills = "None",
/obj/item/organ/external/snout = "Round",
diff --git a/code/modules/mob/living/carbon/human/species_types/monkeys.dm b/code/modules/mob/living/carbon/human/species_types/monkeys.dm
index 449f2d775a301..1ca2979d3d6fc 100644
--- a/code/modules/mob/living/carbon/human/species_types/monkeys.dm
+++ b/code/modules/mob/living/carbon/human/species_types/monkeys.dm
@@ -3,7 +3,7 @@
/datum/species/monkey
name = "\improper Monkey"
id = SPECIES_MONKEY
- external_organs = list(
+ mutant_organs = list(
/obj/item/organ/external/tail/monkey = "Monkey",
)
mutanttongue = /obj/item/organ/internal/tongue/monkey
@@ -12,7 +12,6 @@
meat = /obj/item/food/meat/slab/monkey
knife_butcher_results = list(/obj/item/food/meat/slab/monkey = 5, /obj/item/stack/sheet/animalhide/monkey = 1)
inherent_traits = list(
- TRAIT_GUN_NATURAL,
TRAIT_NO_AUGMENTS,
TRAIT_NO_BLOOD_OVERLAY,
TRAIT_NO_DNA_COPY,
@@ -128,7 +127,7 @@
/obj/item/organ/internal/brain/primate //Ook Ook
name = "Primate Brain"
desc = "This wad of meat is small, but has enlaged occipital lobes for spotting bananas."
- organ_traits = list(TRAIT_CAN_STRIP, TRAIT_PRIMITIVE) // No literacy or advanced tool usage.
+ organ_traits = list(TRAIT_CAN_STRIP, TRAIT_PRIMITIVE, TRAIT_GUN_NATURAL) // No literacy or advanced tool usage.
actions_types = list(/datum/action/item_action/organ_action/toggle_trip)
/// Will this monkey stumble if they are crossed by a simple mob or a carbon in combat mode? Toggable by monkeys with clients, and is messed automatically set to true by monkey AI.
var/tripping = TRUE
diff --git a/code/modules/mob/living/carbon/human/species_types/mothmen.dm b/code/modules/mob/living/carbon/human/species_types/mothmen.dm
index 0caa0d996ba1b..f9a17b310fae9 100644
--- a/code/modules/mob/living/carbon/human/species_types/mothmen.dm
+++ b/code/modules/mob/living/carbon/human/species_types/mothmen.dm
@@ -2,13 +2,9 @@
name = "\improper Mothman"
plural_form = "Mothmen"
id = SPECIES_MOTH
- inherent_traits = list(
- TRAIT_TACKLING_WINGED_ATTACKER,
- TRAIT_ANTENNAE,
- )
inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_BUG
body_markings = list(/datum/bodypart_overlay/simple/body_marking/moth = "None")
- external_organs = list(/obj/item/organ/external/wings/moth = "Plain", /obj/item/organ/external/antennae = "Plain")
+ mutant_organs = list(/obj/item/organ/external/wings/moth = "Plain", /obj/item/organ/external/antennae = "Plain")
meat = /obj/item/food/meat/slab/human/mutant/moth
mutanttongue = /obj/item/organ/internal/tongue/moth
mutanteyes = /obj/item/organ/internal/eyes/moth
@@ -28,12 +24,6 @@
BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/moth,
)
-/datum/species/moth/regenerate_organs(mob/living/carbon/C, datum/species/old_species, replace_current= TRUE, list/excluded_zones, visual_only)
- . = ..()
- if(ishuman(C))
- var/mob/living/carbon/human/H = C
- handle_mutant_bodyparts(H)
-
/datum/species/moth/on_species_gain(mob/living/carbon/human/human_who_gained_species, datum/species/old_species, pref_load)
. = ..()
RegisterSignal(human_who_gained_species, COMSIG_MOB_APPLY_DAMAGE_MODIFIERS, PROC_REF(damage_weakness))
diff --git a/code/modules/mob/living/carbon/human/species_types/mushpeople.dm b/code/modules/mob/living/carbon/human/species_types/mushpeople.dm
index 14d6c1437f0da..1e2b73616d91c 100644
--- a/code/modules/mob/living/carbon/human/species_types/mushpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/mushpeople.dm
@@ -6,7 +6,7 @@
fixed_mut_color = "#DBBF92"
- external_organs = list(/obj/item/organ/external/mushroom_cap = "Round")
+ mutant_organs = list(/obj/item/organ/external/mushroom_cap = "Round")
inherent_traits = list(
TRAIT_MUTANT_COLORS,
diff --git a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm
index 0cb0d9d85f084..8b347a22cca96 100644
--- a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm
+++ b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm
@@ -27,7 +27,7 @@
heatmod = 1.5
payday_modifier = 1.0
breathid = GAS_PLASMA
- changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC
+ changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC | ERT_SPAWN
species_cookie = /obj/item/reagent_containers/condiment/milk
outfit_important_for_life = /datum/outfit/plasmaman
species_language_holder = /datum/language_holder/skeleton
diff --git a/code/modules/mob/living/carbon/human/species_types/podpeople.dm b/code/modules/mob/living/carbon/human/species_types/podpeople.dm
index bcc0b6c4b677c..e5e735b31e44f 100644
--- a/code/modules/mob/living/carbon/human/species_types/podpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/podpeople.dm
@@ -7,7 +7,7 @@
TRAIT_MUTANT_COLORS,
TRAIT_PLANT_SAFE,
)
- external_organs = list(
+ mutant_organs = list(
/obj/item/organ/external/pod_hair = "None",
)
inherent_biotypes = MOB_ORGANIC | MOB_HUMANOID | MOB_PLANT
diff --git a/code/modules/mob/living/carbon/human/species_types/vampire.dm b/code/modules/mob/living/carbon/human/species_types/vampire.dm
index 111b35cb7f7bf..d3dfb81352004 100644
--- a/code/modules/mob/living/carbon/human/species_types/vampire.dm
+++ b/code/modules/mob/living/carbon/human/species_types/vampire.dm
@@ -17,7 +17,6 @@
TRAIT_NO_MIRROR_REFLECTION,
)
inherent_biotypes = MOB_UNDEAD|MOB_HUMANOID
- mutant_bodyparts = list("wings" = "None")
changesource_flags = MIRROR_BADMIN | WABBAJACK | ERT_SPAWN
exotic_bloodtype = "U"
blood_deficiency_drain_rate = BLOOD_DEFICIENCY_MODIFIER // vampires already passively lose blood, so this just makes them lose it slightly more quickly when they have blood deficiency.
diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm
index 62030cf1eba59..a626cb47cc6d8 100644
--- a/code/modules/mob/living/emote.dm
+++ b/code/modules/mob/living/emote.dm
@@ -4,6 +4,16 @@
mob_type_allowed_typecache = /mob/living
mob_type_blacklist_typecache = list(/mob/living/brain)
+/datum/emote/living/taunt
+ key = "taunt"
+ key_third_person = "taunts"
+ message = "taunts!"
+ cooldown = 1.6 SECONDS //note when changing this- this is used by the matrix taunt to block projectiles.
+
+/datum/emote/living/taunt/run_emote(mob/living/user, params, type_override, intentional)
+ . = ..()
+ user.spin(TAUNT_EMOTE_DURATION, 0.1 SECONDS)
+
/datum/emote/living/blush
key = "blush"
key_third_person = "blushes"
@@ -225,20 +235,6 @@
key_third_person = "grimaces"
message = "grimaces."
-/datum/emote/living/jump
- key = "jump"
- key_third_person = "jumps"
- message = "jumps!"
- hands_use_check = TRUE
-
-/datum/emote/living/jump/run_emote(mob/living/user, params, type_override, intentional)
- . = ..()
- animate(user, pixel_y = user.pixel_y + 4, time = 0.1 SECONDS)
- animate(pixel_y = user.pixel_y - 4, time = 0.1 SECONDS)
-
-/datum/emote/living/jump/get_sound(mob/living/user)
- return 'sound/weapons/thudswoosh.ogg'
-
/datum/emote/living/kiss
key = "kiss"
key_third_person = "kisses"
@@ -248,6 +244,9 @@
. = ..()
var/kiss_type = /obj/item/hand_item/kisser
+ if(HAS_TRAIT(user, TRAIT_SYNDIE_KISS))
+ kiss_type = /obj/item/hand_item/kisser/syndie
+
if(HAS_TRAIT(user, TRAIT_KISS_OF_DEATH))
kiss_type = /obj/item/hand_item/kisser/death
diff --git a/code/modules/mob/living/init_signals.dm b/code/modules/mob/living/init_signals.dm
index 4bf0407c4670a..0797f77c08210 100644
--- a/code/modules/mob/living/init_signals.dm
+++ b/code/modules/mob/living/init_signals.dm
@@ -40,6 +40,8 @@
RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_DEAF), PROC_REF(on_hearing_loss))
RegisterSignal(src, SIGNAL_REMOVETRAIT(TRAIT_DEAF), PROC_REF(on_hearing_regain))
+ RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_STASIS), PROC_REF(on_stasis_trait_gain))
+ RegisterSignal(src, SIGNAL_REMOVETRAIT(TRAIT_STASIS), PROC_REF(on_stasis_trait_loss))
RegisterSignals(src, list(
SIGNAL_ADDTRAIT(TRAIT_CRITICAL_CONDITION),
@@ -187,24 +189,36 @@
SIGNAL_HANDLER
add_traits(list(TRAIT_UI_BLOCKED, TRAIT_PULL_BLOCKED), TRAIT_INCAPACITATED)
update_appearance()
+ update_incapacitated()
/// Called when [TRAIT_INCAPACITATED] is removed from the mob.
/mob/living/proc/on_incapacitated_trait_loss(datum/source)
SIGNAL_HANDLER
remove_traits(list(TRAIT_UI_BLOCKED, TRAIT_PULL_BLOCKED), TRAIT_INCAPACITATED)
update_appearance()
-
+ update_incapacitated()
/// Called when [TRAIT_RESTRAINED] is added to the mob.
/mob/living/proc/on_restrained_trait_gain(datum/source)
SIGNAL_HANDLER
ADD_TRAIT(src, TRAIT_HANDS_BLOCKED, TRAIT_RESTRAINED)
+ update_incapacitated()
/// Called when [TRAIT_RESTRAINED] is removed from the mob.
/mob/living/proc/on_restrained_trait_loss(datum/source)
SIGNAL_HANDLER
REMOVE_TRAIT(src, TRAIT_HANDS_BLOCKED, TRAIT_RESTRAINED)
+ update_incapacitated()
+
+/// Called when [TRAIT_STASIS] is added to the mob
+/mob/living/proc/on_stasis_trait_gain(datum/source)
+ SIGNAL_HANDLER
+ update_incapacitated()
+/// Called when [TRAIT_STASIS] is removed from the mob
+/mob/living/proc/on_stasis_trait_loss(datum/source)
+ SIGNAL_HANDLER
+ update_incapacitated()
/**
* Called when traits that alter succumbing are added/removed.
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 70f268c2a454a..005eff4d542c8 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -70,7 +70,7 @@
damage_softening_multiplier *= potential_spine.athletics_boost_multiplier
// If you are incapped, you probably can't brace yourself
- var/can_help_themselves = !incapacitated(IGNORE_RESTRAINTS)
+ var/can_help_themselves = !INCAPACITATED_IGNORING(src, INCAPABLE_RESTRAINTS)
if(levels <= 1 && can_help_themselves)
var/obj/item/organ/external/wings/gliders = get_organ_by_type(/obj/item/organ/external/wings)
if(HAS_TRAIT(src, TRAIT_FREERUNNING) || gliders?.can_soften_fall()) // the power of parkour or wings allows falling short distances unscathed
@@ -516,7 +516,7 @@
//same as above
/mob/living/pointed(atom/A as mob|obj|turf in view(client.view, src))
- if(incapacitated())
+ if(incapacitated)
return FALSE
return ..()
@@ -545,31 +545,21 @@
investigate_log("has succumbed to death.", INVESTIGATE_DEATHS)
death()
-/**
- * Checks if a mob is incapacitated
- *
- * Normally being restrained, agressively grabbed, or in stasis counts as incapacitated
- * unless there is a flag being used to check if it's ignored
- *
- * args:
- * * flags (optional) bitflags that determine if special situations are exempt from being considered incapacitated
- *
- * bitflags: (see code/__DEFINES/status_effects.dm)
- * * IGNORE_RESTRAINTS - mob in a restraint (handcuffs) is not considered incapacitated
- * * IGNORE_STASIS - mob in stasis (stasis bed, etc.) is not considered incapacitated
- * * IGNORE_GRAB - mob that is agressively grabbed is not considered incapacitated
-**/
-/mob/living/incapacitated(flags)
+// Remember, anything that influences this needs to call update_incapacitated somehow when it changes
+// Most often best done in [code/modules/mob/living/init_signals.dm]
+/mob/living/build_incapacitated(flags)
+ // Holds a set of flags that describe how we are currently incapacitated
+ var/incap_status = NONE
if(HAS_TRAIT(src, TRAIT_INCAPACITATED))
- return TRUE
+ incap_status |= TRADITIONAL_INCAPACITATED
+ if(HAS_TRAIT(src, TRAIT_RESTRAINED))
+ incap_status |= INCAPABLE_RESTRAINTS
+ if(pulledby && pulledby.grab_state >= GRAB_AGGRESSIVE)
+ incap_status |= INCAPABLE_GRAB
+ if(HAS_TRAIT(src, TRAIT_STASIS))
+ incap_status |= INCAPABLE_STASIS
- if(!(flags & IGNORE_RESTRAINTS) && HAS_TRAIT(src, TRAIT_RESTRAINED))
- return TRUE
- if(!(flags & IGNORE_GRAB) && pulledby && pulledby.grab_state >= GRAB_AGGRESSIVE)
- return TRUE
- if(!(flags & IGNORE_STASIS) && HAS_TRAIT(src, TRAIT_STASIS))
- return TRUE
- return FALSE
+ return incap_status
/mob/living/canUseStorage()
if (usable_hands <= 0)
@@ -1124,7 +1114,7 @@
/mob/living/proc/itch(obj/item/bodypart/target_part = null, damage = 0.5, can_scratch = TRUE, silent = FALSE)
if ((mob_biotypes & (MOB_ROBOTIC | MOB_SPIRIT)))
return FALSE
- var/will_scratch = can_scratch && !incapacitated()
+ var/will_scratch = can_scratch && !incapacitated
var/applied_damage = 0
if (will_scratch && damage)
applied_damage = apply_damage(damage, damagetype = BRUTE, def_zone = target_part)
@@ -1210,7 +1200,7 @@
/mob/living/resist_grab(moving_resist)
. = TRUE
//If we're in an aggressive grab or higher, we're lying down, we're vulnerable to grabs, or we're staggered and we have some amount of stamina loss, we must resist
- if(pulledby.grab_state || body_position == LYING_DOWN || HAS_TRAIT(src, TRAIT_GRABWEAKNESS) || get_timed_status_effect_duration(/datum/status_effect/staggered) && getStaminaLoss() >= 30)
+ if(pulledby.grab_state || body_position == LYING_DOWN || HAS_TRAIT(src, TRAIT_GRABWEAKNESS) || get_timed_status_effect_duration(/datum/status_effect/staggered) && (getFireLoss()*0.5 + getBruteLoss()*0.5) >= 40)
var/altered_grab_state = pulledby.grab_state
if((body_position == LYING_DOWN || HAS_TRAIT(src, TRAIT_GRABWEAKNESS) || get_timed_status_effect_duration(/datum/status_effect/staggered)) && pulledby.grab_state < GRAB_KILL) //If prone, resisting out of a grab is equivalent to 1 grab state higher. won't make the grab state exceed the normal max, however
altered_grab_state++
@@ -1354,11 +1344,11 @@
if(!(interaction_flags_atom & INTERACT_ATOM_IGNORE_INCAPACITATED))
var/ignore_flags = NONE
if(interaction_flags_atom & INTERACT_ATOM_IGNORE_RESTRAINED)
- ignore_flags |= IGNORE_RESTRAINTS
+ ignore_flags |= INCAPABLE_RESTRAINTS
if(!(interaction_flags_atom & INTERACT_ATOM_CHECK_GRAB))
- ignore_flags |= IGNORE_GRAB
+ ignore_flags |= INCAPABLE_GRAB
- if(incapacitated(ignore_flags))
+ if(INCAPACITATED_IGNORING(src, ignore_flags))
to_chat(src, span_warning("You are incapacitated at the moment!"))
return FALSE
@@ -1842,7 +1832,7 @@ GLOBAL_LIST_EMPTY(fire_appearances)
var/old_level_new_clients = (registered_z ? SSmobs.clients_by_zlevel[registered_z].len : null)
//No one is left after we're gone, shut off inactive ones
if(registered_z && old_level_new_clients == 0)
- for(var/datum/ai_controller/controller as anything in SSai_controllers.ai_controllers_by_zlevel[registered_z])
+ for(var/datum/ai_controller/controller as anything in GLOB.ai_controllers_by_zlevel[registered_z])
controller.set_ai_status(AI_STATUS_OFF)
if(new_z)
@@ -1853,7 +1843,7 @@ GLOBAL_LIST_EMPTY(fire_appearances)
SSmobs.clients_by_zlevel[new_z] += src
if(new_level_old_clients == 0) //No one was here before, wake up all the AIs.
- for (var/datum/ai_controller/controller as anything in SSai_controllers.ai_controllers_by_zlevel[new_z])
+ for (var/datum/ai_controller/controller as anything in GLOB.ai_controllers_by_zlevel[new_z])
//We don't set them directly on, for instances like AIs acting while dead and other cases that may exist in the future.
//This isn't a problem for AIs with a client since the client will prevent this from being called anyway.
controller.set_ai_status(controller.get_expected_ai_status())
@@ -2152,10 +2142,9 @@ GLOBAL_LIST_EMPTY(fire_appearances)
/mob/living/proc/can_look_up()
if(next_move > world.time)
return FALSE
- if(incapacitated(IGNORE_RESTRAINTS))
+ if(INCAPACITATED_IGNORING(src, INCAPABLE_RESTRAINTS))
return FALSE
return TRUE
-
/**
* look_up Changes the perspective of the mob to any openspace turf above the mob
*
@@ -2289,12 +2278,14 @@ GLOBAL_LIST_EMPTY(fire_appearances)
if(. >= UNCONSCIOUS)
REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, TRAIT_KNOCKEDOUT)
remove_traits(list(TRAIT_HANDS_BLOCKED, TRAIT_INCAPACITATED, TRAIT_FLOORED, TRAIT_CRITICAL_CONDITION), STAT_TRAIT)
+ log_combat(src, src, "regained consciousness")
if(SOFT_CRIT)
if(pulledby)
ADD_TRAIT(src, TRAIT_IMMOBILIZED, PULLED_WHILE_SOFTCRIT_TRAIT) //adding trait sources should come before removing to avoid unnecessary updates
if(. >= UNCONSCIOUS)
REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, TRAIT_KNOCKEDOUT)
ADD_TRAIT(src, TRAIT_CRITICAL_CONDITION, STAT_TRAIT)
+ log_combat(src, src, "entered soft crit")
if(UNCONSCIOUS)
if(. != HARD_CRIT)
become_blind(UNCONSCIOUS_TRAIT)
@@ -2302,14 +2293,17 @@ GLOBAL_LIST_EMPTY(fire_appearances)
ADD_TRAIT(src, TRAIT_CRITICAL_CONDITION, STAT_TRAIT)
else
REMOVE_TRAIT(src, TRAIT_CRITICAL_CONDITION, STAT_TRAIT)
+ log_combat(src, src, "lost consciousness")
if(HARD_CRIT)
if(. != UNCONSCIOUS)
become_blind(UNCONSCIOUS_TRAIT)
ADD_TRAIT(src, TRAIT_CRITICAL_CONDITION, STAT_TRAIT)
+ log_combat(src, src, "entered hard crit")
if(DEAD)
REMOVE_TRAIT(src, TRAIT_CRITICAL_CONDITION, STAT_TRAIT)
remove_from_alive_mob_list()
add_to_dead_mob_list()
+ log_combat(src, src, "died")
if(!can_hear())
stop_sound_channel(CHANNEL_AMBIENCE)
refresh_looping_ambience()
@@ -2346,6 +2340,7 @@ GLOBAL_LIST_EMPTY(fire_appearances)
/mob/living/set_pulledby(new_pulledby)
. = ..()
+ update_incapacitated()
if(. == FALSE) //null is a valid value here, we only want to return if FALSE is explicitly passed.
return
if(pulledby)
@@ -2819,3 +2814,25 @@ GLOBAL_LIST_EMPTY(fire_appearances)
return "[span_notice("You'd estimate [p_their()] fitness level at about...")] [span_boldwarning("What?!? [our_fitness_level]???")]"
return span_notice("You'd estimate [p_their()] fitness level at about [our_fitness_level]. [comparative_fitness <= 0.33 ? "Pathetic." : ""]")
+
+///Performs the aftereffects of blocking a projectile.
+/mob/living/proc/block_projectile_effects()
+ var/static/list/icon/blocking_overlay
+ if(isnull(blocking_overlay))
+ blocking_overlay = list(
+ mutable_appearance('icons/mob/effects/blocking.dmi', "wow"),
+ mutable_appearance('icons/mob/effects/blocking.dmi', "nice"),
+ mutable_appearance('icons/mob/effects/blocking.dmi', "good"),
+ )
+ ADD_TRAIT(src, TRAIT_BLOCKING_PROJECTILES, BLOCKING_TRAIT)
+ var/icon/selected_overlay = pick(blocking_overlay)
+ add_overlay(selected_overlay)
+ playsound(src, 'sound/weapons/fwoosh.ogg', 90, FALSE, frequency = 0.7)
+ update_transform(1.25)
+ addtimer(CALLBACK(src, PROC_REF(end_block_effects), selected_overlay), 0.6 SECONDS)
+
+///Remoevs the effects of blocking a projectile and allows the user to block another.
+/mob/living/proc/end_block_effects(selected_overlay)
+ REMOVE_TRAIT(src, TRAIT_BLOCKING_PROJECTILES, BLOCKING_TRAIT)
+ cut_overlay(selected_overlay)
+ update_transform(0.8)
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index a06a71262490a..2b61f5ac68d8b 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -268,6 +268,7 @@
return FALSE
grippedby(user)
+ update_incapacitated()
//proc to upgrade a simple pull into a more aggressive grab.
/mob/living/proc/grippedby(mob/living/user, instant = FALSE)
diff --git a/code/modules/mob/living/living_movement.dm b/code/modules/mob/living/living_movement.dm
index 62c290217fd3f..4522b6ca69a52 100644
--- a/code/modules/mob/living/living_movement.dm
+++ b/code/modules/mob/living/living_movement.dm
@@ -124,7 +124,7 @@
return ..()
/mob/living/can_z_move(direction, turf/start, turf/destination, z_move_flags = ZMOVE_FLIGHT_FLAGS, mob/living/rider)
- if(z_move_flags & ZMOVE_INCAPACITATED_CHECKS && incapacitated())
+ if(z_move_flags & ZMOVE_INCAPACITATED_CHECKS && incapacitated)
if(z_move_flags & ZMOVE_FEEDBACK)
to_chat(rider || src, span_warning("[rider ? src : "You"] can't do that right now!"))
return FALSE
diff --git a/code/modules/mob/living/living_say.dm b/code/modules/mob/living/living_say.dm
index 459410d0a026a..c5f41678732cf 100644
--- a/code/modules/mob/living/living_say.dm
+++ b/code/modules/mob/living/living_say.dm
@@ -28,6 +28,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
// Misc
RADIO_KEY_AI_PRIVATE = RADIO_CHANNEL_AI_PRIVATE, // AI Upload channel
+ RADIO_KEY_ENTERTAINMENT = RADIO_CHANNEL_ENTERTAINMENT, // Entertainment monitors
//kinda localization -- rastaf0
@@ -56,7 +57,8 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
"в" = MODE_KEY_DEADMIN,
// Misc
- "щ" = RADIO_CHANNEL_AI_PRIVATE
+ "щ" = RADIO_CHANNEL_AI_PRIVATE,
+ "з" = RADIO_CHANNEL_ENTERTAINMENT,
))
/**
diff --git a/code/modules/mob/living/navigation.dm b/code/modules/mob/living/navigation.dm
index 3096efb3a7c47..a18342c445616 100644
--- a/code/modules/mob/living/navigation.dm
+++ b/code/modules/mob/living/navigation.dm
@@ -12,7 +12,7 @@
set name = "Navigate"
set category = "IC"
- if(incapacitated())
+ if(incapacitated)
return
if(length(client.navigation_images))
addtimer(CALLBACK(src, PROC_REF(cut_navigation)), world.tick_lag)
@@ -46,7 +46,7 @@
if(isnull(navigate_target))
return
- if(incapacitated())
+ if(incapacitated)
return
COOLDOWN_START(src, navigate_cooldown, 15 SECONDS)
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index 7e0cd4e5ef3e7..92c853ba72c4c 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -181,7 +181,7 @@
RegisterSignal(ai_tracking_tool, COMSIG_TRACKABLE_TRACKING_TARGET, PROC_REF(on_track_target))
RegisterSignal(ai_tracking_tool, COMSIG_TRACKABLE_GLIDE_CHANGED, PROC_REF(tracked_glidesize_changed))
- add_traits(list(TRAIT_PULL_BLOCKED, TRAIT_HANDS_BLOCKED), ROUNDSTART_TRAIT)
+ add_traits(list(TRAIT_PULL_BLOCKED, TRAIT_AI_ACCESS, TRAIT_HANDS_BLOCKED), INNATE_TRAIT)
alert_control = new(src, list(ALARM_ATMOS, ALARM_FIRE, ALARM_POWER, ALARM_CAMERA, ALARM_BURGLAR, ALARM_MOTION), list(z), camera_view = TRUE)
RegisterSignal(alert_control.listener, COMSIG_ALARM_LISTENER_TRIGGERED, PROC_REF(alarm_triggered))
@@ -288,7 +288,7 @@
/mob/living/silicon/ai/verb/pick_icon()
set category = "AI Commands"
set name = "Set AI Core Display"
- if(incapacitated())
+ if(incapacitated)
return
icon = initial(icon)
icon_state = "ai"
@@ -306,7 +306,7 @@
view_core()
var/ai_core_icon = show_radial_menu(src, src , iconstates, radius = 42)
- if(!ai_core_icon || incapacitated())
+ if(!ai_core_icon || incapacitated)
return
display_icon_override = ai_core_icon
@@ -347,7 +347,7 @@
var/reason = tgui_input_text(src, "What is the nature of your emergency? ([CALL_SHUTTLE_REASON_LENGTH] characters required.)", "Confirm Shuttle Call")
- if(incapacitated())
+ if(incapacitated)
return
if(trim(reason))
@@ -409,7 +409,7 @@
return // stop
if(stat == DEAD)
return
- if(incapacitated())
+ if(incapacitated)
if(battery < 50)
to_chat(src, span_warning("Insufficient backup power!"))
return
@@ -481,14 +481,14 @@
if(usr != src)
return
- if(href_list["emergencyAPC"]) //This check comes before incapacitated() because the only time it would be useful is when we have no power.
+ if(href_list["emergencyAPC"]) //This check comes before incapacitated because the only time it would be useful is when we have no power.
if(!apc_override)
to_chat(src, span_notice("APC backdoor is no longer available."))
return
apc_override.ui_interact(src)
return
- if(incapacitated())
+ if(incapacitated)
return
if (href_list["switchcamera"])
@@ -638,7 +638,7 @@
ai_tracking_tool.reset_tracking()
var/cameralist[0]
- if(incapacitated())
+ if(incapacitated)
return
var/mob/living/silicon/ai/U = usr
@@ -680,7 +680,7 @@
set desc = "Change the default hologram available to AI to something else."
set category = "AI Commands"
- if(incapacitated())
+ if(incapacitated)
return
var/input
switch(tgui_input_list(usr, "Would you like to select a hologram based on a custom character, an animal, or switch to a unique avatar?", "Customize", list("Custom Character","Unique","Animal")))
@@ -830,7 +830,7 @@
set desc = "Allows you to change settings of your radio."
set category = "AI Commands"
- if(incapacitated())
+ if(incapacitated)
return
to_chat(src, "Accessing Subspace Transceiver control...")
@@ -846,7 +846,7 @@
set desc = "Modify the default radio setting for your automatic announcements."
set category = "AI Commands"
- if(incapacitated())
+ if(incapacitated)
return
set_autosay()
@@ -1046,7 +1046,7 @@
set category = "AI Commands"
set name = "Deploy to Shell"
- if(incapacitated())
+ if(incapacitated)
return
if(control_disabled)
to_chat(src, span_warning("Wireless networking module is offline."))
diff --git a/code/modules/mob/living/silicon/ai/ai_defense.dm b/code/modules/mob/living/silicon/ai/ai_defense.dm
index 0c5eb6ec164b2..55a00a6ffc0bc 100644
--- a/code/modules/mob/living/silicon/ai/ai_defense.dm
+++ b/code/modules/mob/living/silicon/ai/ai_defense.dm
@@ -63,7 +63,7 @@
. = ..()
if(user.combat_mode)
return
- if(stat != DEAD && !incapacitated() && (client || deployed_shell?.client))
+ if(stat != DEAD && !incapacitated && (client || deployed_shell?.client))
// alive and well AIs control their floor bolts
balloon_alert(user, "the AI's bolt motors resist.")
return ITEM_INTERACT_SUCCESS
diff --git a/code/modules/mob/living/silicon/ai/ai_portrait_picker.dm b/code/modules/mob/living/silicon/ai/ai_portrait_picker.dm
index 2d099ea8bb00a..5415b7b1931b7 100644
--- a/code/modules/mob/living/silicon/ai/ai_portrait_picker.dm
+++ b/code/modules/mob/living/silicon/ai/ai_portrait_picker.dm
@@ -47,7 +47,7 @@
data["search_mode"] = search_mode == PAINTINGS_FILTER_SEARCH_TITLE ? "Title" : "Author"
return data
-/datum/portrait_picker/ui_act(action, params)
+/datum/portrait_picker/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/mob/living/silicon/ai/ai_say.dm b/code/modules/mob/living/silicon/ai/ai_say.dm
index 48b3cdc437350..a71074f9a014c 100644
--- a/code/modules/mob/living/silicon/ai/ai_say.dm
+++ b/code/modules/mob/living/silicon/ai/ai_say.dm
@@ -18,12 +18,23 @@
return ..()
/mob/living/silicon/ai/radio(message, list/message_mods = list(), list/spans, language)
- if(incapacitated())
+ if(incapacitated)
return FALSE
if(!radio_enabled) //AI cannot speak if radio is disabled (via intellicard) or depowered.
to_chat(src, span_danger("Your radio transmitter is offline!"))
return FALSE
- ..()
+ . = ..()
+ if(.)
+ return .
+ if(message_mods[MODE_HEADSET])
+ if(radio)
+ radio.talk_into(src, message, , spans, language, message_mods)
+ return NOPASS
+ else if(message_mods[RADIO_EXTENSION] in GLOB.radiochannels)
+ if(radio)
+ radio.talk_into(src, message, message_mods[RADIO_EXTENSION], spans, language, message_mods)
+ return NOPASS
+ return FALSE
//For holopads only. Usable by AI.
/mob/living/silicon/ai/proc/holopad_talk(message, language)
@@ -56,7 +67,7 @@
set desc = "Display a list of vocal words to announce to the crew."
set category = "AI Commands"
- if(incapacitated())
+ if(incapacitated)
return
var/dat = {"
@@ -95,7 +106,7 @@
last_announcement = message
- if(incapacitated())
+ if(incapacitated)
return
if(control_disabled)
diff --git a/code/modules/mob/living/silicon/ai/freelook/eye.dm b/code/modules/mob/living/silicon/ai/freelook/eye.dm
index 98a2e629776b1..32382b663398b 100644
--- a/code/modules/mob/living/silicon/ai/freelook/eye.dm
+++ b/code/modules/mob/living/silicon/ai/freelook/eye.dm
@@ -235,7 +235,7 @@
set category = "AI Commands"
set name = "Toggle Camera Acceleration"
- if(incapacitated())
+ if(incapacitated)
return
acceleration = !acceleration
to_chat(usr, "Camera acceleration has been toggled [acceleration ? "on" : "off"].")
diff --git a/code/modules/mob/living/silicon/ai/robot_control.dm b/code/modules/mob/living/silicon/ai/robot_control.dm
index d963fc77be62f..a04d1c3af75c4 100644
--- a/code/modules/mob/living/silicon/ai/robot_control.dm
+++ b/code/modules/mob/living/silicon/ai/robot_control.dm
@@ -7,7 +7,7 @@
owner = new_owner
/datum/robot_control/proc/is_interactable(mob/user)
- if(user != owner || owner.incapacitated())
+ if(user != owner || owner.incapacitated)
return FALSE
if(owner.control_disabled)
to_chat(user, span_warning("Wireless control is disabled."))
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index 4871370d16c3d..cddb496158004 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -389,7 +389,7 @@
return ..()
/mob/living/silicon/robot/execute_mode()
- if(incapacitated())
+ if(incapacitated)
return
var/obj/item/W = get_active_held_item()
if(W)
@@ -874,7 +874,7 @@
lawupdate = TRUE
lawsync()
if(radio && AI.radio) //AI keeps all channels, including Syndie if it is a Traitor
- if(AI.radio.syndie)
+ if((AI.radio.special_channels & RADIO_SPECIAL_SYNDIE))
radio.make_syndie()
radio.subspace_transmission = TRUE
radio.channels = AI.radio.channels
@@ -936,7 +936,7 @@
M.visible_message(span_warning("[M] really can't seem to mount [src]..."))
return
- if(stat || incapacitated())
+ if(stat || incapacitated)
return
if(model && !model.allow_riding)
M.visible_message(span_boldwarning("Unfortunately, [M] just can't seem to hold onto [src]!"))
diff --git a/code/modules/mob/living/silicon/robot/robot_model.dm b/code/modules/mob/living/silicon/robot/robot_model.dm
index 015f23182dca3..7aabdafaa4825 100644
--- a/code/modules/mob/living/silicon/robot/robot_model.dm
+++ b/code/modules/mob/living/silicon/robot/robot_model.dm
@@ -327,7 +327,7 @@
/obj/item/robot_model/proc/check_menu(mob/living/silicon/robot/user, obj/item/robot_model/old_model)
if(!istype(user))
return FALSE
- if(user.incapacitated())
+ if(user.incapacitated)
return FALSE
if(user.model != old_model)
return FALSE
diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm
index e41cd2157080f..507008caf943c 100644
--- a/code/modules/mob/living/silicon/silicon.dm
+++ b/code/modules/mob/living/silicon/silicon.dm
@@ -1,6 +1,5 @@
/mob/living/silicon
gender = NEUTER
- has_unlimited_silicon_privilege = TRUE
verb_say = "states"
verb_ask = "queries"
verb_exclaim = "declares"
@@ -75,6 +74,9 @@
TRAIT_NOFIRE_SPREAD,
TRAIT_BRAWLING_KNOCKDOWN_BLOCKED,
TRAIT_FENCE_CLIMBER,
+ TRAIT_SILICON_ACCESS,
+ TRAIT_REAGENT_SCANNER,
+ TRAIT_UNOBSERVANT,
)
add_traits(traits_to_apply, ROUNDSTART_TRAIT)
@@ -400,7 +402,7 @@
silicon_hud.show_to(src)
/mob/living/silicon/proc/toggle_sensors()
- if(incapacitated())
+ if(incapacitated)
return
sensors_on = !sensors_on
if (!sensors_on)
diff --git a/code/modules/mob/living/silicon/silicon_say.dm b/code/modules/mob/living/silicon/silicon_say.dm
index 9310211aa0e6d..824bba98dc070 100644
--- a/code/modules/mob/living/silicon/silicon_say.dm
+++ b/code/modules/mob/living/silicon/silicon_say.dm
@@ -82,10 +82,10 @@
if(message_mods[MODE_HEADSET])
if(radio)
radio.talk_into(src, message, , spans, language, message_mods)
- return REDUCE_RANGE
+ return NOPASS
else if(message_mods[RADIO_EXTENSION] in GLOB.radiochannels)
if(radio)
radio.talk_into(src, message, message_mods[RADIO_EXTENSION], spans, language, message_mods)
- return ITALICS | REDUCE_RANGE
+ return NOPASS
return FALSE
diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm
index e2bb112e1565e..ee7cd1357989e 100644
--- a/code/modules/mob/living/simple_animal/bot/bot.dm
+++ b/code/modules/mob/living/simple_animal/bot/bot.dm
@@ -12,7 +12,6 @@
hud_possible = list(DIAG_STAT_HUD, DIAG_BOT_HUD, DIAG_HUD, DIAG_BATT_HUD, DIAG_PATH_HUD = HUD_LIST_LIST)
maxbodytemp = INFINITY
minbodytemp = 0
- has_unlimited_silicon_privilege = TRUE
sentience_type = SENTIENCE_ARTIFICIAL
status_flags = NONE //no default canpush
pass_flags = PASSFLAPS
@@ -163,6 +162,7 @@
/mob/living/simple_animal/bot/Initialize(mapload)
. = ..()
+ add_traits(list(TRAIT_SILICON_ACCESS, TRAIT_REAGENT_SCANNER, TRAIT_UNOBSERVANT), INNATE_TRAIT)
GLOB.bots_list += src
path_hud = new /datum/atom_hud/data/bot_path/private()
@@ -378,9 +378,9 @@
if(HAS_TRAIT(src, TRAIT_COMMISSIONED) && COOLDOWN_FINISHED(src, next_salute_check))
COOLDOWN_START(src, next_salute_check, BOT_COMMISSIONED_SALUTE_DELAY)
- for(var/mob/living/simple_animal/bot/B in view(5, src))
- if(!HAS_TRAIT(B, TRAIT_COMMISSIONED) && B.bot_mode_flags & BOT_MODE_ON)
- manual_emote("performs an elaborate salute for [src]!")
+ for(var/mob/living/simple_animal/bot/nearby_bot in view(5, src))
+ if(!HAS_TRAIT(nearby_bot, TRAIT_COMMISSIONED) && nearby_bot.bot_mode_flags & BOT_MODE_ON)
+ manual_emote("performs an elaborate salute for [nearby_bot]!")
break
switch(mode) //High-priority overrides are processed first. Bots can do nothing else while under direct command.
@@ -976,13 +976,13 @@ Pass a positive integer as an argument to override a bot's default speed.
return data
// Actions received from TGUI
-/mob/living/simple_animal/bot/ui_act(action, params)
+/mob/living/simple_animal/bot/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
- var/mob/user = usr
+ var/mob/user = ui.user
if(!allowed(user))
- to_chat(usr, span_warning("Access denied."))
+ to_chat(user, span_warning("Access denied."))
return
if(action == "lock")
@@ -1002,38 +1002,38 @@ Pass a positive integer as an argument to override a bot's default speed.
if("airplane")
bot_mode_flags ^= BOT_MODE_REMOTE_ENABLED
if("hack")
- if(!HAS_SILICON_ACCESS(usr))
+ if(!HAS_SILICON_ACCESS(user))
return
if(!(bot_cover_flags & BOT_COVER_EMAGGED))
bot_cover_flags |= (BOT_COVER_EMAGGED|BOT_COVER_HACKED|BOT_COVER_LOCKED)
- to_chat(usr, span_warning("You overload [src]'s [hackables]."))
- message_admins("Safety lock of [ADMIN_LOOKUPFLW(src)] was disabled by [ADMIN_LOOKUPFLW(usr)] in [ADMIN_VERBOSEJMP(src)]")
- usr.log_message("disabled safety lock of [src]", LOG_GAME)
+ to_chat(user, span_warning("You overload [src]'s [hackables]."))
+ message_admins("Safety lock of [ADMIN_LOOKUPFLW(src)] was disabled by [ADMIN_LOOKUPFLW(user)] in [ADMIN_VERBOSEJMP(src)]")
+ user.log_message("disabled safety lock of [src]", LOG_GAME)
bot_reset()
to_chat(src, span_userdanger("(#$*#$^^( OVERRIDE DETECTED"))
to_chat(src, span_boldnotice(get_emagged_message()))
return
if(!(bot_cover_flags & BOT_COVER_HACKED))
- to_chat(usr, span_boldannounce("You fail to repair [src]'s [hackables]."))
+ to_chat(user, span_boldannounce("You fail to repair [src]'s [hackables]."))
return
bot_cover_flags &= ~(BOT_COVER_EMAGGED|BOT_COVER_HACKED)
- to_chat(usr, span_notice("You reset the [src]'s [hackables]."))
- usr.log_message("re-enabled safety lock of [src]", LOG_GAME)
+ to_chat(user, span_notice("You reset the [src]'s [hackables]."))
+ user.log_message("re-enabled safety lock of [src]", LOG_GAME)
bot_reset()
to_chat(src, span_userdanger("Software restored to standard."))
to_chat(src, span_boldnotice(possessed_message))
if("eject_pai")
if(!paicard)
return
- to_chat(usr, span_notice("You eject [paicard] from [initial(src.name)]."))
- ejectpai(usr)
+ to_chat(user, span_notice("You eject [paicard] from [initial(src.name)]."))
+ ejectpai(user)
if("toggle_personality")
if (can_be_possessed)
- disable_possession(usr)
+ disable_possession(user)
else
- enable_possession(usr)
+ enable_possession(user)
if("rename")
- rename(usr)
+ rename(user)
/mob/living/simple_animal/bot/update_icon_state()
icon_state = "[isnull(base_icon_state) ? initial(icon_state) : base_icon_state][get_bot_flag(bot_mode_flags, BOT_MODE_ON)]"
diff --git a/code/modules/mob/living/simple_animal/bot/ed209bot.dm b/code/modules/mob/living/simple_animal/bot/ed209bot.dm
index 6c0cd6d16ab55..bbd45e12a2733 100644
--- a/code/modules/mob/living/simple_animal/bot/ed209bot.dm
+++ b/code/modules/mob/living/simple_animal/bot/ed209bot.dm
@@ -42,7 +42,7 @@
var/list/targets = list()
for(var/mob/living/carbon/nearby_carbon in view(7, src)) //Let's find us a target
var/threatlevel = 0
- if(nearby_carbon.incapacitated())
+ if(nearby_carbon.incapacitated)
continue
threatlevel = nearby_carbon.assess_threat(judgement_criteria)
if(threatlevel < THREAT_ASSESS_DANGEROUS)
diff --git a/code/modules/mob/living/simple_animal/bot/floorbot.dm b/code/modules/mob/living/simple_animal/bot/floorbot.dm
index 4bedf0d3d621b..c670f6561c86b 100644
--- a/code/modules/mob/living/simple_animal/bot/floorbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/floorbot.dm
@@ -142,7 +142,8 @@
// Actions received from TGUI
/mob/living/simple_animal/bot/floorbot/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
- if(. || (bot_cover_flags & BOT_COVER_LOCKED && !HAS_SILICON_ACCESS(usr)))
+ var/mob/user = ui.user
+ if(. || (bot_cover_flags & BOT_COVER_LOCKED && !HAS_SILICON_ACCESS(user)))
return
switch(action)
@@ -160,7 +161,7 @@
if(tilestack)
tilestack.forceMove(drop_location())
if("line_mode")
- var/setdir = tgui_input_list(usr, "Select construction direction", "Direction", list("north", "east", "south", "west", "disable"))
+ var/setdir = tgui_input_list(user, "Select construction direction", "Direction", list("north", "east", "south", "west", "disable"))
if(isnull(setdir) || QDELETED(ui) || ui.status != UI_INTERACTIVE)
return
switch(setdir)
diff --git a/code/modules/mob/living/simple_animal/bot/mulebot.dm b/code/modules/mob/living/simple_animal/bot/mulebot.dm
index f3194e88b1862..dbfe987cac57a 100644
--- a/code/modules/mob/living/simple_animal/bot/mulebot.dm
+++ b/code/modules/mob/living/simple_animal/bot/mulebot.dm
@@ -286,29 +286,30 @@
data["paiInserted"] = !!paicard
return data
-/mob/living/simple_animal/bot/mulebot/ui_act(action, params)
+/mob/living/simple_animal/bot/mulebot/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
- if(. || (bot_cover_flags & BOT_COVER_LOCKED && !HAS_SILICON_ACCESS(usr)))
+ var/mob/user = ui.user
+ if(. || (bot_cover_flags & BOT_COVER_LOCKED && !HAS_SILICON_ACCESS(user)))
return
switch(action)
if("lock")
- if(HAS_SILICON_ACCESS(usr))
+ if(HAS_SILICON_ACCESS(user))
bot_cover_flags ^= BOT_COVER_LOCKED
return TRUE
if("on")
if(bot_mode_flags & BOT_MODE_ON)
turn_off()
else if(bot_cover_flags & BOT_COVER_MAINTS_OPEN)
- to_chat(usr, span_warning("[name]'s maintenance panel is open!"))
+ to_chat(user, span_warning("[name]'s maintenance panel is open!"))
return
else if(cell)
if(!turn_on())
- to_chat(usr, span_warning("You can't switch on [src]!"))
+ to_chat(user, span_warning("You can't switch on [src]!"))
return
return TRUE
else
- bot_control(action, usr, params) // Kill this later. // Kill PDAs in general please
+ bot_control(action, user, params) // Kill this later. // Kill PDAs in general please
return TRUE
/mob/living/simple_animal/bot/mulebot/bot_control(command, mob/user, list/params = list(), pda = FALSE)
@@ -711,7 +712,7 @@
// player on mulebot attempted to move
/mob/living/simple_animal/bot/mulebot/relaymove(mob/living/user, direction)
- if(user.incapacitated())
+ if(user.incapacitated)
return
if(load == user)
unload(0)
@@ -805,7 +806,7 @@
/mob/living/simple_animal/bot/mulebot/paranormal/mouse_drop_receive(atom/movable/AM, mob/user, params)
var/mob/living/L = user
- if(user.incapacitated() || (istype(L) && L.body_position == LYING_DOWN))
+ if(user.incapacitated || (istype(L) && L.body_position == LYING_DOWN))
return
if(!istype(AM) || iscameramob(AM) || istype(AM, /obj/effect/dummy/phased_mob)) //allows ghosts!
diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm
index 7448f6d34bc79..ea09441687202 100644
--- a/code/modules/mob/living/simple_animal/bot/secbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/secbot.dm
@@ -202,9 +202,10 @@
return data
// Actions received from TGUI
-/mob/living/simple_animal/bot/secbot/ui_act(action, params)
+/mob/living/simple_animal/bot/secbot/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
- if(. || (bot_cover_flags & BOT_COVER_LOCKED && !HAS_SILICON_ACCESS(usr)))
+ var/mob/user = ui.user
+ if(. || (bot_cover_flags & BOT_COVER_LOCKED && !HAS_SILICON_ACCESS(user)))
return
switch(action)
diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm
index 507563e7c207c..0803d96a706b9 100644
--- a/code/modules/mob/living/simple_animal/hostile/hostile.dm
+++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm
@@ -320,7 +320,7 @@
/mob/living/simple_animal/hostile/proc/CheckAndAttack()
var/atom/target_from = GET_TARGETS_FROM(src)
- if(target && isturf(target_from.loc) && target.Adjacent(target_from) && !incapacitated())
+ if(target && isturf(target_from.loc) && target.Adjacent(target_from) && !incapacitated)
AttackingTarget(target)
/mob/living/simple_animal/hostile/proc/MoveToTarget(list/possible_targets)//Step 5, handle movement between us and our target
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/_megafauna.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/_megafauna.dm
index 31d2e62fba7dc..231977a323954 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/_megafauna.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/_megafauna.dm
@@ -64,7 +64,7 @@
if(gps_name && true_spawn)
AddComponent(/datum/component/gps, gps_name)
ADD_TRAIT(src, TRAIT_SPACEWALK, INNATE_TRAIT)
- add_traits(list(TRAIT_NO_TELEPORT, TRAIT_MARTIAL_ARTS_IMMUNE), MEGAFAUNA_TRAIT)
+ add_traits(list(TRAIT_NO_TELEPORT), MEGAFAUNA_TRAIT)
grant_actions_by_list(attack_action_types)
/mob/living/simple_animal/hostile/megafauna/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change = TRUE)
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm
index 193545d9985fa..935ed7a7215b0 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm
@@ -27,7 +27,7 @@ Difficulty: Medium
icon_living = "miner"
icon = 'icons/mob/simple/broadMobs.dmi'
health_doll_icon = "miner"
- mob_biotypes = MOB_ORGANIC|MOB_HUMANOID
+ mob_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_SPECIAL
light_color = COLOR_LIGHT_GRAYISH_RED
speak_emote = list("roars")
speed = 3
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
index d51a586224603..cde5ecdbc05a8 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
@@ -542,9 +542,9 @@
possessor.investigate_log("has died from [src].", INVESTIGATE_DEATHS)
possessor.death(FALSE)
if(holder_animal)
- possessor.forceMove(get_turf(holder_animal))
holder_animal.mind.transfer_to(possessor)
possessor.mind.grab_ghost(force = TRUE)
+ possessor.forceMove(get_turf(holder_animal))
holder_animal.investigate_log("has been gibbed by [src].", INVESTIGATE_DEATHS)
holder_animal.gib(DROP_ALL_REMAINS)
return ..()
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner.dm
index 2af3018bed306..448896e3700de 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner.dm
@@ -18,7 +18,7 @@ Difficulty: Extremely Hard
attack_verb_continuous = "pummels"
attack_verb_simple = "pummels"
attack_sound = 'sound/weapons/sonic_jackhammer.ogg'
- mob_biotypes = MOB_ORGANIC|MOB_HUMANOID
+ mob_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_SPECIAL
light_color = COLOR_LIGHT_GRAYISH_RED
movement_type = GROUND
weather_immunities = list(TRAIT_SNOWSTORM_IMMUNE)
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm
index 4156d9678bca0..6bf09bc5a490e 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm
@@ -432,7 +432,7 @@ Difficulty: Hard
/mob/living/simple_animal/hostile/megafauna/hierophant/celebrate_kill(mob/living/L)
visible_message(span_hierophant_warning("\"[pick(kill_phrases)]\""))
- visible_message(span_hierophant_warning("[src] obliterates [L]!"),span_userdanger("You absorb [L]'s life force, restoring your health!"))
+ visible_message(span_hierophant_warning("[src] absorbs [L]'s life force!"),span_userdanger("You absorb [L]'s life force, restoring your health!"))
/mob/living/simple_animal/hostile/megafauna/hierophant/CanAttack(atom/the_target)
. = ..()
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index 25d0e566b15dd..9d5041fe870a4 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -495,7 +495,7 @@
//ANIMAL RIDING
/mob/living/simple_animal/user_buckle_mob(mob/living/M, mob/user, check_loc = TRUE)
- if(user.incapacitated())
+ if(user.incapacitated)
return
for(var/atom/movable/A in get_turf(src))
if(A != src && A != M && A.density)
@@ -521,7 +521,7 @@
return
/mob/living/simple_animal/relaymove(mob/living/user, direction)
- if(user.incapacitated())
+ if(user.incapacitated)
return
return relaydrive(user, direction)
diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm
index d017a2acca1be..17e929ba42290 100644
--- a/code/modules/mob/login.dm
+++ b/code/modules/mob/login.dm
@@ -91,11 +91,9 @@
sync_mind()
//Reload alternate appearances
- for(var/v in GLOB.active_alternate_appearances)
- if(!v)
- continue
- var/datum/atom_hud/alternate_appearance/AA = v
- AA.onNewMob(src)
+ for(var/datum/atom_hud/alternate_appearance/alt_hud as anything in GLOB.active_alternate_appearances)
+ if(!alt_hud.apply_to_new_mob(src))
+ alt_hud.hide_from(src, absolute = TRUE)
update_client_colour()
update_mouse_pointer()
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index c90c81b6ce43d..f321a8396a379 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -83,13 +83,12 @@
add_to_dead_mob_list()
else
add_to_alive_mob_list()
+ update_incapacitated()
set_focus(src)
prepare_huds()
- for(var/v in GLOB.active_alternate_appearances)
- if(!v)
- continue
- var/datum/atom_hud/alternate_appearance/AA = v
- AA.onNewMob(src)
+ for(var/datum/atom_hud/alternate_appearance/alt_hud as anything in GLOB.active_alternate_appearances)
+ alt_hud.apply_to_new_mob(src)
+
set_nutrition(rand(NUTRITION_LEVEL_START_MIN, NUTRITION_LEVEL_START_MAX))
. = ..()
setup_hud_traits()
@@ -414,9 +413,21 @@
return null
-///Is the mob incapacitated
-/mob/proc/incapacitated(flags)
- return
+/// Called whenever anything that modifes incapacitated is ran, updates it and sends a signal if it changes
+/// Returns TRUE if anything changed, FALSE otherwise
+/mob/proc/update_incapacitated()
+ SIGNAL_HANDLER
+ var/old_incap = incapacitated
+ incapacitated = build_incapacitated()
+ if(old_incap == incapacitated)
+ return FALSE
+
+ SEND_SIGNAL(src, COMSIG_MOB_INCAPACITATE_CHANGED, old_incap, incapacitated)
+ return TRUE
+
+/// Returns an updated incapacitated bitflag. If a flag is set it means we're incapacitated in that case
+/mob/proc/build_incapacitated()
+ return NONE
/**
* This proc is called whenever someone clicks an inventory ui slot.
@@ -543,7 +554,7 @@
/mob/living/blind_examine_check(atom/examined_thing)
//need to be next to something and awake
- if(!Adjacent(examined_thing) || incapacitated())
+ if(!Adjacent(examined_thing) || incapacitated)
to_chat(src, span_warning("Something is there, but you can't see it!"))
return FALSE
@@ -702,7 +713,7 @@
if(ismecha(loc))
return
- if(incapacitated())
+ if(incapacitated)
return
var/obj/item/I = get_active_held_item()
diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm
index 2206efd0e13ce..24e95cad60800 100644
--- a/code/modules/mob/mob_defines.dm
+++ b/code/modules/mob/mob_defines.dm
@@ -66,6 +66,20 @@
/// Whether a mob is alive or dead. TODO: Move this to living - Nodrak (2019, still here)
var/stat = CONSCIOUS
+ /**
+ * Whether and how a mob is incapacitated
+ *
+ * Normally being restrained, agressively grabbed, or in stasis counts as incapacitated
+ * unless there is a flag being used to check if it's ignored
+ *
+ * * bitflags: (see code/__DEFINES/status_effects.dm)
+ * * INCAPABLE_RESTRAINTS - if our mob is in a restraint (handcuffs)
+ * * INCAPABLE_STASIS - if our mob is in stasis (stasis bed, etc.)
+ * * INCAPABLE_GRAB - if our mob is being agressively grabbed
+ *
+ **/
+ VAR_FINAL/incapacitated = NONE
+
/* A bunch of this stuff really needs to go under their own defines instead of being globally attached to mob.
A variable should only be globally attached to turfs/objects/whatever, when it is in fact needed as such.
The current method unnecessarily clusters up the variable list, especially for humans (although rearranging won't really clean it up a lot but the difference will be noticable for other mobs).
@@ -137,9 +151,6 @@
/// bitflags defining which status effects can be inflicted (replaces canknockdown, canstun, etc)
var/status_flags = CANSTUN|CANKNOCKDOWN|CANUNCONSCIOUS|CANPUSH
- /// Can they interact with station electronics
- var/has_unlimited_silicon_privilege = FALSE
-
///Calls relay_move() to whatever this is set to when the mob tries to move
var/atom/movable/remote_control
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index a6a1c58c7eddf..a3fceb0493e8c 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -345,12 +345,14 @@
return
return TRUE
-///Is the passed in mob an admin ghost WITH AI INTERACT enabled
+///Returns TRUE/FALSE on whether the mob is an Admin Ghost AI.
+///This requires this snowflake check because AI interact gives the access to the mob's client, rather
+///than the mob like everyone else, and we keep it that way so they can't accidentally give someone Admin AI access.
/proc/isAdminGhostAI(mob/user)
if(!isAdminObserver(user))
- return
- if(!user.client.AI_Interact) // Do they have it enabled?
- return
+ return FALSE
+ if(!HAS_TRAIT_FROM(user.client, TRAIT_AI_ACCESS, ADMIN_TRAIT)) // Do they have it enabled?
+ return FALSE
return TRUE
/**
@@ -428,7 +430,7 @@
///Can the mob see reagents inside of containers?
/mob/proc/can_see_reagents()
- return stat == DEAD || has_unlimited_silicon_privilege || HAS_TRAIT(src, TRAIT_REAGENT_SCANNER) //Dead guys and silicons can always see reagents
+ return stat == DEAD || HAS_TRAIT(src, TRAIT_REAGENT_SCANNER) //Dead guys and silicons can always see reagents
///Can this mob hold items
/mob/proc/can_hold_items(obj/item/I)
diff --git a/code/modules/mob_spawn/corpses/mob_corpses.dm b/code/modules/mob_spawn/corpses/mob_corpses.dm
index f83dc13f1eded..c6d0cbd55cf4c 100644
--- a/code/modules/mob_spawn/corpses/mob_corpses.dm
+++ b/code/modules/mob_spawn/corpses/mob_corpses.dm
@@ -162,6 +162,16 @@
head = /obj/item/clothing/head/helmet/space/pirate
back = /obj/item/tank/jetpack/carbondioxide
+/obj/effect/mob_spawn/corpse/human/old_pirate_captain
+ name = "Pirate Captain Skeleton"
+ outfit = /datum/outfit/piratecorpse/captain
+ mob_species = /datum/species/skeleton
+
+/datum/outfit/piratecorpse/captain
+ glasses = /obj/item/clothing/glasses/eyepatch
+ head = /obj/item/clothing/head/costume/pirate
+ suit = /obj/item/clothing/suit/costume/pirate
+
/obj/effect/mob_spawn/corpse/human/russian
name = "Russian"
outfit = /datum/outfit/russiancorpse
diff --git a/code/modules/mob_spawn/ghost_roles/space_roles.dm b/code/modules/mob_spawn/ghost_roles/space_roles.dm
index 79d028bdbcb27..411f6bfd970ff 100644
--- a/code/modules/mob_spawn/ghost_roles/space_roles.dm
+++ b/code/modules/mob_spawn/ghost_roles/space_roles.dm
@@ -160,6 +160,8 @@
l_pocket = /obj/item/uplink/nuclear
r_pocket = /obj/item/modular_computer/pda/nukeops
+ skillchips = list(/obj/item/skillchip/disk_verifier)
+
/obj/effect/mob_spawn/ghost_role/human/syndicate/battlecruiser/captain
name = "Syndicate Battlecruiser Captain"
you_are_text = "You are the captain aboard the syndicate flagship: the SBC Starfury."
diff --git a/code/modules/mob_spawn/mob_spawn.dm b/code/modules/mob_spawn/mob_spawn.dm
index 3337a15b441c5..36562cec6e823 100644
--- a/code/modules/mob_spawn/mob_spawn.dm
+++ b/code/modules/mob_spawn/mob_spawn.dm
@@ -38,6 +38,12 @@
if(faction)
faction = string_list(faction)
+/obj/effect/mob_spawn/Destroy()
+ spawned_mob_ref = null
+ if(istype(outfit))
+ QDEL_NULL(outfit)
+ return ..()
+
/// Creates whatever mob the spawner makes. Return FALSE if we want to exit from here without doing that, returning NULL will be logged to admins.
/obj/effect/mob_spawn/proc/create(mob/mob_possessor, newname)
var/mob/living/spawned_mob = new mob_type(get_turf(src)) //living mobs only
@@ -137,7 +143,7 @@
SSpoints_of_interest.make_point_of_interest(src)
LAZYADD(GLOB.mob_spawners[name], src)
-/obj/effect/mob_spawn/Destroy()
+/obj/effect/mob_spawn/ghost_role/Destroy()
var/list/spawners = GLOB.mob_spawners[name]
LAZYREMOVE(spawners, src)
if(!LAZYLEN(spawners))
@@ -261,6 +267,7 @@
///these mob spawn subtypes trigger immediately (New or Initialize) and are not player controlled... since they're dead, you know?
/obj/effect/mob_spawn/corpse
+ density = FALSE //these are pretty much abstract objects that leave a corpse in their place.
///when this mob spawn should auto trigger.
var/spawn_when = CORPSE_INSTANT
diff --git a/code/modules/mod/mod_activation.dm b/code/modules/mod/mod_activation.dm
index 237e151bcb2c0..b6d2978043cbf 100644
--- a/code/modules/mod/mod_activation.dm
+++ b/code/modules/mod/mod_activation.dm
@@ -17,8 +17,8 @@
if(!pick)
return
var/part_reference = display_names[pick]
- var/obj/item/part = locate(part_reference) in parts
- if(!istype(part) || user.incapacitated())
+ var/obj/item/part = locate(part_reference) in mod_parts
+ if(!istype(part) || user.incapacitated)
return
if(active || activating)
balloon_alert(user, "deactivate the suit first!")
diff --git a/code/modules/mod/mod_control.dm b/code/modules/mod/mod_control.dm
index cf91aaf482c22..aebf4865daf84 100644
--- a/code/modules/mod/mod_control.dm
+++ b/code/modules/mod/mod_control.dm
@@ -233,7 +233,7 @@
balloon_alert(wearer, "retract parts first!")
playsound(src, 'sound/machines/scanbuzz.ogg', 25, FALSE, SILENCED_SOUND_EXTRARANGE)
return
- if(!wearer.incapacitated())
+ if(!wearer.incapacitated)
var/atom/movable/screen/inventory/hand/ui_hand = over_object
if(wearer.putItemFromInventoryInHandIfPossible(src, ui_hand.held_index))
add_fingerprint(user)
diff --git a/code/modules/mod/mod_paint.dm b/code/modules/mod/mod_paint.dm
index 7897b60b794a7..0693b05a34854 100644
--- a/code/modules/mod/mod_paint.dm
+++ b/code/modules/mod/mod_paint.dm
@@ -55,7 +55,7 @@
data["currentColor"] = current_color
return data
-/obj/item/mod/paint/ui_act(action, list/params)
+/obj/item/mod/paint/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
@@ -126,7 +126,7 @@
mod.theme.set_skin(mod, pick)
/obj/item/mod/paint/proc/check_menu(obj/item/mod/control/mod, mob/user)
- if(user.incapacitated() || !user.is_holding(src) || !mod || mod.active || mod.activating)
+ if(user.incapacitated || !user.is_holding(src) || !mod || mod.active || mod.activating)
return FALSE
return TRUE
diff --git a/code/modules/mod/mod_theme.dm b/code/modules/mod/mod_theme.dm
index 394ddea0ecdea..276183eeb92ce 100644
--- a/code/modules/mod/mod_theme.dm
+++ b/code/modules/mod/mod_theme.dm
@@ -1351,6 +1351,7 @@
siemens_coefficient = 0
slowdown_inactive = 0
slowdown_active = 0
+ activation_step_time = MOD_ACTIVATION_STEP_TIME * 0.5
ui_theme = "syndicate"
slot_flags = ITEM_SLOT_BELT
inbuilt_modules = list(/obj/item/mod/module/infiltrator, /obj/item/mod/module/storage/belt, /obj/item/mod/module/demoralizer)
@@ -1407,7 +1408,7 @@
/datum/mod_theme/interdyne
name = "interdyne"
desc = "A corpse-snatching and rapid-retrieval modsuit, resulting from a lucrative tech exchange between Interdyne Pharmaceutics and Cybersun Industries."
- extended_desc = "While Waffle Co. and Azik Interstellar provide the means, Donk Co., Tiger Cooperative, Animal Rights Consortium and \
+ extended_desc = "While Waffle Corp. and Azik Interstellar provide the means, Donk Co., Tiger Cooperative, Animal Rights Consortium and \
Gorlex Marauders willing or easily bribable brawn, S.E.L.F. and MI13 information, the clear syndicate tech providers would be Interdyne and Cybersun, \
their combined knowledge in technologies rivaled by only the most enigmatic of aliens, and certainly not by any Nanotrasen scientist. \
This model is one of the rare fruits created by their joint operations, mashing scrapped designs with super soldier enhancements. \
diff --git a/code/modules/mod/mod_types.dm b/code/modules/mod/mod_types.dm
index db9d150f3438a..b20efa4c66641 100644
--- a/code/modules/mod/mod_types.dm
+++ b/code/modules/mod/mod_types.dm
@@ -493,7 +493,7 @@
/obj/item/mod/control/pre_equipped/responsory/janitor
insignia_type = /obj/item/mod/module/insignia/janitor
- additional_module = /obj/item/mod/module/clamp
+ additional_module = /obj/item/mod/module/noslip
/obj/item/mod/control/pre_equipped/responsory/clown
insignia_type = /obj/item/mod/module/insignia/clown
diff --git a/code/modules/mod/modules/_module.dm b/code/modules/mod/modules/_module.dm
index 4bd4ef0d2ab80..a9bb181cf6b23 100644
--- a/code/modules/mod/modules/_module.dm
+++ b/code/modules/mod/modules/_module.dm
@@ -200,7 +200,7 @@
/// Called when an activated module without a device is used
/obj/item/mod/module/proc/on_select_use(atom/target)
- if(!(allow_flags & MODULE_ALLOW_INCAPACITATED) && mod.wearer.incapacitated(IGNORE_GRAB))
+ if(!(allow_flags & MODULE_ALLOW_INCAPACITATED) && INCAPACITATED_IGNORING(mod.wearer, INCAPABLE_GRAB))
return FALSE
mod.wearer.face_atom(target)
if(!used())
diff --git a/code/modules/mod/modules/module_kinesis.dm b/code/modules/mod/modules/module_kinesis.dm
index 9048701f1d017..374be840d9507 100644
--- a/code/modules/mod/modules/module_kinesis.dm
+++ b/code/modules/mod/modules/module_kinesis.dm
@@ -67,7 +67,7 @@
clear_grab(playsound = !deleting)
/obj/item/mod/module/anomaly_locked/kinesis/process(seconds_per_tick)
- if(!mod.wearer.client || mod.wearer.incapacitated(IGNORE_GRAB))
+ if(!mod.wearer.client || INCAPACITATED_IGNORING(mod.wearer, INCAPABLE_GRAB))
clear_grab()
return
if(!range_check(grabbed_atom))
diff --git a/code/modules/mod/modules/modules_general.dm b/code/modules/mod/modules/modules_general.dm
index 8db88e16ba312..f1b14b0f90056 100644
--- a/code/modules/mod/modules/modules_general.dm
+++ b/code/modules/mod/modules/modules_general.dm
@@ -54,7 +54,7 @@
/obj/item/mod/module/storage/large_capacity
name = "MOD expanded storage module"
- desc = "Reverse engineered by Nakamura Engineering from Donk Corporation designs, this system of hidden compartments \
+ desc = "Reverse engineered by Nakamura Engineering from Donk Company designs, this system of hidden compartments \
is entirely within the suit, distributing items and weight evenly to ensure a comfortable experience for the user; \
whether smuggling, or simply hauling."
icon_state = "storage_large"
@@ -450,7 +450,7 @@
///Dispenser - Dispenses an item after a time passes.
/obj/item/mod/module/dispenser
name = "MOD burger dispenser module"
- desc = "A rare piece of technology reverse-engineered from a prototype found in a Donk Corporation vessel. \
+ desc = "A rare piece of technology reverse-engineered from a prototype found in a Donk Company vessel. \
This can draw incredible amounts of power from the suit's charge to create edible organic matter in the \
palm of the wearer's glove; however, research seemed to have entirely stopped at burgers. \
Notably, all attempts to get it to dispense Earl Grey tea have failed."
@@ -953,6 +953,76 @@
balloon_alert(mod.wearer, "ammo box dispensed.")
playsound(src, 'sound/machines/microwave/microwave-end.ogg', 50, TRUE)
+/obj/item/mod/module/fishing_glove
+ name = "MOD fishing glove module"
+ desc = "A MOD module that takes in an external fishing rod to enable the user to fish without having to hold one."
+ icon_state = "fishing_glove"
+ complexity = 1
+ overlay_state_inactive = "fishing_glove"
+ incompatible_modules = (/obj/item/mod/module/fishing_glove)
+ required_slots = list(ITEM_SLOT_GLOVES)
+ var/obj/item/fishing_rod/equipped
+
+/obj/item/mod/module/fishing_glove/Initialize(mapload)
+ . = ..()
+ register_context()
+
+/obj/item/mod/module/fishing_glove/add_context(atom/source, list/context, obj/item/held_item, mob/user)
+ if(!held_item && equipped)
+ context[SCREENTIP_CONTEXT_RMB] = "Remove rod"
+ return CONTEXTUAL_SCREENTIP_SET
+ if(istype(held_item, /obj/item/fishing_rod))
+ context[SCREENTIP_CONTEXT_LMB] = "Insert rod"
+ return CONTEXTUAL_SCREENTIP_SET
+
+/obj/item/mod/module/fishing_glove/examine(mob/user)
+ . = ..()
+ . += span_info("You can [EXAMINE_HINT("right-click")] the modsuit gloves to open the fishing rod interface once attached and activated.")
+ if(equipped)
+ . += span_info("it has a [icon2html(equipped, user)] installed. [EXAMINE_HINT("Right-Click")] to remove it.")
+
+/obj/item/mod/module/fishing_glove/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
+ if(!istype(tool, /obj/item/fishing_rod))
+ return ..()
+ if(equipped)
+ balloon_alert(user, "remove current rod first!")
+ if(!user.transferItemToLoc(tool, src))
+ user.balloon_alert(user, "it's stuck!")
+ equipped = tool
+ balloon_alert(user, "rod inserted")
+ playsound(src, 'sound/items/click.ogg', 50, TRUE)
+ return ITEM_INTERACT_SUCCESS
+
+/obj/item/mod/module/fishing_glove/attack_hand_secondary(mob/user, list/modifiers)
+ . = ..()
+ if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
+ return
+ if(!equipped)
+ return
+ user.put_in_hands(equipped)
+ balloon_alert(user, "rod removed")
+ playsound(src, 'sound/items/click.ogg', 50, TRUE)
+ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
+
+/obj/item/mod/module/fishing_glove/Exited(atom/movable/gone)
+ if(gone == equipped)
+ equipped = null
+ var/obj/item/gloves = mod?.get_part_from_slot(ITEM_SLOT_GLOVES)
+ if(gloves && !QDELETED(mod))
+ qdel(gloves.GetComponent(/datum/component/profound_fisher))
+
+/obj/item/mod/module/fishing_glove/on_suit_activation()
+ if(!equipped)
+ return
+ var/obj/item/gloves = mod.get_part_from_slot(ITEM_SLOT_GLOVES)
+ if(gloves)
+ gloves.AddComponent(/datum/component/profound_fisher, equipped)
+
+/obj/item/mod/module/fishing_glove/on_suit_deactivation(deleting = FALSE)
+ var/obj/item/gloves = mod.get_part_from_slot(ITEM_SLOT_GLOVES)
+ if(gloves && !deleting)
+ qdel(gloves.GetComponent(/datum/component/profound_fisher))
+
/obj/item/mod/module/shock_absorber
name = "MOD shock absorption module"
desc = "A module that makes the user resistant to the knockdown inflicted by Stun Batons."
diff --git a/code/modules/mod/modules/modules_medical.dm b/code/modules/mod/modules/modules_medical.dm
index 7a802cf0f6cda..8a1d31a92f6b0 100644
--- a/code/modules/mod/modules/modules_medical.dm
+++ b/code/modules/mod/modules/modules_medical.dm
@@ -225,8 +225,7 @@
organ_evacced.Remove(target, special = TRUE)
organ_evacced.forceMove(get_turf(target))
- if (!organ.Insert(target))
- organ.forceMove(drop_location())
+ organ.Insert(target)
organ = null
///Patrient Transport - Generates hardlight bags you can put people in.
diff --git a/code/modules/mod/modules/modules_ninja.dm b/code/modules/mod/modules/modules_ninja.dm
index cfa95fb8a591e..a5215341a06d2 100644
--- a/code/modules/mod/modules/modules_ninja.dm
+++ b/code/modules/mod/modules/modules_ninja.dm
@@ -72,9 +72,11 @@
cooldown_time = 3 SECONDS
/obj/item/mod/module/stealth/ninja/on_activation()
+ . = ..()
ADD_TRAIT(mod.wearer, TRAIT_SILENT_FOOTSTEPS, MOD_TRAIT)
/obj/item/mod/module/stealth/ninja/on_deactivation(display_message = TRUE, deleting = FALSE)
+ . = ..()
REMOVE_TRAIT(mod.wearer, TRAIT_SILENT_FOOTSTEPS, MOD_TRAIT)
///Camera Vision - Prevents flashes, blocks tracking.
diff --git a/code/modules/mod/modules/modules_security.dm b/code/modules/mod/modules/modules_security.dm
index 752273fa0748c..5da8ff00241c9 100644
--- a/code/modules/mod/modules/modules_security.dm
+++ b/code/modules/mod/modules/modules_security.dm
@@ -568,7 +568,7 @@
projectile.ricochets_max += 1
projectile.min_ricochets += 1
projectile.ricochet_incidence_leeway = 0 //allows the projectile to bounce at any angle.
- ADD_TRAIT(projectile, TRAIT_ALWAYS_HIT_ZONE, MOD_TRAIT)
+ projectile.accuracy_falloff = 0
#undef SHOOTING_ASSISTANT_OFF
#undef STORMTROOPER_MODE
diff --git a/code/modules/modular_computers/computers/item/computer.dm b/code/modules/modular_computers/computers/item/computer.dm
index 08bd61945ef47..03503ac36d864 100644
--- a/code/modules/modular_computers/computers/item/computer.dm
+++ b/code/modules/modular_computers/computers/item/computer.dm
@@ -727,6 +727,8 @@
UpdateDisplay()
/obj/item/modular_computer/ui_action_click(mob/user, actiontype)
+ if(!issilicon(user))
+ playsound(src, SFX_KEYBOARD_CLICKS, 10, TRUE, FALSE)
if(istype(actiontype, /datum/action/item_action/toggle_computer_light))
toggle_flashlight(user)
return
diff --git a/code/modules/modular_computers/computers/item/disks/role_disks.dm b/code/modules/modular_computers/computers/item/disks/role_disks.dm
index f7f20efb70b43..2191aaccdff1d 100644
--- a/code/modules/modular_computers/computers/item/disks/role_disks.dm
+++ b/code/modules/modular_computers/computers/item/disks/role_disks.dm
@@ -6,7 +6,6 @@
max_capacity = 32
///Static list of programss ALL command tablets have.
var/static/list/datum/computer_file/command_programs = list(
- /datum/computer_file/program/crew_manifest,
/datum/computer_file/program/science,
/datum/computer_file/program/status,
)
@@ -74,7 +73,6 @@
icon_state = "datadisk9"
starting_programs = list(
/datum/computer_file/program/records/security,
- /datum/computer_file/program/crew_manifest,
)
/**
diff --git a/code/modules/modular_computers/computers/item/disks/unique_disks.dm b/code/modules/modular_computers/computers/item/disks/unique_disks.dm
index 1fd31957befca..a5e9d9750f3ea 100644
--- a/code/modules/modular_computers/computers/item/disks/unique_disks.dm
+++ b/code/modules/modular_computers/computers/item/disks/unique_disks.dm
@@ -23,7 +23,6 @@
/datum/computer_file/program/supermatter_monitor,
/datum/computer_file/program/newscaster,
/datum/computer_file/program/secureye,
- /datum/computer_file/program/crew_manifest,
/datum/computer_file/program/status,
)
potential_programs += subtypesof(/datum/computer_file/program/maintenance) - /datum/computer_file/program/maintenance/theme
diff --git a/code/modules/modular_computers/computers/item/pda.dm b/code/modules/modular_computers/computers/item/pda.dm
index b40ae45f27f91..ae63639aef6f9 100644
--- a/code/modules/modular_computers/computers/item/pda.dm
+++ b/code/modules/modular_computers/computers/item/pda.dm
@@ -38,6 +38,7 @@
/datum/computer_file/program/messenger,
/datum/computer_file/program/nt_pay,
/datum/computer_file/program/notepad,
+ /datum/computer_file/program/crew_manifest,
)
///List of items that can be stored in a PDA
var/static/list/contained_item = list(
@@ -419,7 +420,7 @@
return TRUE
/obj/item/modular_computer/pda/silicon/ui_state(mob/user)
- return GLOB.reverse_contained_state
+ return GLOB.deep_inventory_state
/obj/item/modular_computer/pda/silicon/cyborg/syndicate
icon_state = "tablet-silicon-syndicate"
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 7e4c7402c770b..cbd784b1ef0d4 100644
--- a/code/modules/modular_computers/computers/item/role_tablet_presets.dm
+++ b/code/modules/modular_computers/computers/item/role_tablet_presets.dm
@@ -6,14 +6,19 @@
greyscale_config = /datum/greyscale_config/tablet/head
greyscale_colors = "#67A364#a92323"
max_capacity = parent_type::max_capacity * 2
- starting_programs = list(
- /datum/computer_file/program/crew_manifest,
+ var/static/list/datum/computer_file/head_programs = list(
/datum/computer_file/program/status,
/datum/computer_file/program/science,
/datum/computer_file/program/robocontrol,
/datum/computer_file/program/budgetorders,
)
+/obj/item/modular_computer/pda/heads/Initialize(mapload)
+ . = ..()
+ for(var/programs in head_programs)
+ var/datum/computer_file/program/program_type = new programs
+ store_file(program_type)
+
/obj/item/modular_computer/pda/heads/captain
name = "captain PDA"
greyscale_config = /datum/greyscale_config/tablet/captain
@@ -35,11 +40,6 @@
greyscale_config = /datum/greyscale_config/tablet/stripe_thick/head
greyscale_colors = "#374f7e#a52f29#a52f29"
starting_programs = list(
- /datum/computer_file/program/crew_manifest,
- /datum/computer_file/program/status,
- /datum/computer_file/program/science,
- /datum/computer_file/program/robocontrol,
- /datum/computer_file/program/budgetorders,
/datum/computer_file/program/records/security,
/datum/computer_file/program/job_management,
)
@@ -50,11 +50,6 @@
greyscale_colors = "#EA3232#0000CC"
inserted_item = /obj/item/pen/red/security
starting_programs = list(
- /datum/computer_file/program/crew_manifest,
- /datum/computer_file/program/status,
- /datum/computer_file/program/science,
- /datum/computer_file/program/robocontrol,
- /datum/computer_file/program/budgetorders,
/datum/computer_file/program/records/security,
)
@@ -63,11 +58,6 @@
greyscale_config = /datum/greyscale_config/tablet/stripe_thick/head
greyscale_colors = "#D99A2E#69DBF3#FAFAFA"
starting_programs = list(
- /datum/computer_file/program/crew_manifest,
- /datum/computer_file/program/status,
- /datum/computer_file/program/science,
- /datum/computer_file/program/robocontrol,
- /datum/computer_file/program/budgetorders,
/datum/computer_file/program/atmosscan,
/datum/computer_file/program/alarm_monitor,
/datum/computer_file/program/supermatter_monitor,
@@ -78,11 +68,6 @@
greyscale_config = /datum/greyscale_config/tablet/stripe_thick/head
greyscale_colors = "#FAFAFA#000099#3F96CC"
starting_programs = list(
- /datum/computer_file/program/crew_manifest,
- /datum/computer_file/program/status,
- /datum/computer_file/program/science,
- /datum/computer_file/program/robocontrol,
- /datum/computer_file/program/budgetorders,
/datum/computer_file/program/maintenance/phys_scanner,
/datum/computer_file/program/records/medical,
)
@@ -94,12 +79,7 @@
inserted_item = /obj/item/pen/fountain
starting_programs = list(
/datum/computer_file/program/borg_monitor,
- /datum/computer_file/program/budgetorders,
- /datum/computer_file/program/crew_manifest,
- /datum/computer_file/program/robocontrol,
- /datum/computer_file/program/science,
/datum/computer_file/program/scipaper_program,
- /datum/computer_file/program/status,
/datum/computer_file/program/signal_commander,
)
@@ -110,11 +90,6 @@
inserted_item = /obj/item/pen/survival
stored_paper = 20
starting_programs = list(
- /datum/computer_file/program/crew_manifest,
- /datum/computer_file/program/status,
- /datum/computer_file/program/science,
- /datum/computer_file/program/robocontrol,
- /datum/computer_file/program/budgetorders,
/datum/computer_file/program/shipping,
/datum/computer_file/program/restock_tracker,
)
@@ -129,7 +104,6 @@
inserted_item = /obj/item/pen/red/security
starting_programs = list(
/datum/computer_file/program/records/security,
- /datum/computer_file/program/crew_manifest,
/datum/computer_file/program/robocontrol,
)
@@ -139,7 +113,6 @@
inserted_item = /obj/item/pen/red/security
starting_programs = list(
/datum/computer_file/program/records/security,
- /datum/computer_file/program/crew_manifest,
/datum/computer_file/program/robocontrol,
)
@@ -150,7 +123,6 @@
inserted_item = /obj/item/pen/red/security
starting_programs = list(
/datum/computer_file/program/records/security,
- /datum/computer_file/program/crew_manifest,
/datum/computer_file/program/robocontrol,
)
@@ -244,7 +216,6 @@
greyscale_colors = "#FAFAFA#000099#1f2026"
starting_programs = list(
/datum/computer_file/program/records/medical,
- /datum/computer_file/program/crew_manifest,
)
/**
@@ -405,7 +376,6 @@
greyscale_colors = "#333333#000099#3F96CC"
starting_programs = list(
/datum/computer_file/program/records/medical,
- /datum/computer_file/program/crew_manifest,
/datum/computer_file/program/robocontrol,
)
@@ -422,7 +392,6 @@
name = "bridge assistant PDA"
greyscale_colors = "#374f7e#a92323"
starting_programs = list(
- /datum/computer_file/program/crew_manifest,
/datum/computer_file/program/status,
)
@@ -432,7 +401,6 @@
inserted_item = /obj/item/pen/fountain
starting_programs = list(
/datum/computer_file/program/records/security,
- /datum/computer_file/program/crew_manifest,
/datum/computer_file/program/coupon, //veteran discount
/datum/computer_file/program/skill_tracker,
)
diff --git a/code/modules/modular_computers/file_system/programs/crewmanifest.dm b/code/modules/modular_computers/file_system/programs/crewmanifest.dm
index 39a9d8c3c7fe5..d0dcf0ae873fe 100644
--- a/code/modules/modular_computers/file_system/programs/crewmanifest.dm
+++ b/code/modules/modular_computers/file_system/programs/crewmanifest.dm
@@ -1,15 +1,13 @@
/datum/computer_file/program/crew_manifest
filename = "plexagoncrew"
filedesc = "Plexagon Crew List"
- downloader_category = PROGRAM_CATEGORY_SECURITY
+ downloader_category = PROGRAM_CATEGORY_DEVICE
program_open_overlay = "id"
extended_desc = "Program for viewing and printing the current crew manifest"
- download_access = list(ACCESS_SECURITY, ACCESS_COMMAND)
program_flags = PROGRAM_ON_NTNET_STORE | PROGRAM_REQUIRES_NTNET
- size = 4
+ size = 0
tgui_id = "NtosCrewManifest"
program_icon = "clipboard-list"
- detomatix_resistance = DETOMATIX_RESIST_MAJOR
/datum/computer_file/program/crew_manifest/ui_static_data(mob/user)
var/list/data = list()
diff --git a/code/modules/modular_computers/file_system/programs/frontier.dm b/code/modules/modular_computers/file_system/programs/frontier.dm
index c8030287e8943..04e902a5e8d4c 100644
--- a/code/modules/modular_computers/file_system/programs/frontier.dm
+++ b/code/modules/modular_computers/file_system/programs/frontier.dm
@@ -8,7 +8,7 @@
program_open_overlay = "research"
tgui_id = "NtosScipaper"
program_icon = "paper-plane"
- download_access = list(ACCESS_ORDNANCE, ACCESS_SCIENCE, ACCESS_AWAY_SCIENCE)
+ download_access = list(ACCESS_ORDNANCE, ACCESS_SCIENCE, ACCESS_AWAY_SCIENCE, ACCESS_ATMOSPHERICS)
var/datum/techweb/linked_techweb
/// Unpublished, temporary paper datum.
diff --git a/code/modules/modular_computers/file_system/programs/messenger/messenger_program.dm b/code/modules/modular_computers/file_system/programs/messenger/messenger_program.dm
index 4ad633aa94df4..6436e6be2b862 100644
--- a/code/modules/modular_computers/file_system/programs/messenger/messenger_program.dm
+++ b/code/modules/modular_computers/file_system/programs/messenger/messenger_program.dm
@@ -157,7 +157,7 @@
/datum/computer_file/program/messenger/ui_state(mob/user)
if(issilicon(user))
- return GLOB.reverse_contained_state
+ return GLOB.deep_inventory_state
return GLOB.default_state
/datum/computer_file/program/messenger/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
diff --git a/code/modules/modular_computers/file_system/programs/records.dm b/code/modules/modular_computers/file_system/programs/records.dm
index 063c19d35e18b..fbd0b9edabd66 100644
--- a/code/modules/modular_computers/file_system/programs/records.dm
+++ b/code/modules/modular_computers/file_system/programs/records.dm
@@ -29,6 +29,7 @@
download_access = list(ACCESS_SECURITY, ACCESS_FLAG_COMMAND)
program_flags = PROGRAM_ON_NTNET_STORE
mode = "security"
+ detomatix_resistance = DETOMATIX_RESIST_MINOR
/datum/computer_file/program/records/proc/GetRecordsReadable()
var/list/all_records = list()
diff --git a/code/modules/modular_computers/file_system/programs/statusdisplay.dm b/code/modules/modular_computers/file_system/programs/statusdisplay.dm
index fa844215b93b9..a57940d99c1fa 100644
--- a/code/modules/modular_computers/file_system/programs/statusdisplay.dm
+++ b/code/modules/modular_computers/file_system/programs/statusdisplay.dm
@@ -11,6 +11,7 @@
can_run_on_flags = PROGRAM_ALL
program_flags = PROGRAM_REQUIRES_NTNET
+ detomatix_resistance = DETOMATIX_RESIST_MAJOR
var/upper_text = ""
var/lower_text = ""
diff --git a/code/modules/modular_computers/file_system/programs/virtual_pet.dm b/code/modules/modular_computers/file_system/programs/virtual_pet.dm
index 78a9148b013fe..8f1eef074d46a 100644
--- a/code/modules/modular_computers/file_system/programs/virtual_pet.dm
+++ b/code/modules/modular_computers/file_system/programs/virtual_pet.dm
@@ -429,7 +429,7 @@ GLOBAL_LIST_EMPTY(virtual_pets_list)
var/static/list/possible_emotes = list(
/datum/emote/flip,
- /datum/emote/living/jump,
+ /datum/emote/jump,
/datum/emote/living/shiver,
/datum/emote/spin,
/datum/emote/silicon/beep,
diff --git a/code/modules/pai/hud.dm b/code/modules/pai/hud.dm
index b104c7b90eab4..77bcafefc82d2 100644
--- a/code/modules/pai/hud.dm
+++ b/code/modules/pai/hud.dm
@@ -5,7 +5,7 @@
var/required_software
/atom/movable/screen/pai/Click()
- if(isobserver(usr) || usr.incapacitated())
+ if(isobserver(usr) || usr.incapacitated)
return FALSE
var/mob/living/silicon/pai/user = usr
if(required_software && !user.installed_software.Find(required_software))
diff --git a/code/modules/pai/say.dm b/code/modules/pai/say.dm
index b35abfe7f9d80..c7ed1a566d883 100644
--- a/code/modules/pai/say.dm
+++ b/code/modules/pai/say.dm
@@ -1,2 +1,2 @@
/mob/living/silicon/pai/binarycheck()
- return radio?.translate_binary
+ return (radio?.special_channels & RADIO_SPECIAL_BINARY)
diff --git a/code/modules/pai/shell.dm b/code/modules/pai/shell.dm
index 2ef3cf3d8e2dd..6a8a8e709c82b 100644
--- a/code/modules/pai/shell.dm
+++ b/code/modules/pai/shell.dm
@@ -30,7 +30,7 @@
* FALSE otherwise.
*/
/mob/living/silicon/pai/proc/check_menu(atom/anchor)
- if(incapacitated())
+ if(incapacitated)
return FALSE
if(get_turf(src) != get_turf(anchor))
return FALSE
diff --git a/code/modules/paperwork/clipboard.dm b/code/modules/paperwork/clipboard.dm
index f4e6c7122468d..7750b3926465f 100644
--- a/code/modules/paperwork/clipboard.dm
+++ b/code/modules/paperwork/clipboard.dm
@@ -13,6 +13,13 @@
throw_range = 7
slot_flags = ITEM_SLOT_BELT
resistance_flags = FLAMMABLE
+
+ unique_reskin = list(
+ "Brown" = "clipboard",
+ "Black" = "clipboard_black",
+ "White" = "clipboard_white",
+ )
+
/// The stored pen
var/obj/item/pen/pen
/// Is the pen integrated?
@@ -151,7 +158,7 @@
return data
-/obj/item/clipboard/ui_act(action, params)
+/obj/item/clipboard/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/paperwork/fax.dm b/code/modules/paperwork/fax.dm
index e652b92e97805..fc1b986ce6d67 100644
--- a/code/modules/paperwork/fax.dm
+++ b/code/modules/paperwork/fax.dm
@@ -43,6 +43,9 @@ GLOBAL_VAR_INIT(nt_fax_department, pick("NT HR Department", "NT Legal Department
/obj/item/card,
/obj/item/folder/biscuit,
/obj/item/food/breadslice,
+ /obj/item/food/chapslice,
+ /obj/item/food/cookie,
+ /obj/item/food/grilled_chapslice,
/obj/item/food/pizza/flatbread,
/obj/item/food/pizzaslice,
/obj/item/food/root_flatbread,
@@ -66,6 +69,27 @@ GLOBAL_VAR_INIT(nt_fax_department, pick("NT HR Department", "NT Legal Department
fax_name = "[current_area.name]"
return ..()
+/obj/machinery/fax/admin/syndicate
+ name = "Syndicate Fax Machine"
+
+/obj/machinery/fax/admin/syndicate/Initialize(mapload)
+ fax_name = "[special_networks["syndicate"]["fax_name"]]"
+ fax_id = special_networks["syndicate"]["fax_id"]
+ syndicate_network = TRUE
+ return ..()
+
+/obj/machinery/fax/admin
+ name = "CentCom Fax Machine"
+
+/obj/machinery/fax/admin/Initialize(mapload)
+ if (!fax_name)
+ fax_name = "[GLOB.nt_fax_department]"
+ if(!fax_id)
+ fax_id = special_networks["nanotrasen"]["fax_id"]
+ name = "[fax_name] Fax Machine"
+ visible_to_network = FALSE
+ return ..()
+
/obj/machinery/fax/Initialize(mapload)
. = ..()
if (!fax_id)
@@ -232,7 +256,7 @@ GLOBAL_VAR_INIT(nt_fax_department, pick("NT HR Department", "NT Legal Department
var/list/data = list()
//Record a list of all existing faxes.
for(var/obj/machinery/fax/FAX as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/fax))
- if(FAX.fax_id == fax_id || is_centcom_level(FAX.z)) //skip yourself and the centcom fax machine.
+ if(FAX.fax_id == fax_id) //skip yourself
continue
var/list/fax_data = list()
fax_data["fax_name"] = FAX.fax_name
@@ -253,11 +277,13 @@ GLOBAL_VAR_INIT(nt_fax_department, pick("NT HR Department", "NT Legal Department
data["fax_history"] = fax_history
var/list/special_networks_data = list()
for(var/key in special_networks)
+ if(special_networks[key]["fax_id"] == fax_id)
+ continue
special_networks_data += list(special_networks[key])
data["special_faxes"] = special_networks_data
return data
-/obj/machinery/fax/ui_act(action, list/params)
+/obj/machinery/fax/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
@@ -300,7 +326,7 @@ GLOBAL_VAR_INIT(nt_fax_department, pick("NT HR Department", "NT Legal Department
history_add("Send", params["name"])
GLOB.requests.fax_request(usr.client, "sent a fax message from [fax_name]/[fax_id] to [params["name"]]", fax_paper)
- to_chat(GLOB.admins, span_adminnotice("[icon2html(src.icon, GLOB.admins)]FAX REQUEST: [ADMIN_FULLMONTY(usr)]: [span_linkify("sent a fax message from [fax_name]/[fax_id][ADMIN_FLW(src)] to [html_encode(params["name"])]")] [ADMIN_SHOW_PAPER(fax_paper)] [ADMIN_PRINT_FAX(fax_paper, fax_name)]"), confidential = TRUE)
+ to_chat(GLOB.admins, span_adminnotice("[icon2html(src.icon, GLOB.admins)]FAX REQUEST: [ADMIN_FULLMONTY(usr)]: [span_linkify("sent a fax message from [fax_name]/[fax_id][ADMIN_FLW(src)] to [html_encode(params["name"])]")] [ADMIN_SHOW_PAPER(fax_paper)] [ADMIN_PRINT_FAX(fax_paper, fax_name, params["id"])]"), confidential = TRUE)
for(var/client/staff as anything in GLOB.admins)
if(staff?.prefs.read_preference(/datum/preference/toggle/comms_notification))
SEND_SOUND(staff, sound('sound/misc/server-ready.ogg'))
diff --git a/code/modules/paperwork/filingcabinet.dm b/code/modules/paperwork/filingcabinet.dm
index 46b9b8f31fdd2..41d9aabb54ac8 100644
--- a/code/modules/paperwork/filingcabinet.dm
+++ b/code/modules/paperwork/filingcabinet.dm
@@ -83,7 +83,7 @@
return data
-/obj/structure/filingcabinet/ui_act(action, params)
+/obj/structure/filingcabinet/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/paperwork/folders.dm b/code/modules/paperwork/folders.dm
index 3ee556b3adf4f..50c833ca89fd5 100644
--- a/code/modules/paperwork/folders.dm
+++ b/code/modules/paperwork/folders.dm
@@ -106,7 +106,7 @@
return data
-/obj/item/folder/ui_act(action, params)
+/obj/item/folder/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm
index fe2de7e752030..14202b1bf3b36 100644
--- a/code/modules/paperwork/paper.dm
+++ b/code/modules/paperwork/paper.dm
@@ -64,6 +64,9 @@
///If TRUE, staff can read paper everywhere, but usually from requests panel.
var/request_state = FALSE
+ ///If this paper can be selected as a candidate for a future message in a bottle when spawned outside of mapload. Doesn't affect manually doing that.
+ var/can_become_message_in_bottle = TRUE
+
/obj/item/paper/Initialize(mapload)
. = ..()
pixel_x = base_pixel_x + rand(-9, 9)
@@ -74,10 +77,14 @@
update_appearance()
+ if(can_become_message_in_bottle && !mapload && prob(MESSAGE_BOTTLE_CHANCE))
+ LAZYADD(SSpersistence.queued_message_bottles, src)
+
/obj/item/paper/Destroy()
- . = ..()
camera_holder = null
clear_paper()
+ LAZYREMOVE(SSpersistence.queued_message_bottles, src)
+ return ..()
/// Determines whether this paper has been written or stamped to.
/obj/item/paper/proc/is_empty()
@@ -306,7 +313,7 @@
set category = "Object"
set src in usr
- if(!usr.can_read(src) || usr.is_blind() || usr.incapacitated(IGNORE_RESTRAINTS|IGNORE_GRAB) || (isobserver(usr) && !isAdminGhostAI(usr)))
+ if(!usr.can_read(src) || usr.is_blind() || INCAPACITATED_IGNORING(usr, INCAPABLE_RESTRAINTS|INCAPABLE_GRAB) || (isobserver(usr) && !isAdminGhostAI(usr)))
return
if(ishuman(usr))
var/mob/living/carbon/human/H = usr
@@ -351,7 +358,7 @@
return UI_UPDATE
if(!in_range(user, src) && !isobserver(user))
return UI_CLOSE
- if(user.incapacitated(IGNORE_RESTRAINTS|IGNORE_GRAB) || (isobserver(user) && !isAdminGhostAI(user)))
+ if(INCAPACITATED_IGNORING(user, INCAPABLE_RESTRAINTS|INCAPABLE_GRAB) || (isobserver(user) && !isAdminGhostAI(user)))
return UI_UPDATE
// Even harder to read if your blind...braile? humm
// .. or if you cannot read
@@ -527,22 +534,10 @@
static_data["user_name"] = user.real_name
- static_data["raw_text_input"] = list()
- for(var/datum/paper_input/text_input as anything in raw_text_inputs)
- static_data["raw_text_input"] += list(text_input.to_list())
-
- static_data["raw_field_input"] = list()
- for(var/datum/paper_field/field_input as anything in raw_field_input_data)
- static_data["raw_field_input"] += list(field_input.to_list())
-
- static_data["raw_stamp_input"] = list()
- for(var/datum/paper_stamp/stamp_input as anything in raw_stamp_data)
- static_data["raw_stamp_input"] += list(stamp_input.to_list())
+ static_data += convert_to_data()
static_data["max_length"] = MAX_PAPER_LENGTH
static_data["max_input_field_length"] = MAX_PAPER_INPUT_FIELD_LENGTH
- static_data["paper_color"] = color ? color : COLOR_WHITE
- static_data["paper_name"] = name
static_data["default_pen_font"] = PEN_FONT
static_data["default_pen_color"] = COLOR_BLACK
@@ -550,6 +545,43 @@
return static_data;
+/obj/item/paper/proc/convert_to_data()
+ var/list/data = list()
+
+ data[LIST_PAPER_RAW_TEXT_INPUT] = list()
+ for(var/datum/paper_input/text_input as anything in raw_text_inputs)
+ data[LIST_PAPER_RAW_TEXT_INPUT] += list(text_input.to_list())
+
+ data[LIST_PAPER_RAW_FIELD_INPUT] = list()
+ for(var/datum/paper_field/field_input as anything in raw_field_input_data)
+ data[LIST_PAPER_RAW_FIELD_INPUT] += list(field_input.to_list())
+
+ data[LIST_PAPER_RAW_STAMP_INPUT] = list()
+ for(var/datum/paper_stamp/stamp_input as anything in raw_stamp_data)
+ data[LIST_PAPER_RAW_STAMP_INPUT] += list(stamp_input.to_list())
+
+ data[LIST_PAPER_COLOR] = color ? color : COLOR_WHITE
+ data[LIST_PAPER_NAME] = name
+
+ return data
+
+/obj/item/paper/proc/write_from_data(list/data)
+ for(var/list/input as anything in data[LIST_PAPER_RAW_TEXT_INPUT])
+ add_raw_text(input[LIST_PAPER_RAW_TEXT], input[LIST_PAPER_FONT], input[LIST_PAPER_FIELD_COLOR], input[LIST_PAPER_BOLD], input[LIST_PAPER_ADVANCED_HTML])
+
+ for(var/list/field as anything in data[LIST_PAPER_RAW_FIELD_INPUT])
+ var/list/input = field[LIST_PAPER_FIELD_DATA]
+ add_field_input(field[LIST_PAPER_FIELD_INDEX], input[LIST_PAPER_RAW_TEXT], input[LIST_PAPER_FONT], input[LIST_PAPER_FIELD_COLOR], input[LIST_PAPER_BOLD], field[LIST_PAPER_IS_SIGNATURE])
+
+ for(var/list/stamp as anything in data[LIST_PAPER_RAW_STAMP_INPUT])
+ add_stamp(stamp[LIST_PAPER_CLASS], stamp[LIST_PAPER_STAMP_X], stamp[LIST_PAPER_STAMP_Y], stamp[LIST_PAPER_ROTATION])
+
+ var/new_color = data[LIST_PAPER_COLOR]
+ if(new_color != COLOR_WHITE)
+ add_atom_colour(new_color, FIXED_COLOUR_PRIORITY)
+
+ name = data[LIST_PAPER_NAME]
+
/obj/item/paper/ui_data(mob/user)
var/list/data = list()
@@ -753,11 +785,11 @@
/datum/paper_input/proc/to_list()
return list(
- raw_text = raw_text,
- font = font,
- color = colour,
- bold = bold,
- advanced_html = advanced_html,
+ LIST_PAPER_RAW_TEXT = raw_text,
+ LIST_PAPER_FONT = font,
+ LIST_PAPER_FIELD_COLOR = colour,
+ LIST_PAPER_BOLD = bold,
+ LIST_PAPER_ADVANCED_HTML = advanced_html,
)
/// Returns the raw contents of the input as html, with **ZERO SANITIZATION**
@@ -793,10 +825,10 @@
/datum/paper_stamp/proc/to_list()
return list(
- class = class,
- x = stamp_x,
- y = stamp_y,
- rotation = rotation,
+ LIST_PAPER_CLASS = class,
+ LIST_PAPER_STAMP_X = stamp_x,
+ LIST_PAPER_STAMP_Y = stamp_y,
+ LIST_PAPER_ROTATION = rotation,
)
/// A reference to some data that replaces a modifiable input field at some given index in paper raw input parsing.
@@ -818,9 +850,9 @@
/datum/paper_field/proc/to_list()
return list(
- field_index = field_index,
- field_data = field_data.to_list(),
- is_signature = is_signature,
+ LIST_PAPER_FIELD_INDEX = field_index,
+ LIST_PAPER_FIELD_DATA = field_data.to_list(),
+ LIST_PAPER_IS_SIGNATURE = is_signature,
)
/obj/item/paper/construction
diff --git a/code/modules/paperwork/paperwork.dm b/code/modules/paperwork/paperwork.dm
index cd26482bf6c8a..2acedcf00f093 100644
--- a/code/modules/paperwork/paperwork.dm
+++ b/code/modules/paperwork/paperwork.dm
@@ -44,7 +44,7 @@
if(.)
return
- if(stamped || istype(attacking_item, /obj/item/stamp))
+ if(stamped || !istype(attacking_item, /obj/item/stamp))
return
if(istype(attacking_item, stamp_requested))
diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm
index b72a232017029..1c54aefa269dc 100644
--- a/code/modules/paperwork/photocopier.dm
+++ b/code/modules/paperwork/photocopier.dm
@@ -179,7 +179,7 @@ GLOBAL_LIST_INIT(paper_blanks, init_paper_blanks())
return data
-/obj/machinery/photocopier/ui_act(action, list/params)
+/obj/machinery/photocopier/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/photography/camera/silicon_camera.dm b/code/modules/photography/camera/silicon_camera.dm
index 9cdbee1bc2b7a..a8bf7a3ba90e7 100644
--- a/code/modules/photography/camera/silicon_camera.dm
+++ b/code/modules/photography/camera/silicon_camera.dm
@@ -7,7 +7,7 @@
/// Checks if we can take a picture at this moment. Returns TRUE if we can, FALSE if we can't.
/obj/item/camera/siliconcam/proc/can_take_picture(mob/living/silicon/clicker)
- if(clicker.stat != CONSCIOUS || clicker.incapacitated())
+ if(clicker.stat != CONSCIOUS || clicker.incapacitated)
return FALSE
return TRUE
diff --git a/code/modules/photography/photos/photo.dm b/code/modules/photography/photos/photo.dm
index b009c5b2e7913..342abb1625c5a 100644
--- a/code/modules/photography/photos/photo.dm
+++ b/code/modules/photography/photos/photo.dm
@@ -9,12 +9,21 @@
w_class = WEIGHT_CLASS_TINY
resistance_flags = FLAMMABLE
max_integrity = 50
+ drop_sound = 'sound/items/handling/paper_drop.ogg'
+ pickup_sound = 'sound/items/handling/paper_pickup.ogg'
grind_results = list(/datum/reagent/iodine = 4)
var/datum/picture/picture
var/scribble //Scribble on the back.
/obj/item/photo/Initialize(mapload, datum/picture/P, datum_name = TRUE, datum_desc = TRUE)
set_picture(P, datum_name, datum_desc, TRUE)
+ //Photos are quite rarer than papers, so they're more likely to be added to the queue to make things even.
+ if(!mapload && prob(MESSAGE_BOTTLE_CHANCE * 5) && picture?.id)
+ LAZYADD(SSpersistence.queued_message_bottles, src)
+ return ..()
+
+/obj/item/photo/Destroy()
+ LAZYREMOVE(SSpersistence.queued_message_bottles, src)
return ..()
/obj/item/photo/proc/set_picture(datum/picture/P, setname, setdesc, name_override = FALSE)
@@ -104,7 +113,7 @@
var/n_name = tgui_input_text(usr, "What would you like to label the photo?", "Photo Labelling", max_length = MAX_NAME_LEN)
//loc.loc check is for making possible renaming photos in clipboards
- if(n_name && (loc == usr || loc.loc && loc.loc == usr) && usr.stat == CONSCIOUS && !usr.incapacitated())
+ if(n_name && (loc == usr || loc.loc && loc.loc == usr) && usr.stat == CONSCIOUS && !usr.incapacitated)
name = "photo[(n_name ? "- '[n_name]'" : null)]"
add_fingerprint(usr)
diff --git a/code/modules/plumbing/plumbers/acclimator.dm b/code/modules/plumbing/plumbers/acclimator.dm
index 014ff8499018d..51300af110b01 100644
--- a/code/modules/plumbing/plumbers/acclimator.dm
+++ b/code/modules/plumbing/plumbers/acclimator.dm
@@ -88,7 +88,7 @@
data["emptying"] = emptying
return data
-/obj/machinery/plumbing/acclimator/ui_act(action, params)
+/obj/machinery/plumbing/acclimator/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/plumbing/plumbers/pill_press.dm b/code/modules/plumbing/plumbers/pill_press.dm
index 2f2528a1765c1..23a7c7b03e54f 100644
--- a/code/modules/plumbing/plumbers/pill_press.dm
+++ b/code/modules/plumbing/plumbers/pill_press.dm
@@ -136,7 +136,7 @@
return data
-/obj/machinery/plumbing/pill_press/ui_act(action, params)
+/obj/machinery/plumbing/pill_press/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/plumbing/plumbers/splitters.dm b/code/modules/plumbing/plumbers/splitters.dm
index b87a07d694cc4..c2f9216c92b90 100644
--- a/code/modules/plumbing/plumbers/splitters.dm
+++ b/code/modules/plumbing/plumbers/splitters.dm
@@ -32,7 +32,7 @@
data["max_transfer"] = max_transfer
return data
-/obj/machinery/plumbing/splitter/ui_act(action, params)
+/obj/machinery/plumbing/splitter/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/plumbing/plumbers/synthesizer.dm b/code/modules/plumbing/plumbers/synthesizer.dm
index 0399ad85f3c04..ed4121d6ad02a 100644
--- a/code/modules/plumbing/plumbers/synthesizer.dm
+++ b/code/modules/plumbing/plumbers/synthesizer.dm
@@ -89,7 +89,7 @@
.["current_reagent"] = initial(reagent_id.name)
-/obj/machinery/plumbing/synthesizer/ui_act(action, params)
+/obj/machinery/plumbing/synthesizer/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/point/point.dm b/code/modules/point/point.dm
index 6e61b1154d59c..681fbce2c6bac 100644
--- a/code/modules/point/point.dm
+++ b/code/modules/point/point.dm
@@ -7,22 +7,30 @@
*
* Not intended as a replacement for the mob verb
*/
-/atom/movable/proc/point_at(atom/pointed_atom)
+/atom/movable/proc/point_at(atom/pointed_atom, intentional = FALSE)
if(!isturf(loc))
- return
+ return FALSE
if (pointed_atom in src)
create_point_bubble(pointed_atom)
- return
+ return FALSE
var/turf/tile = get_turf(pointed_atom)
if (!tile)
- return
+ return FALSE
var/turf/our_tile = get_turf(src)
var/obj/visual = new /obj/effect/temp_visual/point(our_tile, invisibility)
+ SEND_SIGNAL(src, COMSIG_MOVABLE_POINTED, pointed_atom, visual, intentional)
+
animate(visual, pixel_x = (tile.x - our_tile.x) * world.icon_size + pointed_atom.pixel_x, pixel_y = (tile.y - our_tile.y) * world.icon_size + pointed_atom.pixel_y, time = 1.7, easing = EASE_OUT)
+ return TRUE
+
+/mob/point_at(atom/pointed_atom, intentional = FALSE)
+ . = ..()
+ if(.)
+ face_atom(pointed_atom)
/atom/movable/proc/create_point_bubble(atom/pointed_atom)
var/mutable_appearance/thought_bubble = mutable_appearance(
@@ -109,7 +117,6 @@
if(client && !(pointing_at in view(client.view, src)))
return FALSE
- point_at(pointing_at)
+ point_at(pointing_at, TRUE)
- SEND_SIGNAL(src, COMSIG_MOB_POINTED, pointing_at)
return TRUE
diff --git a/code/modules/power/apc/apc_main.dm b/code/modules/power/apc/apc_main.dm
index 481ccde663b72..b0c5035a1f845 100644
--- a/code/modules/power/apc/apc_main.dm
+++ b/code/modules/power/apc/apc_main.dm
@@ -444,16 +444,17 @@
if(!QDELETED(remote_control_user) && user == remote_control_user)
. = UI_INTERACTIVE
-/obj/machinery/power/apc/ui_act(action, params)
+/obj/machinery/power/apc/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
+ var/mob/user = ui.user
- if(. || !can_use(usr, 1) || (locked && !HAS_SILICON_ACCESS(usr) && !failure_timer && action != "toggle_nightshift"))
+ if(. || !can_use(user, 1) || (locked && !HAS_SILICON_ACCESS(user) && !failure_timer && action != "toggle_nightshift"))
return
switch(action)
if("lock")
- if(HAS_SILICON_ACCESS(usr))
+ if(HAS_SILICON_ACCESS(user))
if((obj_flags & EMAGGED) || (machine_stat & (BROKEN|MAINT)) || remote_control_user)
- to_chat(usr, span_warning("The APC does not respond to the command!"))
+ to_chat(user, span_warning("The APC does not respond to the command!"))
else
locked = !locked
update_appearance()
@@ -462,10 +463,10 @@
coverlocked = !coverlocked
. = TRUE
if("breaker")
- toggle_breaker(usr)
+ toggle_breaker(user)
. = TRUE
if("toggle_nightshift")
- toggle_nightshift_lights(usr)
+ toggle_nightshift_lights(user)
. = TRUE
if("charge")
chargemode = !chargemode
@@ -488,17 +489,17 @@
update()
. = TRUE
if("overload")
- if(HAS_SILICON_ACCESS(usr))
+ if(HAS_SILICON_ACCESS(user))
overload_lighting()
. = TRUE
if("hack")
- if(get_malf_status(usr))
- malfhack(usr)
+ if(get_malf_status(user))
+ malfhack(user)
if("occupy")
- if(get_malf_status(usr))
- malfoccupy(usr)
+ if(get_malf_status(user))
+ malfoccupy(user)
if("deoccupy")
- if(get_malf_status(usr))
+ if(get_malf_status(user))
malfvacate()
if("reboot")
failure_timer = 0
@@ -684,7 +685,7 @@
/obj/machinery/power/apc/proc/overload_lighting()
if(!operating || shorted)
return
- if(cell && cell.use(0.02 * STANDARD_CELL_CHARGE))
+ if(cell && cell.use(0.02 * STANDARD_BATTERY_CHARGE))
INVOKE_ASYNC(src, PROC_REF(break_lights))
/obj/machinery/power/apc/proc/break_lights()
diff --git a/code/modules/power/apc/apc_tool_act.dm b/code/modules/power/apc/apc_tool_act.dm
index 8e4d51a703da6..9d7c008c6165c 100644
--- a/code/modules/power/apc/apc_tool_act.dm
+++ b/code/modules/power/apc/apc_tool_act.dm
@@ -110,7 +110,7 @@
if(isnull(choice) \
|| !user.is_holding(installing_cable) \
|| !user.Adjacent(src) \
- || user.incapacitated() \
+ || user.incapacitated \
|| !can_place_terminal(user, installing_cable, silent = TRUE) \
)
return ITEM_INTERACT_BLOCKING
diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm
index 65b4f01722959..f68319f4205fb 100644
--- a/code/modules/power/cable.dm
+++ b/code/modules/power/cable.dm
@@ -497,7 +497,7 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list(/obj/structure/gri
if(!ISADVANCEDTOOLUSER(user))
to_chat(user, span_warning("You don't have the dexterity to do this!"))
return FALSE
- if(user.incapacitated() || !user.Adjacent(src))
+ if(user.incapacitated || !user.Adjacent(src))
return FALSE
return TRUE
@@ -581,8 +581,9 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list(/obj/structure/gri
if(isnull(affecting) || !IS_ROBOTIC_LIMB(affecting))
return NONE
- if (!affecting.get_damage())
- return
+ if (!affecting.burn_dam)
+ balloon_alert(user, "limb not damaged")
+ return ITEM_INTERACT_BLOCKING
user.visible_message(span_notice("[user] starts to fix some of the wires in [attacked_humanoid == user ? user.p_their() : "[attacked_humanoid]'s"] [affecting.name]."),
span_notice("You start fixing some of the wires in [attacked_humanoid == user ? "your" : "[attacked_humanoid]'s"] [affecting.name]."))
@@ -766,7 +767,7 @@ GLOBAL_LIST(hub_radial_layer_list)
if(!ISADVANCEDTOOLUSER(user))
to_chat(user, span_warning("You don't have the dexterity to do this!"))
return FALSE
- if(user.incapacitated() || !user.Adjacent(src))
+ if(user.incapacitated || !user.Adjacent(src))
return FALSE
return TRUE
diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm
index fbb36703cc569..addb8cdb6b835 100644
--- a/code/modules/power/cell.dm
+++ b/code/modules/power/cell.dm
@@ -20,6 +20,11 @@
custom_materials = list(/datum/material/iron=SMALL_MATERIAL_AMOUNT*7, /datum/material/glass=SMALL_MATERIAL_AMOUNT*0.5)
grind_results = list(/datum/reagent/lithium = 15, /datum/reagent/iron = 5, /datum/reagent/silicon = 5)
+/obj/item/stock_parts/power_store/cell/Initialize(mapload)
+ . = ..()
+ ADD_TRAIT(src, TRAIT_FISHING_BAIT, INNATE_TRAIT)
+ ADD_TRAIT(src, TRAIT_POISONOUS_BAIT, INNATE_TRAIT) //bro is fishing using lithium...
+
/* Cell variants*/
/obj/item/stock_parts/power_store/cell/empty
empty = TRUE
@@ -221,9 +226,6 @@
custom_materials = null
grind_results = null
-/obj/item/stock_parts/power_store/cell/inducer_supply
- maxcharge = STANDARD_CELL_CHARGE * 5
-
/obj/item/stock_parts/power_store/cell/ethereal
name = "ahelp it"
desc = "you sohuldn't see this"
diff --git a/code/modules/power/gravitygenerator.dm b/code/modules/power/gravitygenerator.dm
index ecab6e4eee9a1..4cfce3c5bc90a 100644
--- a/code/modules/power/gravitygenerator.dm
+++ b/code/modules/power/gravitygenerator.dm
@@ -289,7 +289,7 @@ GLOBAL_LIST_EMPTY(gravity_generators)
return data
-/obj/machinery/gravity_generator/main/ui_act(action, params)
+/obj/machinery/gravity_generator/main/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/power/pipecleaners.dm b/code/modules/power/pipecleaners.dm
index 4c91301978940..4700004904796 100644
--- a/code/modules/power/pipecleaners.dm
+++ b/code/modules/power/pipecleaners.dm
@@ -233,7 +233,7 @@ By design, d1 is the smallest direction and d2 is the highest
return FALSE
if(!user.is_holding(src))
return FALSE
- if(user.incapacitated())
+ if(user.incapacitated)
return FALSE
return TRUE
diff --git a/code/modules/power/port_gen.dm b/code/modules/power/port_gen.dm
index c5353ce62d537..e27ea98f8ca5f 100644
--- a/code/modules/power/port_gen.dm
+++ b/code/modules/power/port_gen.dm
@@ -10,7 +10,7 @@
use_power = NO_POWER_USE
var/active = FALSE
- var/power_gen = 5000
+ var/power_gen = 5 KILO JOULES
var/power_output = 1
var/consumption = 0
var/datum/looping_sound/generator/soundloop
@@ -81,13 +81,13 @@
/obj/machinery/power/port_gen/pacman
name = "\improper P.A.C.M.A.N.-type portable generator"
circuit = /obj/item/circuitboard/machine/pacman
- power_gen = 5000
+ power_gen = 10 KILO JOULES
var/sheets = 0
var/max_sheets = 50
var/sheet_name = ""
var/sheet_path = /obj/item/stack/sheet/mineral/plasma
var/sheet_left = 0 // How much is left of the sheet
- var/time_per_sheet = 60
+ var/time_per_sheet = 180
var/current_heat = 0
/obj/machinery/power/port_gen/pacman/Initialize(mapload)
@@ -108,8 +108,8 @@
icon_state = "portgen1_0"
base_icon_state = "portgen1"
max_sheets = 20
- time_per_sheet = 20
- power_gen = 15000
+ time_per_sheet = 60
+ power_gen = 30 KILO JOULES
sheet_path = /obj/item/stack/sheet/mineral/uranium
/obj/machinery/power/port_gen/pacman/examine(mob/user)
@@ -246,7 +246,7 @@
data["current_heat"] = current_heat
. = data
-/obj/machinery/power/port_gen/pacman/ui_act(action, params)
+/obj/machinery/power/port_gen/pacman/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
@@ -274,8 +274,8 @@
icon_state = "portgen1_0"
base_icon_state = "portgen1"
max_sheets = 20
- time_per_sheet = 20
- power_gen = 15000
+ time_per_sheet = 60
+ power_gen = 30 KILO JOULES
sheet_path = /obj/item/stack/sheet/mineral/uranium
/obj/machinery/power/port_gen/pacman/pre_loaded
diff --git a/code/modules/power/singularity/emitter.dm b/code/modules/power/singularity/emitter.dm
index 562bf4c0825cd..b288fd6aa87cd 100644
--- a/code/modules/power/singularity/emitter.dm
+++ b/code/modules/power/singularity/emitter.dm
@@ -421,7 +421,7 @@
. = ..()
/obj/machinery/power/emitter/prototype/user_buckle_mob(mob/living/buckled_mob, mob/user, check_loc = TRUE)
- if(user.incapacitated() || !istype(user))
+ if(user.incapacitated || !istype(user))
return
for(var/atom/movable/atom in get_turf(src))
if(atom.density && (atom != src && atom != buckled_mob))
diff --git a/code/modules/power/smes.dm b/code/modules/power/smes.dm
index 935601b834bc3..f74a93e263da4 100644
--- a/code/modules/power/smes.dm
+++ b/code/modules/power/smes.dm
@@ -121,7 +121,7 @@
if(isnull(choice) \
|| !user.is_holding(item) \
|| !user.Adjacent(src) \
- || user.incapacitated() \
+ || user.incapacitated \
|| !can_place_terminal(user, item, silent = TRUE) \
)
return
@@ -366,7 +366,7 @@
)
return data
-/obj/machinery/power/smes/ui_act(action, params)
+/obj/machinery/power/smes/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/power/solar.dm b/code/modules/power/solar.dm
index 370140a4f74cd..cd36823a207e9 100644
--- a/code/modules/power/solar.dm
+++ b/code/modules/power/solar.dm
@@ -486,7 +486,7 @@
data["history"] = history
return data
-/obj/machinery/power/solar_control/ui_act(action, params)
+/obj/machinery/power/solar_control/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/power/supermatter/supermatter_extra_effects.dm b/code/modules/power/supermatter/supermatter_extra_effects.dm
index 35c96d298dd34..b6cc1b792bdcf 100644
--- a/code/modules/power/supermatter/supermatter_extra_effects.dm
+++ b/code/modules/power/supermatter/supermatter_extra_effects.dm
@@ -173,7 +173,7 @@
if(VORTEX_ANOMALY)
new /obj/effect/anomaly/bhole(local_turf, 20, FALSE)
if(BIOSCRAMBLER_ANOMALY)
- new /obj/effect/anomaly/bioscrambler(local_turf, null, FALSE)
+ new /obj/effect/anomaly/bioscrambler/docile(local_turf, null, FALSE)
#undef CHANCE_EQUATION_SLOPE
#undef INTEGRITY_EXPONENTIAL_DEGREE
diff --git a/code/modules/power/turbine/turbine_computer.dm b/code/modules/power/turbine/turbine_computer.dm
index f983e11c1f128..2ad777edd6228 100644
--- a/code/modules/power/turbine/turbine_computer.dm
+++ b/code/modules/power/turbine/turbine_computer.dm
@@ -68,7 +68,7 @@
return data
-/obj/machinery/computer/turbine_computer/ui_act(action, params)
+/obj/machinery/computer/turbine_computer/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/projectiles/ammunition/_ammunition.dm b/code/modules/projectiles/ammunition/_ammunition.dm
index 45e09db624caf..42751441fca4f 100644
--- a/code/modules/projectiles/ammunition/_ammunition.dm
+++ b/code/modules/projectiles/ammunition/_ammunition.dm
@@ -32,6 +32,12 @@
var/firing_effect_type = /obj/effect/temp_visual/dir_setting/firing_effect
///pacifism check for boolet, set to FALSE if bullet is non-lethal
var/harmful = TRUE
+ ///If set to true or false, this ammunition can or cannot misfire, regardless the gun can_misfire setting
+ var/can_misfire = null
+ ///This is how much misfire probability is added to the gun when it fires this casing.
+ var/misfire_increment = 0
+ ///If set, this casing will damage any gun it's fired from by the specified amount
+ var/integrity_damage = 0
/obj/item/ammo_casing/spent
name = "spent bullet casing"
diff --git a/code/modules/projectiles/ammunition/_firing.dm b/code/modules/projectiles/ammunition/_firing.dm
index e2afc1bd67e7f..282c722b169e6 100644
--- a/code/modules/projectiles/ammunition/_firing.dm
+++ b/code/modules/projectiles/ammunition/_firing.dm
@@ -52,12 +52,19 @@
loaded_projectile.suppressed = quiet
if(isgun(fired_from))
- var/obj/item/gun/G = fired_from
- loaded_projectile.damage *= G.projectile_damage_multiplier
- loaded_projectile.stamina *= G.projectile_damage_multiplier
+ var/obj/item/gun/gun = fired_from
- loaded_projectile.wound_bonus += G.projectile_wound_bonus
- loaded_projectile.bare_wound_bonus += G.projectile_wound_bonus
+ var/integrity_mult = 0.5 + gun.get_integrity_percentage() * 0.5
+ if(integrity_mult >= 0.95) //Guns that are only mildly smudged don't debuff projectiles.
+ integrity_mult = 1
+
+ loaded_projectile.damage *= gun.projectile_damage_multiplier * integrity_mult
+ loaded_projectile.stamina *= gun.projectile_damage_multiplier * integrity_mult
+
+ loaded_projectile.wound_bonus += gun.projectile_wound_bonus
+ loaded_projectile.wound_bonus *= loaded_projectile.wound_bonus >= 0 ? 1 : 2 - integrity_mult
+ loaded_projectile.bare_wound_bonus += gun.projectile_wound_bonus
+ loaded_projectile.bare_wound_bonus *= loaded_projectile.bare_wound_bonus >= 0 ? 1 : 2 - integrity_mult
if(tk_firing(user, fired_from))
loaded_projectile.ignore_source_check = TRUE
diff --git a/code/modules/projectiles/ammunition/ballistic/shotgun.dm b/code/modules/projectiles/ammunition/ballistic/shotgun.dm
index b7cda3e93e1a8..84c75ed24935e 100644
--- a/code/modules/projectiles/ammunition/ballistic/shotgun.dm
+++ b/code/modules/projectiles/ammunition/ballistic/shotgun.dm
@@ -82,6 +82,20 @@
pellets = 6
variance = 25
+/obj/item/ammo_casing/shotgun/buckshot/old
+ projectile_type = /obj/projectile/bullet/pellet/shotgun_buckshot/old
+ can_misfire = TRUE
+ misfire_increment = 2
+ integrity_damage = 4
+
+/obj/item/ammo_casing/shotgun/buckshot/old/fire_casing(atom/target, mob/living/user, params, distro, quiet, zone_override, spread, atom/fired_from)
+ . = ..()
+ if(!fired_from)
+ return
+
+ var/datum/effect_system/fluid_spread/smoke/smoke = new
+ smoke.set_up(0, holder = fired_from, location = fired_from)
+
/obj/item/ammo_casing/shotgun/buckshot/spent
projectile_type = null
diff --git a/code/modules/projectiles/ammunition/energy/laser.dm b/code/modules/projectiles/ammunition/energy/laser.dm
index 0b1623e9877ab..a77dcfec663b1 100644
--- a/code/modules/projectiles/ammunition/energy/laser.dm
+++ b/code/modules/projectiles/ammunition/energy/laser.dm
@@ -53,6 +53,7 @@
/obj/item/ammo_casing/energy/chameleon
projectile_type = /obj/projectile/energy/chameleon
e_cost = 0 // Can't really use the macro here, unfortunately
+ harmful = FALSE
var/projectile_vars = list()
/obj/item/ammo_casing/energy/chameleon/ready_proj()
diff --git a/code/modules/projectiles/boxes_magazines/internal/rifle.dm b/code/modules/projectiles/boxes_magazines/internal/rifle.dm
index b092e207c10d6..b1f761831ee62 100644
--- a/code/modules/projectiles/boxes_magazines/internal/rifle.dm
+++ b/code/modules/projectiles/boxes_magazines/internal/rifle.dm
@@ -60,5 +60,5 @@
/obj/item/ammo_box/magazine/internal/boltaction/rebarxbow/syndie
max_ammo = 3
caliber = CALIBER_REBAR_SYNDIE
- ammo_type = /obj/item/ammo_casing/rebar
+ ammo_type = /obj/item/ammo_casing/rebar/syndie
diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm
index 1452d879799fa..190f9e1a7aca8 100644
--- a/code/modules/projectiles/gun.dm
+++ b/code/modules/projectiles/gun.dm
@@ -153,6 +153,15 @@
else
. += "It doesn't have a firing pin installed, and won't fire."
+ var/healthpercent = (atom_integrity/max_integrity) * 100
+ switch(healthpercent)
+ if(60 to 95)
+ . += span_info("It looks slightly damaged.")
+ if(25 to 60)
+ . += span_warning("It appears heavily damaged.")
+ if(0 to 25)
+ . += span_boldwarning("It's falling apart!")
+
//called after the gun has successfully fired its chambered ammo.
/obj/item/gun/proc/process_chamber(empty_chamber = TRUE, from_firing = TRUE, chamber_next_round = TRUE)
handle_chamber(empty_chamber, from_firing, chamber_next_round)
@@ -179,36 +188,48 @@
else
playsound(src, fire_sound, fire_sound_volume, vary_fire_sound)
-/obj/item/gun/proc/shoot_live_shot(mob/living/user, pointblank = 0, atom/pbtarget = null, message = 1)
+/obj/item/gun/proc/shoot_live_shot(mob/living/user, pointblank = FALSE, atom/pbtarget = null, message = TRUE)
if(recoil && !tk_firing(user))
shake_camera(user, recoil + 1, recoil)
fire_sounds()
- if(!suppressed)
- if(message)
- if(tk_firing(user))
- visible_message(
- span_danger("[src] fires itself[pointblank ? " point blank at [pbtarget]!" : "!"]"),
- blind_message = span_hear("You hear a gunshot!"),
- vision_distance = COMBAT_MESSAGE_RANGE
- )
- else if(pointblank)
- user.visible_message(
- span_danger("[user] fires [src] point blank at [pbtarget]!"),
- span_danger("You fire [src] point blank at [pbtarget]!"),
- span_hear("You hear a gunshot!"), COMBAT_MESSAGE_RANGE, pbtarget
- )
- to_chat(pbtarget, span_userdanger("[user] fires [src] point blank at you!"))
- if(pb_knockback > 0 && ismob(pbtarget))
- var/mob/PBT = pbtarget
- var/atom/throw_target = get_edge_target_turf(PBT, user.dir)
- PBT.throw_at(throw_target, pb_knockback, 2)
- else if(!tk_firing(user))
- user.visible_message(
- span_danger("[user] fires [src]!"),
- blind_message = span_hear("You hear a gunshot!"),
- vision_distance = COMBAT_MESSAGE_RANGE,
- ignored_mobs = user
- )
+ if(suppressed || !message)
+ return
+ if(tk_firing(user))
+ visible_message(
+ span_danger("[src] fires itself[pointblank ? " point blank at [pbtarget]!" : "!"]"),
+ blind_message = span_hear("You hear a gunshot!"),
+ vision_distance = COMBAT_MESSAGE_RANGE
+ )
+ else if(pointblank)
+ user.visible_message(
+ span_danger("[user] fires [src] point blank at [pbtarget]!"),
+ span_danger("You fire [src] point blank at [pbtarget]!"),
+ span_hear("You hear a gunshot!"), COMBAT_MESSAGE_RANGE, pbtarget
+ )
+ to_chat(pbtarget, span_userdanger("[user] fires [src] point blank at you!"))
+ if(pb_knockback > 0 && ismob(pbtarget))
+ var/mob/PBT = pbtarget
+ var/atom/throw_target = get_edge_target_turf(PBT, user.dir)
+ PBT.throw_at(throw_target, pb_knockback, 2)
+ else if(!tk_firing(user))
+ user.visible_message(
+ span_danger("[user] fires [src]!"),
+ blind_message = span_hear("You hear a gunshot!"),
+ vision_distance = COMBAT_MESSAGE_RANGE,
+ ignored_mobs = user
+ )
+
+ if(chambered?.integrity_damage)
+ take_damage(chambered.integrity_damage, sound_effect = FALSE)
+
+/obj/item/gun/atom_destruction(damage_flag)
+ if(!isliving(loc))
+ return ..()
+ var/mob/living/holder = loc
+ if(holder.is_holding(src) && holder.stat < UNCONSCIOUS)
+ to_chat(holder, span_boldwarning("[src] breaks down!"))
+ holder.playsound_local(get_turf(src), 'sound/weapons/smash.ogg', 50, TRUE)
+ return ..()
/obj/item/gun/emp_act(severity)
. = ..()
@@ -403,9 +424,9 @@
return FALSE
else
if(get_dist(user, target) <= 1) //Making sure whether the target is in vicinity for the pointblank shot
- shoot_live_shot(user, 1, target, message)
+ shoot_live_shot(user, TRUE, target, message)
else
- shoot_live_shot(user, 0, target, message)
+ shoot_live_shot(user, FALSE, target, message)
if (iteration >= burst_size)
firing_burst = FALSE
else
@@ -459,9 +480,9 @@
return
else
if(get_dist(user, target) <= 1) //Making sure whether the target is in vicinity for the pointblank shot
- shoot_live_shot(user, 1, target, message)
+ shoot_live_shot(user, TRUE, target, message)
else
- shoot_live_shot(user, 0, target, message)
+ shoot_live_shot(user, FALSE, target, message)
else
shoot_with_empty_chamber(user)
return
diff --git a/code/modules/projectiles/guns/ballistic.dm b/code/modules/projectiles/guns/ballistic.dm
index 8a8b4dbacfccc..2d77185f1d255 100644
--- a/code/modules/projectiles/guns/ballistic.dm
+++ b/code/modules/projectiles/guns/ballistic.dm
@@ -7,6 +7,7 @@
w_class = WEIGHT_CLASS_NORMAL
pickup_sound = 'sound/items/gun_pick_up.ogg'
drop_sound = 'sound/items/gun_drop.ogg'
+ sound_vary = TRUE
///sound when inserting magazine
var/load_sound = 'sound/weapons/gun/general/magazine_insert_full.ogg'
@@ -451,7 +452,7 @@
if (sawoff(user, A))
return
- if(can_misfire && istype(A, /obj/item/stack/sheet/cloth))
+ if(misfire_probability && istype(A, /obj/item/stack/sheet/cloth))
if(guncleaning(user, A))
return
@@ -463,7 +464,8 @@
return TRUE
/obj/item/gun/ballistic/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
- if(target != user && chambered.loaded_projectile && can_misfire && prob(misfire_probability) && blow_up(user))
+ var/could_it_misfire = (can_misfire && chambered.can_misfire != FALSE) || chambered.can_misfire
+ if(target != user && chambered.loaded_projectile && could_it_misfire && prob(misfire_probability) && blow_up(user))
to_chat(user, span_userdanger("[src] misfires!"))
return
@@ -473,9 +475,14 @@
return ..()
/obj/item/gun/ballistic/shoot_live_shot(mob/living/user, pointblank = 0, atom/pbtarget = null, message = 1)
- if(can_misfire)
+ if(isnull(chambered))
+ return ..()
+ if(can_misfire && chambered.can_misfire != FALSE)
misfire_probability += misfire_percentage_increment
misfire_probability = clamp(misfire_probability, 0, misfire_probability_cap)
+ if(chambered.can_misfire)
+ misfire_probability += chambered.misfire_increment
+ misfire_probability = clamp(misfire_probability, 0, misfire_probability_cap)
return ..()
///Installs a new suppressor, assumes that the suppressor is already in the contents of src
@@ -579,6 +586,9 @@
. += span_danger("You get the feeling this might explode if you fire it...")
if(misfire_probability > 0)
. += span_danger("Given the state of the gun, there is a [misfire_probability]% chance it'll misfire.")
+ else if(misfire_probability > 0)
+ . += span_warning("You get a feeling this might explode if you fire it with the wrong ammunitions...")
+ . += span_warning("Given the state of the gun, there is a [EXAMINE_HINT("[misfire_probability]%")] chance it'll misfire.")
///Gets the number of bullets in the gun
/obj/item/gun/ballistic/proc/get_ammo(countchambered = TRUE)
diff --git a/code/modules/projectiles/guns/ballistic/revolver.dm b/code/modules/projectiles/guns/ballistic/revolver.dm
index f7d9ed19cbea5..cd7d75556727b 100644
--- a/code/modules/projectiles/guns/ballistic/revolver.dm
+++ b/code/modules/projectiles/guns/ballistic/revolver.dm
@@ -137,7 +137,7 @@
/obj/item/gun/ballistic/revolver/syndicate
name = "\improper Syndicate Revolver"
- desc = "A modernized 7 round revolver manufactured by Waffle Co. Uses .357 ammo."
+ desc = "A modernized 7 round revolver manufactured by Waffle Corp. Uses .357 ammo."
icon_state = "revolversyndie"
/obj/item/gun/ballistic/revolver/syndicate/nuclear
diff --git a/code/modules/projectiles/guns/ballistic/rifle.dm b/code/modules/projectiles/guns/ballistic/rifle.dm
index 024f8353ddb48..a79d4db30825e 100644
--- a/code/modules/projectiles/guns/ballistic/rifle.dm
+++ b/code/modules/projectiles/guns/ballistic/rifle.dm
@@ -201,10 +201,9 @@
inhand_icon_state = "rebarxbow"
worn_icon_state = "rebarxbow"
rack_sound = 'sound/weapons/gun/sniper/rack.ogg'
- must_hold_to_load = TRUE
mag_display = FALSE
empty_indicator = TRUE
- bolt_type = BOLT_TYPE_LOCKING
+ bolt_type = BOLT_TYPE_OPEN
semi_auto = FALSE
internal_magazine = TRUE
can_modify_ammo = FALSE
@@ -250,10 +249,22 @@
return FALSE
return ..()
+/obj/item/gun/ballistic/rifle/rebarxbow/shoot_with_empty_chamber(mob/living/user)
+ if(chambered || !magazine || !length(magazine.contents))
+ return ..()
+ drop_bolt(user)
+
/obj/item/gun/ballistic/rifle/rebarxbow/examine(mob/user)
. = ..()
. += "The crossbow is [bolt_locked ? "not ready" : "ready"] to fire."
+/obj/item/gun/ballistic/rifle/rebarxbow/update_overlays()
+ . = ..()
+ if(!magazine)
+ . += "[initial(icon_state)]" + "_empty"
+ if(!bolt_locked)
+ . += "[initial(icon_state)]" + "_bolt_locked"
+
/obj/item/gun/ballistic/rifle/rebarxbow/forced
name = "Stressed Rebar Crossbow"
desc = "Some idiot decided that they would risk shooting themselves in the face if it meant they could have a draw this crossbow a bit faster. Hopefully, it was worth it."
diff --git a/code/modules/projectiles/guns/ballistic/shotgun.dm b/code/modules/projectiles/guns/ballistic/shotgun.dm
index 9f854926dbdff..9be59ffb5344b 100644
--- a/code/modules/projectiles/guns/ballistic/shotgun.dm
+++ b/code/modules/projectiles/guns/ballistic/shotgun.dm
@@ -24,6 +24,7 @@
cartridge_wording = "shell"
tac_reloads = FALSE
weapon_weight = WEAPON_HEAVY
+ misfire_probability_cap = 35 // Even if the misfire probability and increment are both zero, we've some shots that may do that.
pb_knockback = 2
diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm
index 9c16133e1ea35..39e55f94fca17 100644
--- a/code/modules/projectiles/guns/energy.dm
+++ b/code/modules/projectiles/guns/energy.dm
@@ -5,6 +5,7 @@
icon = 'icons/obj/weapons/guns/energy.dmi'
pickup_sound = 'sound/items/gun_pick_up.ogg'
drop_sound = 'sound/items/gun_drop.ogg'
+ sound_vary = TRUE
/// What type of power cell this uses
var/obj/item/stock_parts/power_store/cell
diff --git a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
index 53cbe825085b2..1180a90e8d217 100644
--- a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
+++ b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
@@ -123,7 +123,7 @@
/obj/item/gun/energy/recharge/kinetic_accelerator/proc/check_menu(mob/living/carbon/human/user)
if(!istype(user))
return FALSE
- if(user.incapacitated())
+ if(user.incapacitated)
return FALSE
return TRUE
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index c501f15db90e6..5e06f115acea3 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -209,6 +209,10 @@
var/wound_falloff_tile
///How much we want to drop the embed_chance value, if we can embed, per tile, for falloff purposes
var/embed_falloff_tile
+ ///How much accuracy is lost for each tile travelled
+ var/accuracy_falloff = 7
+ ///How much accuracy before falloff starts to matter. Formula is range - falloff * tiles travelled
+ var/accurate_range = 100
var/static/list/projectile_connections = list(COMSIG_ATOM_ENTERED = PROC_REF(on_entered))
/// If true directly targeted turfs can be hit
var/can_hit_turfs = FALSE
@@ -296,6 +300,12 @@
hitx = target.pixel_x + rand(-8, 8)
hity = target.pixel_y + rand(-8, 8)
+ if(isturf(target) && hitsound_wall)
+ var/volume = clamp(vol_by_damage() + 20, 0, 100)
+ if(suppressed)
+ volume = 5
+ playsound(loc, hitsound_wall, volume, TRUE, -1)
+
if(damage > 0 && (damage_type == BRUTE || damage_type == BURN) && iswallturf(target_turf) && prob(75))
var/turf/closed/wall/target_wall = target_turf
if(impact_effect_type && !hitscan)
@@ -308,11 +318,7 @@
if(!isliving(target))
if(impact_effect_type && !hitscan)
new impact_effect_type(target_turf, hitx, hity)
- if(isturf(target) && hitsound_wall)
- var/volume = clamp(vol_by_damage() + 20, 0, 100)
- if(suppressed)
- volume = 5
- playsound(loc, hitsound_wall, volume, TRUE, -1)
+
return BULLET_ACT_HIT
var/mob/living/living_target = target
@@ -450,9 +456,8 @@
store_hitscan_collision(point_cache)
return TRUE
- if(!HAS_TRAIT(src, TRAIT_ALWAYS_HIT_ZONE))
- var/distance = get_dist(T, starting) // Get the distance between the turf shot from and the mob we hit and use that for the calculations.
- def_zone = ran_zone(def_zone, max(100-(7*distance), 5)) //Lower accurancy/longer range tradeoff. 7 is a balanced number to use.
+ var/distance = get_dist(T, starting) // Get the distance between the turf shot from and the mob we hit and use that for the calculations.
+ def_zone = ran_zone(def_zone, clamp(accurate_range - (accuracy_falloff * distance), 5, 100)) //Lower accurancy/longer range tradeoff. 7 is a balanced number to use.
return process_hit(T, select_target(T, A, A), A) // SELECT TARGET FIRST!
@@ -569,6 +574,9 @@
if((target.pass_flags_self & pass_flags) && !direct_target)
return FALSE
if(HAS_TRAIT(target, TRAIT_UNHITTABLE_BY_PROJECTILES))
+ if(!HAS_TRAIT(target, TRAIT_BLOCKING_PROJECTILES) && isliving(target))
+ var/mob/living/living_target = target
+ living_target.block_projectile_effects()
return FALSE
if(!ignore_source_check && firer)
var/mob/M = firer
diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm
index 542c2aaa35d92..0e50326f1b07c 100644
--- a/code/modules/projectiles/projectile/beams.dm
+++ b/code/modules/projectiles/projectile/beams.dm
@@ -50,13 +50,11 @@
//overclocked laser, does a bit more damage but has much higher wound power (-0 vs -20)
/obj/projectile/beam/laser/hellfire
name = "hellfire laser"
+ icon_state = "hellfire"
wound_bonus = 0
damage = 30
speed = 0.6 // higher power = faster, that's how light works right
-
-/obj/projectile/beam/laser/hellfire/Initialize(mapload)
- . = ..()
- transform *= 2
+ light_color = "#FF969D"
/obj/projectile/beam/laser/heavylaser
name = "heavy laser"
diff --git a/code/modules/projectiles/projectile/bullets/rifle.dm b/code/modules/projectiles/projectile/bullets/rifle.dm
index 6f14df2f4c8bd..2915e3e59bd6c 100644
--- a/code/modules/projectiles/projectile/bullets/rifle.dm
+++ b/code/modules/projectiles/projectile/bullets/rifle.dm
@@ -140,27 +140,38 @@
/obj/projectile/bullet/rebar/hydrogen
name = "metallic hydrogen bolt"
icon_state = "rebar_hydrogen"
- damage = 40
+ damage = 55
speed = 0.6
+ projectile_piercing = PASSMOB|PASSVEHICLE
+ projectile_phasing = ~(PASSMOB|PASSVEHICLE)
+ phasing_ignore_direct_target = TRUE
dismemberment = 0 //goes through clean.
damage_type = BRUTE
armour_penetration = 30 //very pointy.
- projectile_piercing = PASSMOB //felt this might have been a nice compromise for the lower damage for the difficulty of getting it
wound_bonus = -15
bare_wound_bonus = 10
+ shrapnel_type = /obj/item/ammo_casing/rebar/hydrogen
embed_type = /datum/embed_data/rebar_hydrogen
embed_falloff_tile = -3
shrapnel_type = /obj/item/ammo_casing/rebar/hydrogen
+ accurate_range = 205 //15 tiles before falloff starts to kick in
+
+/obj/projectile/bullet/rebar/hydrogen/Impact(atom/A)
+ . = ..()
+ def_zone = ran_zone(def_zone, clamp(205-(7*get_dist(get_turf(A), starting)), 5, 100))
/datum/embed_data/rebar_hydrogen
- embed_chance = 50
- fall_chance = 2
- jostle_chance = 3
- ignore_throwspeed_threshold = TRUE
- pain_stam_pct = 0.6
- pain_mult = 4
- jostle_pain_mult = 2
- rip_time =18
+ embed_chance = 0
+
+/obj/projectile/bullet/rebar/hydrogen/on_hit(atom/target, blocked, pierce_hit)
+ if(isAI(target))
+ return BULLET_ACT_FORCE_PIERCE
+ return ..()
+
+/obj/projectile/bullet/rebar/hydrogen/process_hit(turf/T, atom/target, atom/bumped, hit_something)
+ . = ..()
+ if(pierces >= 3)
+ qdel(src)
/obj/projectile/bullet/rebar/healium
name = "healium bolt"
diff --git a/code/modules/projectiles/projectile/bullets/shotgun.dm b/code/modules/projectiles/projectile/bullets/shotgun.dm
index 7ae5741f3b992..215093c9f100e 100644
--- a/code/modules/projectiles/projectile/bullets/shotgun.dm
+++ b/code/modules/projectiles/projectile/bullets/shotgun.dm
@@ -79,6 +79,15 @@
bare_wound_bonus = 5
wound_falloff_tile = -2.5 // low damage + additional dropoff will already curb wounding potential anything past point blank
+/**
+ * A slightly weaker version of the buckshot, available from the blackmarket.
+ * The casings they're in have a very small chance to misfire and will gradually damage the firearm, making it weaker.
+ */
+/obj/projectile/bullet/pellet/shotgun_buckshot/old
+ damage_falloff_tile = -0.47
+ wound_bonus = -100
+ bare_wound_bonus = -100
+
/obj/projectile/bullet/pellet/shotgun_rubbershot
name = "rubber shot pellet"
damage = 3
diff --git a/code/modules/reagents/chemistry/holder/holder.dm b/code/modules/reagents/chemistry/holder/holder.dm
index 11117142d70e5..f084a7eaa39d4 100644
--- a/code/modules/reagents/chemistry/holder/holder.dm
+++ b/code/modules/reagents/chemistry/holder/holder.dm
@@ -344,26 +344,29 @@
stack_trace("invalid reagent path passed to convert reagent [source_reagent_typepath]")
return FALSE
- var/reagent_amount
- var/reagent_purity
- var/reagent_ph
+ var/reagent_amount = 0
+ var/reagent_purity = 0
+ var/reagent_ph = 0
if(include_source_subtypes)
reagent_ph = ph
var/weighted_purity
var/list/reagent_type_list = typecacheof(source_reagent_typepath)
for(var/datum/reagent/reagent as anything in reagent_list)
- if(reagent.type in reagent_type_list)
+ if(is_type_in_typecache(reagent, reagent_type_list))
weighted_purity += reagent.volume * reagent.purity
reagent_amount += reagent.volume
remove_reagent(reagent.type, reagent.volume * multiplier)
reagent_purity = weighted_purity / reagent_amount
else
var/datum/reagent/source_reagent = has_reagent(source_reagent_typepath)
- reagent_amount = source_reagent.volume
- reagent_purity = source_reagent.purity
- reagent_ph = source_reagent.ph
- remove_reagent(source_reagent_typepath, reagent_amount)
- add_reagent(target_reagent_typepath, reagent_amount * multiplier, reagtemp = chem_temp, added_purity = reagent_purity, added_ph = reagent_ph)
+ if(istype(source_reagent))
+ reagent_amount = source_reagent.volume
+ reagent_purity = source_reagent.purity
+ reagent_ph = source_reagent.ph
+ remove_reagent(source_reagent_typepath, reagent_amount)
+
+ if(reagent_amount > 0)
+ add_reagent(target_reagent_typepath, reagent_amount * multiplier, reagtemp = chem_temp, added_purity = reagent_purity, added_ph = reagent_ph)
/// Removes all reagents
/datum/reagents/proc/clear_reagents()
diff --git a/code/modules/reagents/chemistry/holder/ui_data.dm b/code/modules/reagents/chemistry/holder/ui_data.dm
index 97820c2fd6c0e..244b264721fd2 100644
--- a/code/modules/reagents/chemistry/holder/ui_data.dm
+++ b/code/modules/reagents/chemistry/holder/ui_data.dm
@@ -297,7 +297,7 @@
var/datum/chemical_reaction/reaction = sub_reactions[ui_reaction_index]
return reaction.type
-/datum/reagents/ui_act(action, params)
+/datum/reagents/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
index cf193decb6931..5f665d876afaa 100644
--- a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
+++ b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
@@ -572,6 +572,7 @@
/obj/machinery/chem_dispenser/drinks/fullupgrade //fully ugpraded stock parts, emagged
desc = "Contains a large reservoir of soft drinks. This model has had its safeties shorted out."
obj_flags = CAN_BE_HIT | EMAGGED
+ circuit = /obj/item/circuitboard/machine/chem_dispenser/drinks/fullupgrade
/obj/machinery/chem_dispenser/drinks/fullupgrade/Initialize(mapload)
. = ..()
diff --git a/code/modules/reagents/chemistry/machinery/pandemic.dm b/code/modules/reagents/chemistry/machinery/pandemic.dm
index dca2b603ca40f..c9ad2424b2de7 100644
--- a/code/modules/reagents/chemistry/machinery/pandemic.dm
+++ b/code/modules/reagents/chemistry/machinery/pandemic.dm
@@ -153,7 +153,7 @@
data["resistances"] = get_resistance_data(blood)
return data
-/obj/machinery/computer/pandemic/ui_act(action, params)
+/obj/machinery/computer/pandemic/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/reagents/chemistry/machinery/portable_chem_mixer.dm b/code/modules/reagents/chemistry/machinery/portable_chem_mixer.dm
index 9c92cc631be79..21f23a209b6b7 100644
--- a/code/modules/reagents/chemistry/machinery/portable_chem_mixer.dm
+++ b/code/modules/reagents/chemistry/machinery/portable_chem_mixer.dm
@@ -1,5 +1,5 @@
/obj/item/storage/portable_chem_mixer
- name = "Portable Chemical Mixer"
+ name = "portable chemical mixer"
desc = "A portable device that dispenses and mixes chemicals using the beakers inserted inside."
icon = 'icons/obj/medical/chemical.dmi'
icon_state = "portablechemicalmixer_open"
@@ -132,10 +132,12 @@
return
beaker = new_beaker
-/obj/item/storage/portable_chem_mixer/ui_interact(mob/user, datum/tgui/ui)
+/obj/item/storage/portable_chem_mixer/ui_status(mob/user, datum/ui_state/state)
if(loc != user)
- balloon_alert(user, "hold it in your hand!")
- return
+ return UI_CLOSE
+ return ..()
+
+/obj/item/storage/portable_chem_mixer/ui_interact(mob/user, datum/tgui/ui)
if(!atom_storage.locked)
balloon_alert(user, "lock it first!")
return
diff --git a/code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm
index 3f5b7e3a24479..ca416d53adf03 100644
--- a/code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm
@@ -344,6 +344,28 @@
taste_description = "spiked butterscotch"
ph = 6.5
default_container = /obj/item/reagent_containers/cup/glass/bottle/rum
+ chemical_flags = REAGENT_CAN_BE_SYNTHESIZED
+
+/datum/reagent/consumable/ethanol/rum/aged
+ name = "Aged Rum"
+ description = "Sink me! That's some fancy rum to share with buckoos."
+ color = "#c0b675" // rgb: 192,183,117
+ boozepwr = 70
+ taste_description = "extra-spiked butterscotch"
+ default_container = /obj/item/reagent_containers/cup/glass/bottle/rum/aged
+ quality = DRINK_FANTASTIC
+ metabolized_traits = list(TRAIT_STRONG_STOMACH)
+
+/datum/reagent/consumable/ethanol/rum/aged/on_mob_metabolize(mob/living/drinker)
+ . = ..()
+ drinker.add_blocked_language(subtypesof(/datum/language) - /datum/language/piratespeak, LANGUAGE_DRINK)
+ drinker.grant_language(/datum/language/piratespeak, source = LANGUAGE_DRINK)
+
+/datum/reagent/consumable/ethanol/rum/aged/on_mob_end_metabolize(mob/living/drinker)
+ if(!QDELING(drinker))
+ drinker.remove_blocked_language(subtypesof(/datum/language), LANGUAGE_DRINK)
+ drinker.remove_language(/datum/language/piratespeak, source = LANGUAGE_DRINK)
+ return ..()
/datum/reagent/consumable/ethanol/tequila
name = "Tequila"
diff --git a/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm b/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm
index d3070474558d7..47456020da05e 100644
--- a/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm
@@ -650,13 +650,13 @@
. = ..()
affected_mob.adjust_drowsiness(3 SECONDS * REM * seconds_per_tick)
var/need_mob_update
- switch(affected_mob.mob_mood.sanity)
- if (SANITY_INSANE to SANITY_CRAZY)
- need_mob_update = affected_mob.adjustStaminaLoss(3 * REM * seconds_per_tick, updating_stamina = FALSE)
- if (SANITY_UNSTABLE to SANITY_DISTURBED)
- affected_mob.add_mood_event("wellcheers", /datum/mood_event/wellcheers)
- if (SANITY_NEUTRAL to SANITY_GREAT)
+ switch(affected_mob.mob_mood.sanity_level)
+ if (SANITY_LEVEL_GREAT to SANITY_LEVEL_NEUTRAL)
need_mob_update = affected_mob.adjustBruteLoss(-1.5 * REM * seconds_per_tick, updating_health = FALSE)
+ if (SANITY_LEVEL_DISTURBED to SANITY_LEVEL_UNSTABLE)
+ affected_mob.add_mood_event("wellcheers", /datum/mood_event/wellcheers)
+ if (SANITY_LEVEL_CRAZY to SANITY_LEVEL_INSANE)
+ need_mob_update = affected_mob.adjustStaminaLoss(3 * REM * seconds_per_tick, updating_stamina = FALSE)
if(need_mob_update)
return UPDATE_MOB_HEALTH
diff --git a/code/modules/reagents/chemistry/reagents/impure_reagents/impure_medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/impure_reagents/impure_medicine_reagents.dm
index 336ab2353947a..ce829a6ac1222 100644
--- a/code/modules/reagents/chemistry/reagents/impure_reagents/impure_medicine_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/impure_reagents/impure_medicine_reagents.dm
@@ -230,7 +230,7 @@ Basically, we fill the time between now and 2s from now with hands based off the
//Just the removed itching mechanism - omage to its origins.
/datum/reagent/inverse/ichiyuri/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired)
. = ..()
- if(prob(resetting_probability) && !(HAS_TRAIT(affected_mob, TRAIT_RESTRAINED) || affected_mob.incapacitated()))
+ if(prob(resetting_probability) && !(HAS_TRAIT(affected_mob, TRAIT_RESTRAINED) || affected_mob.incapacitated))
. = TRUE
if(spammer < world.time)
to_chat(affected_mob,span_warning("You can't help but itch yourself."))
@@ -783,7 +783,10 @@ Basically, we fill the time between now and 2s from now with hands based off the
if(!isnull(speaker) && HAS_TRAIT(speaker, TRAIT_SIGN_LANG))
return
- hearing_args[HEARING_SPANS] |= random_span
+ var/list/spans = hearing_args[HEARING_SPANS]
+ var/list/copied_spans = spans.Copy()
+ copied_spans |= random_span
+ hearing_args[HEARING_SPANS] = copied_spans
/datum/reagent/inverse/sal_acid
name = "Benzoic Acid"
diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm
index 1ecc9ca9b5db5..18d02ba2e31fc 100644
--- a/code/modules/reagents/chemistry/reagents/other_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm
@@ -1349,7 +1349,7 @@
/datum/reagent/space_cleaner/ez_clean
name = "EZ Clean"
- description = "A powerful, acidic cleaner sold by Waffle Co. Affects organic matter while leaving other objects unaffected."
+ description = "A powerful, acidic cleaner sold by Waffle Corp. Affects organic matter while leaving other objects unaffected."
metabolization_rate = 1.5 * REAGENTS_METABOLISM
taste_description = "acid"
penetrates_skin = VAPOR
diff --git a/code/modules/reagents/chemistry/recipes/others.dm b/code/modules/reagents/chemistry/recipes/others.dm
index cf9c7ae38c64e..bff4d526333be 100644
--- a/code/modules/reagents/chemistry/recipes/others.dm
+++ b/code/modules/reagents/chemistry/recipes/others.dm
@@ -38,6 +38,13 @@
results = list(/datum/reagent/consumable/salt = 2)
required_reagents = list(/datum/reagent/sodium = 1, /datum/reagent/chlorine = 1) // That's what I said! Sodium Chloride!
reaction_tags = REACTION_TAG_EASY | REACTION_TAG_FOOD
+ required_other = TRUE
+
+/datum/chemical_reaction/sodiumchloride/pre_reaction_other_checks(datum/reagents/holder)
+ . = ..()
+ if(holder.has_reagent(/datum/reagent/consumable/liquidelectricity) || holder.has_reagent(/datum/reagent/consumable/liquidelectricity/enriched))
+ return FALSE
+
/datum/chemical_reaction/stable_plasma
results = list(/datum/reagent/stable_plasma = 1)
@@ -600,6 +607,18 @@
results = list(/datum/reagent/oxygen = 2.5, /datum/reagent/hydrogen = 5)
required_reagents = list(/datum/reagent/consumable/liquidelectricity/enriched = 1, /datum/reagent/water = 5)
reaction_tags = REACTION_TAG_EASY | REACTION_TAG_CHEMICAL
+
+//salt electrolysis
+/datum/chemical_reaction/saltelectrolysis
+ results = list(/datum/reagent/chlorine = 2.5, /datum/reagent/sodium = 2.5)
+ required_reagents = list(/datum/reagent/consumable/salt = 5)
+ required_catalysts = list(/datum/reagent/consumable/liquidelectricity = 1)
+ reaction_tags = REACTION_TAG_EASY | REACTION_TAG_CHEMICAL
+
+/datum/chemical_reaction/saltelectrolysis/enriched
+ required_catalysts = list(/datum/reagent/consumable/liquidelectricity/enriched = 1)
+
+
//butterflium
/datum/chemical_reaction/butterflium
required_reagents = list(/datum/reagent/colorful_reagent = 1, /datum/reagent/medicine/omnizine = 1, /datum/reagent/medicine/strange_reagent = 1, /datum/reagent/consumable/nutriment = 1)
diff --git a/code/modules/reagents/reagent_containers/cups/_cup.dm b/code/modules/reagents/reagent_containers/cups/_cup.dm
index 87df7765233ec..5590be84f4386 100644
--- a/code/modules/reagents/reagent_containers/cups/_cup.dm
+++ b/code/modules/reagents/reagent_containers/cups/_cup.dm
@@ -161,7 +161,7 @@
to_chat(user, span_notice("You fill [src] with [trans] unit\s of the contents of [target]."))
target.update_appearance()
- return ITEM_INTERACT_SUCCESS
+ return NONE
/obj/item/reagent_containers/cup/attackby(obj/item/attacking_item, mob/user, params)
var/hotness = attacking_item.get_temperature()
@@ -230,6 +230,7 @@
fill_icon_thresholds = list(0, 1, 20, 40, 60, 80, 100)
pickup_sound = 'sound/items/handling/beaker_pickup.ogg'
drop_sound = 'sound/items/handling/beaker_place.ogg'
+ sound_vary = TRUE
/obj/item/reagent_containers/cup/beaker/Initialize(mapload)
. = ..()
diff --git a/code/modules/reagents/reagent_containers/cups/bottle.dm b/code/modules/reagents/reagent_containers/cups/bottle.dm
index fda39ed4877ba..2259cda34d79c 100644
--- a/code/modules/reagents/reagent_containers/cups/bottle.dm
+++ b/code/modules/reagents/reagent_containers/cups/bottle.dm
@@ -129,6 +129,11 @@
desc = "A small bottle. Contains cold sauce."
list_reagents = list(/datum/reagent/consumable/frostoil = 30)
+/obj/item/reagent_containers/cup/bottle/strange_reagent
+ name = "Strange Reagent Bottle"
+ desc = "A small bottle. May be used to revive people."
+ list_reagents = list(/datum/reagent/medicine/strange_reagent = 30)
+
/obj/item/reagent_containers/cup/bottle/traitor
name = "syndicate bottle"
desc = "A small bottle. Contains a random nasty chemical."
diff --git a/code/modules/reagents/reagent_containers/cups/drinkingglass.dm b/code/modules/reagents/reagent_containers/cups/drinkingglass.dm
index 7441614682c06..fa3a53434bbcc 100644
--- a/code/modules/reagents/reagent_containers/cups/drinkingglass.dm
+++ b/code/modules/reagents/reagent_containers/cups/drinkingglass.dm
@@ -14,6 +14,7 @@
obj_flags = UNIQUE_RENAME
drop_sound = 'sound/items/handling/drinkglass_drop.ogg'
pickup_sound = 'sound/items/handling/drinkglass_pickup.ogg'
+ sound_vary = TRUE
custom_price = PAYCHECK_LOWER
//the screwdriver cocktail can make a drinking glass into the world's worst screwdriver. beautiful.
toolspeed = 25
diff --git a/code/modules/reagents/reagent_containers/cups/glassbottle.dm b/code/modules/reagents/reagent_containers/cups/glassbottle.dm
index b246cc01e07e9..a214ea47eb148 100644
--- a/code/modules/reagents/reagent_containers/cups/glassbottle.dm
+++ b/code/modules/reagents/reagent_containers/cups/glassbottle.dm
@@ -39,11 +39,93 @@
var/bottle_knockdown_duration = BOTTLE_KNOCKDOWN_DEFAULT_DURATION
tool_behaviour = TOOL_ROLLINGPIN // Used to knock out the Chef.
toolspeed = 1.3 //it's a little awkward to use, but it's a cylinder alright.
+ /// A contained piece of paper, a photo, or space cash, that we can use as a message or gift to future spessmen.
+ var/obj/item/message_in_a_bottle
/obj/item/reagent_containers/cup/glass/bottle/Initialize(mapload, vol)
. = ..()
var/static/list/recipes = list(/datum/crafting_recipe/molotov)
AddElement(/datum/element/slapcrafting, recipes)
+ register_context()
+ register_item_context()
+
+/obj/item/reagent_containers/cup/glass/bottle/add_context(atom/source, list/context, obj/item/held_item, mob/living/user)
+ if(message_in_a_bottle)
+ return NONE
+ if(istype(held_item, /obj/item/paper) || istype(held_item, /obj/item/stack/spacecash) || istype(held_item, /obj/item/photo))
+ context[SCREENTIP_CONTEXT_LMB] = "Insert message"
+ return CONTEXTUAL_SCREENTIP_SET
+ return NONE
+
+/obj/item/reagent_containers/cup/glass/bottle/add_item_context(obj/item/source, list/context, atom/target, mob/living/user)
+ if(message_in_a_bottle && HAS_TRAIT(target, TRAIT_MESSAGE_IN_A_BOTTLE_LOCATION))
+ context[SCREENTIP_CONTEXT_RMB] = "Toss message"
+ return CONTEXTUAL_SCREENTIP_SET
+ return NONE
+
+/obj/item/reagent_containers/cup/glass/bottle/Exited(atom/movable/gone, atom/newloc)
+ if(gone == message_in_a_bottle)
+ message_in_a_bottle = null
+ if(!QDELETED(src))
+ update_icon(UPDATE_OVERLAYS)
+ return ..()
+
+/obj/item/reagent_containers/cup/glass/bottle/CheckParts(list/parts_list)
+ . = ..()
+ var/obj/item/reagent_containers/cup/glass/bottle/bottle = locate() in contents
+ if(bottle.message_in_a_bottle)
+ message_in_a_bottle = bottle.message_in_a_bottle
+ bottle.message_in_a_bottle.forceMove(src)
+
+/obj/item/reagent_containers/cup/glass/bottle/examine(mob/user)
+ . = ..()
+ if(message_in_a_bottle)
+ . += span_info("there's \a [message_in_a_bottle] inside it. Break it to take it out, or find a beach or ocean and toss it with [EXAMINE_HINT("right-click")].")
+ else if(isGlass)
+ . += span_tinynoticeital("you could place a paper, photo or space cash inside it...")
+
+/obj/item/reagent_containers/cup/glass/bottle/update_overlays()
+ . = ..()
+ if(message_in_a_bottle)
+ var/overlay = add_message_overlay()
+ if(overlay)
+ . += overlay
+
+/obj/item/reagent_containers/cup/glass/bottle/interact_with_atom_secondary(atom/target, mob/living/user, list/modifiers)
+ if(user.combat_mode || !HAS_TRAIT(target, TRAIT_MESSAGE_IN_A_BOTTLE_LOCATION))
+ return ..()
+ if(!user.temporarilyRemoveItemFromInventory(src))
+ balloon_alert(user, "it's stuck to your hand!")
+ return ITEM_INTERACT_BLOCKING
+ user.visible_message(span_notice("[user] tosses [src] in [target]"), span_notice("You toss [src] in [target]"), span_notice("you hear a splash."))
+ SSpersistence.save_message_bottle(message_in_a_bottle, type)
+ playsound(target, 'sound/effects/bigsplash.ogg', 70)
+ qdel(src)
+ return ITEM_INTERACT_SUCCESS
+
+/obj/item/reagent_containers/cup/glass/bottle/item_interaction(mob/living/user, obj/item/item, list/modifiers)
+ if(!isGlass)
+ return NONE
+ if(!istype(item, /obj/item/paper) && !istype(item, /obj/item/stack/spacecash) && !istype(item, /obj/item/photo))
+ return NONE
+ if(message_in_a_bottle)
+ balloon_alert(user, "has a message already!")
+ return ITEM_INTERACT_BLOCKING
+ if(!user.transferItemToLoc(item, src))
+ balloon_alert(user, "it's stuck to your hand!")
+ return ITEM_INTERACT_BLOCKING
+ balloon_alert(user, "message inserted")
+ message_in_a_bottle = item
+ update_icon(UPDATE_OVERLAYS)
+ return ITEM_INTERACT_SUCCESS
+
+/obj/item/reagent_containers/cup/glass/bottle/proc/add_message_overlay()
+ if(istype(message_in_a_bottle, /obj/item/paper))
+ return "paper_in_bottle"
+ if(istype(message_in_a_bottle, /obj/item/photo))
+ return "photo_in_bottle"
+ if(istype(message_in_a_bottle, /obj/item/stack/spacecash))
+ return "cash_in_bottle"
/obj/item/reagent_containers/cup/glass/bottle/small
name = "small glass bottle"
@@ -56,14 +138,16 @@
if(bartender_check(target) && ranged)
return
SplashReagents(target, ranged, override_spillable = TRUE)
- var/obj/item/broken_bottle/B = new(drop_location())
+ var/obj/item/broken_bottle/broken = new(drop_location())
if(!ranged && thrower)
- thrower.put_in_hands(B)
- B.mimic_broken(src, target, break_top)
- B.inhand_icon_state = broken_inhand_icon_state
+ thrower.put_in_hands(broken)
+ broken.mimic_broken(src, target, break_top)
+ broken.inhand_icon_state = broken_inhand_icon_state
+ if(message_in_a_bottle)
+ message_in_a_bottle.forceMove(drop_location())
qdel(src)
- target.Bumped(B)
+ target.Bumped(broken)
/obj/item/reagent_containers/cup/glass/bottle/try_splash(mob/living/user, atom/target)
@@ -316,6 +400,12 @@
icon_state = "rumbottle"
list_reagents = list(/datum/reagent/consumable/ethanol/rum = 100)
+/obj/item/reagent_containers/cup/glass/bottle/rum/aged
+ name = "Captain Pete's Vintage spiced rum"
+ desc = "Shiver me timbers, a vintage edition of Captain Pete's rum. It's pratically GRIFF in a bottle from over 50 years ago."
+ icon_state = "rumbottle_gold"
+ list_reagents = list(/datum/reagent/consumable/ethanol/rum/aged = 100)
+
/obj/item/reagent_containers/cup/glass/bottle/maltliquor
name = "\improper Rabid Bear malt liquor"
desc = "A 40 full of malt liquor. Kicks stronger than, well, a rabid bear."
@@ -333,6 +423,9 @@
list_reagents = list(/datum/reagent/water/holywater = 100)
drink_type = NONE
+/obj/item/reagent_containers/cup/glass/bottle/holywater/add_message_overlay()
+ return //looks too weird...
+
/obj/item/reagent_containers/cup/glass/bottle/holywater/hell
desc = "A flask of holy water...it's been sitting in the Necropolis a while though."
icon_state = "unholyflask"
@@ -495,7 +588,6 @@
list_reagents = list(/datum/reagent/consumable/ethanol/sake = 100)
/obj/item/reagent_containers/cup/glass/bottle/sake/Initialize(mapload)
- . = ..()
if(prob(10))
name = "Fluffy Tail Sake"
desc += " On the bottle is a picture of a kitsune with nine touchable tails."
@@ -504,6 +596,12 @@
name = "Inubashiri's Home Brew"
desc += " Awoo."
icon_state = "sakebottle_i"
+ return ..()
+
+/obj/item/reagent_containers/cup/glass/bottle/sake/add_message_overlay()
+ if(icon_state == "sakebottle_k") //doesn't fit the sprite
+ return
+ return ..()
/obj/item/reagent_containers/cup/glass/bottle/fernet
name = "Fernet Bronca"
@@ -524,6 +622,9 @@
icon_state = "curacao_bottle"
list_reagents = list(/datum/reagent/consumable/ethanol/curacao = 100)
+/obj/item/reagent_containers/cup/glass/bottle/curacao/add_message_overlay()
+ return //doesn't fit the sprite
+
/obj/item/reagent_containers/cup/glass/bottle/navy_rum
name = "Pride of the Union Navy-Strength Rum"
desc = "Ironically named, given it's made in Bermuda."
@@ -568,6 +669,9 @@
///Whether this bottle was a victim of a successful sabrage attempt
var/sabraged = FALSE
+/obj/item/reagent_containers/cup/glass/bottle/champagne/add_message_overlay()
+ return //doesn't stylistically fit the sprite
+
/obj/item/reagent_containers/cup/glass/bottle/champagne/cursed
sabrage_success_percentile = 0 //force of the sharp item used to sabrage will not increase success chance
@@ -727,12 +831,18 @@
icon_state = "hoochbottle"
list_reagents = list(/datum/reagent/consumable/ethanol/hooch = 100)
+/obj/item/reagent_containers/cup/glass/bottle/hooch/add_message_overlay()
+ return //doesn't fit the sprite
+
/obj/item/reagent_containers/cup/glass/bottle/moonshine
name = "moonshine jug"
desc = "It is said that the ancient Applalacians used these stoneware jugs to capture lightning in a bottle."
icon_state = "moonshinebottle"
list_reagents = list(/datum/reagent/consumable/ethanol/moonshine = 100)
+/obj/item/reagent_containers/cup/glass/bottle/moonshine/add_message_overlay()
+ return //doesn't fit the sprite
+
/obj/item/reagent_containers/cup/glass/bottle/mushi_kombucha
name = "Solzara Brewing Company Mushi Kombucha"
desc = "Best drunk over ice to savour the mushroomy flavour."
@@ -784,15 +894,15 @@
)
/obj/item/reagent_containers/cup/glass/bottle/molotov/CheckParts(list/parts_list)
- ..()
- var/obj/item/reagent_containers/cup/glass/bottle/B = locate() in contents
- if(B)
- icon_state = B.icon_state
- B.reagents.copy_to(src, 100)
- if(istype(B, /obj/item/reagent_containers/cup/glass/bottle/juice))
- desc += " You're not sure if making this out of a carton was the brightest idea."
- isGlass = FALSE
- return
+ . = ..()
+ var/obj/item/reagent_containers/cup/glass/bottle/bottle = locate() in contents
+ if(!bottle)
+ return
+ icon_state = bottle.icon_state
+ bottle.reagents.copy_to(src, 100)
+ if(istype(bottle, /obj/item/reagent_containers/cup/glass/bottle/juice))
+ desc += " You're not sure if making this out of a carton was the brightest idea."
+ isGlass = FALSE
/obj/item/reagent_containers/cup/glass/bottle/molotov/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum, do_splash = FALSE)
..(hit_atom, throwingdatum, do_splash = FALSE)
diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm
index dc54dcd7db44b..4b6ee9c8c7860 100644
--- a/code/modules/reagents/reagent_containers/spray.dm
+++ b/code/modules/reagents/reagent_containers/spray.dm
@@ -154,7 +154,7 @@
set name = "Empty Spray Bottle"
set category = "Object"
set src in usr
- if(usr.incapacitated())
+ if(usr.incapacitated)
return
if (tgui_alert(usr, "Are you sure you want to empty that?", "Empty Bottle:", list("Yes", "No")) != "Yes")
return
diff --git a/code/modules/recycling/conveyor.dm b/code/modules/recycling/conveyor.dm
index 21c5aa7a1a902..0d207ed7e11fc 100644
--- a/code/modules/recycling/conveyor.dm
+++ b/code/modules/recycling/conveyor.dm
@@ -434,6 +434,8 @@ GLOBAL_LIST_EMPTY(conveyors_by_id)
/// Updates the switch's `position` and `last_pos` variable. Useful so that the switch can properly cycle between the forwards, backwards and neutral positions.
/obj/machinery/conveyor_switch/proc/update_position(direction)
if(position == CONVEYOR_OFF)
+ playsound(src, 'sound/machines/lever_start.ogg', 40, TRUE)
+
if(oneway) //is it a oneway switch
position = oneway
else
@@ -442,6 +444,7 @@ GLOBAL_LIST_EMPTY(conveyors_by_id)
else
position = CONVEYOR_BACKWARDS
else
+ playsound(src, 'sound/machines/lever_stop.ogg', 40, TRUE)
position = CONVEYOR_OFF
/obj/machinery/conveyor_switch/proc/on_user_activation(mob/user, direction)
diff --git a/code/modules/recycling/disposal/bin.dm b/code/modules/recycling/disposal/bin.dm
index 4b54cf9f4b023..46d023dbfaf3f 100644
--- a/code/modules/recycling/disposal/bin.dm
+++ b/code/modules/recycling/disposal/bin.dm
@@ -416,7 +416,7 @@
data["isai"] = HAS_AI_ACCESS(user)
return data
-/obj/machinery/disposal/bin/ui_act(action, params)
+/obj/machinery/disposal/bin/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
@@ -624,6 +624,12 @@
SIGNAL_HANDLER
if((shove_flags & SHOVE_KNOCKDOWN_BLOCKED) || !(shove_flags & SHOVE_BLOCKED))
return
+ var/cur_density = density
+ density = FALSE
+ if (!target.Move(get_turf(src), get_dir(target, src)))
+ density = cur_density
+ return
+ density = cur_density
target.Knockdown(SHOVE_KNOCKDOWN_SOLID)
target.forceMove(src)
target.visible_message(span_danger("[shover.name] shoves [target.name] into \the [src]!"),
diff --git a/code/modules/recycling/disposal/holder.dm b/code/modules/recycling/disposal/holder.dm
index b842a69413d7d..78469d491912b 100644
--- a/code/modules/recycling/disposal/holder.dm
+++ b/code/modules/recycling/disposal/holder.dm
@@ -195,7 +195,7 @@
// called when player tries to move while in a pipe
/obj/structure/disposalholder/relaymove(mob/living/user, direction)
- if(user.incapacitated())
+ if(user.incapacitated)
return
for(var/mob/M in range(5, get_turf(src)))
M.show_message("CLONG, clong!", MSG_AUDIBLE)
diff --git a/code/modules/recycling/sortingmachinery.dm b/code/modules/recycling/sortingmachinery.dm
index a6be96a43a811..a61bf0f59445b 100644
--- a/code/modules/recycling/sortingmachinery.dm
+++ b/code/modules/recycling/sortingmachinery.dm
@@ -309,7 +309,7 @@
return data
/** User clicks a button on the tagger */
-/obj/item/dest_tagger/ui_act(action, params)
+/obj/item/dest_tagger/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/religion/sparring/sparring_contract.dm b/code/modules/religion/sparring/sparring_contract.dm
index c31be81f64945..314953dce28ab 100644
--- a/code/modules/religion/sparring/sparring_contract.dm
+++ b/code/modules/religion/sparring/sparring_contract.dm
@@ -65,7 +65,7 @@
area_names += key
return area_names
-/obj/item/sparring_contract/ui_act(action, list/params)
+/obj/item/sparring_contract/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/research/anomaly/anomaly_core.dm b/code/modules/research/anomaly/anomaly_core.dm
index febb25add5301..9cf762e58d219 100644
--- a/code/modules/research/anomaly/anomaly_core.dm
+++ b/code/modules/research/anomaly/anomaly_core.dm
@@ -20,8 +20,9 @@
A.anomalyNeutralize()
return TRUE
-/obj/item/assembly/signaler/anomaly/manual_suicide(mob/living/carbon/user)
- user.visible_message(span_suicide("[user]'s [src] is reacting to the radio signal, warping [user.p_their()] body!"))
+/obj/item/assembly/signaler/anomaly/manual_suicide(datum/mind/suicidee)
+ var/mob/living/user = suicidee.current
+ user.visible_message(span_suicide("[user]'s [name] is reacting to the radio signal, warping [user.p_their()] body!"))
user.set_suicide(TRUE)
user.gib(DROP_ALL_REMAINS)
diff --git a/code/modules/research/anomaly/anomaly_refinery.dm b/code/modules/research/anomaly/anomaly_refinery.dm
index bae2b4f116261..1269edb926561 100644
--- a/code/modules/research/anomaly/anomaly_refinery.dm
+++ b/code/modules/research/anomaly/anomaly_refinery.dm
@@ -315,7 +315,7 @@
ui = new(user, src, "AnomalyRefinery")
ui.open()
-/obj/machinery/research/anomaly_refinery/ui_act(action, list/params)
+/obj/machinery/research/anomaly_refinery/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if (.)
return
diff --git a/code/modules/research/designs/autolathe/service_designs.dm b/code/modules/research/designs/autolathe/service_designs.dm
index e7177037e522c..94772421b69ab 100644
--- a/code/modules/research/designs/autolathe/service_designs.dm
+++ b/code/modules/research/designs/autolathe/service_designs.dm
@@ -581,7 +581,7 @@
/datum/design/telescreen_entertainment
name = "Entertainment Telescreen"
id = "telescreen_entertainment"
- build_type = PROTOLATHE
+ build_type = AUTOLATHE | PROTOLATHE
materials = list(
/datum/material/iron = SHEET_MATERIAL_AMOUNT*5,
/datum/material/glass =SHEET_MATERIAL_AMOUNT * 2.5,
@@ -593,6 +593,21 @@
)
departmental_flags = DEPARTMENT_BITFLAG_SERVICE
+/datum/design/entertainment_radio
+ name = "Entertainment Radio"
+ id = "radio_entertainment"
+ build_type = AUTOLATHE | PROTOLATHE
+ materials = list(
+ /datum/material/iron = SMALL_MATERIAL_AMOUNT*0.75,
+ /datum/material/glass =SMALL_MATERIAL_AMOUNT*0.25
+ )
+ build_path = /obj/item/radio/entertainment/speakers/physical
+ category = list(
+ RND_CATEGORY_INITIAL,
+ RND_CATEGORY_CONSTRUCTION + RND_SUBCATEGORY_CONSTRUCTION_MOUNTS,
+ )
+ departmental_flags = DEPARTMENT_BITFLAG_SERVICE
+
/datum/design/barcode_scanner
name = "Barcode Scanner"
id = "barcode_scanner"
diff --git a/code/modules/research/designs/machine_designs.dm b/code/modules/research/designs/machine_designs.dm
index 53104494c820e..d07deca292691 100644
--- a/code/modules/research/designs/machine_designs.dm
+++ b/code/modules/research/designs/machine_designs.dm
@@ -540,7 +540,7 @@
category = list(
RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_RESEARCH
)
- departmental_flags = DEPARTMENT_BITFLAG_SCIENCE
+ departmental_flags = DEPARTMENT_BITFLAG_SCIENCE | DEPARTMENT_BITFLAG_ENGINEERING
/datum/design/board/microwave
name = "Microwave Board"
@@ -1247,3 +1247,13 @@
RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_SERVICE
)
departmental_flags = DEPARTMENT_BITFLAG_SERVICE
+
+/datum/design/board/big_manipulator
+ name = "Big Manipulator Board"
+ desc = "The circuit board for a big manipulator."
+ id = "big_manipulator"
+ build_path = /obj/item/circuitboard/machine/big_manipulator
+ category = list(
+ RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_ENGINEERING
+ )
+ departmental_flags = DEPARTMENT_BITFLAG_SCIENCE | DEPARTMENT_BITFLAG_ENGINEERING | DEPARTMENT_BITFLAG_CARGO | DEPARTMENT_BITFLAG_SERVICE
diff --git a/code/modules/research/designs/mechfabricator_designs.dm b/code/modules/research/designs/mechfabricator_designs.dm
index 96b3e60c63505..fb15c40b32fe8 100644
--- a/code/modules/research/designs/mechfabricator_designs.dm
+++ b/code/modules/research/designs/mechfabricator_designs.dm
@@ -1578,6 +1578,20 @@
RND_CATEGORY_MECHFAB_CYBORG_MODULES + RND_SUBCATEGORY_MECHFAB_CYBORG_MODULES_JANITOR
)
+/datum/design/borg_upgrade_plunger
+ name = "Integrated Plunger"
+ id = "borg_upgrade_plunger"
+ build_type = MECHFAB
+ build_path = /obj/item/borg/upgrade/plunger
+ materials = list(
+ /datum/material/iron = SHEET_MATERIAL_AMOUNT*1.125,
+ /datum/material/glass = HALF_SHEET_MATERIAL_AMOUNT*0.75,
+ )
+ construction_time = 4 SECONDS
+ category = list(
+ RND_CATEGORY_MECHFAB_CYBORG_MODULES + RND_SUBCATEGORY_MECHFAB_CYBORG_MODULES_JANITOR
+ )
+
/datum/design/borg_upgrade_rolling_table
name = "Rolling Table Dock"
id = "borg_upgrade_rolling_table"
@@ -2727,6 +2741,17 @@
RND_CATEGORY_MODSUIT_MODULES + RND_SUBCATEGORY_MODSUIT_MODULES_ENGINEERING
)
+/datum/design/module/fishing_glove
+ name = "MOD Fishing Glove Module"
+ id = "mod_fishing"
+ materials = list(
+ /datum/material/titanium = HALF_SHEET_MATERIAL_AMOUNT,
+ /datum/material/glass = HALF_SHEET_MATERIAL_AMOUNT,
+ /datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT,
+ /datum/material/plastic = HALF_SHEET_MATERIAL_AMOUNT,
+ )
+ build_path = /obj/item/mod/module/fishing_glove
+
/datum/design/posisphere
name = "Positronic Sphere"
desc = "The latest in Artificial Pesterance."
diff --git a/code/modules/research/designs/misc_designs.dm b/code/modules/research/designs/misc_designs.dm
index d9feba5179e08..22306cffe71a3 100644
--- a/code/modules/research/designs/misc_designs.dm
+++ b/code/modules/research/designs/misc_designs.dm
@@ -473,7 +473,7 @@
/datum/design/plasticducky
name = "Rubber Ducky"
- desc = "The classic Nanotrasen design for competitively priced bath based duck toys. No need for fancy Waffle co. rubber, buy Plastic Ducks today!"
+ desc = "The classic Nanotrasen design for competitively priced bath based duck toys. No need for fancy Waffle Corp. rubber, buy Plastic Ducks today!"
id = "plasticducky"
build_type = PROTOLATHE | AWAY_LATHE
materials = list(/datum/material/plastic =HALF_SHEET_MATERIAL_AMOUNT)
@@ -986,6 +986,18 @@
)
departmental_flags = DEPARTMENT_BITFLAG_SERVICE | DEPARTMENT_BITFLAG_CARGO | DEPARTMENT_BITFLAG_SCIENCE
+/datum/design/fishing_gloves
+ name = "Athletic Fishing Gloves"
+ desc = "A pair of gloves to fish without a fishing rod and train your athletics with."
+ id = "fishing_gloves"
+ build_type = PROTOLATHE | AWAY_LATHE
+ materials = list(/datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT, /datum/material/plastic = SHEET_MATERIAL_AMOUNT)
+ build_path = /obj/item/clothing/gloves/fishing
+ category = list(
+ RND_CATEGORY_EQUIPMENT + RND_SUBCATEGORY_EQUIPMENT_SERVICE
+ )
+ departmental_flags = DEPARTMENT_BITFLAG_SERVICE | DEPARTMENT_BITFLAG_CARGO | DEPARTMENT_BITFLAG_SCIENCE
+
/datum/design/stabilized_hook
name = "Gyro-Stabilized Hook"
desc = "An advanced fishing hook that gives the user a tighter control on the fish when reeling in."
@@ -1022,6 +1034,18 @@
)
departmental_flags = DEPARTMENT_BITFLAG_SERVICE | DEPARTMENT_BITFLAG_CARGO | DEPARTMENT_BITFLAG_SCIENCE
+/datum/design/bluespace_fish_case
+ name = "Bluespace Fish Case"
+ desc = "An improved fish case to keep large fish in stasis in a compact little space."
+ id = "bluespace_fish_case"
+ build_type = PROTOLATHE | AWAY_LATHE
+ materials = list(/datum/material/iron = SMALL_MATERIAL_AMOUNT, /datum/material/plastic = SMALL_MATERIAL_AMOUNT, /datum/material/bluespace = SMALL_MATERIAL_AMOUNT)
+ build_path = /obj/item/storage/fish_case/bluespace
+ category = list(
+ RND_CATEGORY_EQUIPMENT + RND_SUBCATEGORY_EQUIPMENT_SERVICE
+ )
+ departmental_flags = DEPARTMENT_BITFLAG_SERVICE | DEPARTMENT_BITFLAG_CARGO | DEPARTMENT_BITFLAG_SCIENCE
+
// Coffeemaker Stuff
/datum/design/coffeepot
diff --git a/code/modules/research/designs/wiremod_designs.dm b/code/modules/research/designs/wiremod_designs.dm
index dbcd74165946a..e848356359dac 100644
--- a/code/modules/research/designs/wiremod_designs.dm
+++ b/code/modules/research/designs/wiremod_designs.dm
@@ -39,7 +39,7 @@
name = "Component ( NULL ENTRY )"
desc = "A component that goes into an integrated circuit."
build_type = COMPONENT_PRINTER
- materials = list(/datum/material/glass =HALF_SHEET_MATERIAL_AMOUNT)
+ materials = list(/datum/material/glass = HALF_SHEET_MATERIAL_AMOUNT)
departmental_flags = DEPARTMENT_BITFLAG_SCIENCE
category = list(
RND_CATEGORY_CIRCUITRY + RND_SUBCATEGORY_CIRCUITRY_COMPONENTS
diff --git a/code/modules/research/experimentor.dm b/code/modules/research/experimentor.dm
index 0c28fcab2bf6e..ded27054695cc 100644
--- a/code/modules/research/experimentor.dm
+++ b/code/modules/research/experimentor.dm
@@ -166,7 +166,7 @@
return data
-/obj/machinery/rnd/experimentor/ui_act(action, list/params)
+/obj/machinery/rnd/experimentor/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/research/ordnance/doppler_array.dm b/code/modules/research/ordnance/doppler_array.dm
index 5e44c2dc703e4..6b1be6769844d 100644
--- a/code/modules/research/ordnance/doppler_array.dm
+++ b/code/modules/research/ordnance/doppler_array.dm
@@ -290,7 +290,7 @@
data["records"] += list(record_data)
return data
-/obj/machinery/doppler_array/ui_act(action, list/params)
+/obj/machinery/doppler_array/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/research/ordnance/scipaper_partner.dm b/code/modules/research/ordnance/scipaper_partner.dm
index 7120c78cecde9..5bbe3e7d62746 100644
--- a/code/modules/research/ordnance/scipaper_partner.dm
+++ b/code/modules/research/ordnance/scipaper_partner.dm
@@ -1,14 +1,18 @@
/datum/scientific_partner/mining
name = "Mining Corps"
- flufftext = "A local group of miners are looking for ways to improve their mining output. They are interested in smaller scale explosives."
- accepted_experiments = list(/datum/experiment/ordnance/explosive/lowyieldbomb)
+ flufftext = "A local group of miners are looking for ways to improve their mining output. They are interested in smaller scale explosives and plasma research."
+ accepted_experiments = list(
+ /datum/experiment/ordnance/gaseous/plasma,
+ /datum/experiment/ordnance/explosive/lowyieldbomb,
+ /datum/experiment/ordnance/explosive/highyieldbomb,
+ )
multipliers = list(SCIPAPER_COOPERATION_INDEX = 0.75, SCIPAPER_FUNDING_INDEX = 0.75)
boostable_nodes = list(
- TECHWEB_NODE_BLUESPACE_THEORY = TECHWEB_TIER_3_POINTS,
- TECHWEB_NODE_NIGHT_VISION = TECHWEB_TIER_2_POINTS,
- TECHWEB_NODE_ANOMALY_RESEARCH = TECHWEB_TIER_2_POINTS,
- TECHWEB_NODE_MINING = TECHWEB_TIER_1_POINTS,
- TECHWEB_NODE_MINING_ADV = TECHWEB_TIER_2_POINTS,
+ TECHWEB_NODE_LOW_PRESSURE_EXCAVATION = TECHWEB_TIER_2_POINTS,
+ TECHWEB_NODE_PLASMA_MINING = TECHWEB_TIER_3_POINTS,
+ TECHWEB_NODE_MINING_ADV = TECHWEB_TIER_4_POINTS,
+ TECHWEB_NODE_NIGHT_VISION = TECHWEB_TIER_4_POINTS,
+ TECHWEB_NODE_BORG_ENGI = TECHWEB_TIER_3_POINTS,
)
/datum/scientific_partner/baron
@@ -17,23 +21,26 @@
multipliers = list(SCIPAPER_COOPERATION_INDEX = 0.25, SCIPAPER_FUNDING_INDEX = 2)
boostable_nodes = list(
TECHWEB_NODE_CONSOLES = TECHWEB_TIER_1_POINTS,
- TECHWEB_NODE_FUNDIMENTAL_SCI = TECHWEB_TIER_1_POINTS,
+ TECHWEB_NODE_GAMING = TECHWEB_TIER_2_POINTS,
+ TECHWEB_NODE_BITRUNNING = TECHWEB_TIER_3_POINTS,
+ TECHWEB_NODE_PROGRAMMED_SERVER = TECHWEB_TIER_3_POINTS,
)
/datum/scientific_partner/defense
name = "Defense Partnership"
- flufftext = "We can work directly for Nanotrasen's \[REDACTED\] division, potentially providing us access with advanced defensive gadgets."
+ flufftext = "We can work directly for Nanotrasen's \[REDACTED\] division, potentially providing us access with advanced offensive and defensive gadgets."
accepted_experiments = list(
+ /datum/experiment/ordnance/explosive/lowyieldbomb,
/datum/experiment/ordnance/explosive/highyieldbomb,
/datum/experiment/ordnance/explosive/pressurebomb,
/datum/experiment/ordnance/explosive/hydrogenbomb,
)
boostable_nodes = list(
- TECHWEB_NODE_RIOT_SUPRESSION = TECHWEB_TIER_3_POINTS,
- TECHWEB_NODE_SEC_EQUIP = TECHWEB_TIER_1_POINTS,
- TECHWEB_NODE_EXPLOSIVES = TECHWEB_TIER_2_POINTS,
- TECHWEB_NODE_ELECTRIC_WEAPONS = TECHWEB_TIER_2_POINTS,
- TECHWEB_NODE_BEAM_WEAPONS = TECHWEB_TIER_3_POINTS,
+ TECHWEB_NODE_RIOT_SUPRESSION = TECHWEB_TIER_2_POINTS,
+ TECHWEB_NODE_EXPLOSIVES = TECHWEB_TIER_3_POINTS,
+ TECHWEB_NODE_MECH_ENERGY_GUNS = TECHWEB_TIER_4_POINTS,
+ TECHWEB_NODE_MECH_FIREARMS = TECHWEB_TIER_5_POINTS,
+ TECHWEB_NODE_MECH_HEAVY_ARMS = TECHWEB_TIER_5_POINTS,
)
/datum/scientific_partner/medical
@@ -44,24 +51,27 @@
/datum/experiment/ordnance/gaseous/bz,
)
boostable_nodes = list(
- TECHWEB_NODE_CYBER_ORGANS = TECHWEB_TIER_1_POINTS,
- TECHWEB_NODE_CYBER_ORGANS_UPGRADED = TECHWEB_TIER_2_POINTS,
- TECHWEB_NODE_GENE_ENGINEERING = TECHWEB_TIER_1_POINTS,
- TECHWEB_NODE_PASSIVE_IMPLANTS = TECHWEB_TIER_1_POINTS,
- TECHWEB_NODE_BIO_SCAN = TECHWEB_TIER_1_POINTS,
- TECHWEB_NODE_CHEM_SYNTHESIS = TECHWEB_TIER_2_POINTS,
+ TECHWEB_NODE_CYBER_ORGANS = TECHWEB_TIER_2_POINTS,
+ TECHWEB_NODE_CYBER_ORGANS_UPGRADED = TECHWEB_TIER_3_POINTS,
+ TECHWEB_NODE_MEDBAY_EQUIP_ADV = TECHWEB_TIER_3_POINTS,
+ TECHWEB_NODE_CYTOLOGY = TECHWEB_TIER_3_POINTS,
+ TECHWEB_NODE_BORG_MEDICAL = TECHWEB_TIER_3_POINTS,
+ TECHWEB_NODE_COMBAT_IMPLANTS = TECHWEB_TIER_4_POINTS,
)
/datum/scientific_partner/physics
name = "NT Physics Quarterly"
flufftext = "A prestigious physics journal managed by Nanotrasen. The main journal for publishing cutting-edge physics research conducted by Nanotrasen, given that they aren't classified."
accepted_experiments = list(
+ /datum/experiment/ordnance/gaseous/bz,
+ /datum/experiment/ordnance/explosive/hydrogenbomb,
/datum/experiment/ordnance/gaseous/noblium,
/datum/experiment/ordnance/explosive/nobliumbomb,
)
boostable_nodes = list(
- TECHWEB_NODE_PARTS_UPG = TECHWEB_TIER_2_POINTS,
- TECHWEB_NODE_EXP_TOOLS = TECHWEB_TIER_4_POINTS,
- TECHWEB_NODE_PARTS_BLUESPACE = TECHWEB_TIER_3_POINTS,
- TECHWEB_NODE_PARTS_ADV = TECHWEB_TIER_1_POINTS,
+ TECHWEB_NODE_PARTS_ADV = TECHWEB_TIER_3_POINTS,
+ TECHWEB_NODE_BLUESPACE_TRAVEL = TECHWEB_TIER_3_POINTS,
+ TECHWEB_NODE_ANOMALY_RESEARCH = TECHWEB_TIER_3_POINTS,
+ TECHWEB_NODE_TELECOMS = TECHWEB_TIER_5_POINTS,
+ TECHWEB_NODE_MECH_EQUIP_BLUESPACE = TECHWEB_TIER_5_POINTS,
)
diff --git a/code/modules/research/ordnance/tank_compressor.dm b/code/modules/research/ordnance/tank_compressor.dm
index d0393d9e10374..89f38ee4a32e0 100644
--- a/code/modules/research/ordnance/tank_compressor.dm
+++ b/code/modules/research/ordnance/tank_compressor.dm
@@ -275,7 +275,7 @@
ui = new(user, src, "TankCompressor")
ui.open()
-/obj/machinery/atmospherics/components/binary/tank_compressor/ui_act(action, list/params)
+/obj/machinery/atmospherics/components/binary/tank_compressor/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if (.)
return
diff --git a/code/modules/research/rdconsole.dm b/code/modules/research/rdconsole.dm
index 91cf89582d369..d4dde8732a0e9 100644
--- a/code/modules/research/rdconsole.dm
+++ b/code/modules/research/rdconsole.dm
@@ -319,7 +319,7 @@ Nothing else in the console has ID requirements.
"id_cache" = flat_id_cache,
)
-/obj/machinery/computer/rdconsole/ui_act(action, list/params)
+/obj/machinery/computer/rdconsole/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if (.)
return
diff --git a/code/modules/research/server_control.dm b/code/modules/research/server_control.dm
index 24327a731a64e..73596925a2d78 100644
--- a/code/modules/research/server_control.dm
+++ b/code/modules/research/server_control.dm
@@ -61,7 +61,7 @@
return data
-/obj/machinery/computer/rdservercontrol/ui_act(action, params)
+/obj/machinery/computer/rdservercontrol/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return TRUE
diff --git a/code/modules/research/techweb/nodes/atmos_nodes.dm b/code/modules/research/techweb/nodes/atmos_nodes.dm
index ef4fee5ed92a7..f1ec74b50f482 100644
--- a/code/modules/research/techweb/nodes/atmos_nodes.dm
+++ b/code/modules/research/techweb/nodes/atmos_nodes.dm
@@ -42,6 +42,12 @@
"pneumatic_seal",
)
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS)
+ experiments_to_unlock = list(
+ /datum/experiment/ordnance/gaseous/plasma,
+ /datum/experiment/ordnance/gaseous/nitrous_oxide,
+ /datum/experiment/ordnance/gaseous/bz,
+ /datum/experiment/ordnance/gaseous/noblium,
+ )
/datum/techweb_node/plasma_control
id = TECHWEB_NODE_PLASMA_CONTROL
@@ -77,7 +83,6 @@
"crystallizer",
)
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS)
- required_experiments = list(/datum/experiment/ordnance/gaseous/bz)
discount_experiments = list(/datum/experiment/ordnance/gaseous/nitrous_oxide = TECHWEB_TIER_3_POINTS)
/datum/techweb_node/exp_tools
@@ -99,7 +104,7 @@
"magboots",
)
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_4_POINTS)
- discount_experiments = list(/datum/experiment/ordnance/gaseous/noblium = TECHWEB_TIER_4_POINTS)
+ discount_experiments = list(/datum/experiment/ordnance/gaseous/bz = TECHWEB_TIER_4_POINTS)
/datum/techweb_node/rcd_upgrade
id = TECHWEB_NODE_RCD_UPGRADE
@@ -116,3 +121,4 @@
"rpd_upgrade_unwrench",
)
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_5_POINTS)
+ discount_experiments = list(/datum/experiment/ordnance/gaseous/noblium = TECHWEB_TIER_5_POINTS)
diff --git a/code/modules/research/techweb/nodes/biology_nodes.dm b/code/modules/research/techweb/nodes/biology_nodes.dm
index 3599dfb9fc5a1..7b553445a9c2a 100644
--- a/code/modules/research/techweb/nodes/biology_nodes.dm
+++ b/code/modules/research/techweb/nodes/biology_nodes.dm
@@ -44,7 +44,7 @@
"limbdesign_plasmaman",
)
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS)
- required_experiments = list(/datum/experiment/scanning/cytology/slime)
+ discount_experiments = list(/datum/experiment/scanning/cytology/slime = TECHWEB_TIER_3_POINTS)
/datum/techweb_node/gene_engineering
id = TECHWEB_NODE_GENE_ENGINEERING
diff --git a/code/modules/research/techweb/nodes/cyborg_nodes.dm b/code/modules/research/techweb/nodes/cyborg_nodes.dm
index 5e0ad2f64e0e9..9c93405b2824a 100644
--- a/code/modules/research/techweb/nodes/cyborg_nodes.dm
+++ b/code/modules/research/techweb/nodes/cyborg_nodes.dm
@@ -11,6 +11,7 @@
"borg_l_leg",
"borg_r_arm",
"borg_r_leg",
+ "borg_suit",
"cybernetic_eyes",
"cybernetic_eyes_moth",
"cybernetic_ears",
@@ -32,7 +33,6 @@
"robocontrol",
"borgupload",
"cyborgrecharger",
- "borg_suit",
"mmi_posi",
"mmi",
"mmi_m",
@@ -98,6 +98,7 @@
"borg_upgrade_broomer",
"borg_upgrade_expand",
"borg_upgrade_prt",
+ "borg_upgrade_plunger",
"borg_upgrade_selfrepair",
"borg_upgrade_thrusters",
"borg_upgrade_trashofholding",
diff --git a/code/modules/research/techweb/nodes/engi_nodes.dm b/code/modules/research/techweb/nodes/engi_nodes.dm
index 0fe1b7bd75f33..949b880d1f23a 100644
--- a/code/modules/research/techweb/nodes/engi_nodes.dm
+++ b/code/modules/research/techweb/nodes/engi_nodes.dm
@@ -126,6 +126,7 @@
"firelock_board",
"trapdoor_electronics",
"blast",
+ "big_manipulator",
"tile_sprayer",
"airlock_painter",
"decal_painter",
diff --git a/code/modules/research/techweb/nodes/mech_nodes.dm b/code/modules/research/techweb/nodes/mech_nodes.dm
index d6b7171d55b37..b09957076d712 100644
--- a/code/modules/research/techweb/nodes/mech_nodes.dm
+++ b/code/modules/research/techweb/nodes/mech_nodes.dm
@@ -254,7 +254,7 @@
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_5_POINTS)
/datum/techweb_node/mech_equip_bluespace
- id = TECHWEB_NODE_BLUESPACE
+ id = TECHWEB_NODE_MECH_EQUIP_BLUESPACE
display_name = "Bluespace Exosuit Equipment"
description = "An array of equipment empowered by bluespace, providing unmatched mobility and utility."
prereq_ids = list(TECHWEB_NODE_MECH_INFILTRATOR, TECHWEB_NODE_BLUESPACE_TRAVEL)
diff --git a/code/modules/research/techweb/nodes/medbay_nodes.dm b/code/modules/research/techweb/nodes/medbay_nodes.dm
index f5b122ccd287d..fababbc55e748 100644
--- a/code/modules/research/techweb/nodes/medbay_nodes.dm
+++ b/code/modules/research/techweb/nodes/medbay_nodes.dm
@@ -84,7 +84,7 @@
id = TECHWEB_NODE_CRYOSTASIS
display_name = "Cryostasis"
description = "The result of clown accidentally drinking a chemical, now repurposed for safely preserving crew members in suspended animation."
- prereq_ids = list(TECHWEB_NODE_FUSION)
+ prereq_ids = list(TECHWEB_NODE_MEDBAY_EQUIP_ADV, TECHWEB_NODE_FUSION)
design_ids = list(
"cryotube",
"mech_sleeper",
diff --git a/code/modules/research/techweb/nodes/service_nodes.dm b/code/modules/research/techweb/nodes/service_nodes.dm
index 591308947b23f..3735dc41b3b2c 100644
--- a/code/modules/research/techweb/nodes/service_nodes.dm
+++ b/code/modules/research/techweb/nodes/service_nodes.dm
@@ -165,9 +165,12 @@
prereq_ids = list(TECHWEB_NODE_FISHING_EQUIP)
design_ids = list(
"fishing_rod_tech",
+ "fishing_gloves",
+ "mod_fishing",
"stabilized_hook",
"auto_reel",
"fish_analyzer",
+ "bluespace_fish_case",
)
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_2_POINTS)
required_experiments = list(/datum/experiment/scanning/fish)
diff --git a/code/modules/research/xenobiology/vatgrowing/petri_dish.dm b/code/modules/research/xenobiology/vatgrowing/petri_dish.dm
index 0187fa8eda359..df2fa619cc3d1 100644
--- a/code/modules/research/xenobiology/vatgrowing/petri_dish.dm
+++ b/code/modules/research/xenobiology/vatgrowing/petri_dish.dm
@@ -59,6 +59,7 @@
list(CELL_LINE_TABLE_COCKROACH, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 7),
list(CELL_LINE_TABLE_BLOBBERNAUT, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5)
)
+ name = "basic sample petri dish"
/obj/item/petri_dish/random/Initialize(mapload)
. = ..()
diff --git a/code/modules/security_levels/keycard_authentication.dm b/code/modules/security_levels/keycard_authentication.dm
index 69fc6f73289e1..adb62496d8bbb 100644
--- a/code/modules/security_levels/keycard_authentication.dm
+++ b/code/modules/security_levels/keycard_authentication.dm
@@ -60,7 +60,7 @@ GLOBAL_DATUM_INIT(keycard_events, /datum/events, new)
return UI_CLOSE
return ..()
-/obj/machinery/keycard_auth/ui_act(action, params)
+/obj/machinery/keycard_auth/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(. || waiting || !allowed(usr))
return
diff --git a/code/modules/shuttle/computer.dm b/code/modules/shuttle/computer.dm
index cf53fef368c1b..5ce62f8c04226 100644
--- a/code/modules/shuttle/computer.dm
+++ b/code/modules/shuttle/computer.dm
@@ -174,7 +174,7 @@
else
return SHUTTLE_CONSOLE_ERROR
-/obj/machinery/computer/shuttle/ui_act(action, params)
+/obj/machinery/computer/shuttle/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/shuttle/emergency.dm b/code/modules/shuttle/emergency.dm
index 6740424cf801a..6586539b1d05f 100644
--- a/code/modules/shuttle/emergency.dm
+++ b/code/modules/shuttle/emergency.dm
@@ -755,12 +755,13 @@
name = "emergency space helmet"
icon_state = "syndicate-helm-orange"
inhand_icon_state = "syndicate-helm-orange"
+ slowdown = 1.5
/obj/item/clothing/suit/space/orange
name = "emergency space suit"
icon_state = "syndicate-orange"
inhand_icon_state = "syndicate-orange"
- slowdown = 3
+ slowdown = 1.5
/obj/item/pickaxe/emergency
name = "emergency disembarkation tool"
diff --git a/code/modules/spells/spell_types/pointed/finger_guns.dm b/code/modules/spells/spell_types/pointed/finger_guns.dm
index 24f51a0e90862..cf80489fc916a 100644
--- a/code/modules/spells/spell_types/pointed/finger_guns.dm
+++ b/code/modules/spells/spell_types/pointed/finger_guns.dm
@@ -33,7 +33,7 @@
return FALSE
var/mob/living/carbon/human/human_invoker = invoker
- if(human_invoker.incapacitated())
+ if(human_invoker.incapacitated)
if(feedback)
to_chat(human_invoker, span_warning("You can't properly point your fingers while incapacitated."))
return FALSE
diff --git a/code/modules/spells/spell_types/shapeshift/_shapeshift.dm b/code/modules/spells/spell_types/shapeshift/_shapeshift.dm
index 59c9ffdde3b0b..b7542d4077f3c 100644
--- a/code/modules/spells/spell_types/shapeshift/_shapeshift.dm
+++ b/code/modules/spells/spell_types/shapeshift/_shapeshift.dm
@@ -141,7 +141,7 @@
if(QDELETED(caster))
return FALSE
- return !caster.incapacitated()
+ return !caster.incapacitated
/// Actually does the shapeshift, for the caster.
/datum/action/cooldown/spell/shapeshift/proc/do_shapeshift(mob/living/caster)
diff --git a/code/modules/spells/spell_types/teleport/teleport.dm b/code/modules/spells/spell_types/teleport/teleport.dm
index d486157204283..57e88b9852025 100644
--- a/code/modules/spells/spell_types/teleport/teleport.dm
+++ b/code/modules/spells/spell_types/teleport/teleport.dm
@@ -48,5 +48,5 @@
return
var/mob/living/carbon/caster = cast_on
- if(caster.incapacitated() || !caster.is_holding(target))
+ if(caster.incapacitated || !caster.is_holding(target))
return . | SPELL_CANCEL_CAST
diff --git a/code/modules/station_goals/bsa.dm b/code/modules/station_goals/bsa.dm
index e2feaa2bc26ed..683afe605c983 100644
--- a/code/modules/station_goals/bsa.dm
+++ b/code/modules/station_goals/bsa.dm
@@ -299,7 +299,7 @@ GLOBAL_VAR_INIT(bsa_unlock, FALSE)
data["target"] = get_target_name()
return data
-/obj/machinery/computer/bsa_control/ui_act(action, params)
+/obj/machinery/computer/bsa_control/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/station_goals/dna_vault.dm b/code/modules/station_goals/dna_vault.dm
index 6c2661bbe2237..5a14c0e16b66d 100644
--- a/code/modules/station_goals/dna_vault.dm
+++ b/code/modules/station_goals/dna_vault.dm
@@ -164,7 +164,7 @@
data["choiceB"] = initial(mutation2.name)
return data
-/obj/machinery/dna_vault/ui_act(action, params)
+/obj/machinery/dna_vault/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/surgery/advanced/brainwashing.dm b/code/modules/surgery/advanced/brainwashing.dm
index 0e80f89b6dc60..21870ae57b8df 100644
--- a/code/modules/surgery/advanced/brainwashing.dm
+++ b/code/modules/surgery/advanced/brainwashing.dm
@@ -81,7 +81,7 @@
if(!target.mind)
to_chat(user, span_warning("[target] doesn't respond to the brainwashing, as if [target.p_they()] lacked a mind..."))
return FALSE
- if(HAS_TRAIT(target, TRAIT_MINDSHIELD))
+ if(HAS_MIND_TRAIT(target, TRAIT_UNCONVERTABLE))
to_chat(user, span_warning("You hear a faint buzzing from a device inside [target]'s brain, and the brainwashing is erased."))
return FALSE
display_results(
diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm
index 9cec7dcca8984..296f818e58744 100644
--- a/code/modules/surgery/bodyparts/_bodyparts.dm
+++ b/code/modules/surgery/bodyparts/_bodyparts.dm
@@ -183,7 +183,7 @@
///Determines the accuracy bonus, armor penetration and knockdown probability.
var/unarmed_effectiveness = 10
- /// Traits that are given to the holder of the part. If you want an effect that changes this, don't add directly to this. Use the add_bodypart_trait() proc
+ /// Traits that are given to the holder of the part. This does not update automatically on life(), only when the organs are initially generated or inserted!
var/list/bodypart_traits = list()
/// The name of the trait source that the organ gives. Should not be altered during the events of gameplay, and will cause problems if it is.
var/bodypart_trait_source = BODYPART_TRAIT
@@ -953,7 +953,7 @@
if(should_draw_greyscale) //Should the limb be colored?
draw_color ||= species_color || (skin_tone ? skintone2hex(skin_tone) : null)
- recolor_external_organs()
+ recolor_bodypart_overlays()
return TRUE
//to update the bodypart's icon when not attached to a mob
@@ -1274,7 +1274,7 @@
QDEL_NULL(current_gauze)
///Loops through all of the bodypart's external organs and update's their color.
-/obj/item/bodypart/proc/recolor_external_organs()
+/obj/item/bodypart/proc/recolor_bodypart_overlays()
for(var/datum/bodypart_overlay/mutant/overlay in bodypart_overlays)
overlay.inherit_color(src, force = TRUE)
diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm
index 517847fb24f3d..5579cb64d83d5 100644
--- a/code/modules/surgery/bodyparts/dismemberment.dm
+++ b/code/modules/surgery/bodyparts/dismemberment.dm
@@ -231,8 +231,6 @@
for(var/obj/item/head_item as anything in list(owner.glasses, owner.ears, owner.wear_mask, owner.head))
owner.dropItemToGround(head_item, force = TRUE)
- qdel(owner.GetComponent(/datum/component/creamed)) //clean creampie overlay flushed emoji
-
//Handle dental implants
for(var/datum/action/item_action/activate_pill/pill_action in owner.actions)
pill_action.Remove(owner)
@@ -404,12 +402,12 @@
qdel(phantom_loss)
//Copied from /datum/species/proc/on_species_gain()
- for(var/obj/item/organ/external/organ_path as anything in dna.species.external_organs)
+ for(var/obj/item/organ/organ_path as anything in dna.species.mutant_organs)
//Load a persons preferences from DNA
var/zone = initial(organ_path.zone)
if(zone != limb_zone)
continue
- var/obj/item/organ/external/new_organ = SSwardrobe.provide_type(organ_path)
+ var/obj/item/organ/new_organ = SSwardrobe.provide_type(organ_path)
new_organ.Insert(src)
update_body_parts()
diff --git a/code/modules/surgery/bodyparts/helpers.dm b/code/modules/surgery/bodyparts/helpers.dm
index 8833f87e28ee8..dec8efb154eae 100644
--- a/code/modules/surgery/bodyparts/helpers.dm
+++ b/code/modules/surgery/bodyparts/helpers.dm
@@ -182,8 +182,8 @@
/mob/living/carbon/proc/synchronize_bodytypes()
var/all_limb_flags = NONE
for(var/obj/item/bodypart/limb as anything in bodyparts)
- for(var/obj/item/organ/external/ext_organ in limb)
- all_limb_flags |= ext_organ.external_bodytypes
+ for(var/obj/item/organ/organ in limb)
+ all_limb_flags |= organ.external_bodytypes
all_limb_flags |= limb.bodytype
bodytype = all_limb_flags
@@ -192,8 +192,8 @@
/mob/living/carbon/proc/synchronize_bodyshapes()
var/all_limb_flags = NONE
for(var/obj/item/bodypart/limb as anything in bodyparts)
- for(var/obj/item/organ/external/ext_organ in limb)
- all_limb_flags |= ext_organ.external_bodyshapes
+ for(var/obj/item/organ/organ in limb)
+ all_limb_flags |= organ.external_bodyshapes
all_limb_flags |= limb.bodyshape
bodyshape = all_limb_flags
diff --git a/code/modules/surgery/bodyparts/robot_bodyparts.dm b/code/modules/surgery/bodyparts/robot_bodyparts.dm
index 314f3396f0afe..738b3ce97ac3b 100644
--- a/code/modules/surgery/bodyparts/robot_bodyparts.dm
+++ b/code/modules/surgery/bodyparts/robot_bodyparts.dm
@@ -124,8 +124,8 @@
if (severity == EMP_HEAVY)
knockdown_time *= 2
owner.Knockdown(knockdown_time)
- if(owner.incapacitated(IGNORE_RESTRAINTS|IGNORE_GRAB)) // So the message isn't duplicated. If they were stunned beforehand by something else, then the message not showing makes more sense anyways.
- return FALSE
+ if(INCAPACITATED_IGNORING(owner, INCAPABLE_RESTRAINTS|INCAPABLE_GRAB)) // So the message isn't duplicated. If they were stunned beforehand by something else, then the message not showing makes more sense anyways.
+ return
to_chat(owner, span_danger("As your [plaintext_zone] unexpectedly malfunctions, it causes you to fall to the ground!"))
return
@@ -173,8 +173,8 @@
if (severity == EMP_HEAVY)
knockdown_time *= 2
owner.Knockdown(knockdown_time)
- if(owner.incapacitated(IGNORE_RESTRAINTS|IGNORE_GRAB)) // So the message isn't duplicated. If they were stunned beforehand by something else, then the message not showing makes more sense anyways.
- return FALSE
+ if(INCAPACITATED_IGNORING(owner, INCAPABLE_RESTRAINTS|INCAPABLE_GRAB)) // So the message isn't duplicated. If they were stunned beforehand by something else, then the message not showing makes more sense anyways.
+ return
to_chat(owner, span_danger("As your [plaintext_zone] unexpectedly malfunctions, it causes you to fall to the ground!"))
return
diff --git a/code/modules/surgery/bodyparts/species_parts/ethereal_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/ethereal_bodyparts.dm
index 05645ed20df2e..d97b00c58af68 100644
--- a/code/modules/surgery/bodyparts/species_parts/ethereal_bodyparts.dm
+++ b/code/modules/surgery/bodyparts/species_parts/ethereal_bodyparts.dm
@@ -23,6 +23,7 @@
dmg_overlay_type = null
brute_modifier = 1.25 //ethereal are weak to brute damages
wing_types = NONE
+ bodypart_traits = list(TRAIT_NO_UNDERWEAR)
/obj/item/bodypart/chest/ethereal/update_limb(dropping_limb, is_creating)
. = ..()
diff --git a/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm
index 350e2f32883fb..acf64c3493160 100644
--- a/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm
+++ b/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm
@@ -47,54 +47,58 @@
icon_greyscale = 'icons/mob/human/species/lizard/bodyparts.dmi'
limb_id = SPECIES_LIZARD
+/// Checks if this mob is wearing anything that does not have a valid sprite set for digitigrade legs
+/// (In other words, is the mob's digitigrade body squished by its clothing?)
+/mob/living/carbon/proc/is_digitigrade_squished()
+ return FALSE
+
+/mob/living/carbon/human/is_digitigrade_squished()
+ var/obj/item/clothing/shoes/worn_shoes = shoes
+ var/obj/item/clothing/under/worn_suit = wear_suit
+ var/obj/item/clothing/under/worn_uniform = w_uniform
+
+ var/uniform_compatible = isnull(worn_uniform) \
+ || (worn_uniform.supports_variations_flags & DIGITIGRADE_VARIATIONS) \
+ || !(worn_uniform.body_parts_covered & LEGS) \
+ || (worn_suit?.flags_inv & HIDEJUMPSUIT) // If suit hides our jumpsuit, it doesn't matter if it squishes
+
+ var/suit_compatible = isnull(worn_suit) \
+ || (worn_suit.supports_variations_flags & DIGITIGRADE_VARIATIONS) \
+ || !(worn_suit.body_parts_covered & LEGS)
+
+ var/shoes_compatible = isnull(worn_shoes) \
+ || (worn_shoes.supports_variations_flags & DIGITIGRADE_VARIATIONS)
+
+ return !uniform_compatible || !suit_compatible || !shoes_compatible
+
/obj/item/bodypart/leg/left/digitigrade
icon_greyscale = 'icons/mob/human/species/lizard/bodyparts.dmi'
limb_id = BODYPART_ID_DIGITIGRADE
bodyshape = BODYSHAPE_HUMANOID | BODYSHAPE_DIGITIGRADE
+ footprint_sprite = FOOTPRINT_SPRITE_CLAWS
/obj/item/bodypart/leg/left/digitigrade/update_limb(dropping_limb = FALSE, is_creating = FALSE)
. = ..()
- if(ishuman(owner))
- var/mob/living/carbon/human/human_owner = owner
- var/obj/item/clothing/shoes/worn_shoes = human_owner.get_item_by_slot(ITEM_SLOT_FEET)
- var/uniform_compatible = FALSE
- var/suit_compatible = FALSE
- var/shoes_compatible = FALSE
- if(!(human_owner.w_uniform) || (human_owner.w_uniform.supports_variations_flags & (CLOTHING_DIGITIGRADE_VARIATION|CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON))) //Checks uniform compatibility
- uniform_compatible = TRUE
- if((!human_owner.wear_suit) || (human_owner.wear_suit.supports_variations_flags & (CLOTHING_DIGITIGRADE_VARIATION|CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON)) || !(human_owner.wear_suit.body_parts_covered & LEGS)) //Checks suit compatability
- suit_compatible = TRUE
- if((worn_shoes == null) || (worn_shoes.supports_variations_flags & (CLOTHING_DIGITIGRADE_VARIATION|CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON)))
- shoes_compatible = TRUE
-
- if((uniform_compatible && suit_compatible && shoes_compatible) || (suit_compatible && shoes_compatible && human_owner.wear_suit?.flags_inv & HIDEJUMPSUIT)) //If the uniform is hidden, it doesnt matter if its compatible
- limb_id = BODYPART_ID_DIGITIGRADE
-
- else
- limb_id = SPECIES_LIZARD
+ var/old_id = limb_id
+ limb_id = owner?.is_digitigrade_squished() ? SPECIES_LIZARD : BODYPART_ID_DIGITIGRADE
+ if(old_id != limb_id)
+ // Something unsquished / squished us so we need to go through and update everything that is affected
+ for(var/obj/item/thing as anything in owner?.get_equipped_items())
+ if(thing.supports_variations_flags & DIGITIGRADE_VARIATIONS)
+ thing.update_slot_icon()
/obj/item/bodypart/leg/right/digitigrade
icon_greyscale = 'icons/mob/human/species/lizard/bodyparts.dmi'
limb_id = BODYPART_ID_DIGITIGRADE
bodyshape = BODYSHAPE_HUMANOID | BODYSHAPE_DIGITIGRADE
+ footprint_sprite = FOOTPRINT_SPRITE_CLAWS
/obj/item/bodypart/leg/right/digitigrade/update_limb(dropping_limb = FALSE, is_creating = FALSE)
. = ..()
- if(ishuman(owner))
- var/mob/living/carbon/human/human_owner = owner
- var/obj/item/clothing/shoes/worn_shoes = human_owner.get_item_by_slot(ITEM_SLOT_FEET)
- var/uniform_compatible = FALSE
- var/suit_compatible = FALSE
- var/shoes_compatible = FALSE
- if(!(human_owner.w_uniform) || (human_owner.w_uniform.supports_variations_flags & (CLOTHING_DIGITIGRADE_VARIATION|CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON))) //Checks uniform compatibility
- uniform_compatible = TRUE
- if((!human_owner.wear_suit) || (human_owner.wear_suit.supports_variations_flags & (CLOTHING_DIGITIGRADE_VARIATION|CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON)) || !(human_owner.wear_suit.body_parts_covered & LEGS)) //Checks suit compatability
- suit_compatible = TRUE
- if((worn_shoes == null) || (worn_shoes.supports_variations_flags & (CLOTHING_DIGITIGRADE_VARIATION|CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON)))
- shoes_compatible = TRUE
-
- if((uniform_compatible && suit_compatible && shoes_compatible) || (suit_compatible && shoes_compatible && human_owner.wear_suit?.flags_inv & HIDEJUMPSUIT)) //If the uniform is hidden, it doesnt matter if its compatible
- limb_id = BODYPART_ID_DIGITIGRADE
-
- else
- limb_id = SPECIES_LIZARD
+ var/old_id = limb_id
+ limb_id = owner?.is_digitigrade_squished() ? SPECIES_LIZARD : BODYPART_ID_DIGITIGRADE
+ if(old_id != limb_id)
+ // Something unsquished / squished us so we need to go through and update everything that is affected
+ for(var/obj/item/thing as anything in owner?.get_equipped_items())
+ if(thing.supports_variations_flags & DIGITIGRADE_VARIATIONS)
+ thing.update_slot_icon()
diff --git a/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm
index f9a71a4e6d4dd..f8619943a81ed 100644
--- a/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm
+++ b/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm
@@ -254,12 +254,14 @@
should_draw_greyscale = FALSE
head_flags = HEAD_EYESPRITES|HEAD_EYEHOLES|HEAD_DEBRAIN
teeth_count = 0
+ bodypart_traits = list(TRAIT_ANTENNAE)
/obj/item/bodypart/chest/fly
limb_id = SPECIES_FLYPERSON
is_dimorphic = TRUE
should_draw_greyscale = FALSE
wing_types = list(/obj/item/organ/external/wings/functional/fly)
+ bodypart_traits = list(TRAIT_TACKLING_FRAIL_ATTACKER)
/obj/item/bodypart/arm/left/fly
limb_id = SPECIES_FLYPERSON
diff --git a/code/modules/surgery/bodyparts/species_parts/moth_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/moth_bodyparts.dm
index 323cef05b8c5d..b437129db35c3 100644
--- a/code/modules/surgery/bodyparts/species_parts/moth_bodyparts.dm
+++ b/code/modules/surgery/bodyparts/species_parts/moth_bodyparts.dm
@@ -7,6 +7,7 @@
should_draw_greyscale = FALSE
head_flags = HEAD_LIPS|HEAD_EYESPRITES|HEAD_EYEHOLES|HEAD_DEBRAIN //what the fuck, moths have lips?
teeth_count = 0
+ bodypart_traits = list(TRAIT_ANTENNAE)
/obj/item/bodypart/chest/moth
icon = 'icons/mob/human/species/moth/bodyparts.dmi'
@@ -16,6 +17,7 @@
is_dimorphic = TRUE
should_draw_greyscale = FALSE
wing_types = list(/obj/item/organ/external/wings/functional/moth/megamoth, /obj/item/organ/external/wings/functional/moth/mothra)
+ bodypart_traits = list(TRAIT_TACKLING_WINGED_ATTACKER)
/obj/item/bodypart/chest/moth/get_butt_sprite()
return icon('icons/mob/butts.dmi', BUTT_SPRITE_FUZZY)
diff --git a/code/modules/surgery/organ_manipulation.dm b/code/modules/surgery/organ_manipulation.dm
index d96d558863b12..83474363c6cf2 100644
--- a/code/modules/surgery/organ_manipulation.dm
+++ b/code/modules/surgery/organ_manipulation.dm
@@ -239,22 +239,20 @@
tool = tool.contents[1]
target_organ = tool
user.temporarilyRemoveItemFromInventory(target_organ, TRUE)
- if(target_organ.Insert(target))
- if(apparatus)
- apparatus.icon_state = initial(apparatus.icon_state)
- apparatus.desc = initial(apparatus.desc)
- apparatus.cut_overlays()
- display_results(
- user,
- target,
- span_notice("You insert [tool] into [target]'s [target.parse_zone_with_bodypart(target_zone)]."),
- span_notice("[user] inserts [tool] into [target]'s [target.parse_zone_with_bodypart(target_zone)]!"),
- span_notice("[user] inserts something into [target]'s [target.parse_zone_with_bodypart(target_zone)]!"),
- )
- display_pain(target, "Your [target.parse_zone_with_bodypart(target_zone)] throbs with pain as your new [tool.name] comes to life!")
- target_organ.on_surgical_insertion(user, target, target_zone, tool)
- else
- target_organ.forceMove(target.loc)
+ target_organ.Insert(target)
+ if(apparatus)
+ apparatus.icon_state = initial(apparatus.icon_state)
+ apparatus.desc = initial(apparatus.desc)
+ apparatus.cut_overlays()
+ display_results(
+ user,
+ target,
+ span_notice("You insert [tool] into [target]'s [target.parse_zone_with_bodypart(target_zone)]."),
+ span_notice("[user] inserts [tool] into [target]'s [target.parse_zone_with_bodypart(target_zone)]!"),
+ span_notice("[user] inserts something into [target]'s [target.parse_zone_with_bodypart(target_zone)]!"),
+ )
+ display_pain(target, "Your [target.parse_zone_with_bodypart(target_zone)] throbs with pain as your new [tool.name] comes to life!")
+ target_organ.on_surgical_insertion(user, target, target_zone, tool)
else if(current_type == "extract")
if(target_organ && target_organ.owner == target)
diff --git a/code/modules/surgery/organs/_organ.dm b/code/modules/surgery/organs/_organ.dm
index 98d947793efae..4d28b987abcaf 100644
--- a/code/modules/surgery/organs/_organ.dm
+++ b/code/modules/surgery/organs/_organ.dm
@@ -1,4 +1,3 @@
-
/obj/item/organ
name = "organ"
icon = 'icons/obj/medical/organs/organs.dmi'
@@ -79,6 +78,9 @@ INITIALIZE_IMMEDIATE(/obj/item/organ)
volume = reagent_vol,\
after_eat = CALLBACK(src, PROC_REF(OnEatFrom)))
+ if(bodypart_overlay)
+ setup_bodypart_overlay()
+
/obj/item/organ/Destroy()
if(bodypart_owner && !owner && !QDELETED(bodypart_owner))
bodypart_remove(bodypart_owner)
@@ -140,7 +142,7 @@ INITIALIZE_IMMEDIATE(/obj/item/organ)
return
/obj/item/organ/proc/on_life(seconds_per_tick, times_fired)
- CRASH("Oh god oh fuck something is calling parent organ life")
+ return
/obj/item/organ/examine(mob/user)
. = ..()
@@ -342,3 +344,16 @@ INITIALIZE_IMMEDIATE(/obj/item/organ)
/// Tries to replace the existing organ on the passed mob with this one, with special handling for replacing a brain without ghosting target
/obj/item/organ/proc/replace_into(mob/living/carbon/new_owner)
return Insert(new_owner, special = TRUE, movement_flags = DELETE_IF_REPLACED)
+
+
+/// Get all possible organ slots by checking every organ, and then store it and give it whenever needed
+/proc/get_all_slots()
+ var/static/list/all_organ_slots = list()
+
+ if(!all_organ_slots.len)
+ for(var/obj/item/organ/an_organ as anything in subtypesof(/obj/item/organ))
+ if(!initial(an_organ.slot))
+ continue
+ all_organ_slots |= initial(an_organ.slot)
+
+ return all_organ_slots
diff --git a/code/modules/surgery/organs/external/_external_organ.dm b/code/modules/surgery/organs/external/_visual_organs.dm
similarity index 75%
rename from code/modules/surgery/organs/external/_external_organ.dm
rename to code/modules/surgery/organs/external/_visual_organs.dm
index f41cb2a82bd8c..3aa54f27418cc 100644
--- a/code/modules/surgery/organs/external/_external_organ.dm
+++ b/code/modules/surgery/organs/external/_visual_organs.dm
@@ -1,19 +1,11 @@
-/**
-* System for drawing organs with overlays. These overlays are drawn directly on the bodypart, attached to a person or not
-* Works in tandem with the /datum/sprite_accessory datum to generate sprites
-* Unlike normal organs, we're actually inside a persons limbs at all times
+/*
+System for drawing organs with overlays. These overlays are drawn directly on the bodypart, attached to a person or not
+Works in tandem with the /datum/sprite_accessory datum to generate sprites
+Unlike normal organs, we're actually inside a persons limbs at all times
*/
-/obj/item/organ/external
- name = "external organ"
- desc = "An external organ that is too external."
-
- organ_flags = ORGAN_ORGANIC | ORGAN_EDIBLE
- visual = TRUE
-
+/obj/item/organ
///The overlay datum that actually draws stuff on the limb
var/datum/bodypart_overlay/mutant/bodypart_overlay
- ///If not null, overrides the appearance with this sprite accessory datum
- var/sprite_accessory_override
/// The savefile_key of the preference this relates to. Used for the preferences UI.
var/preference
@@ -23,21 +15,24 @@
///Set to EXTERNAL_BEHIND, EXTERNAL_FRONT or EXTERNAL_ADJACENT if you want to draw one of those layers as the object sprite. FALSE to use your own
///This will not work if it doesn't have a limb to generate its icon with
var/use_mob_sprite_as_obj_sprite = FALSE
+
///Does this organ have any bodytypes to pass to its bodypart_owner?
var/external_bodytypes = NONE
///Does this organ have any bodyshapes to pass to its bodypart_owner?
var/external_bodyshapes = NONE
+
///Which flags does a 'modification tool' need to have to restyle us, if it all possible (located in code/_DEFINES/mobs)
var/restyle_flags = NONE
-/**mob_sprite is optional if you havent set sprite_datums for the object, and is used mostly to generate sprite_datums from a persons DNA
+ ///If not null, overrides the appearance with this sprite accessory datum
+ var/sprite_accessory_override
+
+/**accessory_type is optional if you havent set sprite_datums for the object, and is used mostly to generate sprite_datums from a persons DNA
* For _mob_sprite we make a distinction between "Round Snout" and "round". Round Snout is the name of the sprite datum, while "round" would be part of the sprite
* I'm sorry
*/
-/obj/item/organ/external/Initialize(mapload, accessory_type)
- . = ..()
-
- bodypart_overlay = new bodypart_overlay()
+/obj/item/organ/proc/setup_bodypart_overlay(accessory_type)
+ bodypart_overlay = new bodypart_overlay(src)
accessory_type = accessory_type ? accessory_type : sprite_accessory_override
var/update_overlays = TRUE
@@ -55,61 +50,13 @@
if(restyle_flags)
RegisterSignal(src, COMSIG_ATOM_RESTYLE, PROC_REF(on_attempt_feature_restyle))
-/obj/item/organ/external/Insert(mob/living/carbon/receiver, special, movement_flags)
- . = ..()
- receiver.update_body_parts()
-
-/obj/item/organ/external/Remove(mob/living/carbon/organ_owner, special, movement_flags)
- . = ..()
- if(!special)
- organ_owner.update_body_parts()
-
-/obj/item/organ/external/mob_insert(mob/living/carbon/receiver, special, movement_flags)
- if(!should_external_organ_apply_to(type, receiver))
- stack_trace("adding a [type] to a [receiver.type] when it shouldn't be!")
-
- . = ..()
-
- if(!.)
- return
-
- if(bodypart_overlay.imprint_on_next_insertion) //We only want this set *once*
- var/feature_name = receiver.dna.features[bodypart_overlay.feature_key]
- if (isnull(feature_name))
- feature_name = receiver.dna.species.external_organs[type]
- bodypart_overlay.set_appearance_from_name(feature_name)
- bodypart_overlay.imprint_on_next_insertion = FALSE
-
- if(external_bodytypes)
- receiver.synchronize_bodytypes()
- if(external_bodyshapes)
- receiver.synchronize_bodyshapes()
-
- receiver.update_body_parts()
-
-/obj/item/organ/external/mob_remove(mob/living/carbon/organ_owner, special, moving)
- if(!special)
- organ_owner.synchronize_bodytypes()
- organ_owner.synchronize_bodyshapes()
- organ_owner.update_body_parts()
- return ..()
-
-/obj/item/organ/external/on_bodypart_insert(obj/item/bodypart/bodypart)
- bodypart.add_bodypart_overlay(bodypart_overlay)
- return ..()
-
-/obj/item/organ/external/on_bodypart_remove(obj/item/bodypart/bodypart)
- bodypart.remove_bodypart_overlay(bodypart_overlay)
-
- if(use_mob_sprite_as_obj_sprite)
- update_appearance(UPDATE_OVERLAYS)
-
- color = bodypart_overlay.draw_color // so a pink felinid doesn't drop a gray tail
- return ..()
+/// Some sanity checks, but mostly to check if the person has their preference/dna set to load
+/proc/should_visual_organ_apply_to(obj/item/organ/organpath, mob/living/carbon/target)
+ if(!initial(organpath.bodypart_overlay))
+ return TRUE
-/proc/should_external_organ_apply_to(obj/item/organ/external/organpath, mob/living/carbon/target)
if(isnull(organpath) || isnull(target))
- stack_trace("passed a null path or mob to 'should_external_organ_apply_to'")
+ stack_trace("passed a null path or mob to 'should_visual_organ_apply_to'")
return FALSE
var/datum/bodypart_overlay/mutant/bodypart_overlay = initial(organpath.bodypart_overlay)
@@ -122,7 +69,7 @@
return FALSE
///Update our features after something changed our appearance
-/obj/item/organ/external/proc/mutate_feature(features, mob/living/carbon/human/human)
+/obj/item/organ/proc/mutate_feature(features, mob/living/carbon/human/human)
if(!dna_block)
return
@@ -131,7 +78,7 @@
bodypart_overlay.set_appearance_from_name(feature_list[deconstruct_block(get_uni_feature_block(features, dna_block), feature_list.len)])
///If you need to change an external_organ for simple one-offs, use this. Pass the accessory type : /datum/accessory/something
-/obj/item/organ/external/proc/simple_change_sprite(accessory_type)
+/obj/item/organ/proc/simple_change_sprite(accessory_type)
var/datum/sprite_accessory/typed_accessory = accessory_type //we only take types for maintainability
bodypart_overlay.set_appearance(typed_accessory)
@@ -142,10 +89,7 @@
bodypart_owner.update_icon_dropped()
//else if(use_mob_sprite_as_obj_sprite) //are we out in the world, unprotected by flesh?
-/obj/item/organ/external/on_life(seconds_per_tick, times_fired)
- return
-
-/obj/item/organ/external/update_overlays()
+/obj/item/organ/update_overlays()
. = ..()
if(!use_mob_sprite_as_obj_sprite)
@@ -260,17 +204,16 @@
///Store our old datum here for if our antennae are healed
var/original_sprite_datum
-/obj/item/organ/external/antennae/Insert(mob/living/carbon/receiver, special, movement_flags)
+/obj/item/organ/external/antennae/mob_insert(mob/living/carbon/receiver, special, movement_flags)
. = ..()
- if(!.)
- return
+
RegisterSignal(receiver, COMSIG_HUMAN_BURNING, PROC_REF(try_burn_antennae))
RegisterSignal(receiver, COMSIG_LIVING_POST_FULLY_HEAL, PROC_REF(heal_antennae))
-/obj/item/organ/external/antennae/Remove(mob/living/carbon/organ_owner, special, movement_flags)
+/obj/item/organ/external/antennae/mob_remove(mob/living/carbon/organ_owner, special, movement_flags)
. = ..()
- if(organ_owner)
- UnregisterSignal(organ_owner, list(COMSIG_HUMAN_BURNING, COMSIG_LIVING_POST_FULLY_HEAL))
+
+ UnregisterSignal(organ_owner, list(COMSIG_HUMAN_BURNING, COMSIG_LIVING_POST_FULLY_HEAL))
///check if our antennae can burn off ;_;
/obj/item/organ/external/antennae/proc/try_burn_antennae(mob/living/carbon/human/human)
diff --git a/code/modules/surgery/organs/external/restyling.dm b/code/modules/surgery/organs/external/restyling.dm
index 7d6be1b6d58e3..f862d9e9c0867 100644
--- a/code/modules/surgery/organs/external/restyling.dm
+++ b/code/modules/surgery/organs/external/restyling.dm
@@ -1,7 +1,7 @@
-//Contains a bunch of procs for different types, but in the end it just lets you restyle external_organs so thats why its here
+//Contains a bunch of procs for different types, but in the end it just lets you restyle the bodypart overlay so thats why its here
///Helper proc to fetch a list of styles a player might want to restyle their features into during the round : returns list("Cabbage" = /datum/sprite_accessory/cabbage)
-/obj/item/organ/external/proc/get_valid_restyles()
+/obj/item/organ/proc/get_valid_restyles()
var/list/valid_restyles
valid_restyles = list()
@@ -31,18 +31,18 @@
///Asks the external organs inside the limb if they can restyle
/obj/item/bodypart/proc/attempt_feature_restyle(atom/source, mob/living/trimmer, atom/movable/original_target, body_zone, restyle_type, style_speed)
var/list/valid_features = list()
- for(var/obj/item/organ/external/feature in contents)
+ for(var/obj/item/organ/feature in contents)
if(feature.restyle_flags & restyle_type)
valid_features.Add(feature)
- var/obj/item/organ/external/target_organ
+ var/obj/item/organ/target_organ
switch(LAZYLEN(valid_features))
if(1)
target_organ = valid_features[1]
if(2 to INFINITY)
var/choose_options = list()
var/name_to_organ = list() //literally so I dont have to loop again after someones made their choice
- for(var/obj/item/organ/external/organ_choice as anything in valid_features)
+ for(var/obj/item/organ/organ_choice as anything in valid_features)
choose_options[organ_choice.name] = image(organ_choice)
name_to_organ[organ_choice.name] = organ_choice
var/picked_option = show_radial_menu(trimmer, original_target, choose_options, radius = 38, require_near = TRUE)
@@ -57,7 +57,7 @@
target_organ.attempt_feature_restyle(source, trimmer, original_target, body_zone, restyle_type, style_speed)
///Invoke async so we dont break signals
-/obj/item/organ/external/proc/on_attempt_feature_restyle(atom/source, mob/living/trimmer, atom/movable/original_target, body_zone, restyle_type, style_speed)
+/obj/item/organ/proc/on_attempt_feature_restyle(atom/source, mob/living/trimmer, atom/movable/original_target, body_zone, restyle_type, style_speed)
SIGNAL_HANDLER
if(restyle_flags & restyle_type)
@@ -66,7 +66,7 @@
to_chat(trimmer, span_warning("This tool is incompatible with the [src.name]!"))
///Restyles the external organ from a list of valid options
-/obj/item/organ/external/proc/attempt_feature_restyle(atom/source, mob/living/trimmer, atom/movable/original_target, body_zone, restyle_type, style_speed)
+/obj/item/organ/proc/attempt_feature_restyle(atom/source, mob/living/trimmer, atom/movable/original_target, body_zone, restyle_type, style_speed)
var/list/restyles = get_valid_restyles()
var/new_style = tgui_input_list(trimmer, "Select a new style", "Grooming", restyles)
@@ -80,5 +80,4 @@
span_notice("You successfully change [original_target == trimmer ? "your" : original_target.name + "'s"] [name].")
)
-
simple_change_sprite(restyles[new_style]) //turn name to type and pass it on
diff --git a/code/modules/surgery/organs/external/spines.dm b/code/modules/surgery/organs/external/spines.dm
index 86bff9a768939..214c58df09923 100644
--- a/code/modules/surgery/organs/external/spines.dm
+++ b/code/modules/surgery/organs/external/spines.dm
@@ -14,13 +14,13 @@
bodypart_overlay = /datum/bodypart_overlay/mutant/spines
-/obj/item/organ/external/spines/Insert(mob/living/carbon/receiver, special, movement_flags)
+/obj/item/organ/external/spines/mob_insert(mob/living/carbon/receiver, special, movement_flags)
// If we have a tail, attempt to add a tail spines overlay
var/obj/item/organ/external/tail/our_tail = receiver.get_organ_slot(ORGAN_SLOT_EXTERNAL_TAIL)
our_tail?.try_insert_tail_spines(our_tail.bodypart_owner)
return ..()
-/obj/item/organ/external/spines/Remove(mob/living/carbon/organ_owner, special, movement_flags)
+/obj/item/organ/external/spines/mob_remove(mob/living/carbon/organ_owner, special, movement_flags)
// If we have a tail, remove any tail spines overlay
var/obj/item/organ/external/tail/our_tail = organ_owner.get_organ_slot(ORGAN_SLOT_EXTERNAL_TAIL)
our_tail?.remove_tail_spines(our_tail.bodypart_owner)
diff --git a/code/modules/surgery/organs/external/tails.dm b/code/modules/surgery/organs/external/tails.dm
index 1a52bbe56cd5b..cae83153bdc55 100644
--- a/code/modules/surgery/organs/external/tails.dm
+++ b/code/modules/surgery/organs/external/tails.dm
@@ -20,7 +20,7 @@
///The overlay for tail spines, if any
var/datum/bodypart_overlay/mutant/tail_spines/tail_spines_overlay
-/obj/item/organ/external/tail/Insert(mob/living/carbon/receiver, special, movement_flags)
+/obj/item/organ/external/tail/mob_insert(mob/living/carbon/receiver, special, movement_flags)
. = ..()
if(.)
receiver.clear_mood_event("tail_lost")
@@ -34,7 +34,7 @@
// If it's not your tail AND of different species, we are horrified
if(IS_WEAKREF_OF(receiver, original_owner))
receiver.add_mood_event("tail_regained", /datum/mood_event/tail_regained_right)
- else if(type in receiver.dna.species.external_organs)
+ else if(type in receiver.dna.species.mutant_organs)
receiver.add_mood_event("tail_regained", /datum/mood_event/tail_regained_species)
else
receiver.add_mood_event("tail_regained", /datum/mood_event/tail_regained_wrong)
@@ -83,7 +83,7 @@
organ_owner.clear_mood_event("tail_regained")
- if(type in organ_owner.dna.species.external_organs)
+ if(type in organ_owner.dna.species.mutant_organs)
organ_owner.add_mood_event("tail_lost", /datum/mood_event/tail_lost)
organ_owner.add_mood_event("tail_balance_lost", /datum/mood_event/tail_balance_lost)
diff --git a/code/modules/surgery/organs/external/wings/functional_wings.dm b/code/modules/surgery/organs/external/wings/functional_wings.dm
index f4a5a23bf69ef..e1f364f547559 100644
--- a/code/modules/surgery/organs/external/wings/functional_wings.dm
+++ b/code/modules/surgery/organs/external/wings/functional_wings.dm
@@ -35,15 +35,14 @@
QDEL_NULL(fly)
return ..()
-/obj/item/organ/external/wings/functional/Insert(mob/living/carbon/receiver, special, movement_flags)
+/obj/item/organ/external/wings/functional/mob_insert(mob/living/carbon/receiver, special, movement_flags)
. = ..()
- if(!.)
- return
+
if(QDELETED(fly))
fly = new
fly.Grant(receiver)
-/obj/item/organ/external/wings/functional/Remove(mob/living/carbon/organ_owner, special, movement_flags)
+/obj/item/organ/external/wings/functional/mob_remove(mob/living/carbon/organ_owner, special, movement_flags)
. = ..()
fly?.Remove(organ_owner)
if(wings_open)
diff --git a/code/modules/surgery/organs/internal/appendix/_appendix.dm b/code/modules/surgery/organs/internal/appendix/_appendix.dm
index 83ed8da84aca0..169495bccaa33 100644
--- a/code/modules/surgery/organs/internal/appendix/_appendix.dm
+++ b/code/modules/surgery/organs/internal/appendix/_appendix.dm
@@ -6,7 +6,7 @@
name = "appendix"
icon_state = "appendix"
base_icon_state = "appendix"
- visual = FALSE
+
zone = BODY_ZONE_PRECISE_GROIN
slot = ORGAN_SLOT_APPENDIX
food_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/toxin/bad_food = 5)
diff --git a/code/modules/surgery/organs/internal/cyberimp/augments_eyes.dm b/code/modules/surgery/organs/internal/cyberimp/augments_eyes.dm
index d4c4b57d75f6b..aa67fe0c08de8 100644
--- a/code/modules/surgery/organs/internal/cyberimp/augments_eyes.dm
+++ b/code/modules/surgery/organs/internal/cyberimp/augments_eyes.dm
@@ -27,14 +27,13 @@
eye_owner.remove_traits(HUD_traits, ORGAN_TRAIT)
balloon_alert(eye_owner, "hud enabled")
-/obj/item/organ/internal/cyberimp/eyes/hud/Insert(mob/living/carbon/eye_owner, special = FALSE, movement_flags)
+/obj/item/organ/internal/cyberimp/eyes/hud/mob_insert(mob/living/carbon/eye_owner, special = FALSE, movement_flags)
. = ..()
- if(!.)
- return
+
eye_owner.add_traits(HUD_traits, ORGAN_TRAIT)
toggled_on = TRUE
-/obj/item/organ/internal/cyberimp/eyes/hud/Remove(mob/living/carbon/eye_owner, special, movement_flags)
+/obj/item/organ/internal/cyberimp/eyes/hud/mob_remove(mob/living/carbon/eye_owner, special, movement_flags)
. = ..()
eye_owner.remove_traits(HUD_traits, ORGAN_TRAIT)
toggled_on = FALSE
diff --git a/code/modules/surgery/organs/internal/cyberimp/augments_internal.dm b/code/modules/surgery/organs/internal/cyberimp/augments_internal.dm
index f71e29631b384..09955f45b0349 100644
--- a/code/modules/surgery/organs/internal/cyberimp/augments_internal.dm
+++ b/code/modules/surgery/organs/internal/cyberimp/augments_internal.dm
@@ -2,7 +2,7 @@
/obj/item/organ/internal/cyberimp
name = "cybernetic implant"
desc = "A state-of-the-art implant that improves a baseline's functionality."
- visual = FALSE
+
organ_flags = ORGAN_ROBOTIC
failing_desc = "seems to be broken."
var/implant_color = COLOR_WHITE
diff --git a/code/modules/surgery/organs/internal/ears/_ears.dm b/code/modules/surgery/organs/internal/ears/_ears.dm
index eba24086cca2b..53b95b54d9bcf 100644
--- a/code/modules/surgery/organs/internal/ears/_ears.dm
+++ b/code/modules/surgery/organs/internal/ears/_ears.dm
@@ -4,7 +4,6 @@
desc = "There are three parts to the ear. Inner, middle and outer. Only one of these parts should be normally visible."
zone = BODY_ZONE_HEAD
slot = ORGAN_SLOT_EARS
- visual = FALSE
gender = PLURAL
healing_factor = STANDARD_ORGAN_HEALING
@@ -136,28 +135,34 @@
icon_state = "kitty"
visual = TRUE
damage_multiplier = 2
- // Keeps track of which cat ears sprite is associated with this.
- var/variant = "Cat"
-/obj/item/organ/internal/ears/cat/Initialize(mapload, variant_pref)
- . = ..()
- if(variant_pref)
- variant = variant_pref
+ preference = "feature_human_ears"
-/obj/item/organ/internal/ears/cat/on_mob_insert(mob/living/carbon/human/ear_owner)
- . = ..()
- if(istype(ear_owner) && ear_owner.dna)
- color = ear_owner.hair_color
- ear_owner.dna.features["ears"] = ear_owner.dna.species.mutant_bodyparts["ears"] = variant
- ear_owner.dna.update_uf_block(DNA_EARS_BLOCK)
- ear_owner.update_body()
+ dna_block = DNA_EARS_BLOCK
-/obj/item/organ/internal/ears/cat/on_mob_remove(mob/living/carbon/human/ear_owner)
- . = ..()
- if(istype(ear_owner) && ear_owner.dna)
- color = ear_owner.hair_color
- ear_owner.dna.species.mutant_bodyparts -= "ears"
- ear_owner.update_body()
+ bodypart_overlay = /datum/bodypart_overlay/mutant/cat_ears
+
+/// Bodypart overlay for the horrible cat ears
+/datum/bodypart_overlay/mutant/cat_ears
+ layers = EXTERNAL_FRONT | EXTERNAL_ADJACENT
+ color_source = ORGAN_COLOR_HAIR
+ feature_key = "ears"
+
+ /// We dont color the inner part, which is the front layer
+ var/colorless_layer = EXTERNAL_FRONT
+
+/datum/bodypart_overlay/mutant/cat_ears/get_global_feature_list()
+ return SSaccessories.ears_list
+
+/datum/bodypart_overlay/mutant/cat_ears/can_draw_on_bodypart(mob/living/carbon/human/human)
+ if((human.head?.flags_inv & HIDEHAIR) || (human.wear_mask?.flags_inv & HIDEHAIR))
+ return FALSE
+ return TRUE
+
+/datum/bodypart_overlay/mutant/cat_ears/color_image(image/overlay, draw_layer, obj/item/bodypart/limb)
+ if(draw_layer != bitflag_to_layer(colorless_layer))
+ return ..()
+ return overlay
/obj/item/organ/internal/ears/penguin
name = "penguin ears"
diff --git a/code/modules/surgery/organs/internal/eyes/_eyes.dm b/code/modules/surgery/organs/internal/eyes/_eyes.dm
index bffdf1ae44d08..4b611852b79b7 100644
--- a/code/modules/surgery/organs/internal/eyes/_eyes.dm
+++ b/code/modules/surgery/organs/internal/eyes/_eyes.dm
@@ -52,21 +52,18 @@
/// Native FOV that will be applied if a config is enabled
var/native_fov = FOV_90_DEGREES
-/obj/item/organ/internal/eyes/Insert(mob/living/carbon/eye_recipient, special = FALSE, movement_flags = DELETE_IF_REPLACED)
+/obj/item/organ/internal/eyes/mob_insert(mob/living/carbon/receiver, special, movement_flags)
// If we don't do this before everything else, heterochromia will be reset leading to eye_color_right no longer being accurate
- if(ishuman(eye_recipient))
- var/mob/living/carbon/human/human_recipient = eye_recipient
+ if(ishuman(receiver))
+ var/mob/living/carbon/human/human_recipient = receiver
old_eye_color_left = human_recipient.eye_color_left
old_eye_color_right = human_recipient.eye_color_right
. = ..()
- if(!.)
- return
-
- eye_recipient.cure_blind(NO_EYES)
+ receiver.cure_blind(NO_EYES)
apply_damaged_eye_effects()
- refresh(eye_recipient, call_update = TRUE)
+ refresh(receiver, call_update = TRUE)
/// Refreshes the visuals of the eyes
/// If call_update is TRUE, we also will call update_body
@@ -94,31 +91,32 @@
if(call_update)
affected_human.update_body()
-/obj/item/organ/internal/eyes/Remove(mob/living/carbon/eye_owner, special, movement_flags)
+/obj/item/organ/internal/eyes/mob_remove(mob/living/carbon/organ_owner, special, movement_flags)
. = ..()
- if(ishuman(eye_owner))
- var/mob/living/carbon/human/human_owner = eye_owner
+
+ if(ishuman(organ_owner))
+ var/mob/living/carbon/human/human_owner = organ_owner
if(initial(eye_color_left))
human_owner.eye_color_left = old_eye_color_left
if(initial(eye_color_right))
human_owner.eye_color_right = old_eye_color_right
if(native_fov)
- eye_owner.remove_fov_trait(type)
+ organ_owner.remove_fov_trait(type)
if(!special)
human_owner.update_body()
// Cure blindness from eye damage
- eye_owner.cure_blind(EYE_DAMAGE)
- eye_owner.cure_nearsighted(EYE_DAMAGE)
+ organ_owner.cure_blind(EYE_DAMAGE)
+ organ_owner.cure_nearsighted(EYE_DAMAGE)
// Eye blind and temp blind go to, even if this is a bit of cheesy way to clear blindness
- eye_owner.remove_status_effect(/datum/status_effect/eye_blur)
- eye_owner.remove_status_effect(/datum/status_effect/temporary_blindness)
+ organ_owner.remove_status_effect(/datum/status_effect/eye_blur)
+ organ_owner.remove_status_effect(/datum/status_effect/temporary_blindness)
// Then become blind anyways (if not special)
if(!special)
- eye_owner.become_blind(NO_EYES)
+ organ_owner.become_blind(NO_EYES)
- eye_owner.update_tint()
- eye_owner.update_sight()
+ organ_owner.update_tint()
+ organ_owner.update_sight()
#define OFFSET_X 1
#define OFFSET_Y 2
@@ -428,7 +426,7 @@
deactivate(close_ui = TRUE)
/// Set the initial color of the eyes on insert to be the mob's previous eye color.
-/obj/item/organ/internal/eyes/robotic/glow/Insert(mob/living/carbon/eye_recipient, special = FALSE, movement_flags = DELETE_IF_REPLACED)
+/obj/item/organ/internal/eyes/robotic/glow/mob_insert(mob/living/carbon/eye_recipient, special = FALSE, movement_flags = DELETE_IF_REPLACED)
. = ..()
left_eye_color_string = old_eye_color_left
right_eye_color_string = old_eye_color_right
diff --git a/code/modules/surgery/organs/internal/heart/_heart.dm b/code/modules/surgery/organs/internal/heart/_heart.dm
index b0fac316ad3e3..d52e483da389d 100644
--- a/code/modules/surgery/organs/internal/heart/_heart.dm
+++ b/code/modules/surgery/organs/internal/heart/_heart.dm
@@ -3,7 +3,7 @@
desc = "I feel bad for the heartless bastard who lost this."
icon_state = "heart-on"
base_icon_state = "heart"
- visual = FALSE
+
zone = BODY_ZONE_CHEST
slot = ORGAN_SLOT_HEART
item_flags = NO_BLOOD_ON_ITEM
diff --git a/code/modules/surgery/organs/internal/heart/heart_ethereal.dm b/code/modules/surgery/organs/internal/heart/heart_ethereal.dm
index bd30318a72225..3e853a965b1bf 100644
--- a/code/modules/surgery/organs/internal/heart/heart_ethereal.dm
+++ b/code/modules/surgery/organs/internal/heart/heart_ethereal.dm
@@ -21,15 +21,14 @@
add_atom_colour(ethereal_color, FIXED_COLOUR_PRIORITY)
update_appearance()
-/obj/item/organ/internal/heart/ethereal/Insert(mob/living/carbon/heart_owner, special = FALSE, movement_flags)
+/obj/item/organ/internal/heart/ethereal/mob_insert(mob/living/carbon/heart_owner, special = FALSE, movement_flags)
. = ..()
- if(!.)
- return
+
RegisterSignal(heart_owner, COMSIG_MOB_STATCHANGE, PROC_REF(on_stat_change))
RegisterSignal(heart_owner, COMSIG_LIVING_POST_FULLY_HEAL, PROC_REF(on_owner_fully_heal))
RegisterSignal(heart_owner, COMSIG_QDELETING, PROC_REF(owner_deleted))
-/obj/item/organ/internal/heart/ethereal/Remove(mob/living/carbon/heart_owner, special, movement_flags)
+/obj/item/organ/internal/heart/ethereal/mob_remove(mob/living/carbon/heart_owner, special, movement_flags)
UnregisterSignal(heart_owner, list(COMSIG_MOB_STATCHANGE, COMSIG_LIVING_POST_FULLY_HEAL, COMSIG_QDELETING))
REMOVE_TRAIT(heart_owner, TRAIT_CORPSELOCKED, SPECIES_TRAIT)
stop_crystalization_process(heart_owner)
diff --git a/code/modules/surgery/organs/internal/liver/_liver.dm b/code/modules/surgery/organs/internal/liver/_liver.dm
index ef21595faf0fd..3933a9efa5930 100755
--- a/code/modules/surgery/organs/internal/liver/_liver.dm
+++ b/code/modules/surgery/organs/internal/liver/_liver.dm
@@ -7,7 +7,7 @@
name = "liver"
desc = "Pairing suggestion: chianti and fava beans."
icon_state = "liver"
- visual = FALSE
+
w_class = WEIGHT_CLASS_SMALL
zone = BODY_ZONE_CHEST
slot = ORGAN_SLOT_LIVER
diff --git a/code/modules/surgery/organs/internal/lungs/_lungs.dm b/code/modules/surgery/organs/internal/lungs/_lungs.dm
index 47078bfc8038e..9b38803dd7743 100644
--- a/code/modules/surgery/organs/internal/lungs/_lungs.dm
+++ b/code/modules/surgery/organs/internal/lungs/_lungs.dm
@@ -1,7 +1,7 @@
/obj/item/organ/internal/lungs
name = "lungs"
icon_state = "lungs"
- visual = FALSE
+
zone = BODY_ZONE_CHEST
slot = ORGAN_SLOT_LUNGS
gender = PLURAL
@@ -154,17 +154,16 @@
add_gas_reaction(/datum/gas/zauker, while_present = PROC_REF(too_much_zauker))
///Simply exists so that you don't keep any alerts from your previous lack of lungs.
-/obj/item/organ/internal/lungs/Insert(mob/living/carbon/receiver, special = FALSE, movement_flags)
+/obj/item/organ/internal/lungs/mob_insert(mob/living/carbon/receiver, special = FALSE, movement_flags)
. = ..()
- if(!.)
- return .
+
receiver.clear_alert(ALERT_NOT_ENOUGH_OXYGEN)
receiver.clear_alert(ALERT_NOT_ENOUGH_CO2)
receiver.clear_alert(ALERT_NOT_ENOUGH_NITRO)
receiver.clear_alert(ALERT_NOT_ENOUGH_PLASMA)
receiver.clear_alert(ALERT_NOT_ENOUGH_N2O)
-/obj/item/organ/internal/lungs/Remove(mob/living/carbon/organ_owner, special, movement_flags)
+/obj/item/organ/internal/lungs/mob_remove(mob/living/carbon/organ_owner, special, movement_flags)
. = ..()
// This is very "manual" I realize, but it's useful to ensure cleanup for gases we're removing happens
// Avoids stuck alerts and such
diff --git a/code/modules/surgery/organs/internal/stomach/_stomach.dm b/code/modules/surgery/organs/internal/stomach/_stomach.dm
index 3b6cf14e84464..4f1edd1542d69 100644
--- a/code/modules/surgery/organs/internal/stomach/_stomach.dm
+++ b/code/modules/surgery/organs/internal/stomach/_stomach.dm
@@ -5,7 +5,7 @@
name = "stomach"
desc = "Onaka ga suite imasu."
icon_state = "stomach"
- visual = FALSE
+
w_class = WEIGHT_CLASS_SMALL
zone = BODY_ZONE_CHEST
slot = ORGAN_SLOT_STOMACH
@@ -217,6 +217,7 @@
disgusted.adjust_confusion(2.5 SECONDS)
disgusted.adjust_stutter(2 SECONDS)
disgusted.vomit(VOMIT_CATEGORY_KNOCKDOWN, distance = 0)
+ disgusted.adjust_disgust(-50)
disgusted.set_dizzy_if_lower(10 SECONDS)
if(disgust >= DISGUST_LEVEL_DISGUSTED)
if(SPT_PROB(13, seconds_per_tick))
@@ -245,11 +246,11 @@
disgusted.throw_alert(ALERT_DISGUST, /atom/movable/screen/alert/disgusted)
disgusted.add_mood_event("disgust", /datum/mood_event/disgusted)
-/obj/item/organ/internal/stomach/Insert(mob/living/carbon/receiver, special, movement_flags)
+/obj/item/organ/internal/stomach/mob_insert(mob/living/carbon/receiver, special, movement_flags)
. = ..()
receiver.hud_used?.hunger?.update_appearance()
-/obj/item/organ/internal/stomach/Remove(mob/living/carbon/stomach_owner, special, movement_flags)
+/obj/item/organ/internal/stomach/mob_remove(mob/living/carbon/stomach_owner, special, movement_flags)
if(ishuman(stomach_owner))
var/mob/living/carbon/human/human_owner = owner
human_owner.clear_alert(ALERT_DISGUST)
diff --git a/code/modules/surgery/organs/internal/tongue/_tongue.dm b/code/modules/surgery/organs/internal/tongue/_tongue.dm
index fa034acf22bd7..7ddcfb6164fbf 100644
--- a/code/modules/surgery/organs/internal/tongue/_tongue.dm
+++ b/code/modules/surgery/organs/internal/tongue/_tongue.dm
@@ -2,7 +2,7 @@
name = "tongue"
desc = "A fleshy muscle mostly used for lying."
icon_state = "tongue"
- visual = FALSE
+
zone = BODY_ZONE_PRECISE_MOUTH
slot = ORGAN_SLOT_TONGUE
attack_verb_continuous = list("licks", "slobbers", "slaps", "frenches", "tongues")
@@ -124,30 +124,30 @@
food_taste_reaction = FOOD_LIKED
return food_taste_reaction
-/obj/item/organ/internal/tongue/Insert(mob/living/carbon/tongue_owner, special = FALSE, movement_flags)
+/obj/item/organ/internal/tongue/mob_insert(mob/living/carbon/receiver, special, movement_flags)
. = ..()
- if(!.)
- return
+
if(modifies_speech)
- RegisterSignal(tongue_owner, COMSIG_MOB_SAY, PROC_REF(handle_speech))
- tongue_owner.voice_filter = voice_filter
+ RegisterSignal(receiver, COMSIG_MOB_SAY, PROC_REF(handle_speech))
+ receiver.voice_filter = voice_filter
/* This could be slightly simpler, by making the removal of the
* NO_TONGUE_TRAIT conditional on the tongue's `sense_of_taste`, but
* then you can distinguish between ageusia from no tongue, and
* ageusia from having a non-tasting tongue.
*/
- REMOVE_TRAIT(tongue_owner, TRAIT_AGEUSIA, NO_TONGUE_TRAIT)
+ REMOVE_TRAIT(receiver, TRAIT_AGEUSIA, NO_TONGUE_TRAIT)
apply_tongue_effects()
-/obj/item/organ/internal/tongue/Remove(mob/living/carbon/tongue_owner, special, movement_flags)
+/obj/item/organ/internal/tongue/mob_remove(mob/living/carbon/organ_owner, special, movement_flags)
. = ..()
+
temp_say_mod = ""
- UnregisterSignal(tongue_owner, COMSIG_MOB_SAY)
- REMOVE_TRAIT(tongue_owner, TRAIT_SPEAKS_CLEARLY, SPEAKING_FROM_TONGUE)
- REMOVE_TRAIT(tongue_owner, TRAIT_AGEUSIA, ORGAN_TRAIT)
+ UnregisterSignal(organ_owner, COMSIG_MOB_SAY)
+ REMOVE_TRAIT(organ_owner, TRAIT_SPEAKS_CLEARLY, SPEAKING_FROM_TONGUE)
+ REMOVE_TRAIT(organ_owner, TRAIT_AGEUSIA, ORGAN_TRAIT)
// Carbons by default start with NO_TONGUE_TRAIT caused TRAIT_AGEUSIA
- ADD_TRAIT(tongue_owner, TRAIT_AGEUSIA, NO_TONGUE_TRAIT)
- tongue_owner.voice_filter = initial(tongue_owner.voice_filter)
+ ADD_TRAIT(organ_owner, TRAIT_AGEUSIA, NO_TONGUE_TRAIT)
+ organ_owner.voice_filter = initial(organ_owner.voice_filter)
/obj/item/organ/internal/tongue/apply_organ_damage(damage_amount, maximum = maxHealth, required_organ_flag)
. = ..()
diff --git a/code/modules/surgery/organs/internal/vocal_cords/_vocal_cords.dm b/code/modules/surgery/organs/internal/vocal_cords/_vocal_cords.dm
index 9183c7eb80944..f2d9abae41669 100644
--- a/code/modules/surgery/organs/internal/vocal_cords/_vocal_cords.dm
+++ b/code/modules/surgery/organs/internal/vocal_cords/_vocal_cords.dm
@@ -1,7 +1,6 @@
/obj/item/organ/internal/vocal_cords //organs that are activated through speech with the :x/MODE_KEY_VOCALCORDS channel
name = "vocal cords"
icon_state = "appendix"
- visual = FALSE
zone = BODY_ZONE_PRECISE_MOUTH
slot = ORGAN_SLOT_VOICE
gender = PLURAL
@@ -87,7 +86,6 @@
next_command = world.time + (cooldown * cooldown_mod)
/obj/item/organ/internal/adamantine_resonator
- visual = FALSE
name = "adamantine resonator"
desc = "Fragments of adamantine exist in all golems, stemming from their origins as purely magical constructs. These are used to \"hear\" messages from their leaders."
zone = BODY_ZONE_HEAD
diff --git a/code/modules/surgery/organs/organ_movement.dm b/code/modules/surgery/organs/organ_movement.dm
index ff9f753ce18a1..010daa3fd24c5 100644
--- a/code/modules/surgery/organs/organ_movement.dm
+++ b/code/modules/surgery/organs/organ_movement.dm
@@ -18,7 +18,8 @@
mob_insert(receiver, special, movement_flags)
bodypart_insert(limb_owner = receiver, movement_flags = movement_flags)
- return TRUE
+ if(!special)
+ receiver.update_body_parts()
/*
* Remove the organ from the select mob.
@@ -32,6 +33,9 @@
mob_remove(organ_owner, special, movement_flags)
bodypart_remove(limb_owner = organ_owner, movement_flags = movement_flags)
+ if(!special)
+ organ_owner.update_body_parts()
+
/*
* Insert the organ into the select mob.
*
@@ -65,6 +69,11 @@
wash(CLEAN_TYPE_BLOOD)
organ_flags &= ~ORGAN_VIRGIN
+ if(external_bodytypes)
+ receiver.synchronize_bodytypes()
+ if(external_bodyshapes)
+ receiver.synchronize_bodyshapes()
+
receiver.organs |= src
receiver.organs_slot[slot] = src
owner = receiver
@@ -120,6 +129,9 @@
ADD_TRAIT(src, TRAIT_NODROP, ORGAN_INSIDE_BODY_TRAIT)
interaction_flags_item &= ~INTERACT_ITEM_ATTACK_HAND_PICKUP
+ if(bodypart_overlay)
+ limb.add_bodypart_overlay(bodypart_overlay)
+
/*
* Remove the organ from the select mob.
*
@@ -163,6 +175,9 @@
SEND_SIGNAL(organ_owner, COMSIG_CARBON_LOSE_ORGAN, src, special)
ADD_TRAIT(src, TRAIT_USED_ORGAN, ORGAN_TRAIT)
+ organ_owner.synchronize_bodytypes()
+ organ_owner.synchronize_bodyshapes()
+
var/list/diseases = organ_owner.get_static_viruses()
if(!LAZYLEN(diseases))
return
@@ -211,6 +226,16 @@
REMOVE_TRAIT(src, TRAIT_NODROP, ORGAN_INSIDE_BODY_TRAIT)
interaction_flags_item |= INTERACT_ITEM_ATTACK_HAND_PICKUP
+ if(!bodypart_overlay)
+ return
+
+ limb.remove_bodypart_overlay(bodypart_overlay)
+
+ if(use_mob_sprite_as_obj_sprite)
+ update_appearance(UPDATE_OVERLAYS)
+
+ color = bodypart_overlay.draw_color // so a pink felinid doesn't drop a gray tail
+
/// In space station videogame, nothing is sacred. If somehow an organ is removed unexpectedly, handle it properly
/obj/item/organ/proc/forced_removal()
SIGNAL_HANDLER
diff --git a/code/modules/surgery/tools.dm b/code/modules/surgery/tools.dm
index 2bd8f485887f8..c0f71b57ca235 100644
--- a/code/modules/surgery/tools.dm
+++ b/code/modules/surgery/tools.dm
@@ -644,7 +644,7 @@
for(var/key in whitelist)
.["whitelist"] += whitelist[key]
-/obj/item/blood_filter/ui_act(action, params)
+/obj/item/blood_filter/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/tgs/core/README.md b/code/modules/tgs/core/README.md
index b82d8f49e297f..965e21b549a3e 100644
--- a/code/modules/tgs/core/README.md
+++ b/code/modules/tgs/core/README.md
@@ -3,7 +3,7 @@
This folder contains all DMAPI code not directly involved in an API.
- [_definitions.dm](./definitions.dm) contains defines needed across DMAPI internals.
+- [byond_world_export.dm](./byond_world_export.dm) contains the default `/datum/tgs_http_handler` implementation which uses `world.Export()`.
- [core.dm](./core.dm) contains the implementations of the `/world/proc/TgsXXX()` procs. Many map directly to the `/datum/tgs_api` functions. It also contains the /datum selection and setup code.
- [datum.dm](./datum.dm) contains the `/datum/tgs_api` declarations that all APIs must implement.
- [tgs_version.dm](./tgs_version.dm) contains the `/datum/tgs_version` definition
--
diff --git a/code/modules/tgs/core/byond_world_export.dm b/code/modules/tgs/core/byond_world_export.dm
new file mode 100644
index 0000000000000..6ef8d841b8f76
--- /dev/null
+++ b/code/modules/tgs/core/byond_world_export.dm
@@ -0,0 +1,22 @@
+/datum/tgs_http_handler/byond_world_export
+
+/datum/tgs_http_handler/byond_world_export/PerformGet(url)
+ // This is an infinite sleep until we get a response
+ var/export_response = world.Export(url)
+ TGS_DEBUG_LOG("byond_world_export: Export complete")
+
+ if(!export_response)
+ TGS_ERROR_LOG("byond_world_export: Failed request: [url]")
+ return new /datum/tgs_http_result(null, FALSE)
+
+ var/content = export_response["CONTENT"]
+ if(!content)
+ TGS_ERROR_LOG("byond_world_export: Failed request, missing content!")
+ return new /datum/tgs_http_result(null, FALSE)
+
+ var/response_json = TGS_FILE2TEXT_NATIVE(content)
+ if(!response_json)
+ TGS_ERROR_LOG("byond_world_export: Failed request, failed to load content!")
+ return new /datum/tgs_http_result(null, FALSE)
+
+ return new /datum/tgs_http_result(response_json, TRUE)
diff --git a/code/modules/tgs/core/core.dm b/code/modules/tgs/core/core.dm
index 15622228e91fe..63cb5a2c35147 100644
--- a/code/modules/tgs/core/core.dm
+++ b/code/modules/tgs/core/core.dm
@@ -1,4 +1,4 @@
-/world/TgsNew(datum/tgs_event_handler/event_handler, minimum_required_security_level = TGS_SECURITY_ULTRASAFE)
+/world/TgsNew(datum/tgs_event_handler/event_handler, minimum_required_security_level = TGS_SECURITY_ULTRASAFE, datum/tgs_http_handler/http_handler = null)
var/current_api = TGS_READ_GLOBAL(tgs)
if(current_api)
TGS_ERROR_LOG("API datum already set (\ref[current_api] ([current_api]))! Was TgsNew() called more than once?")
@@ -55,7 +55,10 @@
TGS_ERROR_LOG("Invalid parameter for event_handler: [event_handler]")
event_handler = null
- var/datum/tgs_api/new_api = new api_datum(event_handler, version)
+ if(!http_handler)
+ http_handler = new /datum/tgs_http_handler/byond_world_export
+
+ var/datum/tgs_api/new_api = new api_datum(event_handler, version, http_handler)
TGS_WRITE_GLOBAL(tgs, new_api)
diff --git a/code/modules/tgs/core/datum.dm b/code/modules/tgs/core/datum.dm
index f734fd0527f0e..3ca53e9bf7c65 100644
--- a/code/modules/tgs/core/datum.dm
+++ b/code/modules/tgs/core/datum.dm
@@ -6,7 +6,7 @@ TGS_DEFINE_AND_SET_GLOBAL(tgs, null)
var/list/warned_deprecated_command_runs
-/datum/tgs_api/New(datum/tgs_event_handler/event_handler, datum/tgs_version/version)
+/datum/tgs_api/New(datum/tgs_event_handler/event_handler, datum/tgs_version/version, datum/tgs_http_handler/http_handler)
..()
src.event_handler = event_handler
src.version = version
diff --git a/code/modules/tgs/includes.dm b/code/modules/tgs/includes.dm
index 23b714f9d0643..f5118ed55a3c2 100644
--- a/code/modules/tgs/includes.dm
+++ b/code/modules/tgs/includes.dm
@@ -1,4 +1,5 @@
#include "core\_definitions.dm"
+#include "core\byond_world_export.dm"
#include "core\core.dm"
#include "core\datum.dm"
#include "core\tgs_version.dm"
diff --git a/code/modules/tgs/v5/api.dm b/code/modules/tgs/v5/api.dm
index 05d0dee25b3c2..3e328fc7c27d5 100644
--- a/code/modules/tgs/v5/api.dm
+++ b/code/modules/tgs/v5/api.dm
@@ -31,9 +31,12 @@
var/detached = FALSE
-/datum/tgs_api/v5/New()
+ var/datum/tgs_http_handler/http_handler
+
+/datum/tgs_api/v5/New(datum/tgs_event_handler/event_handler, datum/tgs_version/version, datum/tgs_http_handler/http_handler)
. = ..()
interop_version = version
+ src.http_handler = http_handler
TGS_DEBUG_LOG("V5 API created: [json_encode(args)]")
/datum/tgs_api/v5/ApiVersion()
diff --git a/code/modules/tgs/v5/bridge.dm b/code/modules/tgs/v5/bridge.dm
index 0c5e701a32b60..62201fcc9e58b 100644
--- a/code/modules/tgs/v5/bridge.dm
+++ b/code/modules/tgs/v5/bridge.dm
@@ -78,27 +78,24 @@
WaitForReattach(FALSE)
TGS_DEBUG_LOG("Bridge request start")
- // This is an infinite sleep until we get a response
- var/export_response = world.Export(bridge_request)
+ var/datum/tgs_http_result/result = http_handler.PerformGet(bridge_request)
TGS_DEBUG_LOG("Bridge request complete")
- if(!export_response)
- TGS_ERROR_LOG("Failed bridge request: [bridge_request]")
+ if(isnull(result))
+ TGS_ERROR_LOG("Failed bridge request, handler returned null!")
return
- var/content = export_response["CONTENT"]
- if(!content)
- TGS_ERROR_LOG("Failed bridge request, missing content!")
+ if(!istype(result) || result.type != /datum/tgs_http_result)
+ TGS_ERROR_LOG("Failed bridge request, handler returned non-[/datum/tgs_http_result]!")
return
- var/response_json = TGS_FILE2TEXT_NATIVE(content)
- if(!response_json)
- TGS_ERROR_LOG("Failed bridge request, failed to load content!")
+ if(!result.success)
+ TGS_DEBUG_LOG("Failed bridge request, HTTP request failed!")
return
- var/list/bridge_response = json_decode(response_json)
+ var/list/bridge_response = json_decode(result.response_text)
if(!bridge_response)
- TGS_ERROR_LOG("Failed bridge request, bad json: [response_json]")
+ TGS_ERROR_LOG("Failed bridge request, bad json: [result.response_text]")
return
var/error = bridge_response[DMAPI5_RESPONSE_ERROR_MESSAGE]
diff --git a/code/modules/tgui/states.dm b/code/modules/tgui/states.dm
index dc3d543f14364..a29279457a04a 100644
--- a/code/modules/tgui/states.dm
+++ b/code/modules/tgui/states.dm
@@ -67,7 +67,7 @@
else if(stat)
return UI_DISABLED
// Update UIs if incapicitated but concious.
- else if(incapacitated())
+ else if(incapacitated)
return UI_UPDATE
return UI_INTERACTIVE
diff --git a/code/modules/tgui/states/not_incapacitated.dm b/code/modules/tgui/states/not_incapacitated.dm
index f7278c86de473..ab8cd5f6246fd 100644
--- a/code/modules/tgui/states/not_incapacitated.dm
+++ b/code/modules/tgui/states/not_incapacitated.dm
@@ -29,6 +29,6 @@ GLOBAL_DATUM_INIT(not_incapacitated_turf_state, /datum/ui_state/not_incapacitate
/datum/ui_state/not_incapacitated_state/can_use_topic(src_object, mob/user)
if(user.stat != CONSCIOUS)
return UI_CLOSE
- if(HAS_TRAIT(src, TRAIT_UI_BLOCKED) || user.incapacitated() || (turf_check && !isturf(user.loc)))
+ if(HAS_TRAIT(src, TRAIT_UI_BLOCKED) || user.incapacitated || (turf_check && !isturf(user.loc)))
return UI_DISABLED
return UI_INTERACTIVE
diff --git a/code/modules/tgui/states/reverse_contained.dm b/code/modules/tgui/states/reverse_contained.dm
deleted file mode 100644
index a6d1034a78919..0000000000000
--- a/code/modules/tgui/states/reverse_contained.dm
+++ /dev/null
@@ -1,18 +0,0 @@
-/*!
- * Not copyrighted, but magatsuchi made it.
- *
- */
-
-/**
- * tgui state: reverse_contained_state
- *
- *
- * Checks if src_object is inside of user.
- */
-
-GLOBAL_DATUM_INIT(reverse_contained_state, /datum/ui_state/reverse_contained_state, new)
-
-/datum/ui_state/reverse_contained_state/can_use_topic(atom/src_object, mob/user)
- if(!user.contains(src_object))
- return UI_CLOSE
- return user.shared_ui_interaction(src_object)
diff --git a/code/modules/tgui_input/alert.dm b/code/modules/tgui_input/alert.dm
index 4749ef278725e..0b12184ba7a88 100644
--- a/code/modules/tgui_input/alert.dm
+++ b/code/modules/tgui_input/alert.dm
@@ -120,7 +120,7 @@
data["timeout"] = CLAMP01((timeout - (world.time - start_time) - 1 SECONDS) / (timeout - 1 SECONDS))
return data
-/datum/tgui_alert/ui_act(action, list/params)
+/datum/tgui_alert/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if (.)
return
diff --git a/code/modules/tgui_input/checkboxes.dm b/code/modules/tgui_input/checkboxes.dm
index 53b264038dc20..9e548b9c13640 100644
--- a/code/modules/tgui_input/checkboxes.dm
+++ b/code/modules/tgui_input/checkboxes.dm
@@ -115,7 +115,7 @@
return data
-/datum/tgui_checkbox_input/ui_act(action, list/params)
+/datum/tgui_checkbox_input/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if (.)
return
diff --git a/code/modules/tgui_input/keycombo.dm b/code/modules/tgui_input/keycombo.dm
index 948dbaea234a8..7a9e8399a8cfb 100644
--- a/code/modules/tgui_input/keycombo.dm
+++ b/code/modules/tgui_input/keycombo.dm
@@ -8,7 +8,7 @@
* * user - The user to show the number input to.
* * message - The content of the number input, shown in the body of the TGUI window.
* * title - The title of the number input modal, shown on the top of the TGUI window.
- * * default - The default (or current) key, shown as a placeholder.
+ * * default - The default (or current) key, shown as a placeholder.
*/
/proc/tgui_input_keycombo(mob/user = usr, message, title = "Key Input", default = 0, timeout = 0, ui_state = GLOB.always_state)
if (!istype(user))
@@ -107,7 +107,7 @@
data["timeout"] = CLAMP01((timeout - (world.time - start_time) - 1 SECONDS) / (timeout - 1 SECONDS))
return data
-/datum/tgui_input_keycombo/ui_act(action, list/params)
+/datum/tgui_input_keycombo/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if (.)
return
diff --git a/code/modules/tgui_input/list.dm b/code/modules/tgui_input/list.dm
index 22c6d48edfc5a..fcee265e5a8b4 100644
--- a/code/modules/tgui_input/list.dm
+++ b/code/modules/tgui_input/list.dm
@@ -137,7 +137,7 @@
data["timeout"] = clamp((timeout - (world.time - start_time) - 1 SECONDS) / (timeout - 1 SECONDS), 0, 1)
return data
-/datum/tgui_list_input/ui_act(action, list/params)
+/datum/tgui_list_input/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if (.)
return
diff --git a/code/modules/tgui_input/number.dm b/code/modules/tgui_input/number.dm
index 68998acb0331f..0266610b84c99 100644
--- a/code/modules/tgui_input/number.dm
+++ b/code/modules/tgui_input/number.dm
@@ -136,7 +136,7 @@
data["timeout"] = CLAMP01((timeout - (world.time - start_time) - 1 SECONDS) / (timeout - 1 SECONDS))
return data
-/datum/tgui_input_number/ui_act(action, list/params)
+/datum/tgui_input_number/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if (.)
return
diff --git a/code/modules/tgui_input/text.dm b/code/modules/tgui_input/text.dm
index 806696dcf4f44..ec94fbd6766ac 100644
--- a/code/modules/tgui_input/text.dm
+++ b/code/modules/tgui_input/text.dm
@@ -133,7 +133,7 @@
data["timeout"] = CLAMP01((timeout - (world.time - start_time) - 1 SECONDS) / (timeout - 1 SECONDS))
return data
-/datum/tgui_input_text/ui_act(action, list/params)
+/datum/tgui_input_text/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if (.)
return
diff --git a/code/modules/transport/elevator/elev_panel.dm b/code/modules/transport/elevator/elev_panel.dm
index 0b5e99bdbb059..659049a7448ca 100644
--- a/code/modules/transport/elevator/elev_panel.dm
+++ b/code/modules/transport/elevator/elev_panel.dm
@@ -299,7 +299,7 @@
return data
-/obj/machinery/elevator_control_panel/ui_act(action, list/params)
+/obj/machinery/elevator_control_panel/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/transport/tram/tram_controller.dm b/code/modules/transport/tram/tram_controller.dm
index 1323953de78f7..11b3bbcdec9e9 100644
--- a/code/modules/transport/tram/tram_controller.dm
+++ b/code/modules/transport/tram/tram_controller.dm
@@ -1096,7 +1096,7 @@
return data
-/obj/machinery/transport/tram_controller/ui_act(action, params)
+/obj/machinery/transport/tram_controller/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if (.)
return
diff --git a/code/modules/transport/tram/tram_controls.dm b/code/modules/transport/tram/tram_controls.dm
index 0bfce56aa5c96..308e58cf5f049 100644
--- a/code/modules/transport/tram/tram_controls.dm
+++ b/code/modules/transport/tram/tram_controls.dm
@@ -130,7 +130,7 @@
this_destination["id"] = destination.platform_code
. += list(this_destination)
-/obj/machinery/computer/tram_controls/ui_act(action, params)
+/obj/machinery/computer/tram_controls/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/transport/tram/tram_signals.dm b/code/modules/transport/tram/tram_signals.dm
index faf4a46e11e28..a5d309b8378b0 100644
--- a/code/modules/transport/tram/tram_signals.dm
+++ b/code/modules/transport/tram/tram_signals.dm
@@ -150,8 +150,8 @@
. += span_notice("The orange [EXAMINE_HINT("remote warning")] light is on.")
. += span_notice("The status display reads: Check track sensor.")
if(TRANSPORT_REMOTE_FAULT)
- . += span_notice("The blue [EXAMINE_HINT("remote fault")] light is on.")
- . += span_notice("The status display reads: Check tram controller.")
+ . += span_notice("The blue [EXAMINE_HINT("telecoms failure")] light is on.")
+ . += span_notice("The status display reads: Check telecommunications network.")
if(TRANSPORT_LOCAL_FAULT)
. += span_notice("The red [EXAMINE_HINT("local fault")] light is on.")
. += span_notice("The status display reads: Repair required.")
@@ -246,10 +246,10 @@
operating_status = TRANSPORT_REMOTE_FAULT
else
operating_status = TRANSPORT_SYSTEM_NORMAL
+ if(isnull(linked_sensor))
+ link_sensor()
+ wake_sensor()
- if(isnull(linked_sensor))
- link_sensor()
- wake_sensor()
update_operating()
/obj/machinery/transport/crossing_signal/on_set_machine_stat()
@@ -304,6 +304,8 @@
// degraded signal operating conditions of any type show blue
var/idle_aspect = operating_status == TRANSPORT_SYSTEM_NORMAL ? XING_STATE_GREEN : XING_STATE_MALF
var/datum/transport_controller/linear/tram/tram = transport_ref?.resolve()
+ if(tram.controller_status & COMM_ERROR)
+ idle_aspect = XING_STATE_MALF
// Check for stopped states. Will kill the process since tram starting up will restart process.
if(!tram || !tram.controller_operational || !tram.controller_active || !is_operational || !inbound || !outbound)
diff --git a/code/modules/transport/transport_module.dm b/code/modules/transport/transport_module.dm
index af8f4199438db..01a3493130501 100644
--- a/code/modules/transport/transport_module.dm
+++ b/code/modules/transport/transport_module.dm
@@ -612,7 +612,7 @@
if(!isliving(user))
return FALSE
// Gotta be awake and aware
- if(user.incapacitated())
+ if(user.incapacitated)
return FALSE
// Maintain the god given right to fight an elevator
if(user.combat_mode)
@@ -704,7 +704,7 @@
* * boolean, FALSE if the menu should be closed, TRUE if the menu is clear to stay opened.
*/
/obj/structure/transport/linear/proc/check_menu(mob/user, starting_loc)
- if(user.incapacitated() || !user.Adjacent(src) || starting_loc != src.loc)
+ if(user.incapacitated || !user.Adjacent(src) || starting_loc != src.loc)
return FALSE
return TRUE
diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm
index a42c25dc94ee1..f56eab7af5fda 100644
--- a/code/modules/unit_tests/_unit_tests.dm
+++ b/code/modules/unit_tests/_unit_tests.dm
@@ -150,6 +150,7 @@
#include "gas_transfer.dm"
#include "get_turf_pixel.dm"
#include "geyser.dm"
+#include "gloves_and_shoes_armor.dm"
#include "greyscale_config.dm"
#include "hallucination_icons.dm"
#include "heretic_knowledge.dm"
diff --git a/code/modules/unit_tests/fish_unit_tests.dm b/code/modules/unit_tests/fish_unit_tests.dm
index 5cb582ca9694a..2fb2487f7810d 100644
--- a/code/modules/unit_tests/fish_unit_tests.dm
+++ b/code/modules/unit_tests/fish_unit_tests.dm
@@ -1,5 +1,21 @@
#define TRAIT_FISH_TESTING "made_you_read_this"
+///Ensures that all fish have an aquarium icon state and that sprite_width and sprite_height have been set.
+/datum/unit_test/fish_aquarium_icons
+
+/datum/unit_test/fish_aquarium_icons/Run()
+ for(var/obj/item/fish/fish as anything in subtypesof(/obj/item/fish))
+ if(ispath(fish, /obj/item/fish/testdummy)) //We don't care about unit test fish.
+ continue
+ var/init_icon = fish::dedicated_in_aquarium_icon
+ var/init_icon_state = fish::dedicated_in_aquarium_icon_state || "[fish::icon_state]_small"
+ if(!icon_exists(init_icon, init_icon_state))
+ TEST_FAIL("[fish] with doesn't have a \"[init_icon_state]\" aquarium icon state in [init_icon]. Please make one.")
+ if(!fish::sprite_width)
+ TEST_FAIL("[fish] doesn't have a set sprite_width.")
+ if(!fish::sprite_height)
+ TEST_FAIL("[fish] doesn't have a set sprite_height.")
+
///Checks that things associated with fish size and weight work correctly.
/datum/unit_test/fish_size_weight
@@ -76,10 +92,11 @@
incompatible_traits = list(/datum/fish_trait/dummy/two)
inheritability = 100
diff_traits_inheritability = 100
+ reagents_to_add = list(/datum/reagent = 10)
/datum/fish_trait/dummy/apply_to_fish(obj/item/fish/fish)
+ . = ..()
ADD_TRAIT(fish, TRAIT_FISH_TESTING, FISH_TRAIT_DATUM)
- fish.grind_results[/datum/reagent] = 10
/datum/fish_trait/dummy/two
incompatible_traits = list(/datum/fish_trait/dummy)
@@ -259,15 +276,17 @@
/datum/unit_test/explosive_fishing/Run()
var/datum/fish_source/source = GLOB.preset_fish_sources[/datum/fish_source/unit_test]
source.spawn_reward_from_explosion(run_loc_floor_bottom_left, 1)
- if(length(source.fish_table))
+ if(source.fish_counts[/obj/item/wrench])
TEST_FAIL("The unit test item wasn't removed/spawned from fish_table during 'spawn_reward_from_explosion'.")
/datum/fish_source/unit_test
fish_table = list(
/obj/item/wrench = 1,
+ /obj/item/screwdriver = INFINITY,
)
fish_counts = list(
/obj/item/wrench = 1,
+ /obj/item/screwdriver = 0,
)
#undef TRAIT_FISH_TESTING
diff --git a/code/modules/unit_tests/gloves_and_shoes_armor.dm b/code/modules/unit_tests/gloves_and_shoes_armor.dm
new file mode 100644
index 0000000000000..fc67b21537e0b
--- /dev/null
+++ b/code/modules/unit_tests/gloves_and_shoes_armor.dm
@@ -0,0 +1,25 @@
+/// Checks if any gloves or shoes that have non bio/fire/acid armor haven't been marked with ARMS or LEGS coverage respectively
+/datum/unit_test/gloves_and_shoes_armor
+
+/datum/unit_test/gloves_and_shoes_armor/Run()
+ for (var/obj/item/clothing/gloves/gloves as anything in subtypesof(/obj/item/clothing/gloves))
+ var/datum/armor/armor = gloves::armor_type
+ if (!armor)
+ continue
+
+ if (gloves::body_parts_covered != HANDS)
+ continue
+
+ if (armor::melee || armor::bomb || armor::energy || armor::laser || armor::bullet || armor::wound)
+ TEST_FAIL("[gloves] has non-bio/acid/fire armor but doesn't cover non-hand bodyparts.")
+
+ for (var/obj/item/clothing/shoes/shoes as anything in subtypesof(/obj/item/clothing/shoes))
+ var/datum/armor/armor = shoes::armor_type
+ if (!armor)
+ continue
+
+ if (shoes::body_parts_covered != FEET)
+ continue
+
+ if (armor::melee || armor::bomb || armor::energy || armor::laser || armor::bullet || armor::wound)
+ TEST_FAIL("[shoes] has non-bio/acid/fire armor but doesn't cover non-feet bodyparts.")
diff --git a/code/modules/unit_tests/mecha_damage.dm b/code/modules/unit_tests/mecha_damage.dm
index dc5f4ecae8a1d..9dd82dddc41ec 100644
--- a/code/modules/unit_tests/mecha_damage.dm
+++ b/code/modules/unit_tests/mecha_damage.dm
@@ -25,7 +25,8 @@
// Get a sample "melee" weapon.
// The energy axe is chosen here due to having a high base force, to make sure we get over the equipment DT.
var/obj/item/dummy_melee = allocate(/obj/item/melee/energy/axe)
- var/expected_melee_damage = round(dummy_melee.force * (1 - expected_melee_armor / 100) * dummy_melee.demolition_mod, DAMAGE_PRECISION)
+ dummy_melee.force = 150
+ var/expected_melee_damage = round(dummy_melee.force * (1 - expected_melee_armor / 100) * dummy_melee.demolition_mod * demo_mech.facing_modifiers[MECHA_FRONT_ARMOUR], DAMAGE_PRECISION)
// Get a sample laser weapon.
// The captain's laser gun here is chosen primarily because it deals more damage than normal lasers.
diff --git a/code/modules/unit_tests/organ_bodypart_shuffle.dm b/code/modules/unit_tests/organ_bodypart_shuffle.dm
index 842dd1c6c1344..11c0bcd71becb 100644
--- a/code/modules/unit_tests/organ_bodypart_shuffle.dm
+++ b/code/modules/unit_tests/organ_bodypart_shuffle.dm
@@ -2,7 +2,7 @@
/datum/unit_test/organ_bodypart_shuffle
/datum/unit_test/organ_bodypart_shuffle/Run()
- var/mob/living/carbon/human/hollow_boy = allocate(/mob/living/carbon/human/consistent)
+ var/mob/living/carbon/human/hollow_boy = allocate(/mob/living/carbon/human/consistent) //freshly filled with wet insides
// Test if organs are all properly updating when forcefully removed
var/list/removed_organs = list()
@@ -30,5 +30,3 @@
continue
TEST_ASSERT(organ in hollow_boy.organs, "Organ '[organ.name] was put in an empty bodypart that replaced a humans, but the organ did not come with.")
- // Test if bodyparts are all properly updating when forcefully removed
- hollow_boy = allocate(/mob/living/carbon/human/consistent) //freshly filled with wet insides
diff --git a/code/modules/unit_tests/organ_set_bonus.dm b/code/modules/unit_tests/organ_set_bonus.dm
index 967803e223f17..1231ddd5c6670 100644
--- a/code/modules/unit_tests/organ_set_bonus.dm
+++ b/code/modules/unit_tests/organ_set_bonus.dm
@@ -30,7 +30,7 @@
// Attempt to insert entire list of mutant organs for the given infusion_entry.
for(var/obj/item/organ/organ as anything in output_organs)
organ = new organ()
- TEST_ASSERT(organ.Insert(lab_rat, special = TRUE, movement_flags = DELETE_IF_REPLACED), "The organ `[organ.type]` for `[infuser_entry.type]` was not inserted in the mob when expected, Insert() returned falsy when TRUE was expected.")
+ organ.Insert(lab_rat, special = TRUE, movement_flags = DELETE_IF_REPLACED)
inserted_organs += organ
// Search for added Status Effect.
diff --git a/code/modules/unit_tests/outfit_sanity.dm b/code/modules/unit_tests/outfit_sanity.dm
index 36fc4570540f4..d0de12a7b204b 100644
--- a/code/modules/unit_tests/outfit_sanity.dm
+++ b/code/modules/unit_tests/outfit_sanity.dm
@@ -87,4 +87,13 @@
if (!H.equip_to_slot_or_del(new path(H), ITEM_SLOT_BACKPACK, TRUE, indirect_action = TRUE))
TEST_FAIL("[outfit.name]'s backpack_contents are invalid! Couldn't add [path] to backpack.")
+ if (outfit.belt_contents)
+ var/list/belt_contents = outfit.belt_contents?.Copy()
+ for (var/path in belt_contents)
+ var/number = belt_contents[path] || 1
+ for (var/_ in 1 to number)
+ if (!H.equip_to_slot_or_del(new path(H), ITEM_SLOT_BELTPACK, TRUE, indirect_action = TRUE))
+ TEST_FAIL("[outfit.name]'s belt_contents are invalid! Couldn't add [path] to backpack.")
+
+
#undef CHECK_OUTFIT_SLOT
diff --git a/code/modules/unit_tests/say.dm b/code/modules/unit_tests/say.dm
index 7536392e70cd4..a845b6ccf9886 100644
--- a/code/modules/unit_tests/say.dm
+++ b/code/modules/unit_tests/say.dm
@@ -237,9 +237,9 @@
// Normally speaking, if there isn't a functional telecomms array on the same z-level, then handheld radios
// have a short delay before sending the message. We use the centcom frequency to get around this.
speaker_radio.set_frequency(FREQ_CENTCOM)
- speaker_radio.independent = TRUE
+ speaker_radio.special_channels = RADIO_SPECIAL_CENTCOM
listener_radio.set_frequency(FREQ_CENTCOM)
- listener_radio.independent = TRUE
+ listener_radio.special_channels = RADIO_SPECIAL_CENTCOM
var/pangram_quote = "The quick brown fox jumps over the lazy dog"
diff --git a/code/modules/unit_tests/screenshots/screenshot_antag_icons_bloodbrother.png b/code/modules/unit_tests/screenshots/screenshot_antag_icons_bloodbrother.png
index f34414bdc13d3..61b7c36d94a02 100644
Binary files a/code/modules/unit_tests/screenshots/screenshot_antag_icons_bloodbrother.png and b/code/modules/unit_tests/screenshots/screenshot_antag_icons_bloodbrother.png differ
diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_lizard_ashwalker.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_lizard_ashwalker.png
index 70d445b771277..3437280e851ba 100644
Binary files a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_lizard_ashwalker.png and b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_lizard_ashwalker.png differ
diff --git a/code/modules/unit_tests/unit_test.dm b/code/modules/unit_tests/unit_test.dm
index ed2510b829434..84c0fa20a678b 100644
--- a/code/modules/unit_tests/unit_test.dm
+++ b/code/modules/unit_tests/unit_test.dm
@@ -112,6 +112,16 @@ GLOBAL_VAR_INIT(focused_tests, focused_tests())
allocated += instance
return instance
+/// Resets the air of our testing room to its default
+/datum/unit_test/proc/restore_atmos()
+ var/area/working_area = run_loc_floor_bottom_left.loc
+ var/list/turf/to_restore = working_area.get_turfs_from_all_zlevels()
+ for(var/turf/open/restore in to_restore)
+ var/datum/gas_mixture/GM = SSair.parse_gas_string(restore.initial_gas_mix, /datum/gas_mixture/turf)
+ restore.copy_air(GM)
+ restore.temperature = initial(restore.temperature)
+ restore.air_update_turf(update = FALSE, remove = FALSE)
+
/datum/unit_test/proc/test_screenshot(name, icon/icon)
if (!istype(icon))
TEST_FAIL("[icon] is not an icon.")
@@ -179,6 +189,7 @@ GLOBAL_VAR_INIT(focused_tests, focused_tests())
else
test.Run()
+ test.restore_atmos()
duration = REALTIMEOFDAY - duration
GLOB.current_test = null
diff --git a/code/modules/uplink/uplink_items.dm b/code/modules/uplink/uplink_items.dm
index 7e501217eb68c..0d347709536ee 100644
--- a/code/modules/uplink/uplink_items.dm
+++ b/code/modules/uplink/uplink_items.dm
@@ -172,6 +172,8 @@
ADD_TRAIT(created, TRAIT_CONTRABAND, INNATE_TRAIT)
for(var/obj/contained as anything in created.get_all_contents())
ADD_TRAIT(contained, TRAIT_CONTRABAND, INNATE_TRAIT)
+
+ if(isgun(created))
replace_pin(created)
else if(istype(created, /obj/item/storage/toolbox/guncase))
for(var/obj/item/gun/gun in created)
diff --git a/code/modules/uplink/uplink_items/badass.dm b/code/modules/uplink/uplink_items/badass.dm
index 08cf3affe0741..5c5e0390b5046 100644
--- a/code/modules/uplink/uplink_items/badass.dm
+++ b/code/modules/uplink/uplink_items/badass.dm
@@ -91,7 +91,7 @@
/datum/uplink_item/badass/stickers
name = "Syndicate Sticker Pack"
desc = "Contains 8 random stickers precisely engineered to resemble suspicious objects, which may or may not be useful for fooling crew."
- item = /obj/item/storage/box/syndie_kit/stickers
+ item = /obj/item/storage/box/stickers/syndie_kit
cost = 1
/datum/uplink_item/badass/demotivational_posters
diff --git a/code/modules/uplink/uplink_items/dangerous.dm b/code/modules/uplink/uplink_items/dangerous.dm
index 691f4f2c8f37f..faf3751d7a51e 100644
--- a/code/modules/uplink/uplink_items/dangerous.dm
+++ b/code/modules/uplink/uplink_items/dangerous.dm
@@ -91,7 +91,7 @@
/datum/uplink_item/dangerous/revolver
name = "Syndicate Revolver"
- desc = "Waffle Co.'s modernized Syndicate revolver. Fires 7 brutal rounds of .357 Magnum."
+ desc = "Waffle Corp's modernized Syndicate revolver. Fires 7 brutal rounds of .357 Magnum."
item = /obj/item/gun/ballistic/revolver/syndicate
cost = 13
surplus = 50
diff --git a/code/modules/uplink/uplink_items/job.dm b/code/modules/uplink/uplink_items/job.dm
index bfb9aa3f332cd..be9d558687d8c 100644
--- a/code/modules/uplink/uplink_items/job.dm
+++ b/code/modules/uplink/uplink_items/job.dm
@@ -109,7 +109,7 @@
/datum/uplink_item/role_restricted/ez_clean_bundle
name = "EZ Clean Grenade Bundle"
- desc = "A box with three cleaner grenades using the trademark Waffle Co. formula. Serves as a cleaner and causes acid damage to anyone standing nearby. \
+ desc = "A box with three cleaner grenades using the trademark Waffle Corp. formula. Serves as a cleaner and causes acid damage to anyone standing nearby. \
The acid only affects carbon-based creatures."
item = /obj/item/storage/box/syndie_kit/ez_clean
cost = 6
@@ -164,7 +164,7 @@
/datum/uplink_item/role_restricted/gorillacube
name = "Gorilla Cube"
- desc = "A Waffle Co. brand gorilla cube. Eat big to get big. \
+ desc = "A Waffle Corp. brand gorilla cube. Eat big to get big. \
Caution: Product may rehydrate when exposed to water."
item = /obj/item/food/monkeycube/gorilla
cost = 6
@@ -389,5 +389,6 @@
restricted_roles = list(JOB_MIME)
restricted = TRUE
refundable = FALSE
+ progression_minimum = 30 MINUTES
purchasable_from = parent_type::purchasable_from & ~UPLINK_SPY
diff --git a/code/modules/uplink/uplink_items/nukeops.dm b/code/modules/uplink/uplink_items/nukeops.dm
index 80df9de47cfbc..9b86a91b0264c 100644
--- a/code/modules/uplink/uplink_items/nukeops.dm
+++ b/code/modules/uplink/uplink_items/nukeops.dm
@@ -194,7 +194,7 @@
/datum/uplink_item/weapon_kits/medium_cost/revolvercase
name = "Syndicate Revolver Case (Moderate)"
- desc = "Waffle Co.'s modernized Syndicate revolver. Fires 7 brutal rounds of .357 Magnum. \
+ desc = "Waffle Corp's modernized Syndicate revolver. Fires 7 brutal rounds of .357 Magnum. \
A classic operative weapon, brought to the modern era. Comes with 3 additional speedloaders of .357."
item = /obj/item/storage/toolbox/guncase/revolver
diff --git a/code/modules/uplink/uplink_items/stealthy.dm b/code/modules/uplink/uplink_items/stealthy.dm
index e4c4de412fb44..6bd315498afa1 100644
--- a/code/modules/uplink/uplink_items/stealthy.dm
+++ b/code/modules/uplink/uplink_items/stealthy.dm
@@ -29,6 +29,12 @@
item = /obj/item/pen/edagger
cost = 2
+/datum/uplink_item/stealthy_weapons/slipstick
+ name = "Syndie Lipstick"
+ desc = "Stylish way to kiss to death, isn't it syndiekisser?"
+ item = /obj/item/lipstick/syndie
+ cost = 6
+
/datum/uplink_item/stealthy_weapons/traitor_chem_bottle
name = "Poison Kit"
desc = "An assortment of deadly chemicals packed into a compact box. Comes with a syringe for more precise application."
diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm
index d28b510328a98..846d6a6434b1e 100644
--- a/code/modules/vehicles/mecha/_mecha.dm
+++ b/code/modules/vehicles/mecha/_mecha.dm
@@ -586,7 +586,7 @@
/obj/vehicle/sealed/mecha/proc/process_occupants(seconds_per_tick)
for(var/mob/living/occupant as anything in occupants)
- if(!(mecha_flags & IS_ENCLOSED) && occupant?.incapacitated()) //no sides mean it's easy to just sorta fall out if you're incapacitated.
+ if(!(mecha_flags & IS_ENCLOSED) && occupant?.incapacitated) //no sides mean it's easy to just sorta fall out if you're incapacitated.
mob_exit(occupant, randomstep = TRUE) //bye bye
continue
if(cell && cell.maxcharge)
@@ -658,7 +658,7 @@
if(phasing)
balloon_alert(user, "not while [phasing]!")
return
- if(user.incapacitated())
+ if(user.incapacitated)
return
if(!get_charge())
return
diff --git a/code/modules/vehicles/mecha/combat/durand.dm b/code/modules/vehicles/mecha/combat/durand.dm
index c6fcae75bc98f..a466bc30d2245 100644
--- a/code/modules/vehicles/mecha/combat/durand.dm
+++ b/code/modules/vehicles/mecha/combat/durand.dm
@@ -50,7 +50,7 @@
/obj/vehicle/sealed/mecha/durand/process()
. = ..()
- if(defense_mode && !use_energy(100 KILO JOULES)) //Defence mode can only be on with a occupant so we check if one of them can toggle it and toggle
+ if(defense_mode && !use_energy(0.01 * STANDARD_CELL_CHARGE)) //Defence mode can only be on with a occupant so we check if one of them can toggle it and toggle
for(var/O in occupants)
var/mob/living/occupant = O
var/datum/action/action = LAZYACCESSASSOC(occupant_actions, occupant, /datum/action/vehicle/sealed/mecha/mech_defense_mode)
@@ -82,7 +82,6 @@
stack_trace("Durand triggered relay without a shield")
shield = new /obj/durand_shield(loc, src, layer)
shield.setDir(dir)
- SEND_SIGNAL(shield, COMSIG_MECHA_ACTION_TRIGGER, owner, signal_args)
//Redirects projectiles to the shield if defense_check decides they should be blocked and returns true.
/obj/vehicle/sealed/mecha/durand/proc/prehit(obj/projectile/source, list/signal_args)
@@ -144,6 +143,8 @@ Expects a turf. Returns true if the attack should be blocked, false if not.*/
button_icon_state = "mech_defense_mode_off"
/datum/action/vehicle/sealed/mecha/mech_defense_mode/Trigger(trigger_flags, forced_state = FALSE)
+ if(!owner || !chassis || !(owner in chassis.occupants))
+ return
SEND_SIGNAL(chassis, COMSIG_MECHA_ACTION_TRIGGER, owner, args) //Signal sent to the mech, to be handed to the shield. See durand.dm for more details
////////////////////////////
@@ -165,9 +166,9 @@ own integrity back to max. Shield is automatically dropped if we run out of powe
max_integrity = 10000
anchored = TRUE
light_system = OVERLAY_LIGHT
- light_range = MINIMUM_USEFUL_LIGHT_RANGE
- light_power = 2
- light_color = LIGHT_COLOR_ELECTRIC_CYAN
+ light_range = 2.8
+ light_power = 1
+ light_color = LIGHT_COLOR_FAINT_CYAN
light_on = FALSE
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF //The shield should not take damage from fire, lava, or acid; that's the mech's job.
///Our link back to the durand
@@ -181,7 +182,7 @@ own integrity back to max. Shield is automatically dropped if we run out of powe
src.layer = ABOVE_MOB_LAYER
SET_PLANE_IMPLICIT(src, plane)
setDir(dir)
- RegisterSignal(src, COMSIG_MECHA_ACTION_TRIGGER, PROC_REF(activate))
+ RegisterSignal(chassis, COMSIG_MECHA_ACTION_TRIGGER, PROC_REF(activate))
RegisterSignal(chassis, COMSIG_MOVABLE_UPDATE_GLIDE_SIZE, PROC_REF(shield_glide_size_update))
/obj/durand_shield/Destroy()
diff --git a/code/modules/vehicles/mecha/equipment/tools/radio.dm b/code/modules/vehicles/mecha/equipment/tools/radio.dm
index 33a113a8274f5..18740fc22b9bd 100644
--- a/code/modules/vehicles/mecha/equipment/tools/radio.dm
+++ b/code/modules/vehicles/mecha/equipment/tools/radio.dm
@@ -36,7 +36,7 @@
return TRUE
if("set_frequency")
var/new_frequency = text2num(params["new_frequency"])
- radio.set_frequency(sanitize_frequency(new_frequency, radio.freerange, radio.syndie))
+ radio.set_frequency(sanitize_frequency(new_frequency, radio.freerange, (radio.special_channels & RADIO_SPECIAL_SYNDIE)))
return TRUE
return FALSE
diff --git a/code/modules/vehicles/mecha/equipment/tools/work_tools.dm b/code/modules/vehicles/mecha/equipment/tools/work_tools.dm
index 34216db38d3cd..c19aede50d93b 100644
--- a/code/modules/vehicles/mecha/equipment/tools/work_tools.dm
+++ b/code/modules/vehicles/mecha/equipment/tools/work_tools.dm
@@ -55,7 +55,7 @@
if(istype(target, /obj/machinery/door/firedoor) || istype(target, /obj/machinery/door/airlock))
var/obj/machinery/door/target_door = target
playsound(chassis, clampsound, 50, FALSE, -6)
- target_door.try_to_crowbar(src, source)
+ target_door.try_to_crowbar(src, source, TRUE)
return ..()
if(isobj(target))
diff --git a/code/modules/vehicles/mecha/mech_bay.dm b/code/modules/vehicles/mecha/mech_bay.dm
index 5166b9c5fdfc5..c9f0aa20fa736 100644
--- a/code/modules/vehicles/mecha/mech_bay.dm
+++ b/code/modules/vehicles/mecha/mech_bay.dm
@@ -114,7 +114,7 @@
ui = new(user, src, "MechBayPowerConsole", name)
ui.open()
-/obj/machinery/computer/mech_bay_power_console/ui_act(action, params)
+/obj/machinery/computer/mech_bay_power_console/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/vehicles/mecha/mech_fabricator.dm b/code/modules/vehicles/mecha/mech_fabricator.dm
index b4c292202542e..b167f38141594 100644
--- a/code/modules/vehicles/mecha/mech_fabricator.dm
+++ b/code/modules/vehicles/mecha/mech_fabricator.dm
@@ -427,7 +427,7 @@
return data
-/obj/machinery/mecha_part_fabricator/ui_act(action, list/params)
+/obj/machinery/mecha_part_fabricator/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
diff --git a/code/modules/vehicles/mecha/mecha_control_console.dm b/code/modules/vehicles/mecha/mecha_control_console.dm
index 3b465994e9e02..d31bd5a5bd290 100644
--- a/code/modules/vehicles/mecha/mecha_control_console.dm
+++ b/code/modules/vehicles/mecha/mecha_control_console.dm
@@ -45,7 +45,7 @@
return data
-/obj/machinery/computer/mecha/ui_act(action, params)
+/obj/machinery/computer/mecha/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/vehicles/mecha/mecha_defense.dm b/code/modules/vehicles/mecha/mecha_defense.dm
index 912993d1ee640..1237c931b33a5 100644
--- a/code/modules/vehicles/mecha/mecha_defense.dm
+++ b/code/modules/vehicles/mecha/mecha_defense.dm
@@ -317,7 +317,7 @@
if(!attacking_item.force)
return
- var/damage_taken = take_damage(attacking_item.force * attacking_item.demolition_mod, attacking_item.damtype, MELEE, 1)
+ var/damage_taken = take_damage(attacking_item.force * attacking_item.demolition_mod, attacking_item.damtype, MELEE, 1, get_dir(src, user))
try_damage_component(damage_taken, user.zone_selected)
var/hit_verb = length(attacking_item.attack_verb_simple) ? "[pick(attacking_item.attack_verb_simple)]" : "hit"
diff --git a/code/modules/vehicles/mecha/mecha_mob_interaction.dm b/code/modules/vehicles/mecha/mecha_mob_interaction.dm
index 7a9141e80c1a7..a1e398f6f90cf 100644
--- a/code/modules/vehicles/mecha/mecha_mob_interaction.dm
+++ b/code/modules/vehicles/mecha/mecha_mob_interaction.dm
@@ -20,7 +20,7 @@
moved_inside(M)
/obj/vehicle/sealed/mecha/enter_checks(mob/M)
- if(M.incapacitated())
+ if(M.incapacitated)
return FALSE
if(atom_integrity <= 0)
to_chat(M, span_warning("You cannot get in the [src], it has been destroyed!"))
diff --git a/code/modules/vehicles/mecha/working/clarke.dm b/code/modules/vehicles/mecha/working/clarke.dm
index 2ec0b4a473648..0acfa2749a5bd 100644
--- a/code/modules/vehicles/mecha/working/clarke.dm
+++ b/code/modules/vehicles/mecha/working/clarke.dm
@@ -77,22 +77,26 @@
/obj/item/mecha_parts/mecha_equipment/orebox_manager/get_snowflake_data()
var/list/contents = chassis.ore_box?.contents
var/list/contents_grouped = list()
- for(var/obj/item/stack/ore/item as anything in contents)
+ for(var/atom/movable/item as anything in contents)
+ var/amount = 1
+ if(isstack(item))
+ var/obj/item/stack/stack = item
+ amount = stack.amount
if(isnull(contents_grouped[item.icon_state]))
var/ore_data = list()
ore_data["name"] = item.name
ore_data["icon"] = item.icon_state
- ore_data["amount"] = item.amount
+ ore_data["amount"] = amount
contents_grouped[item.icon_state] = ore_data
else
- contents_grouped[item.icon_state]["amount"] += item.amount
+ contents_grouped[item.icon_state]["amount"] += amount
var/list/data = list(
"snowflake_id" = MECHA_SNOWFLAKE_ID_OREBOX_MANAGER,
"contents" = contents_grouped,
)
return data
-/obj/item/mecha_parts/mecha_equipment/orebox_manager/ui_act(action, list/params)
+/obj/item/mecha_parts/mecha_equipment/orebox_manager/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return TRUE
diff --git a/code/modules/vehicles/mecha/working/ripley.dm b/code/modules/vehicles/mecha/working/ripley.dm
index 754a6b820d721..f5c55f613ee10 100644
--- a/code/modules/vehicles/mecha/working/ripley.dm
+++ b/code/modules/vehicles/mecha/working/ripley.dm
@@ -338,7 +338,7 @@ GLOBAL_DATUM(cargo_ripley, /obj/vehicle/sealed/mecha/ripley/cargo)
))
return data
-/obj/item/mecha_parts/mecha_equipment/ejector/ui_act(action, list/params)
+/obj/item/mecha_parts/mecha_equipment/ejector/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return TRUE
@@ -382,7 +382,7 @@ GLOBAL_DATUM(cargo_ripley, /obj/vehicle/sealed/mecha/ripley/cargo)
to_chat(source, span_warning("You don't have the room to remove [cuffs]!"))
return COMSIG_MOB_BLOCK_CUFF_REMOVAL
-/obj/item/mecha_parts/mecha_equipment/ejector/seccage/ui_act(action, list/params)
+/obj/item/mecha_parts/mecha_equipment/ejector/seccage/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
if(action == "eject")
var/mob/passenger = locate(params["cargoref"]) in contents
if(!passenger)
diff --git a/code/modules/vehicles/scooter.dm b/code/modules/vehicles/scooter.dm
index 82146976ad1f8..25e8ed9740943 100644
--- a/code/modules/vehicles/scooter.dm
+++ b/code/modules/vehicles/scooter.dm
@@ -169,7 +169,7 @@
pick_up_board(skater)
/obj/vehicle/ridden/scooter/skateboard/proc/pick_up_board(mob/living/carbon/skater)
- if (skater.incapacitated() || !Adjacent(skater))
+ if (skater.incapacitated || !Adjacent(skater))
return
if(has_buckled_mobs())
to_chat(skater, span_warning("You can't lift this up when somebody's on it."))
diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm
index 6e63000951cbc..817d3b6803302 100644
--- a/code/modules/vending/_vending.dm
+++ b/code/modules/vending/_vending.dm
@@ -831,7 +831,7 @@ GLOBAL_LIST_EMPTY(vending_machines_to_restock)
* Args:
* * turf/target: The turf to fall onto. Cannot be null.
* * damage: The raw numerical damage to do by default.
- * * chance_to_crit: The percent chance of a critical hit occuring. Default: 0
+ * * chance_to_crit: The percent chance of a critical hit occurring. Default: 0
* * forced_crit_case: If given a value from crushing.dm, [target] and its contents will always be hit with that specific critical hit. Default: null
* * paralyze_time: The time, in deciseconds, a given mob/living will be paralyzed for if crushed.
* * crush_dir: The direction the crush is coming from. Default: dir of src to [target].
@@ -988,7 +988,7 @@ GLOBAL_LIST_EMPTY(vending_machines_to_restock)
var/list/weighted_crits = list()
weighted_crits[CRUSH_CRIT_SHATTER_LEGS] = 100
- weighted_crits[CRUSH_CRIT_PARAPALEGIC] = 80
+ weighted_crits[CRUSH_CRIT_PARAPLEGIC] = 80
weighted_crits[CRUSH_CRIT_HEADGIB] = 20
weighted_crits[CRUSH_CRIT_SQUISH_LIMB] = 100
@@ -1027,7 +1027,7 @@ GLOBAL_LIST_EMPTY(vending_machines_to_restock)
if(left_leg || right_leg)
carbon_target.visible_message(span_danger("[carbon_target]'s legs shatter with a sickening crunch!"), span_userdanger("Your legs shatter with a sickening crunch!"))
return TRUE
- if(CRUSH_CRIT_PARAPALEGIC) // paralyze this binch
+ if(CRUSH_CRIT_PARAPLEGIC) // paralyze this binch
// the new paraplegic gets like 4 lines of losing their legs so skip them
if (!iscarbon(atom_target))
return FALSE
@@ -1184,17 +1184,19 @@ GLOBAL_LIST_EMPTY(vending_machines_to_restock)
return TRUE
/obj/machinery/vending/interact(mob/user)
- if (!HAS_AI_ACCESS(user))
- if(seconds_electrified && !(machine_stat & NOPOWER))
- if(shock(user, 100))
- return
+ if (HAS_AI_ACCESS(user))
+ return ..()
- if(tilted && !user.buckled && !isAdminGhostAI(user))
- to_chat(user, span_notice("You begin righting [src]."))
- if(do_after(user, 5 SECONDS, target=src))
- untilt(user)
+ if(seconds_electrified && !(machine_stat & NOPOWER))
+ if(shock(user, 100))
return
+ if(tilted && !user.buckled)
+ to_chat(user, span_notice("You begin righting [src]."))
+ if(do_after(user, 5 SECONDS, target=src))
+ untilt(user)
+ return
+
return ..()
/obj/machinery/vending/attack_robot_secondary(mob/user, list/modifiers)
@@ -1317,7 +1319,7 @@ GLOBAL_LIST_EMPTY(vending_machines_to_restock)
.["extended_inventory"] = extended_inventory
-/obj/machinery/vending/ui_act(action, params)
+/obj/machinery/vending/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
@@ -1766,7 +1768,7 @@ GLOBAL_LIST_EMPTY(vending_machines_to_restock)
)
.["vending_machine_input"] += list(data)
-/obj/machinery/vending/custom/ui_act(action, params)
+/obj/machinery/vending/custom/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/vending/autodrobe.dm b/code/modules/vending/autodrobe.dm
index 8b9f704569545..8211b05553d8b 100644
--- a/code/modules/vending/autodrobe.dm
+++ b/code/modules/vending/autodrobe.dm
@@ -195,13 +195,14 @@ GLOBAL_LIST_INIT(autodrobe_contraband_items, list(
/obj/item/clothing/head/costume/powdered_wig = 1,
/obj/item/clothing/head/costume/tv_head = 1,
/obj/item/clothing/mask/muzzle = 2,
- /obj/item/clothing/shoes/ducky_shoes = 1,
/obj/item/clothing/shoes/clown_shoes/meown_shoes = 1,
/obj/item/clothing/shoes/clown_shoes/moffers = 1,
+ /obj/item/clothing/shoes/ducky_shoes = 1,
/obj/item/clothing/suit/costume/judgerobe = 1,
/obj/item/clothing/head/costume/lobsterhat = 1,
/obj/item/clothing/under/costume/lobster = 1,
/obj/item/gun/magic/wand/nothing = 2,
+ /obj/item/skillchip/musical = 3,
/obj/item/storage/box/tape_wizard = 1,
))
diff --git a/code/modules/vending/cytopro.dm b/code/modules/vending/cytopro.dm
new file mode 100644
index 0000000000000..ce351be7769da
--- /dev/null
+++ b/code/modules/vending/cytopro.dm
@@ -0,0 +1,35 @@
+/obj/machinery/vending/cytopro
+ name = "\improper CytoPro"
+ desc = "For all your cytology needs!"
+ product_slogans = "Cloning? Don't be ridiculous.;Don't be uncultured, get some cells growing!;Who needs farms when we got vats?"
+ product_ads = "Grow your own little creatures!;Biology, at your fingertips!"
+ icon_state = "cytopro"
+ icon_deny = "cytopro-deny"
+ panel_type = "panel2"
+ light_mask = "cytopro-light-mask"
+ products = list(
+ /obj/item/storage/bag/xeno = 5,
+ /obj/item/reagent_containers/condiment/protein = 10,
+ /obj/item/storage/box/swab = 3,
+ /obj/item/storage/box/petridish = 3,
+ /obj/item/storage/box/monkeycubes = 3,
+ /obj/item/biopsy_tool = 3,
+ /obj/item/clothing/under/rank/rnd/scientist = 5,
+ /obj/item/clothing/suit/toggle/labcoat/science = 5,
+ /obj/item/clothing/suit/bio_suit/scientist = 3,
+ /obj/item/clothing/head/bio_hood/scientist = 3,
+ /obj/item/reagent_containers/dropper = 5,
+ /obj/item/reagent_containers/syringe = 5,
+ /obj/item/petri_dish/random = 6,
+ )
+ contraband = list(
+ /obj/item/knife/kitchen = 3,
+ )
+ refill_canister = /obj/item/vending_refill/cytopro
+ default_price = PAYCHECK_CREW * 1
+ extra_price = PAYCHECK_COMMAND * 0.5
+ payment_department = ACCOUNT_SCI
+
+/obj/item/vending_refill/cytopro
+ machine_name = "CytoPro"
+ icon_state = "refill_plant"
diff --git a/code/modules/vending/games.dm b/code/modules/vending/games.dm
index 33fefd08d2e79..d1a237eaf640f 100644
--- a/code/modules/vending/games.dm
+++ b/code/modules/vending/games.dm
@@ -58,6 +58,7 @@
/obj/item/skillchip/sabrage = 2,
/obj/item/skillchip/useless_adapter = 5,
/obj/item/skillchip/wine_taster = 2,
+ /obj/item/skillchip/big_pointer = 2,
),
),
list(
@@ -66,7 +67,7 @@
"products" = list(
/obj/item/camera = 3,
/obj/item/camera_film = 5,
- /obj/item/cardpack/resin = 20, //Both card packs have had their count raised to 20 from 10 until card persistance is implimented.
+ /obj/item/cardpack/resin = 20, //Both card packs have had their count raised to 20 from 10 until card persistence is implemented.
/obj/item/cardpack/series_one = 20,
/obj/item/dyespray = 3,
/obj/item/hourglass = 2,
diff --git a/code/modules/vending/wardrobes.dm b/code/modules/vending/wardrobes.dm
index 3b962490347a3..3d8a1f6cf60e2 100644
--- a/code/modules/vending/wardrobes.dm
+++ b/code/modules/vending/wardrobes.dm
@@ -331,7 +331,7 @@ GLOBAL_VAR_INIT(roaches_deployed, FALSE)
/obj/item/storage/backpack/satchel/explorer = 1,
/obj/item/storage/backpack/messenger/explorer = 1,
/obj/item/storage/bag/books = 1,
- /obj/item/radio/headset/headset_srv = 2,
+ /obj/item/radio/headset/headset_srvent = 2,
)
refill_canister = /obj/item/vending_refill/wardrobe/curator_wardrobe
payment_department = ACCOUNT_SRV
diff --git a/code/modules/wiremod/components/abstract/module.dm b/code/modules/wiremod/components/abstract/module.dm
index 4dd144b4c80e3..0622577016acc 100644
--- a/code/modules/wiremod/components/abstract/module.dm
+++ b/code/modules/wiremod/components/abstract/module.dm
@@ -237,7 +237,7 @@
#define WITHIN_RANGE(id, table) (id >= 1 && id <= length(table))
-/obj/item/circuit_component/module/ui_act(action, list/params)
+/obj/item/circuit_component/module/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/wiremod/components/action/pathfind.dm b/code/modules/wiremod/components/action/pathfind.dm
index 0de6d346db17f..6852905644775 100644
--- a/code/modules/wiremod/components/action/pathfind.dm
+++ b/code/modules/wiremod/components/action/pathfind.dm
@@ -24,7 +24,7 @@
// Cooldown to limit how frequently we can path to the same location.
var/same_path_cooldown = 5 SECONDS
- var/different_path_cooldown = 30 SECONDS
+ var/different_path_cooldown = 5 SECONDS
var/max_range = 60
diff --git a/code/modules/wiremod/components/admin/proccall.dm b/code/modules/wiremod/components/admin/proccall.dm
index b86e05e6c8a8b..594c0a6e7d1b6 100644
--- a/code/modules/wiremod/components/admin/proccall.dm
+++ b/code/modules/wiremod/components/admin/proccall.dm
@@ -114,7 +114,7 @@
arguments += add_input_port(data["name"], data["datatype"])
return ..()
-/obj/item/circuit_component/proccall/ui_act(action, list/params)
+/obj/item/circuit_component/proccall/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/wiremod/components/atom/health.dm b/code/modules/wiremod/components/atom/health.dm
index ee04030259e60..49798930d9768 100644
--- a/code/modules/wiremod/components/atom/health.dm
+++ b/code/modules/wiremod/components/atom/health.dm
@@ -43,7 +43,8 @@
var/mob/living/organism = input_port.value
var/turf/current_turf = get_location()
- if(!istype(organism) || get_dist(current_turf, organism) > max_range || current_turf.z != organism.z)
+ var/turf/target_location = get_turf(organism)
+ if(!istype(organism) || get_dist(current_turf, target_location) > max_range || current_turf.z != target_location.z)
brute.set_output(null)
burn.set_output(null)
toxin.set_output(null)
diff --git a/code/modules/wiremod/components/atom/health_state.dm b/code/modules/wiremod/components/atom/health_state.dm
index dc83a41fdfd8d..650311159415b 100644
--- a/code/modules/wiremod/components/atom/health_state.dm
+++ b/code/modules/wiremod/components/atom/health_state.dm
@@ -36,7 +36,8 @@
/obj/item/circuit_component/compare/health_state/do_comparisons()
var/mob/living/organism = input_port.value
var/turf/current_turf = get_location()
- if(!istype(organism) || current_turf.z != organism.z || get_dist(current_turf, organism) > max_range)
+ var/turf/target_location = get_turf(organism)
+ if(!istype(organism) || current_turf.z != target_location.z || get_dist(current_turf, target_location) > max_range)
return FALSE
var/current_option = state_option.value
diff --git a/code/modules/wiremod/components/bci/hud/target_intercept.dm b/code/modules/wiremod/components/bci/hud/target_intercept.dm
index bfdaec13122a0..2ee37e8ff4f3d 100644
--- a/code/modules/wiremod/components/bci/hud/target_intercept.dm
+++ b/code/modules/wiremod/components/bci/hud/target_intercept.dm
@@ -39,7 +39,7 @@
return
var/mob/living/owner = bci.owner
- if(!owner || !istype(owner) || !owner.client)
+ if(!owner || !istype(owner) || !owner.client || owner.stat >= SOFT_CRIT)
return
if(TIMER_COOLDOWN_RUNNING(parent.shell, COOLDOWN_CIRCUIT_TARGET_INTERCEPT))
diff --git a/code/modules/wiremod/components/bci/thought_listener.dm b/code/modules/wiremod/components/bci/thought_listener.dm
index ae6889e2da904..aa788b1a4be88 100644
--- a/code/modules/wiremod/components/bci/thought_listener.dm
+++ b/code/modules/wiremod/components/bci/thought_listener.dm
@@ -48,7 +48,7 @@
var/mob/living/owner = bci.owner
- if(!owner || !istype(owner) || !owner.client || (owner.stat >= UNCONSCIOUS))
+ if(!owner || !istype(owner) || !owner.client || (owner.stat >= SOFT_CRIT))
failure.set_output(COMPONENT_SIGNAL)
return
@@ -57,6 +57,8 @@
/obj/item/circuit_component/thought_listener/proc/thought_listen(mob/living/owner)
var/message = tgui_input_text(owner, input_desc.value ? input_desc.value : "", input_name.value ? input_name.value : "Thought Listener", "")
+ if(QDELETED(owner) || owner.stat >= SOFT_CRIT)
+ return
output.set_output(message)
trigger_output.set_output(COMPONENT_SIGNAL)
ready = TRUE
diff --git a/code/modules/wiremod/components/id/access_checker.dm b/code/modules/wiremod/components/id/access_checker.dm
index 038f4078ecb11..1644d12cba508 100644
--- a/code/modules/wiremod/components/id/access_checker.dm
+++ b/code/modules/wiremod/components/id/access_checker.dm
@@ -87,7 +87,7 @@
data["oneAccess"] = check_any.value
return data
-/obj/item/circuit_component/compare/access/ui_act(action, params)
+/obj/item/circuit_component/compare/access/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
diff --git a/code/modules/wiremod/core/component.dm b/code/modules/wiremod/core/component.dm
index ff0e64cd9a4dc..02e88e53c2381 100644
--- a/code/modules/wiremod/core/component.dm
+++ b/code/modules/wiremod/core/component.dm
@@ -14,6 +14,7 @@
inhand_icon_state = "electronic"
lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi'
righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi'
+ custom_materials = list(/datum/material/glass = HALF_SHEET_MATERIAL_AMOUNT)
/// The name of the component shown on the UI
var/display_name = "Generic"
diff --git a/code/modules/wiremod/core/component_printer.dm b/code/modules/wiremod/core/component_printer.dm
index 370a6cfea5244..cb51a0e8ab786 100644
--- a/code/modules/wiremod/core/component_printer.dm
+++ b/code/modules/wiremod/core/component_printer.dm
@@ -22,7 +22,7 @@
/obj/machinery/component_printer/Initialize(mapload)
. = ..()
- materials = AddComponent(/datum/component/remote_materials, mapload)
+ materials = AddComponent(/datum/component/remote_materials, mapload, whitelist_typecache = typecacheof(/obj/item/circuit_component))
/obj/machinery/component_printer/post_machine_initialize()
. = ..()
@@ -117,7 +117,7 @@
materials.use_materials(design.materials, efficiency_coeff, 1, "printed", "[design.name]")
return new design.build_path(drop_location())
-/obj/machinery/component_printer/ui_act(action, list/params)
+/obj/machinery/component_printer/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if (.)
return
@@ -192,13 +192,22 @@
return data
/obj/machinery/component_printer/attackby(obj/item/weapon, mob/living/user, params)
- if(istype(weapon, /obj/item/integrated_circuit) && !user.combat_mode)
- var/obj/item/integrated_circuit/circuit = weapon
- circuit.linked_component_printer = WEAKREF(src)
- circuit.update_static_data_for_all_viewers()
- balloon_alert(user, "successfully linked to the integrated circuit")
- return
- return ..()
+ if (user.combat_mode)
+ return ..()
+
+ var/obj/item/integrated_circuit/circuit
+ if(istype(weapon, /obj/item/integrated_circuit))
+ circuit = weapon
+ else if (istype(weapon, /obj/item/circuit_component/module))
+ var/obj/item/circuit_component/module/module = weapon
+ circuit = module.internal_circuit
+ if (isnull(circuit))
+ return ..()
+
+ circuit.linked_component_printer = WEAKREF(src)
+ circuit.update_static_data_for_all_viewers()
+ balloon_alert(user, "successfully linked to the integrated circuit")
+
/obj/machinery/component_printer/crowbar_act(mob/living/user, obj/item/tool)
if(..())
@@ -267,7 +276,7 @@
get_asset_datum(/datum/asset/spritesheet/research_designs)
)
-/obj/machinery/debug_component_printer/ui_act(action, list/params)
+/obj/machinery/debug_component_printer/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if (.)
return
@@ -355,7 +364,7 @@
update_static_data_for_all_viewers()
-/obj/machinery/module_duplicator/ui_act(action, list/params)
+/obj/machinery/module_duplicator/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if (.)
return
diff --git a/code/modules/wiremod/core/integrated_circuit.dm b/code/modules/wiremod/core/integrated_circuit.dm
index f24c5dac6671e..db1fd8ac588c0 100644
--- a/code/modules/wiremod/core/integrated_circuit.dm
+++ b/code/modules/wiremod/core/integrated_circuit.dm
@@ -502,6 +502,9 @@ GLOBAL_LIST_EMPTY_TYPED(integrated_circuits, /obj/item/integrated_circuit)
remove_component(component)
if(component.loc == src)
usr.put_in_hands(component)
+ var/obj/machinery/component_printer/printer = linked_component_printer?.resolve()
+ if (!isnull(printer))
+ printer.attackby(component, usr)
. = TRUE
if("set_component_coordinates")
var/component_id = text2num(params["component_id"])
diff --git a/code/modules/wiremod/shell/brain_computer_interface.dm b/code/modules/wiremod/shell/brain_computer_interface.dm
index 67a3a41a48828..7adefcaa5eda6 100644
--- a/code/modules/wiremod/shell/brain_computer_interface.dm
+++ b/code/modules/wiremod/shell/brain_computer_interface.dm
@@ -3,7 +3,6 @@
desc = "An implant that can be placed in a user's head to control circuits using their brain."
icon = 'icons/obj/science/circuits.dmi'
icon_state = "bci"
- visual = FALSE
zone = BODY_ZONE_HEAD
w_class = WEIGHT_CLASS_TINY
diff --git a/code/modules/wiremod/shell/controller.dm b/code/modules/wiremod/shell/controller.dm
index 126cc8894368f..ae0eb01b36763 100644
--- a/code/modules/wiremod/shell/controller.dm
+++ b/code/modules/wiremod/shell/controller.dm
@@ -53,7 +53,7 @@
/obj/item/circuit_component/controller/proc/handle_trigger(atom/source, user, port_name, datum/port/output/port_signal)
source.balloon_alert(user, "clicked [port_name] button")
- playsound(source, SFX_TERMINAL_TYPE, 25, FALSE)
+ playsound(source, SFX_KEYBOARD_CLICKS, 25, FALSE)
entity.set_output(user)
port_signal.set_output(COMPONENT_SIGNAL)
diff --git a/code/world.dm b/code/world.dm
index 7cc35e5529ad8..31437dda2f539 100644
--- a/code/world.dm
+++ b/code/world.dm
@@ -6,7 +6,7 @@
*
* Two possibilities exist: either we are alone in the Universe or we are not. Both are equally terrifying. ~ Arthur C. Clarke
*
- * The byond world object stores some basic byond level config, and has a few hub specific procs for managing hub visiblity
+ * The byond world object stores some basic byond level config, and has a few hub specific procs for managing hub visibility
*/
/world
mob = /mob/dead/new_player
diff --git a/config/config.txt b/config/config.txt
index 770d7aed75aa7..2e7ff11ea1f9d 100644
--- a/config/config.txt
+++ b/config/config.txt
@@ -209,19 +209,19 @@ IPINTEL_REJECT_BAD
## Ban appeals URL - usually for a forum or wherever people should go to contact your admins.
# BANAPPEALS http://justanotherday.example.com
-## System command that invokes youtube-dl, used by Play Internet Sound.
-## You can install youtube-dl with
-## "pip install youtube-dl" if you have pip installed
-## from https://github.com/rg3/youtube-dl/releases
+## System command that invokes yt-dlp, used by Play Internet Sound.
+## You can install yt-dlp with
+## "pip install yt-dlp" if you have pip installed
+## from https://github.com/yt-dlp/yt-dlp/releases
## or your package manager
-## The default value assumes youtube-dl is in your system PATH
-# INVOKE_YOUTUBEDL youtube-dl
+## The default value assumes yt-dlp is in your system PATH
+# INVOKE_YOUTUBEDL yt-dlp
## Comment this out to disable users ability to use the request internet sounds to be played.
REQUEST_INTERNET_SOUND
## Request Internet Sound Allowed URL'S comma separated, urls here are the only sites allowed through Request Internet Sound, Add more to allow more, or remove to disallow.
-## The Defaults here are all supported by youtube-dl
+## The Defaults here are all supported by yt-dlp
## Ensure . and / are escaped with \
REQUEST_INTERNET_ALLOWED youtube\.com\/watch?v=,youtu\.be\/,soundcloud\.com\/,bandcamp\.com\/track\/
diff --git a/config/lavaruinblacklist.txt b/config/lavaruinblacklist.txt
index fe4cbc86e1ef4..aaa507374cb68 100644
--- a/config/lavaruinblacklist.txt
+++ b/config/lavaruinblacklist.txt
@@ -43,4 +43,4 @@
#_maps/RandomRuins/LavaRuins/lavaland_surface_ww_vault.dmm
#_maps/RandomRuins/LavaRuins/lavaland_surface_wwiioutpost.dmm
#_maps/RandomRuins/LavaRuins/lavaland_surface_xeno_nest.dmm
-
+#_maps/RandomRuins/Lavaruins/lavaland_surface_crashsite.dmm
diff --git a/dependencies.sh b/dependencies.sh
index 60753e1411c8d..60e72e8b8988c 100644
--- a/dependencies.sh
+++ b/dependencies.sh
@@ -17,7 +17,7 @@ export NODE_VERSION_LTS=20.13.0
export NODE_VERSION_COMPAT=20.2.0
# SpacemanDMM git tag
-export SPACEMAN_DMM_VERSION=suite-1.8
+export SPACEMAN_DMM_VERSION=suite-1.9
# Python version for mapmerge and other tools
export PYTHON_VERSION=3.9.0
@@ -26,10 +26,10 @@ export PYTHON_VERSION=3.9.0
export DREAMLUAU_REPO="tgstation/dreamluau"
#dreamluau git tag
-export DREAMLUAU_VERSION=0.1.0
+export DREAMLUAU_VERSION=0.1.1
#hypnagogic repo
export CUTTER_REPO=spacestation13/hypnagogic
#hypnagogic git tag
-export CUTTER_VERSION=v3.1.0
+export CUTTER_VERSION=v4.0.0
diff --git a/html/changelogs/AutoChangeLog-pr-85290.yml b/html/changelogs/AutoChangeLog-pr-85290.yml
deleted file mode 100644
index f64fde94ba83b..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-85290.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Ben10Omintrix"
-delete-after: True
-changes:
- - refactor: "refactors pet collars and cultist pets into elements"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-85473.yml b/html/changelogs/AutoChangeLog-pr-85473.yml
deleted file mode 100644
index d3f12bf94347d..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-85473.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "SmArtKar"
-delete-after: True
-changes:
- - bugfix: "Bitrunning crate capture zones can no longer be destroyed"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-85490.yml b/html/changelogs/AutoChangeLog-pr-85490.yml
deleted file mode 100644
index c86f16c571394..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-85490.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Gaxeer"
-delete-after: True
-changes:
- - rscdel: "Remove narsie and ratvar plushies from loadout"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-85537.yml b/html/changelogs/AutoChangeLog-pr-85537.yml
deleted file mode 100644
index 1f219cb2d5de6..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-85537.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "SmArtKar"
-delete-after: True
-changes:
- - code_imp: "Removed multiple cases of unnecessary updatehealth"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-85541.yml b/html/changelogs/AutoChangeLog-pr-85541.yml
deleted file mode 100644
index 18374b79f2b44..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-85541.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "SmArtKar"
-delete-after: True
-changes:
- - bugfix: "Elevator music no longer restarts when you take a step"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-86090.yml b/html/changelogs/AutoChangeLog-pr-86090.yml
new file mode 100644
index 0000000000000..0b1f13e2f9a4a
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-86090.yml
@@ -0,0 +1,4 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - bugfix: "fixed a few minor nits with aquarium fish visuals."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-86092.yml b/html/changelogs/AutoChangeLog-pr-86092.yml
new file mode 100644
index 0000000000000..e939cb33ac8c7
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-86092.yml
@@ -0,0 +1,4 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - bugfix: "Syndie sleepers now drop the appropriate syndicate sleeper boards."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-86099.yml b/html/changelogs/AutoChangeLog-pr-86099.yml
new file mode 100644
index 0000000000000..b745e32405641
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-86099.yml
@@ -0,0 +1,4 @@
+author: "KazooBard"
+delete-after: True
+changes:
+ - qol: "All cans (soda cans etc) fit on utility belts now. Drink on the job!"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-86121.yml b/html/changelogs/AutoChangeLog-pr-86121.yml
new file mode 100644
index 0000000000000..7ee758555a6a5
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-86121.yml
@@ -0,0 +1,4 @@
+author: "SmArtKar"
+delete-after: True
+changes:
+ - bugfix: "Acromegaly no longer makes you bonk your head on airlocks while you're inside of objects"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-86224.yml b/html/changelogs/AutoChangeLog-pr-86224.yml
new file mode 100644
index 0000000000000..ea2db37e08d32
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-86224.yml
@@ -0,0 +1,4 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - qol: "You can kill germs by actually cooking the food (i.e. frying and grilling) now, or by setting it on fire."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-86448.yml b/html/changelogs/AutoChangeLog-pr-86448.yml
new file mode 100644
index 0000000000000..69a0fff11549a
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-86448.yml
@@ -0,0 +1,4 @@
+author: "SmArtKar"
+delete-after: True
+changes:
+ - bugfix: "Changelings can no longer spawn undetectable spider eggs inside of vents"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-86451.yml b/html/changelogs/AutoChangeLog-pr-86451.yml
new file mode 100644
index 0000000000000..7936d3f29ca36
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-86451.yml
@@ -0,0 +1,4 @@
+author: "LT3"
+delete-after: True
+changes:
+ - image: "The 'shit is fucked' default turf no longer flashes\n/:cl"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-86455.yml b/html/changelogs/AutoChangeLog-pr-86455.yml
new file mode 100644
index 0000000000000..f80691149e4d0
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-86455.yml
@@ -0,0 +1,4 @@
+author: "Rhials"
+delete-after: True
+changes:
+ - bugfix: "Runtime station has delivery beacons and navbeacons again."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-86463.yml b/html/changelogs/AutoChangeLog-pr-86463.yml
new file mode 100644
index 0000000000000..b9b29f403c63a
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-86463.yml
@@ -0,0 +1,4 @@
+author: "vinylspiders"
+delete-after: True
+changes:
+ - bugfix: "fixed a bug that could sometimes cause jump boots users to retain the floating trait indefinitely when using the ability"
\ No newline at end of file
diff --git a/html/changelogs/archive/2024-08.yml b/html/changelogs/archive/2024-08.yml
index 0665fba035a2a..e40667b93e971 100644
--- a/html/changelogs/archive/2024-08.yml
+++ b/html/changelogs/archive/2024-08.yml
@@ -159,3 +159,672 @@
- bugfix: Fixed handyman assistants spawning without a PDA
Y0SH1M4S73R:
- bugfix: lua scripting now works on linux
+2024-08-06:
+ Ben10Omintrix:
+ - refactor: refactors pet collars and cultist pets into elements
+ EnterTheJake:
+ - image: Ash Blade has received a new sprite.
+ Gaxeer:
+ - rscdel: Remove narsie and ratvar plushies from loadout
+ SmArtKar:
+ - bugfix: Plasmamen helmets now display their smiles + can be painted with spraycans
+ - bugfix: Elevator music no longer restarts when you take a step
+ - image: Resprited teleporter beacons
+ - code_imp: Removed multiple cases of unnecessary updatehealth
+ - bugfix: Bitrunning crate capture zones can no longer be destroyed
+ mc-oofert:
+ - admin: fix hard restart option
+2024-08-07:
+ Absolucy:
+ - bugfix: Fixed a runtime error after draining a heretic influence.
+ LT3:
+ - bugfix: Fixed players being incorrectly immune to certain virus severities
+ MrMelbert, SmArtKar:
+ - bugfix: Holding someone at gunpoint no longer makes all shots count as point blank
+ SmArtKar:
+ - image: Updated clipboard sprite, adds white and black clipboard skins for med/sci
+ and security
+ - bugfix: Tinacusiate no longer changes hearing spans for every single person in-game
+2024-08-08:
+ MTandi:
+ - bugfix: Smartfridges properly dispense `\Improper` items
+ Rhials:
+ - sound: Zipties no longer make handcuff noises when picked up or dropped.
+2024-08-09:
+ SmArtKar:
+ - bugfix: Circuit UI scale no longer has weird rounding
+ - bugfix: Circuit UI no longer gets covered by components menu
+ - bugfix: Fixed Charlie MOD installer not installing MODsuit unless you have a backpack
+ to drop
+2024-08-10:
+ FlufflesTheDog:
+ - bugfix: tadpoles can actually be scooped from ponds
+2024-08-11:
+ DaCoolBoss:
+ - spellcheck: fixed many incorrect spellings of Waffle Corp and Donk Co.
+2024-08-12:
+ SmArtKar:
+ - bugfix: You no longer kill yourself in cockroach form if you attempt to unposess
+ it
+ grungussuss:
+ - sound: ore and sandstone blocks have their own sound
+ grungussuss and kayozz:
+ - sound: white noise from some ambience sounds has been pruned
+2024-08-13:
+ Majkl-J:
+ - bugfix: Felinids no longer phase through diagonal gaps upon seeing a laser
+2024-08-15:
+ 00-Steven:
+ - bugfix: Fixed pipes/cables/disposals rendering above closed catwalks.
+ - bugfix: Fixed catwalks covering pipes generating illogical pipe caps when screwed.
+ - bugfix: Opened catwalks are no longer assumed to be above-floor for the sake of
+ generating pipe caps.
+ - bugfix: Fixes getting a "You are too far away!" interaction block on inventory
+ items when inside of another object. This includes accessing storage or using
+ your PDA from a closet, or as pAI using your digital messenger while inside
+ of your card.
+ Archemagus:
+ - bugfix: Strange zeros in paid off citations on sec records
+ - bugfix: Now invalidating citations works
+ - bugfix: You can change crimes description
+ - bugfix: Synths have 'armory access' for sec records logic
+ - qol: Paying off citation now automaticaly voiding it
+ - qol: Crime issuer can void the crime without armory access
+ - qol: In case of invalidation crime shows who voided it
+ Astrogem2:
+ - bugfix: Raw durathread bundles and sinew strands no longer make metal clang sounds.
+ Ben10Omintrix:
+ - bugfix: wolf AI will no longer get stuck
+ - bugfix: idle basic mobs will now plan behaviors rather than completely shut down
+ - bugfix: fixes monkey ai hitting u from a distance with unloaded guns
+ Bisar:
+ - qol: The preserved terrarium vault now has tier 4 hydroponics trays, making volume
+ based tray chemistry take less time.
+ - rscadd: The interns remembered to water the plants around the station; their foilage
+ is so thick that it totally hides the identity of anyone holding them!
+ DATA-xPUNGED:
+ - qol: Nanotrasen has fitted the Janitorial Emergency Response Team with equipment
+ better suited for the job.
+ Dmeto:
+ - bugfix: Wawastation Science is connected to distro,Floor Electrical Relay cable
+ fixed
+ - qol: Cargo Gorka suit slot now allows emergency/plasmaman internals.
+ FlufflesTheDog:
+ - bugfix: pre-upgraded soda dispensers are actually pre-upgraded again
+ GPeckman:
+ - bugfix: Hydraulic clamps (the mech tool) can force powered doors open again.
+ - balance: Abductors (the antag, not the species) can no longer be converted by
+ any antagonist.
+ Kocma-san:
+ - code_imp: "\u0441hanges for a fax located on the CC"
+ - qol: 'added centcom stamps to centcom
+
+ /:cl
+
+
+
+ '
+ MTandi:
+ - balance: 'TechWeb: NT Frontier partners now give full discounts for many high
+ tier nodes, corresponding to the partner theme, instead of partial discounts
+ for random nodes'
+ - qol: Atmos techs can download NT frontier and build compressor board in engi imprinter
+ - balance: Roboticists now always have ordnance access for the discount experiments
+ they need
+ - balance: 'TechWeb: BZ shell is now a discount experiment for experimental tools
+ instead of required exp for fusion'
+ - balance: 'TechWeb: Noblium shell is a discount experiment for RCD upgrades instead
+ of exp tools discount'
+ - balance: 'TechWeb: Vat-grown slime scan is a discount experiment instead of required
+ one'
+ - bugfix: 'TechWeb: Cryostasis node properly requires advanced medbay equipment
+ as it should'
+ Melbert:
+ - rscadd: 'Adds a copy of the famous 1995 musical "Space Station 13: The Musical"
+ to contraband of the autodrobe'
+ Paxilmaniac:
+ - rscadd: The new smartgun has replaced the unusable energy cannon in mystery boxes
+ ? Raccoff, aa07, ActionNinja, ArcaneMusic, Armhulen, Azlan, Ben10Omintrix, BigBimmer,
+ Capsandi, CapybaraExtravagante, Draco, Floyd, Iamgoofball, Imaginos16, Infrared,
+ Jacquerel, Justice12354, Kryson, KylerAce, LemonInTheDark, Meyhazah, Mothblocks,
+ MTandi, Ninjanomnom, oranges, Rohesie, Runi-c, san7890, Senefi, SimplyLogan, SomeAngryMiner,
+ SpaceSmithers, Tattle, Thunder12345, Time-Green, Twaticus, unit0016, Viro, Waltermeldon,
+ WatlerJe, ZephyrTFA with thanks to the Mojave Sun team!
+ : - rscadd: Resprites or offsets almost all "tall" objects in the game to match
+ a 3/4ths perspective
+ - rscadd: Bunch of rendering mumbo jumbo to make said 3/4ths perspective work
+ Rhials:
+ - bugfix: Centcom ERT hiring standards have been expanded to include plasmamen,
+ again.
+ Runi-c:
+ - bugfix: Wellcheers no longer does nothing half the time
+ ShadowLarkens:
+ - bugfix: Fixed action buttons relative to EAST,SOUTH, or CENTER being improperly
+ moved during view_audit_buttons()
+ SmArtKar:
+ - bugfix: Circuit health analyzer/state components now work on targets inside lockers
+ - image: Resprited all main assemblies
+ - bugfix: Ninjas can cloak again
+ - image: Durand shield got a glowup
+ - bugfix: Durand shield no longer instantly drains its battery
+ - bugfix: Mech UI no longer lies about the amount of power your mech has left
+ - bugfix: Fixed chanterelles runtiming upon being hollowed out with a spoon and
+ not spawning a hat
+ - bugfix: Ash drakes no longer get stuck in flight if their target changes Z levels
+ or is destroyed and doesn't spawn lavaland turfs after the lava arena attack
+ ends
+ - bugfix: Fixed shuttle loan paperwork being unstampable
+ - balance: Multiple gloves/shoes that had armor values but failed to apply them
+ got fixed
+ - bugfix: Soulscythe now deletes the soul mob when destroyed
+ - bugfix: Bubblegum can no longer bloodcrawl to other Z levels
+ - bugfix: Fixed portable chem mixer spamming you if not held while its UI is open
+ - bugfix: Fixed bileworms not having a deaggro range
+ - bugfix: Heretic sacrifice area no longer modifies global ambience lists
+ - bugfix: Fixed fish analyzers not being able to scan fish
+ - bugfix: Fixed DNA samplers not being able to interact with non-scannable objects
+ - bugfix: Fake aurora caelus event no longer permanently paints space green
+ - code_imp: Cult magic item paths are no longer strings
+ - bugfix: Fixed monk staffs not displaying a wielded sprite
+ - bugfix: Fixed nuke toggle, smite and machine upgrade admin verbs using incorrect
+ sorting
+ - admin: Updated nuke toggle, smite and machine upgrade admin verbs to use TGUI
+ - qol: Magicarps no longer fire their projectiles while out of combat mode
+ - bugfix: Chameleon gun counts as harmless and can be fired by pacifists
+ - qol: Integrated circuit modules now can be linked to component printers
+ - bugfix: You can no longer shove people into closets through directional glass
+ - bugfix: Slimes no longer can feed when they're inside of objects or attacking
+ a target that became invalid after they chose their dinner
+ - bugfix: Fixed Creatures not being able to use non-jaunt actions when seen
+ - bugfix: Void storm now updates mob health
+ - qol: Circuit components can now be recycles in circuit printers, and automatically
+ do so upon being removed if a circuit has a linked printer
+ - spellcheck: Recycling a single item no longer outputs a line with a rogue space
+ infront of it
+ Vekter:
+ - balance: Removes the research requirement from cyborg endoskeletons, meaning they
+ can be built at roundstart again.
+ Watermelon914:
+ - bugfix: Fixed activating specific BCI actions whilst unconsious
+ - balance: Space suits no longer provide all of the slowdown when wearing space
+ gear. Helmets now share the burden and you can now move faster when wearing
+ only a space suit. Helmets now provide a bit of slowdown when worn alone as
+ a result.
+ Xackii:
+ - bugfix: Firelocks can be opened with crowbar rigth-click in combat mode.
+ carlarctg:
+ - balance: Supermatter bioscrambler anomalies are now docile.
+ - balance: Reduced caltrop default paralyze timer from 6 to 2
+ flleeppyy:
+ - rscadd: the cyborg shaker in service borgs now have the ability to open the reaction
+ search menu
+ grungussuss:
+ - balance: bushes and other flora have had their HP reduced from 150 to 100. Trees
+ still have 150 HP
+ - balance: flora now has an X4 modifier to damage from burn sources
+ - balance: MODsuits now deploy 2 times faster
+ - balance: The infiltrator MODsuit now deploys 4 times faster
+ - sound: 'added rustle sounds for: toolbox, medkit, box'
+ - sound: 'added open sounds for: toolbox, box'
+ - code_imp: added support for giving container items rustle sounds
+ grungussuss and Beeblie:
+ - sound: internals breathing sound has received more variance and had its volume
+ reduced
+ hack-wrench:
+ - rscadd: add syndicate branded lipstick to uplink (6 TC), after applying lipstick
+ *kiss deals damage equal to energy gun
+ - bugfix: fix wallhit sound for projectile
+ imedial:
+ - bugfix: fixed nested radios with encryption keys giving free comms
+ itseasytosee:
+ - bugfix: illustrious ethereals now properly get the tenacious trait
+ - code_imp: more species features have been moved to their individual body parts.
+ lbnesquik:
+ - qol: Clarified what the Medical Cyborg Omnitool Upgrade does
+ - rscadd: Added a cyborg plunger for janitorial modules
+ loganuk:
+ - bugfix: AI Players can now operate the BRM (Boulder Retrival Matrix)
+ mc-oofert:
+ - bugfix: breaking certain terrain in deathmatch doesnt instantly breach to space
+ r3dj4ck0424:
+ - bugfix: In light of recent allegations of wizardry among the kitchen staff, our
+ cooks will now need bowls when crafting food that comes in bowls. This should
+ also stop said bowls from vanishing once the food is gone.
+ raffclar:
+ - bugfix: Various fixes to TGUI notepad
+ - bugfix: The first tab is now selected with ore redemption machines when opened
+ for the first time
+ tmyqlfpir:
+ - balance: Reduced pathfinding circuit component cooldown from 30 seconds to 5 seconds
+2024-08-16:
+ Absolucy:
+ - bugfix: Empty blood brother teams will now be cleaned up, instead of clogging
+ up the roundend report.
+ Ben10Omintrix:
+ - bugfix: fixes surgery table buckle offsets
+ - bugfix: fixes rcds accounting for player dir only before construction
+ - bugfix: fixes pickup animation not matching player offset
+ Bisar:
+ - bugfix: Potted plants no longer permanently mark you as one of their own.
+ DATA-xPUNGED:
+ - qol: Paraplegics can now opt into appearing on the shift without their legs.
+ Ghommie:
+ - image: Resprited more types of fillets, and moonfish eggs
+ - rscadd: Crabs and lobstrosities (as well as the lobster foam helmet and the fishing
+ hat) now pack a boatload of fish puns.
+ Jacquerel:
+ - bugfix: corrects offset of cobweb fluff object
+ - bugfix: Dimensional anomalies should once again create cool walls, not boring
+ grey ones
+ - bugfix: Mobs shown in ghost alerts shouldn't be offset out of the box
+ - image: Several midround dynamic alert icons should be more demonstrative of what
+ is spawning
+ Melbert:
+ - bugfix: Less floating things on Delta
+ - rscadd: Auto-generated digitigrade clothing sprites for most jumpsuits
+ Metekillot:
+ - bugfix: Raptors properly respect their own factions now.
+ Sadboysuss:
+ - qol: atmos meters can now be attached to layer 1 and 5
+ - sound: generic ship ambience volume has been reduced
+ Shadow-Quill:
+ - bugfix: You can no longer hear radio sounds if you're deaf.
+ SmArtKar:
+ - image: Mirrors have been successfully wallened
+ - bugfix: You can now move horizontally on tall stairs and they no longer have a
+ hole in them when facing south
+ - bugfix: Fixed improvised shield crafting recipe being overriden by moonflowers
+ - image: Floor lights no longer use outdated textures
+ - balance: Deja Vu perk now teleports you to where you were before the last teleport,
+ instead of where you arrived on the station
+ - bugfix: Deja Vu can no longer be used to return to the wizard ship
+ - bugfix: Blade heretic ascension now gives you floating blades once again
+ deathrobotpunch:
+ - rscadd: big pharma now supplies a single pack of experimental medication as an
+ easy to access (albeit expensive) cargo goodie!
+ - balance: price for the cargo crate with 2 pill bottles of experimental medication
+ has been increased to 600 to better reflect the goodie case price.
+ grungussuss:
+ - sound: some sheets that shouldn't be making metal sounds no longer make those
+ sounds
+ - sound: added new sounds for RCD, RPD and Plumbing Constructor.
+ tralezab:
+ - bugfix: bedsheets are laid on beds properly now
+2024-08-17:
+ Ghommie:
+ - rscadd: Added a treasure chest you can rarely fish from the ocean/beach, with
+ loot being a mix of fishing and piratey stuff.
+ - rscadd: You can revive fish with strange reagent now.
+ - rscadd: You can sell items on the blackmarket with the LTSRBT now.
+ - bugfix: Added some checks to prevent the swapper device and bluespace anomalies
+ from theorically being able to send things and people to nullspace.
+ Jacquerel:
+ - bugfix: Beepsky and Mice have more appropriately positioned shadows.
+ Majkl-J:
+ - bugfix: Trying to repair someone's undamaged limb with a welder or wires no longer
+ has you smacking them
+ Shroopy:
+ - bugfix: Added a light switch to the science hallway in Metastation
+ SmArtKar:
+ - rscadd: You can now lean on windows the same way you can lean on walls
+ - bugfix: You no longer stop leaning on walls after clicking on anything
+ - qol: Dumping things into microwave en-masse is done via RMB (drag'n'drop support
+ coming soon!)
+ - bugfix: RPEDs can now upgrade microwaves
+ - bugfix: Spies can finally steal microwaves (Use RMB!)
+ TheVekter:
+ - bugfix: Updated Metastation for Wallening
+ Time-Green:
+ - qol: The Voidwalker wisp void now loops you
+ unit0016:
+ - bugfix: Indestructible reinforced walls now mimic their destructible counterparts
+ as intended.
+ - bugfix: Every bitrunner domain's been patched up for the new perspective shift.
+ zxaber:
+ - image: Airlocks have a better sprite for indicating which directions (if any)
+ you can pass through without ID access.
+2024-08-18:
+ Ben10Omintrix:
+ - bugfix: fixes ai controllers incorrectly idling when changing z level
+ Ghommie:
+ - bugfix: lights placed on walls with the RLD now face the correct direction.
+ - bugfix: Fixes lobby buttons from station traits having no name and being unexaminable.
+ - bugfix: Fixed the shower water visually not coming out behind the showerhead.
+ Justice12354:
+ - bugfix: Fixes the rotation of Centcom's Airlocks
+ KingkumaArt:
+ - image: Resprited mech drills, plasma cutter, pka and cargo clamp.
+ LemonInTheDark:
+ - admin: Subsystem Overview now has the ability to track a rolling average of tick
+ by tick subsystem cpu usage.
+ Melbert:
+ - qol: Icebox now has a trapdoor from Medbay leading into the Morgue (for corpses,
+ of course)
+ - bugfix: Patch exploit allowing nigh-infinite heretic points
+ - qol: Xenos and digi lizards have claw footprints
+ - qol: Some wall mounts will now consistently layer over others (light switches
+ and cameras, notably, should always layer above other mounts like signs and
+ status displays)
+ MrBagHead:
+ - bugfix: Swapped East and West sprites for access buttons to correct previous misalignment.
+ - rscadd: Added South-facing sprite for access buttons.
+ SmArtKar:
+ - bugfix: Mechs' directional armor now actually works
+ - bugfix: Alien beds no longer pretend they can be deconstructed with a wrench
+ - qol: Wallmount balloons are now clickable
+ - admin: Stat change is now logged for living mobs
+ - bugfix: Fixed elephant graveyard active turfs
+ - bugfix: Fixed random lipstick texture, fake syndie lipstick no longer can randomly
+ spawn
+ Timberpoes:
+ - bugfix: Having the Overflow Role set to On will properly ensure you get that role
+ at a High priority as intended by the game code.
+ - bugfix: Job selection is now a little bit more random. Fixes an unintentional
+ bias in random job assignment that could lead to feast-or-famine for roles where
+ everyone is assigned one job and nobody is assigned another job.
+ YesterdaysPromise:
+ - image: adjusted security barriers to be in 3/4 perspective.
+ Zytolg:
+ - bugfix: Updates much of Birdshot for the Wallening
+ mc-oofert:
+ - rscadd: portable gravity unit, bought at cargo
+ necromanceranne:
+ - rscadd: Drunken fist fighting now has bonuses and penalties based on how intoxicated
+ you are. Controlled liquor intake could make you a better brawler. Though you
+ might vomit if you go too hard.
+ - rscadd: Bartenders are now Drunken Brawlers. If they're drunk at all (no matter
+ how drunk), they're stronger at fist fighting.
+ - rscadd: Reintroduces the deterministic stagger combo. The effects of the combo
+ are more varied, and based on attacker unarmed effectiveness and the defender's
+ armor. Read the PR for more details. It's complicated.
+ - qol: Unarmed effects that would utilize stamina values now use a split of half
+ brute, half burn to determine outcomes or for meeting thresholds. This affects;
+ punch accuracy, stagger combo thresholds and grab vulnerability thresholds.
+ thegrb93:
+ - bugfix: Air alarms stuck in warning state despite area completely fine
+2024-08-19:
+ ArcaneMusic:
+ - bugfix: Runtimestation's APC is now connected to the grid again.
+ - rscadd: White crayons (Renamed to Sticks of Chalk) may now be used on dead bodies
+ to draw a body outline onto the ground easily.
+ Bisar:
+ - bugfix: The Nanotrasen Emergency Religious Response Team has blessed the station;
+ heretic summon rituals now actually consume resources, fixing infinite summon
+ loops.
+ Ghommie:
+ - image: Ported and adapted several food sprites from Aurora, Bay and one instance
+ from Paradise -- Bacon, plant meat, slime meat, cutlets, crab meat, crab rangoon,
+ bechamel sauce, cheese curd, waffles, chips, shrimp chips, cheesie honkers,
+ space twinkie, jerky, peanuts bags, chocolate, boritos, syndicake, popcorn,
+ pesto, tomato sauce, pineapple slice, pineapple salsa, bran request cereals
+ and bronx bar have been resprited.
+ - rscdel: Waffles no longer magically conjure a "waffle tray" trash item when eaten.
+ - image: Shrunk the arrow shown when pointing at things to be less invasive.
+ - rscadd: Wearing an ID with the trim of a command/leader position gives you bigger
+ arrows (about the size of arrows before this PR) which may also be of different
+ colors.
+ - rscadd: Added a skillchip that does the same, but also makes the color of the
+ arrow totally customizable.
+ - bugfix: ERT engies and medics now come with the engineering and entrails-reader
+ skillchips respectively, like their station counterparts.
+ - bugfix: Fixed not facing atoms that you're pointing at.
+ - rscadd: Added a bluespace fish case to the advanced fishing node.
+ - balance: Fish cases will keep a fish from getting hungrier or ready to reproduce,
+ while also healing it up to 65% health.
+ - balance: Examining a fish with zero fishing skill whatsoever won't give a reading
+ on its size and weight. Conversely, examining one with the skill leveled two
+ times will give general information on if it's starving, sick, hungry, or dead.
+ - bugfix: paintings now drop canvas and frame when knocked off the wall.
+ Jacquerel:
+ - bugfix: Whatever the roaches were getting into which made them hover above the
+ ground seems to have worn off.
+ - bugfix: Carp, bat, parrot, and dragon corpses no longer float in the air.
+ Rhials:
+ - code_imp: Radios/encryption keys now use a single variable for "special" frequencies.
+ Please report if you experience any strangeness with accessing/being unable
+ to access the Centcom, Syndicate, or Cyborg radio.
+ SmArtKar:
+ - bugfix: Random spraypaint setting now properly paints large decals
+ - image: Added emissives to departamental signs
+ - image: Gas tanks got updated worn sprites
+ - bugfix: Examine balloons for wall-mounted buttons no longer inflate themselves
+ infinitely
+ - bugfix: Fixed active turfs on crashsite ruin
+ - bugfix: Captain's spare safe no longer turns invisible when opened
+ - bugfix: Fixed soapbox component sometimes runtiming roundstart
+ - bugfix: Fixed circuit drone pixel/shadow offsets
+ TwistedSilicon:
+ - bugfix: Clarkes will no longer become unable to dump ores upon picking a boulder
+ up. Mine away.
+ mc-oofert:
+ - balance: wheelchairs no longer double your movement cooldown if you moved diagonally
+ norsvenska:
+ - qol: The CentCom officer's beret has had its slowdown removed to be in line with
+ the winter coat.
+ r3dj4ck0424:
+ - rscadd: A new vendor of cytology equipment, the CytoPro, is now available in your
+ local science department!
+ san7890:
+ - bugfix: The area of the CentCom Z-Level dedicated to the Lobby Screen should look
+ far better now, with a solid black title screen should the lobby image not load
+ in/get deleted.
+ - qol: Reporting issues on the Github should now be a far more simpler experience.
+ Hitting the "Report Issue" button in the top-right of your BYOND Client Screen
+ will still autofill in the fields as expected.
+2024-08-20:
+ JohnFulpWillard:
+ - rscadd: Added Taunting, a faster and cooldowned version of the Spin emote.
+ - balance: Wizards blocking projectiles with Transparence and the bitrunner matrix
+ skillchip now have a visible effect of deflecting the projectile.
+ - balance: The bitrunner skillchip now uses taunt instead of flip.
+ - balance: The style meter now uses taunting instead of flips and spins.
+ - bugfix: Statues don't count as eyes to creatures.
+ - bugfix: Human AIs and Admin ghosts no longer get kicked off of machines that aren't
+ on cameranets.
+ SmArtKar:
+ - image: Utility belts got new tool overlay sprites
+ - spellcheck: CE's toolbelt is no longer capitalized or considered an improper noun
+ - balance: PACMANs now have significantly increased power output and take longer
+ to consume a single sheet
+ - balance: Inducers can now be recharged with plasma
+ - balance: Inducers ordered from cargo now start with upgraded megacells instead
+ of upgraded batteries
+ - balance: Vomiting from disgust now removes 50 of it from you.
+ Vekter:
+ - bugfix: Fixed further Wallening issues on Metastation, including Cargo's shuttle
+ door buttons and Xenobiology's access buttons.
+ - rscdel: Removed department directional signs from Metastation as they are currently
+ broken. They will return once they've been fixed.
+ Zytolg:
+ - bugfix: Continues to update Birdshot into a postwallening playable state
+ carlarctg:
+ - rscadd: Added three new DM maps - Ragnarok, Lattice Battles, Species Showdown.
+ mc-oofert:
+ - bugfix: spawning on a table or other elevated object does not offset you forever
+2024-08-21:
+ Ghommie:
+ - rscadd: Added twelve new fish types to the game. Some are cool, other are not,
+ some come with their own special traits and some are straight-up weapons.
+ - rscadd: Added more fishing spots to the game. Sand, ice, rivers, the cursed spring...
+ - balance: A few fish like salmon, swordfish and pufferfish (poisonous btw) now
+ give better quality fillets when butchered, which can improve the quality of
+ food that uses them even further.
+ - balance: Excessive fish weight will make the fish slowier to carry, while excessive
+ size may make it require two hands.
+ - balance: Adjusted size, weight and cooldowns of several fish, for the better.
+ Iamgoofball:
+ - balance: Air alarms are now usable by Station Engineers as well as Atmospherics
+ Technicians.
+ Rhials:
+ - bugfix: Adjusts some areas by the Icebox Cliffside Bench to generate a bit less
+ weirdly.
+ - sound: '"radio message received" audio now has a brief cooldown.'
+ - bugfix: Beepsky will now salute commissioned bots, instead of himself, when encountering
+ one.
+ SmArtKar:
+ - bugfix: Ragnarok deathmatch arena now has noteleport area
+ - bugfix: Replaced a locked cabinet that you cannot open in ninja den with an unlocked
+ one
+ - qol: Haunted 8ball now gives you a TGUI input with your question for ghosts instead
+ of telling them the last thing it heard.
+ - image: 8ball has received a resprite
+ - bugfix: Fixed examine balloons not being click transparent even while inactive
+ - image: Updated cryostasis beaker's sprite
+ grungussuss:
+ - sound: computers now make clicky clacky sounds
+2024-08-22:
+ Absolucy:
+ - qol: Clicking floor tiles now also closes curator/morgue doors, like with normal
+ airlocks.
+ - qol: Unarmed attacks with carp jaws now uses a bite effect rather than a punch
+ effect.
+ Ben10Omintrix:
+ - bugfix: fences will no longer appear pitch black and they will layer properly
+ Bisar:
+ - rscadd: Nanotrasen Intelligence has received reports of botanical experimentation
+ in a Syndicate base on lavaland. What fiendish flora are taking root in their
+ secret lair?
+ Ghommie:
+ - rscadd: Fishing toolboxes (and occasionally maintenance) now come with a paper
+ slip containing fishing-related tips.
+ - rscadd: Buckshot is back on the menu, on the blackmarket.
+ - balance: the integrity of firearms now counts toward projectile damage. A gun
+ that's on the very verge of breaking down will deal half as much damage.
+ Jacquerel:
+ - balance: Pacifist carp can now be spawned from the friendly gold core reaction,
+ and no longer appear from the hostile one.
+ - bugfix: The teeth of toothless carp will not occasionally reappear
+ - bugfix: Crabs will now run from attackers larger than them and attack things smaller
+ than them, as intended.
+ Redrover1760:
+ - balance: Changed max refined vortex cores from 1 to 3. Changed the Event Horizon
+ Anti-Existential Beam Rifle recipe to require 2 vortex cores.
+ Rhials:
+ - qol: Delivery/Bot pathing nodes have been added to the middle room of Runtime
+ station.
+ - sound: Windows blown out by a Voidwalker blade now have a cool sound that plays
+ as they reform.
+ - admin: You can now choose the humanoid species spawned by an ERT summon in the
+ summon menu.
+ SmArtKar:
+ - bugfix: Fixes kudzu being able to spawn on openspace turfs resulting in it getting
+ stuck
+ - bugfix: Radioactive nebula no longer runtimes on runtime station
+ - bugfix: Fixed delam counter going over objects
+ by Xackii, sprites by ArcaneMusic:
+ - rscadd: Added big manipulators.
+ lizelive:
+ - balance: reticence requires progression
+ r3dj4ck0424:
+ - balance: The CytoPro has had prices raised to slightly more reasonable levels.
+2024-08-23:
+ MMMiracles:
+ - bugfix: More various Tramstation-adjacent wallening fixes.
+ Majkl-J:
+ - bugfix: custom pies and cakes are craftable again
+ SmArtKar:
+ - image: Updated goliath cloak sprites
+ necromanceranne:
+ - rscadd: Punching mitts! Punch wildlife to death and scream the whole time. ADVENTURE!
+ - balance: Megafauna can be affected by martial arts.
+2024-08-24:
+ DaCoolBoss:
+ - bugfix: Aquarium decorations now contain plastic.
+ - spellcheck: Added item descriptions for aquarium decorations.
+ EnterTheJake:
+ - balance: Rusted Ritual now requries 10 sheets of Iron instead of Titanium.
+ Ghommie:
+ - rscadd: Added Athletic Fishing Gloves and Fishing Glove Module to the advanced
+ fishing tech node. Both can be used to fish without having to hold a fishing
+ rod. The athletic fishing gloves will also train your athletics skill.
+ LT3:
+ - spellcheck: Sneak a peek of Hilbert's Hotel, not a sneak peak
+ SmArtKar:
+ - bugfix: Marine helmets no longer change their sprite to security helmets when
+ their flashlight is toggled
+ - spellcheck: Hierophant no longer lies about obliterating someone
+ TheBoondock:
+ - qol: goliath arm can defuse gibonite by bumping or direct click
+2024-08-25:
+ DrDiasyl aka DrTuxedo:
+ - rscadd: Curator has received a new BROADCAST CAMERA which can broadcast the surroundings
+ LIVE on Entertainment Screens/ Alongside with some other Journalism related
+ gear in his Heroic Beacon
+ - sound: Entertainment screens now play muffled speech when hearing a message on
+ Entertainment frequency
+ Ghommie:
+ - rscadd: You can place papers, photos and cash bills (no holochips) inside bottles
+ and then toss them into the ocean (or fishing portal gen with relative settings)
+ with right-click, for others to fish them up on future rounds.
+ - bugfix: You can no longer pickup closets and crates wrapped in a package with
+ a fishing rod.
+ - bugfix: Fixed a few harddel issues with mob spawns that caused charred corpses
+ fished from lavaland to create an invisible blockade.
+ - bugfix: Fixed being able to fish up mobs that have fallen in totally different
+ z-levels with a rescue hook (i.e. from bitrunning domains to lavaland).
+ SmArtKar:
+ - bugfix: Removed all ways of teleportation from deathmatch and replaced all consoles
+ on a certain map with non-functional variants. Loadouts have been adjusted to
+ account for this.
+ - rscdel: Species Warfare no longer has atmospherics-related equipment on it.
+ YesterdaysPromise:
+ - rscadd: Added crates of the following varieties; Interdyne, Interdyne freezer,
+ Tiger Co-Op, S.E.L.F. MI13, A.R.C., Cybersun (4 colour variants), Waffle Corp,
+ Donk, Gorlex, Gorlex weapons, DeForest, Nakamure Engineeing, Robust Industries
+2024-08-26:
+ GPeckman:
+ - bugfix: The instagib, ragecage, mech madness, secu-ring, shooting range, and sniper
+ elite deathmatch maps are available again.
+ Ghommie:
+ - bugfix: Fixes the chainsaw evolution for goldfishes.
+ Majkl-J:
+ - rscadd: Achievement for eating 500 cigarettes
+ - balance: Cigarettes are now edible
+ - code_imp: Adds a variable to hide the food examine on the edible element
+ - bugfix: SSPolling no longer fills in the candidate list with empty entries to
+ guarantee it returns a list size of amount_to_pick
+ SmArtKar:
+ - spellcheck: Fixed a typo on snowdin shuttle transi(s)t consoles
+ grungussuss:
+ - sound: lead pipe has sound
+ vinylspiders:
+ - bugfix: wet hides and hairless hides no longer make metal clanging noises when
+ picked up/dropped
+2024-08-27:
+ Ben10Omintrix:
+ - bugfix: fixes blob spore and slime AI endlessly attacking the dead
+ Sakamoto4ka:
+ - rscadd: Added salt electrolysis reaction
+ SmArtKar:
+ - bugfix: Bioscrambler anomalies no longer affect inorganic species
+2024-08-28:
+ Melbert:
+ - bugfix: Juicing and grinding should break less
+ Vekter:
+ - bugfix: Fixed an issue causing Quartermaster office access to show in the wrong
+ area on Plexagon Access Management.
+ - bugfix: Fixed an inconsistency in the naming for QM Office access.
+ grungussuss:
+ - bugfix: after 4 years, computer sound loop now works properly
+2024-08-29:
+ FeudeyTF:
+ - rscadd: Added board for detective's evidences
+ Rhials:
+ - rscadd: Smokey remains have appeared in maintenance. Make sure to walk when near
+ them!
+ SmArtKar:
+ - bugfix: Stagger animation is no longer horrilbly jittery
+ Xackii:
+ - qol: revolver in roundstart holsters is on the last slot and not on first
+2024-08-30:
+ SmArtKar:
+ - bugfix: Projectiles no longer always play turf hit sound
+ - balance: Plexagon Crew Manifest is now a default PDA app for everyone, and is
+ free.
+ - balance: Plexagon Crew Manifest no longer provides Detomatix resistance, but security
+ records and status display control now do.
diff --git a/html/changelogs/archive/2024-09.yml b/html/changelogs/archive/2024-09.yml
new file mode 100644
index 0000000000000..e87a583c329dc
--- /dev/null
+++ b/html/changelogs/archive/2024-09.yml
@@ -0,0 +1,108 @@
+2024-09-04:
+ 00-Steven:
+ - balance: Fax machines with hacked input servos can now send chap slices and cookies.
+ Please accept them.
+ - bugfix: Buckling yourself to a bed or stasis bed will now make you actually use
+ the headrest/pillow and face up.
+ - qol: Multi-z disposal segments can actually be made with an RPD.
+ - image: Upwards multi-z disposal segments no longer have wonky sprites.
+ - bugfix: Big manipulator hands now move smoothly with the base when it's moved.
+ Absolucy:
+ - bugfix: You will now be ejected from any jaunt (i.e bloodcrawl or shadow walk)
+ if you lose consciousness somehow during the jaunt.
+ Artemchik542:
+ - bugfix: typo in CRUSH_CRIT_PARAPLEGIC
+ AyIong:
+ - qol: Stat Panel settings moved to personal tab
+ - bugfix: Stat Panel tabs no longer create horizontal scrollbar by default, but
+ you can return it into the settings
+ - bugfix: Hovering over a truncated statpanel button, doesn't blocks the button
+ below it anymore
+ FeudeyTF:
+ - bugfix: fixed detective board placing
+ Hardly:
+ - sound: Added sounds for conveyor belt switches
+ JohnFulpWillard:
+ - bugfix: Ice cream vats can be refilled with beakers again.
+ LT3:
+ - bugfix: You can now put Skub back in the Skub box, as intended
+ - bugfix: Ice Box lower floor maints is properly protected during radstorms
+ - bugfix: Fixed malfunctioning tram crossing signals sometimes staying green
+ Melbert:
+ - bugfix: Some spy items should spawn less broken
+ Redrover1760:
+ - bugfix: Fixed light overloads not draining significant amounts of energy.
+ - bugfix: Power sinks now drain APCs at a significant rate instead of glacially
+ slow.
+ - balance: Power sinks are adjusted to not explode within 30 seconds of the average
+ power output a station produces.
+ SmArtKar:
+ - image: Added new sprites for hellfire lasers
+ - bugfix: Cardborg costume no longer gets its appearance deleted when you drop a
+ second hat/suit you are holding in your hand
+ Watermelon914:
+ - bugfix: Fixed a bug that breaks signal handlers on an object if one of the signal
+ handlers doesn't return a number value.
+ Xackii:
+ - bugfix: fixed that screwdriwing radio headset in combat mode don't do anything.
+ alien3301:
+ - balance: When silicons use their radio they will not whisper out loud anymore
+ grungussuss:
+ - sound: being sacrificed by a heretic is now spookier
+ grungussuss and kayozz:
+ - sound: gravity generator has a new sound
+ vinylspiders:
+ - bugfix: due to a clerical error, all ballistic guns were shipping with built-in
+ silencers. this has been resolved-they will now make noise once again when fired.
+ - bugfix: fixes a crafting exploit that allowed you to get more resources back from
+ disassembling than you put into the recipe
+ - bugfix: fixed 'Enable Radio Noise' pref only being respected for deaf people
+2024-09-05:
+ Archimus12:
+ - bugfix: Makes the Cytology Vendor sell science bio suits instead of medical bio
+ suits.
+ - bugfix: Makes the Cytology Vendor sell science lab coats instead of normal lab
+ coats.
+ Astrogem2:
+ - spellcheck: fixed a few typos with energy shield descriptions.
+ Ben10Omintrix:
+ - bugfix: aquarium ui now displays props and fishes correctly
+ - refactor: able_to_run and incapacitated have been refactored to be event based
+ - bugfix: wooden fences will no longer appear pitch black in lower levels of icebox
+ - qol: gives aquariums a new easier to use UI
+ Bisar:
+ - code_imp: The (currently unused) TGUI checkbox components returns a BYOND friendly
+ list of the indexes of any choices now.
+ EnterTheJake:
+ - rscadd: A Syndicate Rebar Quiver has been added to the uplink
+ - qol: Left clicking with a rebar crossbow will now draw/undraw the string.
+ - balance: Rebar quivers are now a neck slot item.
+ - balance: ' Hydrogen bolts damage has been upped to 55 brute and can now pierce
+ through walls, they no longer have infinite piercing and can no longer embed
+ however.'
+ - code_imp: removed the TRAIT_ALWAYS_HIT_ZONE, replaced with 2 new variables.
+ - bugfix: fixes rebar crossbows having a higher capacity than intended if a bolt
+ had already been chambered.
+ FeudeyTF:
+ - bugfix: fixed an UI problems of evidence board
+ Ghommie:
+ - bugfix: Rum can be synthetized again.
+ JohnFulpWillard:
+ - qol: Smartfridges now lets you set how many pills you want to vend, rather than
+ popping out a second separate tgui window.
+ LT3:
+ - rscadd: Added Chief Engineer SEAL OF APPROVAL sticker
+ - code_imp: Stickers now come in sticker packs, not boxes
+ - code_imp: Stickers can now add examine text to whatever they're stuck on
+ Rhials:
+ - spellcheck: Anomaly suicides now use proper grammar.
+ - bugfix: Anomaly suicides work again.
+ Time-Green:
+ - qol: Unsettle (Voidwalker) doesn't go on cooldown if line of sight is broken
+ grungussuss:
+ - sound: fish now have new sounds
+ oranges:
+ - rscadd: ghosts can now jump, bhop your way to life
+ r3dj4ck0424:
+ - rscadd: The vendor of cytology equipment, the CytoPro, is once again available
+ in your local science department!
diff --git a/html/statbrowser.css b/html/statbrowser.css
index cd1d63bf7c060..d8c0f92b626f4 100644
--- a/html/statbrowser.css
+++ b/html/statbrowser.css
@@ -16,7 +16,7 @@ a:hover {
}
h3 {
- margin: 0 -0.5em 0.25em;
+ margin: 0 -0.5em 0.5em;
padding: 1em 0.66em 0.5em;
border-bottom: 0.1667em solid;
}
@@ -41,6 +41,27 @@ img {
background-color: #ffffff;
}
+.menu-wrap {
+ flex-wrap: wrap-reverse;
+}
+
+#menu.tabs-classic {
+ padding: 0.15em;
+}
+
+#menu.tabs-classic .button {
+ min-width: 2em;
+ margin: 0.1em;
+ padding: 0.25em 0.4em;
+ border: 0;
+ border-radius: 0.25em;
+}
+
+#menu.tabs-classic .button.active {
+ background-color: #0668b8;
+ color: white;
+}
+
.button {
display: inline-table;
cursor: pointer;
@@ -62,6 +83,7 @@ img {
}
.button.active {
+ cursor: default;
background-color: #dfdfdf;
color: black;
border-bottom-color: #000000;
@@ -80,7 +102,7 @@ img {
}
.grid-container {
- margin: 0;
+ margin: -0.25em;
}
.grid-item {
@@ -89,13 +111,14 @@ img {
user-select: none;
-ms-user-select: none; /* Remove after Byond 516 */
width: 100%;
- box-sizing: border-box;
+ max-height: 1.85em;
text-decoration: none;
background-color: transparent;
color: black;
}
-.grid-item:hover {
+.grid-item:hover,
+.grid-item:active {
color: #003399;
z-index: 1;
}
@@ -104,21 +127,20 @@ img {
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
- box-sizing: border-box;
white-space: nowrap;
+ pointer-events: none;
width: 100%;
padding: 0.33em 0.5em;
border-radius: 0.25em;
}
-.grid-item-text:hover {
- position: absolute;
- top: -1.33em;
+.grid-item:hover .grid-item-text {
+ overflow: visible;
white-space: normal;
background-color: #ececec;
}
-.grid-item-text:active {
+.grid-item:active .grid-item-text {
background-color: #dfdfdf;
}
@@ -173,7 +195,8 @@ body.dark {
}
.dark a:hover,
-.dark .grid-item:hover {
+.dark .grid-item:hover,
+.dark .grid-item:active {
color: #80bfff;
}
@@ -181,6 +204,10 @@ body.dark {
background-color: #131313;
}
+.dark #menu.tabs-classic .button.active {
+ background-color: #20b142;
+}
+
.dark .button {
color: rgba(255, 255, 255, 0.5);
}
@@ -203,10 +230,10 @@ body.dark {
color: #b2c4dd;
}
-.dark .grid-item-text:hover {
+.dark .grid-item:hover .grid-item-text {
background-color: #252525;
}
-.dark .grid-item-text:active {
+.dark .grid-item:active .grid-item-text {
background-color: #313131;
}
diff --git a/html/statbrowser.js b/html/statbrowser.js
index f6c188c6edd61..3fe115943a702 100644
--- a/html/statbrowser.js
+++ b/html/statbrowser.js
@@ -716,6 +716,19 @@ function set_font_size(size) {
document.body.style.setProperty('font-size', size);
}
+function set_tabs_style(style) {
+ if (style == "default") {
+ menu.classList.add('menu-wrap');
+ menu.classList.remove('tabs-classic');
+ } else if (style == "classic") {
+ menu.classList.add('menu-wrap');
+ menu.classList.add('tabs-classic');
+ } else if (style == "scrollable") {
+ menu.classList.remove('menu-wrap');
+ menu.classList.remove('tabs-classic');
+ }
+}
+
function set_style_sheet(sheet) {
if (document.getElementById("goonStyle")) {
var currentSheet = document.getElementById("goonStyle");
diff --git a/icons/effects/beam.dmi b/icons/effects/beam.dmi
index ae668b0495a56..85d450e03bdd6 100644
Binary files a/icons/effects/beam.dmi and b/icons/effects/beam.dmi differ
diff --git a/icons/effects/random_spawners.dmi b/icons/effects/random_spawners.dmi
index 4e5608330030b..d6e06fb140d04 100644
Binary files a/icons/effects/random_spawners.dmi and b/icons/effects/random_spawners.dmi differ
diff --git a/icons/hud/fishing_hud.dmi b/icons/hud/fishing_hud.dmi
index f18ed7c6cfca9..db36e241a2f33 100644
Binary files a/icons/hud/fishing_hud.dmi and b/icons/hud/fishing_hud.dmi differ
diff --git a/icons/hud/screen_alert.dmi b/icons/hud/screen_alert.dmi
index dda7d6cc635af..10d0b741f0b7c 100644
Binary files a/icons/hud/screen_alert.dmi and b/icons/hud/screen_alert.dmi differ
diff --git a/icons/hud/screen_gen.dmi b/icons/hud/screen_gen.dmi
index 9792124d1b68c..86383abbef1e2 100644
Binary files a/icons/hud/screen_gen.dmi and b/icons/hud/screen_gen.dmi differ
diff --git a/icons/mob/actions/actions_items.dmi b/icons/mob/actions/actions_items.dmi
index 7aaeb9b36d281..3887804e55ddc 100644
Binary files a/icons/mob/actions/actions_items.dmi and b/icons/mob/actions/actions_items.dmi differ
diff --git a/icons/mob/clothing/accessories.dmi b/icons/mob/clothing/accessories.dmi
index 57670005b9240..0e09772a79f50 100644
Binary files a/icons/mob/clothing/accessories.dmi and b/icons/mob/clothing/accessories.dmi differ
diff --git a/icons/mob/clothing/back.dmi b/icons/mob/clothing/back.dmi
index a96beb1cfa936..5bcaa41f5ed58 100644
Binary files a/icons/mob/clothing/back.dmi and b/icons/mob/clothing/back.dmi differ
diff --git a/icons/mob/clothing/belt.dmi b/icons/mob/clothing/belt.dmi
index 724a29de21b0f..4a6cc7ac5c9dd 100644
Binary files a/icons/mob/clothing/belt.dmi and b/icons/mob/clothing/belt.dmi differ
diff --git a/icons/mob/clothing/belt_mirror.dmi b/icons/mob/clothing/belt_mirror.dmi
index 0507a0301944e..7410e2db20b37 100644
Binary files a/icons/mob/clothing/belt_mirror.dmi and b/icons/mob/clothing/belt_mirror.dmi differ
diff --git a/icons/mob/clothing/hands.dmi b/icons/mob/clothing/hands.dmi
index b62b6a0a8ee58..78a07c08e6ede 100644
Binary files a/icons/mob/clothing/hands.dmi and b/icons/mob/clothing/hands.dmi differ
diff --git a/icons/mob/clothing/head/hats.dmi b/icons/mob/clothing/head/hats.dmi
index 5e76ab78608f2..1ff429b68b101 100644
Binary files a/icons/mob/clothing/head/hats.dmi and b/icons/mob/clothing/head/hats.dmi differ
diff --git a/icons/mob/clothing/head/helmet.dmi b/icons/mob/clothing/head/helmet.dmi
index 579f4c53f0f97..db48dda1fd61c 100644
Binary files a/icons/mob/clothing/head/helmet.dmi and b/icons/mob/clothing/head/helmet.dmi differ
diff --git a/icons/mob/clothing/modsuit/mod_modules.dmi b/icons/mob/clothing/modsuit/mod_modules.dmi
index 4f2dc9740d1f7..5c433defa0755 100644
Binary files a/icons/mob/clothing/modsuit/mod_modules.dmi and b/icons/mob/clothing/modsuit/mod_modules.dmi differ
diff --git a/icons/mob/clothing/neck.dmi b/icons/mob/clothing/neck.dmi
index 3467f752ac3a5..bd57cb6eee916 100644
Binary files a/icons/mob/clothing/neck.dmi and b/icons/mob/clothing/neck.dmi differ
diff --git a/icons/mob/clothing/suits/armor.dmi b/icons/mob/clothing/suits/armor.dmi
index ea80204c2cdcc..426a760e7700c 100644
Binary files a/icons/mob/clothing/suits/armor.dmi and b/icons/mob/clothing/suits/armor.dmi differ
diff --git a/icons/mob/clothing/suits/utility.dmi b/icons/mob/clothing/suits/utility.dmi
index 0ef867a2866b8..c8e85bf9a45c7 100644
Binary files a/icons/mob/clothing/suits/utility.dmi and b/icons/mob/clothing/suits/utility.dmi differ
diff --git a/icons/mob/clothing/under/digi_template.dmi b/icons/mob/clothing/under/digi_template.dmi
new file mode 100644
index 0000000000000..0c9db80eb1c88
Binary files /dev/null and b/icons/mob/clothing/under/digi_template.dmi differ
diff --git a/icons/mob/clothing/under/masking_helpers.dmi b/icons/mob/clothing/under/masking_helpers.dmi
index 9ee54a598fad5..dfbec7d1cb8ec 100644
Binary files a/icons/mob/clothing/under/masking_helpers.dmi and b/icons/mob/clothing/under/masking_helpers.dmi differ
diff --git a/icons/mob/effects/blocking.dmi b/icons/mob/effects/blocking.dmi
new file mode 100644
index 0000000000000..03872fa0fe36d
Binary files /dev/null and b/icons/mob/effects/blocking.dmi differ
diff --git a/icons/mob/effects/durand_shield.dmi b/icons/mob/effects/durand_shield.dmi
index 0600e352b316e..8f9016ed74be6 100644
Binary files a/icons/mob/effects/durand_shield.dmi and b/icons/mob/effects/durand_shield.dmi differ
diff --git a/icons/mob/human/cat_features.dmi b/icons/mob/human/cat_features.dmi
index 6e7fd024fee1d..d2d67fdd9b32e 100644
Binary files a/icons/mob/human/cat_features.dmi and b/icons/mob/human/cat_features.dmi differ
diff --git a/icons/mob/human/human_face.dmi b/icons/mob/human/human_face.dmi
index 886094ec49573..5b3b141c7edb0 100644
Binary files a/icons/mob/human/human_face.dmi and b/icons/mob/human/human_face.dmi differ
diff --git a/icons/mob/human/species/misc/bodypart_overlay_simple.dmi b/icons/mob/human/species/misc/bodypart_overlay_simple.dmi
index 8df76eb63147b..dbaaeec55cd24 100644
Binary files a/icons/mob/human/species/misc/bodypart_overlay_simple.dmi and b/icons/mob/human/species/misc/bodypart_overlay_simple.dmi differ
diff --git a/icons/mob/inhands/64x64_lefthand.dmi b/icons/mob/inhands/64x64_lefthand.dmi
index d15a47206f984..14f35aa9ef050 100644
Binary files a/icons/mob/inhands/64x64_lefthand.dmi and b/icons/mob/inhands/64x64_lefthand.dmi differ
diff --git a/icons/mob/inhands/64x64_righthand.dmi b/icons/mob/inhands/64x64_righthand.dmi
index 88ad954734bf5..102417e36f5b7 100644
Binary files a/icons/mob/inhands/64x64_righthand.dmi and b/icons/mob/inhands/64x64_righthand.dmi differ
diff --git a/icons/mob/inhands/clothing/gloves_lefthand.dmi b/icons/mob/inhands/clothing/gloves_lefthand.dmi
index 4d191e42939b7..13b91d3108f46 100644
Binary files a/icons/mob/inhands/clothing/gloves_lefthand.dmi and b/icons/mob/inhands/clothing/gloves_lefthand.dmi differ
diff --git a/icons/mob/inhands/clothing/gloves_righthand.dmi b/icons/mob/inhands/clothing/gloves_righthand.dmi
index f8ce306cc9850..f7325d02e7a63 100644
Binary files a/icons/mob/inhands/clothing/gloves_righthand.dmi and b/icons/mob/inhands/clothing/gloves_righthand.dmi differ
diff --git a/icons/mob/inhands/fish_lefthand.dmi b/icons/mob/inhands/fish_lefthand.dmi
index f5aeef6202713..b61231c6b9d11 100644
Binary files a/icons/mob/inhands/fish_lefthand.dmi and b/icons/mob/inhands/fish_lefthand.dmi differ
diff --git a/icons/mob/inhands/fish_righthand.dmi b/icons/mob/inhands/fish_righthand.dmi
index d9c23c3d1b19e..48ede802899ae 100644
Binary files a/icons/mob/inhands/fish_righthand.dmi and b/icons/mob/inhands/fish_righthand.dmi differ
diff --git a/icons/mob/inhands/items/devices_lefthand.dmi b/icons/mob/inhands/items/devices_lefthand.dmi
index 48c47f872df3c..334d962e4057d 100644
Binary files a/icons/mob/inhands/items/devices_lefthand.dmi and b/icons/mob/inhands/items/devices_lefthand.dmi differ
diff --git a/icons/mob/inhands/items/devices_righthand.dmi b/icons/mob/inhands/items/devices_righthand.dmi
index f8f19a8709b15..d26bf452aa5ec 100644
Binary files a/icons/mob/inhands/items/devices_righthand.dmi and b/icons/mob/inhands/items/devices_righthand.dmi differ
diff --git a/icons/mob/inhands/items_lefthand.dmi b/icons/mob/inhands/items_lefthand.dmi
index 86396dcaa8c67..ebcfea5967596 100644
Binary files a/icons/mob/inhands/items_lefthand.dmi and b/icons/mob/inhands/items_lefthand.dmi differ
diff --git a/icons/mob/inhands/items_righthand.dmi b/icons/mob/inhands/items_righthand.dmi
index 2cbe944aecc52..b8fd65ec07206 100644
Binary files a/icons/mob/inhands/items_righthand.dmi and b/icons/mob/inhands/items_righthand.dmi differ
diff --git a/icons/mob/simple/carp.dmi b/icons/mob/simple/carp.dmi
index 1be59c43ecb6e..e33b9c7ada810 100644
Binary files a/icons/mob/simple/carp.dmi and b/icons/mob/simple/carp.dmi differ
diff --git a/icons/obj/aquarium/fish.dmi b/icons/obj/aquarium/fish.dmi
index 638c8300f304a..069c92c9a3ed9 100644
Binary files a/icons/obj/aquarium/fish.dmi and b/icons/obj/aquarium/fish.dmi differ
diff --git a/icons/obj/aquarium/wide.dmi b/icons/obj/aquarium/wide.dmi
index 7c5f941a1db37..61dfbe1271830 100644
Binary files a/icons/obj/aquarium/wide.dmi and b/icons/obj/aquarium/wide.dmi differ
diff --git a/icons/obj/clothing/accessories.dmi b/icons/obj/clothing/accessories.dmi
index 0253485cec327..578aebd0c65a1 100644
Binary files a/icons/obj/clothing/accessories.dmi and b/icons/obj/clothing/accessories.dmi differ
diff --git a/icons/obj/clothing/belt_overlays.dmi b/icons/obj/clothing/belt_overlays.dmi
index 7a215dcb9b1cc..0692033a5361b 100644
Binary files a/icons/obj/clothing/belt_overlays.dmi and b/icons/obj/clothing/belt_overlays.dmi differ
diff --git a/icons/obj/clothing/gloves.dmi b/icons/obj/clothing/gloves.dmi
index 4739498c16426..b2b3d333bb44f 100644
Binary files a/icons/obj/clothing/gloves.dmi and b/icons/obj/clothing/gloves.dmi differ
diff --git a/icons/obj/clothing/head/hats.dmi b/icons/obj/clothing/head/hats.dmi
index da4a30e996740..2ce0eebb2ad22 100644
Binary files a/icons/obj/clothing/head/hats.dmi and b/icons/obj/clothing/head/hats.dmi differ
diff --git a/icons/obj/clothing/head/helmet.dmi b/icons/obj/clothing/head/helmet.dmi
index cc54b2bf92934..621afe57ddce4 100644
Binary files a/icons/obj/clothing/head/helmet.dmi and b/icons/obj/clothing/head/helmet.dmi differ
diff --git a/icons/obj/clothing/headsets.dmi b/icons/obj/clothing/headsets.dmi
index b977487e2c6ce..57e67e5761a0c 100644
Binary files a/icons/obj/clothing/headsets.dmi and b/icons/obj/clothing/headsets.dmi differ
diff --git a/icons/obj/clothing/modsuit/mod_modules.dmi b/icons/obj/clothing/modsuit/mod_modules.dmi
index 36d95aa61fdbb..5cab83c56d5b2 100644
Binary files a/icons/obj/clothing/modsuit/mod_modules.dmi and b/icons/obj/clothing/modsuit/mod_modules.dmi differ
diff --git a/icons/obj/clothing/suits/armor.dmi b/icons/obj/clothing/suits/armor.dmi
index b1763f5453ffe..b2c9a1aa8b430 100644
Binary files a/icons/obj/clothing/suits/armor.dmi and b/icons/obj/clothing/suits/armor.dmi differ
diff --git a/icons/obj/clothing/suits/utility.dmi b/icons/obj/clothing/suits/utility.dmi
index 25fb8fd502a35..f8e3c4ce46897 100644
Binary files a/icons/obj/clothing/suits/utility.dmi and b/icons/obj/clothing/suits/utility.dmi differ
diff --git a/icons/obj/cosmetic.dmi b/icons/obj/cosmetic.dmi
index b04bde541ad6c..e9f831fbc9690 100644
Binary files a/icons/obj/cosmetic.dmi and b/icons/obj/cosmetic.dmi differ
diff --git a/icons/obj/devices/mecha_equipment.dmi b/icons/obj/devices/mecha_equipment.dmi
index 90f0ce8c736cf..ebfa5438ae911 100644
Binary files a/icons/obj/devices/mecha_equipment.dmi and b/icons/obj/devices/mecha_equipment.dmi differ
diff --git a/icons/obj/devices/new_assemblies.dmi b/icons/obj/devices/new_assemblies.dmi
index 1de208a7736ce..7bf96e5ba92e3 100644
Binary files a/icons/obj/devices/new_assemblies.dmi and b/icons/obj/devices/new_assemblies.dmi differ
diff --git a/icons/obj/devices/tracker.dmi b/icons/obj/devices/tracker.dmi
index 39be63ef4de81..161904825735e 100644
Binary files a/icons/obj/devices/tracker.dmi and b/icons/obj/devices/tracker.dmi differ
diff --git a/icons/obj/devices/voice.dmi b/icons/obj/devices/voice.dmi
index 1e875d9323038..4188d7867eebd 100644
Binary files a/icons/obj/devices/voice.dmi and b/icons/obj/devices/voice.dmi differ
diff --git a/icons/obj/drinks/bottles.dmi b/icons/obj/drinks/bottles.dmi
index 205a67c84e20d..2bdacf0426506 100644
Binary files a/icons/obj/drinks/bottles.dmi and b/icons/obj/drinks/bottles.dmi differ
diff --git a/icons/obj/fishing.dmi b/icons/obj/fishing.dmi
index 92d1cf9a12231..b1d5a787b202f 100644
Binary files a/icons/obj/fishing.dmi and b/icons/obj/fishing.dmi differ
diff --git a/icons/obj/food/food.dmi b/icons/obj/food/food.dmi
index 9ad8d3235e1f0..ad7421dbf6d3a 100644
Binary files a/icons/obj/food/food.dmi and b/icons/obj/food/food.dmi differ
diff --git a/icons/obj/food/lizard.dmi b/icons/obj/food/lizard.dmi
index 15bed265e2f41..29b35cd8a96c5 100644
Binary files a/icons/obj/food/lizard.dmi and b/icons/obj/food/lizard.dmi differ
diff --git a/icons/obj/food/martian.dmi b/icons/obj/food/martian.dmi
index 79efcd1813d58..829cf421cfb51 100644
Binary files a/icons/obj/food/martian.dmi and b/icons/obj/food/martian.dmi differ
diff --git a/icons/obj/food/meat.dmi b/icons/obj/food/meat.dmi
index bf0b1df4f4cd2..ca3007749e7e6 100644
Binary files a/icons/obj/food/meat.dmi and b/icons/obj/food/meat.dmi differ
diff --git a/icons/obj/food/mexican.dmi b/icons/obj/food/mexican.dmi
index ba02c15a0b577..772d6b2e3fc74 100644
Binary files a/icons/obj/food/mexican.dmi and b/icons/obj/food/mexican.dmi differ
diff --git a/icons/obj/food/piecake.dmi b/icons/obj/food/piecake.dmi
index e6c0a71022d50..1097c9d2acd3b 100644
Binary files a/icons/obj/food/piecake.dmi and b/icons/obj/food/piecake.dmi differ
diff --git a/icons/obj/food/spaghetti.dmi b/icons/obj/food/spaghetti.dmi
index 1c97a45e7b788..0d5e473e9b4b6 100644
Binary files a/icons/obj/food/spaghetti.dmi and b/icons/obj/food/spaghetti.dmi differ
diff --git a/icons/obj/machines/big_manipulator.dmi b/icons/obj/machines/big_manipulator.dmi
new file mode 100644
index 0000000000000..b6e878e189842
Binary files /dev/null and b/icons/obj/machines/big_manipulator.dmi differ
diff --git a/icons/obj/machines/big_manipulator_parts/big_manipulator_core.dmi b/icons/obj/machines/big_manipulator_parts/big_manipulator_core.dmi
new file mode 100644
index 0000000000000..614b4d51cbbf9
Binary files /dev/null and b/icons/obj/machines/big_manipulator_parts/big_manipulator_core.dmi differ
diff --git a/icons/obj/machines/big_manipulator_parts/big_manipulator_hand.dmi b/icons/obj/machines/big_manipulator_parts/big_manipulator_hand.dmi
new file mode 100644
index 0000000000000..e165441e8052e
Binary files /dev/null and b/icons/obj/machines/big_manipulator_parts/big_manipulator_hand.dmi differ
diff --git a/icons/obj/machines/gravity_generator.dmi b/icons/obj/machines/gravity_generator.dmi
index 69395034dc840..18ad0ca0c20af 100644
Binary files a/icons/obj/machines/gravity_generator.dmi and b/icons/obj/machines/gravity_generator.dmi differ
diff --git a/icons/obj/machines/ltsrbt.dmi b/icons/obj/machines/ltsrbt.dmi
new file mode 100644
index 0000000000000..cdb7e06cbb3df
Binary files /dev/null and b/icons/obj/machines/ltsrbt.dmi differ
diff --git a/icons/obj/machines/telecomms.dmi b/icons/obj/machines/telecomms.dmi
index f1380268c29cf..1d27e0b10b2d6 100644
Binary files a/icons/obj/machines/telecomms.dmi and b/icons/obj/machines/telecomms.dmi differ
diff --git a/icons/obj/machines/vending.dmi b/icons/obj/machines/vending.dmi
index b9a9ba9568291..319771e4e7fb5 100644
Binary files a/icons/obj/machines/vending.dmi and b/icons/obj/machines/vending.dmi differ
diff --git a/icons/obj/medical/chemical.dmi b/icons/obj/medical/chemical.dmi
index 84dfd01d2d455..e362c5126e193 100644
Binary files a/icons/obj/medical/chemical.dmi and b/icons/obj/medical/chemical.dmi differ
diff --git a/icons/obj/pipes_n_cables/disposal.dmi b/icons/obj/pipes_n_cables/disposal.dmi
index 41207b7a7cd6f..a65413d3d007c 100644
Binary files a/icons/obj/pipes_n_cables/disposal.dmi and b/icons/obj/pipes_n_cables/disposal.dmi differ
diff --git a/icons/obj/service/broadcast.dmi b/icons/obj/service/broadcast.dmi
new file mode 100644
index 0000000000000..e82023791f3d6
Binary files /dev/null and b/icons/obj/service/broadcast.dmi differ
diff --git a/icons/obj/service/bureaucracy.dmi b/icons/obj/service/bureaucracy.dmi
index b400b7aee8b72..f52379a72b36e 100644
Binary files a/icons/obj/service/bureaucracy.dmi and b/icons/obj/service/bureaucracy.dmi differ
diff --git a/icons/obj/service/janitor.dmi b/icons/obj/service/janitor.dmi
index 0e30180832345..b340aa54cee09 100644
Binary files a/icons/obj/service/janitor.dmi and b/icons/obj/service/janitor.dmi differ
diff --git a/icons/obj/service/library.dmi b/icons/obj/service/library.dmi
index f9273a55e5530..5c393ae3c8622 100644
Binary files a/icons/obj/service/library.dmi and b/icons/obj/service/library.dmi differ
diff --git a/icons/obj/smooth_structures/grav_field.dmi b/icons/obj/smooth_structures/grav_field.dmi
new file mode 100644
index 0000000000000..4f51707938e9c
Binary files /dev/null and b/icons/obj/smooth_structures/grav_field.dmi differ
diff --git a/icons/obj/smooth_structures/grav_field.png b/icons/obj/smooth_structures/grav_field.png
new file mode 100644
index 0000000000000..5177e57724049
Binary files /dev/null and b/icons/obj/smooth_structures/grav_field.png differ
diff --git a/icons/obj/smooth_structures/grav_field.png.toml b/icons/obj/smooth_structures/grav_field.png.toml
new file mode 100644
index 0000000000000..49f4000c213db
--- /dev/null
+++ b/icons/obj/smooth_structures/grav_field.png.toml
@@ -0,0 +1,5 @@
+output_name = "grav_field"
+template = "bitmask/diagonal_32x32.toml"
+
+[animation]
+delays = [1, 1, 1]
diff --git a/icons/obj/smooth_structures/grav_field_emissive.dmi b/icons/obj/smooth_structures/grav_field_emissive.dmi
new file mode 100644
index 0000000000000..a2db63f082a5b
Binary files /dev/null and b/icons/obj/smooth_structures/grav_field_emissive.dmi differ
diff --git a/icons/obj/smooth_structures/grav_field_emissive.png b/icons/obj/smooth_structures/grav_field_emissive.png
new file mode 100644
index 0000000000000..d3746ac5b63ac
Binary files /dev/null and b/icons/obj/smooth_structures/grav_field_emissive.png differ
diff --git a/icons/obj/smooth_structures/grav_field_emissive.png.toml b/icons/obj/smooth_structures/grav_field_emissive.png.toml
new file mode 100644
index 0000000000000..ba6a7f73aaf7b
--- /dev/null
+++ b/icons/obj/smooth_structures/grav_field_emissive.png.toml
@@ -0,0 +1,5 @@
+output_name = "grav_field_emissive"
+template = "bitmask/diagonal_32x32.toml"
+
+[animation]
+delays = [1, 1, 1]
diff --git a/icons/obj/storage/box.dmi b/icons/obj/storage/box.dmi
index 01588bd050f74..747fb5462c7df 100644
Binary files a/icons/obj/storage/box.dmi and b/icons/obj/storage/box.dmi differ
diff --git a/icons/obj/storage/case.dmi b/icons/obj/storage/case.dmi
index a29fd3a6f37c0..94b7251f93f46 100644
Binary files a/icons/obj/storage/case.dmi and b/icons/obj/storage/case.dmi differ
diff --git a/icons/obj/storage/crates.dmi b/icons/obj/storage/crates.dmi
index 46c61f8299767..a5a26c285a7d6 100644
Binary files a/icons/obj/storage/crates.dmi and b/icons/obj/storage/crates.dmi differ
diff --git a/icons/obj/toys/stickers.dmi b/icons/obj/toys/stickers.dmi
index 37780f5fd6cfe..80c0e138e38f9 100644
Binary files a/icons/obj/toys/stickers.dmi and b/icons/obj/toys/stickers.dmi differ
diff --git a/icons/obj/toys/toy.dmi b/icons/obj/toys/toy.dmi
index 8d77fd0c757a1..bc6f2f75424c3 100644
Binary files a/icons/obj/toys/toy.dmi and b/icons/obj/toys/toy.dmi differ
diff --git a/icons/obj/vending_restock.dmi b/icons/obj/vending_restock.dmi
index 836aebca7ae2d..ca8e40349c406 100644
Binary files a/icons/obj/vending_restock.dmi and b/icons/obj/vending_restock.dmi differ
diff --git a/icons/obj/weapons/bows/quivers.dmi b/icons/obj/weapons/bows/quivers.dmi
index 615f96ee6af6d..86e6ffd2b925a 100644
Binary files a/icons/obj/weapons/bows/quivers.dmi and b/icons/obj/weapons/bows/quivers.dmi differ
diff --git a/icons/obj/weapons/cannons.dmi b/icons/obj/weapons/cannons.dmi
index f0e37c5310ac6..b9735ba0aef9f 100644
Binary files a/icons/obj/weapons/cannons.dmi and b/icons/obj/weapons/cannons.dmi differ
diff --git a/icons/obj/weapons/grenade.dmi b/icons/obj/weapons/grenade.dmi
index b3fb018bafa07..c65f6d0e9fb80 100644
Binary files a/icons/obj/weapons/grenade.dmi and b/icons/obj/weapons/grenade.dmi differ
diff --git a/icons/obj/weapons/guns/ammo.dmi b/icons/obj/weapons/guns/ammo.dmi
index 4cd031af7ee8b..971bdaf4d2041 100644
Binary files a/icons/obj/weapons/guns/ammo.dmi and b/icons/obj/weapons/guns/ammo.dmi differ
diff --git a/icons/obj/weapons/guns/ballistic.dmi b/icons/obj/weapons/guns/ballistic.dmi
index 824d8b7c0a073..4ebb17baec329 100644
Binary files a/icons/obj/weapons/guns/ballistic.dmi and b/icons/obj/weapons/guns/ballistic.dmi differ
diff --git a/icons/obj/weapons/guns/projectiles.dmi b/icons/obj/weapons/guns/projectiles.dmi
index a6cf89e9b910f..cbf79a92b538f 100644
Binary files a/icons/obj/weapons/guns/projectiles.dmi and b/icons/obj/weapons/guns/projectiles.dmi differ
diff --git a/icons/obj/weapons/khopesh.dmi b/icons/obj/weapons/khopesh.dmi
index 3c4ba40b34ac1..6f4a040f6a410 100644
Binary files a/icons/obj/weapons/khopesh.dmi and b/icons/obj/weapons/khopesh.dmi differ
diff --git a/icons/turf/debug.dmi b/icons/turf/debug.dmi
index debc965d0ecd8..848187dd9f03f 100644
Binary files a/icons/turf/debug.dmi and b/icons/turf/debug.dmi differ
diff --git a/icons/turf/overlays.dmi b/icons/turf/overlays.dmi
index c9decbc5a3af3..2b78f1ae40b41 100644
Binary files a/icons/turf/overlays.dmi and b/icons/turf/overlays.dmi differ
diff --git a/icons/ui/achievements/achievements.dmi b/icons/ui/achievements/achievements.dmi
index 143d0dc0a03ae..740759467e0cc 100644
Binary files a/icons/ui/achievements/achievements.dmi and b/icons/ui/achievements/achievements.dmi differ
diff --git a/interface/interface.dm b/interface/interface.dm
index a32bb758a204f..c90abd9583c45 100644
--- a/interface/interface.dm
+++ b/interface/interface.dm
@@ -58,45 +58,45 @@
set desc = "Report an issue"
set hidden = TRUE
var/githuburl = CONFIG_GET(string/githuburl)
- if(githuburl)
- var/message = "This will open the Github issue reporter in your browser. Are you sure?"
- if(GLOB.revdata.testmerge.len)
- message += "
The following experimental changes are active and are probably the cause of any new or sudden issues you may experience. If possible, please try to find a specific thread for your issue instead of posting to the general issue tracker:
"
- message += GLOB.revdata.GetTestMergeInfo(FALSE)
- // We still use tgalert here because some people were concerned that if someone wanted to report that tgui wasn't working
- // then the report issue button being tgui-based would be problematic.
- if(tgalert(src, message, "Report Issue","Yes","No")!="Yes")
- return
+ if(!githuburl)
+ to_chat(src, span_danger("The Github URL is not set in the server configuration."))
+ return
- // Keep a static version of the template to avoid reading file
- var/static/issue_template = file2text(".github/ISSUE_TEMPLATE/bug_report.md")
+ var/testmerge_data = GLOB.revdata.testmerge
+ var/has_testmerge_data = (length(testmerge_data) != 0)
- // Get a local copy of the template for modification
- var/local_template = issue_template
+ var/message = "This will open the Github issue reporter in your browser. Are you sure?"
+ if(has_testmerge_data)
+ message += "
The following experimental changes are active and are probably the cause of any new or sudden issues you may experience. If possible, please try to find a specific thread for your issue instead of posting to the general issue tracker:
"
+ message += GLOB.revdata.GetTestMergeInfo(FALSE)
- // Remove comment header
- var/content_start = findtext(local_template, "<")
- if(content_start)
- local_template = copytext(local_template, content_start)
+ // We still use tgalert here because some people were concerned that if someone wanted to report that tgui wasn't working
+ // then the report issue button being tgui-based would be problematic.
+ if(tgalert(src, message, "Report Issue","Yes","No") != "Yes")
+ return
- // Insert round
- if(GLOB.round_id)
- local_template = replacetext(local_template, "## Round ID:\n", "## Round ID:\n[GLOB.round_id]")
+ var/base_link = githuburl + "/issues/new?template=bug_report_form.yml"
+ var/list/concatable = list(base_link)
- // Insert testmerges
- if(GLOB.revdata.testmerge.len)
- var/list/all_tms = list()
- for(var/entry in GLOB.revdata.testmerge)
- var/datum/tgs_revision_information/test_merge/tm = entry
- all_tms += "- \[[tm.title]\]([githuburl]/pull/[tm.number])"
- var/all_tms_joined = all_tms.Join("\n") // for some reason this can't go in the []
- local_template = replacetext(local_template, "## Testmerges:\n", "## Testmerges:\n[all_tms_joined]")
+ var/client_version = "[byond_version].[byond_build]"
+ concatable += ("&reporting-version=" + client_version)
+
+ // the way it works is that we use the ID's that are baked into the template YML and replace them with values that we can collect in game.
+ if(GLOB.round_id)
+ concatable += ("&round-id=" + GLOB.round_id)
+
+ // Insert testmerges
+ if(has_testmerge_data)
+ var/list/all_tms = list()
+ for(var/entry in testmerge_data)
+ var/datum/tgs_revision_information/test_merge/tm = entry
+ all_tms += "- \[[tm.title]\]([githuburl]/pull/[tm.number])"
+ var/all_tms_joined = jointext(all_tms, "%0A") // %0A is a newline for URL encoding because i don't trust \n to not break
+
+ concatable += ("&test-merges=" + all_tms_joined)
+
+ DIRECT_OUTPUT(src, link(jointext(concatable, "")))
- var/url_params = "Reporting client version: [byond_version].[byond_build]\n\n[local_template]"
- DIRECT_OUTPUT(src, link("[githuburl]/issues/new?body=[url_encode(url_params)]"))
- else
- to_chat(src, span_danger("The Github URL is not set in the server configuration."))
- return
/client/verb/changelog()
set name = "Changelog"
diff --git a/interface/stylesheet.dm b/interface/stylesheet.dm
index 1ee06ed48550d..e0e1181f93c98 100644
--- a/interface/stylesheet.dm
+++ b/interface/stylesheet.dm
@@ -51,6 +51,7 @@ em {font-style: normal; font-weight: bold;}
.syndradio {color: #6d3f40;}
.centcomradio {color: #686868;}
.aiprivradio {color: #ff00ff;}
+.enteradio {color: #00ff99;}
.redteamradio {color: #ff0000;}
.blueteamradio {color: #0000ff;}
.greenteamradio {color: #00ff00;}
diff --git a/lua/SS13_base.lua b/lua/SS13_base.lua
index 2b0645172ea1c..23f464bf328ab 100644
--- a/lua/SS13_base.lua
+++ b/lua/SS13_base.lua
@@ -56,7 +56,10 @@ end
local function signal_handler(data, ...)
local output = 0
for func, _ in data.functions do
- output = bit32.bor(output, func(...))
+ local result = func(...)
+ if type(result) == "number" then
+ output = bit32.bor(output, math.floor(result))
+ end
end
return output
end
diff --git a/modular_bandastation/aesthetics/radio/icons/headsets.dmi b/modular_bandastation/aesthetics/radio/icons/headsets.dmi
index c1c96a7a0fe11..db6fbbbf576f2 100644
Binary files a/modular_bandastation/aesthetics/radio/icons/headsets.dmi and b/modular_bandastation/aesthetics/radio/icons/headsets.dmi differ
diff --git a/modular_bandastation/aesthetics/radio/icons/radio.dmi b/modular_bandastation/aesthetics/radio/icons/radio.dmi
index 6871fad572d73..ff58eb3d9b569 100644
Binary files a/modular_bandastation/aesthetics/radio/icons/radio.dmi and b/modular_bandastation/aesthetics/radio/icons/radio.dmi differ
diff --git a/modular_bandastation/emote_panel/code/emotes.dm b/modular_bandastation/emote_panel/code/emotes.dm
index 6a19b336748c9..62a7f5e7999cb 100644
--- a/modular_bandastation/emote_panel/code/emotes.dm
+++ b/modular_bandastation/emote_panel/code/emotes.dm
@@ -122,6 +122,8 @@
message = "строит гримасу."
/datum/emote/living/jump
+ key = "jump"
+ key_third_person = "jumps"
name = "прыгнуть"
message = "прыгает!"
diff --git a/modular_bandastation/pixel_shift/code/layer_shift.dm b/modular_bandastation/pixel_shift/code/layer_shift.dm
index 3be3824c06fd1..fbf6fddef6128 100644
--- a/modular_bandastation/pixel_shift/code/layer_shift.dm
+++ b/modular_bandastation/pixel_shift/code/layer_shift.dm
@@ -7,7 +7,7 @@
set name = "Shift Layer Upwards"
set category = "IC"
- if(incapacitated())
+ if(build_incapacitated())
to_chat(src, span_warning("You can't do that right now!"))
return
@@ -23,7 +23,7 @@
set name = "Shift Layer Downwards"
set category = "IC"
- if(incapacitated())
+ if(build_incapacitated())
to_chat(src, span_warning("You can't do that right now!"))
return
diff --git a/sound/ambience/ambigen1.ogg b/sound/ambience/ambigen1.ogg
index 6a5a2d27c92e3..500f0a0bbf6a1 100644
Binary files a/sound/ambience/ambigen1.ogg and b/sound/ambience/ambigen1.ogg differ
diff --git a/sound/ambience/ambigen12.ogg b/sound/ambience/ambigen12.ogg
index 27885070f4c71..2b82bc33348c4 100644
Binary files a/sound/ambience/ambigen12.ogg and b/sound/ambience/ambigen12.ogg differ
diff --git a/sound/ambience/antag/heretic/attribution.txt b/sound/ambience/antag/heretic/attribution.txt
new file mode 100644
index 0000000000000..8744b2497f5bd
--- /dev/null
+++ b/sound/ambience/antag/heretic/attribution.txt
@@ -0,0 +1 @@
+heretic_sacrifice.ogg - made by sadboysusss, License: CC-by-SA
\ No newline at end of file
diff --git a/sound/ambience/antag/heretic/heretic_sacrifice.ogg b/sound/ambience/antag/heretic/heretic_sacrifice.ogg
new file mode 100644
index 0000000000000..5a8efb6508356
Binary files /dev/null and b/sound/ambience/antag/heretic/heretic_sacrifice.ogg differ
diff --git a/sound/ambience/shipambience.ogg b/sound/ambience/shipambience.ogg
index 51e090b02c81c..68a9182fa6672 100644
Binary files a/sound/ambience/shipambience.ogg and b/sound/ambience/shipambience.ogg differ
diff --git a/sound/attributions.txt b/sound/attributions.txt
index 123fde0794c19..3a2468205d027 100644
--- a/sound/attributions.txt
+++ b/sound/attributions.txt
@@ -209,3 +209,7 @@ beaker_pickup.ogg was made by lowering pitch:
Bottle Tap.wav by alex_alexalex -- https://freesound.org/s/395492/ -- License: Attribution NonCommercial 3.0
beaker_place.ogg was made by cutting and lowering pitch:
place glass object.wav by milpower -- https://freesound.org/s/353105/ -- License: Creative Commons 0
+
+glass_reverse.ogg is adapted from a combination of:
+https://freesound.org/people/C_Rogers/sounds/203368/ -- glass-shattering-hit_01.ogg by C_Rogers on freesound.org (CC0)
+https://freesound.org/people/Czarcazas/sounds/330800/ -- Audio reversal/fading of Shattering Glass (Small) by Czarcazas -- https://freesound.org/s/330800/ -- License: Attribution 3.0
\ No newline at end of file
diff --git a/sound/creatures/fish/attritbution.txt b/sound/creatures/fish/attritbution.txt
new file mode 100644
index 0000000000000..2b3d80f408e20
--- /dev/null
+++ b/sound/creatures/fish/attritbution.txt
@@ -0,0 +1,7 @@
+{
+fish_drop1.ogg - fish slap ground or snow writhing wet.wav by kyles -- https://freesound.org/s/450830/ -- License: Creative Commons 0
+fish_pickup1.ogg - fish slap ground or snow writhing wet.wav by kyles -- https://freesound.org/s/450830/ -- License: Creative Commons 0
+fish_pickup2.ogg - fish slap ground or snow writhing wet.wav by kyles -- https://freesound.org/s/450830/ -- License: Creative Commons 0
+fish_slap1.ogg - Slap - Cartoony by AdminMP -- https://freesound.org/s/383201/ -- License: Creative Commons 0
+fish_slap2.ogg - Major punch by janbezouska -- https://freesound.org/s/399183/ -- License: Creative Commons 0
+} - edited by sadboysuss
diff --git a/sound/creatures/fish/fish_drop1.ogg b/sound/creatures/fish/fish_drop1.ogg
new file mode 100644
index 0000000000000..70d7a7364b131
Binary files /dev/null and b/sound/creatures/fish/fish_drop1.ogg differ
diff --git a/sound/creatures/fish/fish_pickup1.ogg b/sound/creatures/fish/fish_pickup1.ogg
new file mode 100644
index 0000000000000..385b6daab9152
Binary files /dev/null and b/sound/creatures/fish/fish_pickup1.ogg differ
diff --git a/sound/creatures/fish/fish_pickup2.ogg b/sound/creatures/fish/fish_pickup2.ogg
new file mode 100644
index 0000000000000..dc9f17461e517
Binary files /dev/null and b/sound/creatures/fish/fish_pickup2.ogg differ
diff --git a/sound/creatures/fish/fish_slap1.ogg b/sound/creatures/fish/fish_slap1.ogg
new file mode 100644
index 0000000000000..fd6ea653871b1
Binary files /dev/null and b/sound/creatures/fish/fish_slap1.ogg differ
diff --git a/sound/creatures/fish/fish_slap2.ogg b/sound/creatures/fish/fish_slap2.ogg
new file mode 100644
index 0000000000000..06df1797d48e3
Binary files /dev/null and b/sound/creatures/fish/fish_slap2.ogg differ
diff --git a/sound/effects/glass_reverse.ogg b/sound/effects/glass_reverse.ogg
new file mode 100644
index 0000000000000..af1492d9b86b4
Binary files /dev/null and b/sound/effects/glass_reverse.ogg differ
diff --git a/sound/effects/muffspeech/muffspeech1.ogg b/sound/effects/muffspeech/muffspeech1.ogg
new file mode 100644
index 0000000000000..b8b2f5f40b19d
Binary files /dev/null and b/sound/effects/muffspeech/muffspeech1.ogg differ
diff --git a/sound/effects/muffspeech/muffspeech2.ogg b/sound/effects/muffspeech/muffspeech2.ogg
new file mode 100644
index 0000000000000..9ffecadf61e06
Binary files /dev/null and b/sound/effects/muffspeech/muffspeech2.ogg differ
diff --git a/sound/effects/muffspeech/muffspeech3.ogg b/sound/effects/muffspeech/muffspeech3.ogg
new file mode 100644
index 0000000000000..dff0e567daccc
Binary files /dev/null and b/sound/effects/muffspeech/muffspeech3.ogg differ
diff --git a/sound/effects/muffspeech/muffspeech4.ogg b/sound/effects/muffspeech/muffspeech4.ogg
new file mode 100644
index 0000000000000..4e46c7a707acc
Binary files /dev/null and b/sound/effects/muffspeech/muffspeech4.ogg differ
diff --git a/sound/effects/muffspeech/muffspeech5.ogg b/sound/effects/muffspeech/muffspeech5.ogg
new file mode 100644
index 0000000000000..ff1c9948c5621
Binary files /dev/null and b/sound/effects/muffspeech/muffspeech5.ogg differ
diff --git a/sound/effects/muffspeech/muffspeech6.ogg b/sound/effects/muffspeech/muffspeech6.ogg
new file mode 100644
index 0000000000000..13b70731ac3e0
Binary files /dev/null and b/sound/effects/muffspeech/muffspeech6.ogg differ
diff --git a/sound/effects/muffspeech/muffspeech7.ogg b/sound/effects/muffspeech/muffspeech7.ogg
new file mode 100644
index 0000000000000..ea566e6ef5872
Binary files /dev/null and b/sound/effects/muffspeech/muffspeech7.ogg differ
diff --git a/sound/effects/muffspeech/muffspeech8.ogg b/sound/effects/muffspeech/muffspeech8.ogg
new file mode 100644
index 0000000000000..ad51432d2da54
Binary files /dev/null and b/sound/effects/muffspeech/muffspeech8.ogg differ
diff --git a/sound/effects/muffspeech/muffspeech9.ogg b/sound/effects/muffspeech/muffspeech9.ogg
new file mode 100644
index 0000000000000..5d1be3b745f3e
Binary files /dev/null and b/sound/effects/muffspeech/muffspeech9.ogg differ
diff --git a/sound/items/attributions.txt b/sound/items/attributions.txt
index 9ad1a09d8cb41..9a000c39eefa2 100644
--- a/sound/items/attributions.txt
+++ b/sound/items/attributions.txt
@@ -56,3 +56,15 @@ gas_tank_drop.ogg
gas_tank_pick_up.ogg
} - https://freesound.org/people/Globofonia/sounds/698346/ , License CC0
edited by grungussuss
+
+{
+cardboad_box_open.ogg - made by sadboysuss
+cardboad_box_rustle.ogg - made by sadboysuss
+toolbox_open.ogg - made by sadboysuss
+toolbox_rustle.ogg - made by sadboysuss
+medkit_rustle.ogg - made by sadboysuss
+} - license: CC-by-SA
+
+lead_pipe_hit.ogg - jixaw-metal-pipe-falling-sound.mp3 by thenotcheeseman -- https://freesound.org/s/679206/ -- License: Creative Commons 0
+lead_pipe_drop.ogg - jixaw-metal-pipe-falling-sound.mp3 by thenotcheeseman -- https://freesound.org/s/679206/ -- License: Creative Commons 0
+lead_pipe_pickup.ogg - Metal pipe hitting the ground.flac by CGEffex -- https://freesound.org/s/93962/ -- License: Attribution 4.0
diff --git a/sound/items/cardboard_box_open.ogg b/sound/items/cardboard_box_open.ogg
new file mode 100644
index 0000000000000..1ad890d159a59
Binary files /dev/null and b/sound/items/cardboard_box_open.ogg differ
diff --git a/sound/items/cardboard_box_rustle.ogg b/sound/items/cardboard_box_rustle.ogg
new file mode 100644
index 0000000000000..01dcc5567b721
Binary files /dev/null and b/sound/items/cardboard_box_rustle.ogg differ
diff --git a/sound/items/handling/attribution.txt b/sound/items/handling/attribution.txt
new file mode 100644
index 0000000000000..c1a72a40c3c91
--- /dev/null
+++ b/sound/items/handling/attribution.txt
@@ -0,0 +1,7 @@
+{
+rcd_drop.ogg - made by sadboysuss - license: CC-by-SA
+rcd_pickup.ogg - made by sadboysuss - license: CC-by-SA
+rpd_drop.ogg - made by sadboysuss - license: CC-by-SA
+rpd_pickup.ogg - made by sadboysuss - license: CC-by-SA
+tool_switch.ogg - made by sadboysuss - license: CC-by-SA
+} - edited by sadboysuss
\ No newline at end of file
diff --git a/sound/items/handling/rcd_drop.ogg b/sound/items/handling/rcd_drop.ogg
new file mode 100644
index 0000000000000..276a014ae3123
Binary files /dev/null and b/sound/items/handling/rcd_drop.ogg differ
diff --git a/sound/items/handling/rcd_pickup.ogg b/sound/items/handling/rcd_pickup.ogg
new file mode 100644
index 0000000000000..bc7d103800bfa
Binary files /dev/null and b/sound/items/handling/rcd_pickup.ogg differ
diff --git a/sound/items/handling/rpd_drop.ogg b/sound/items/handling/rpd_drop.ogg
new file mode 100644
index 0000000000000..8591719c918ea
Binary files /dev/null and b/sound/items/handling/rpd_drop.ogg differ
diff --git a/sound/items/handling/rpd_pickup.ogg b/sound/items/handling/rpd_pickup.ogg
new file mode 100644
index 0000000000000..ef6bf685d0073
Binary files /dev/null and b/sound/items/handling/rpd_pickup.ogg differ
diff --git a/sound/items/handling/tool_switch.ogg b/sound/items/handling/tool_switch.ogg
new file mode 100644
index 0000000000000..b0cacda41623c
Binary files /dev/null and b/sound/items/handling/tool_switch.ogg differ
diff --git a/sound/items/lead_pipe_drop.ogg b/sound/items/lead_pipe_drop.ogg
new file mode 100644
index 0000000000000..144d24ca94c7a
Binary files /dev/null and b/sound/items/lead_pipe_drop.ogg differ
diff --git a/sound/items/lead_pipe_hit.ogg b/sound/items/lead_pipe_hit.ogg
new file mode 100644
index 0000000000000..51b4dbf60b146
Binary files /dev/null and b/sound/items/lead_pipe_hit.ogg differ
diff --git a/sound/items/lead_pipe_pickup.ogg b/sound/items/lead_pipe_pickup.ogg
new file mode 100644
index 0000000000000..559138d66a53f
Binary files /dev/null and b/sound/items/lead_pipe_pickup.ogg differ
diff --git a/sound/items/medkit_drop.ogg b/sound/items/medkit_drop.ogg
index 227d4a8beb220..3acf1db1abc50 100644
Binary files a/sound/items/medkit_drop.ogg and b/sound/items/medkit_drop.ogg differ
diff --git a/sound/items/medkit_pick_up.ogg b/sound/items/medkit_pick_up.ogg
index e13c6848e44df..90de3a19616ef 100644
Binary files a/sound/items/medkit_pick_up.ogg and b/sound/items/medkit_pick_up.ogg differ
diff --git a/sound/items/medkit_rustle.ogg b/sound/items/medkit_rustle.ogg
new file mode 100644
index 0000000000000..55ebc82b911d5
Binary files /dev/null and b/sound/items/medkit_rustle.ogg differ
diff --git a/sound/items/stones/attribution.txt b/sound/items/stones/attribution.txt
new file mode 100644
index 0000000000000..9095ff55594aa
--- /dev/null
+++ b/sound/items/stones/attribution.txt
@@ -0,0 +1,7 @@
+{
+stone_drop1.ogg - https://freesound.org/people/kernschall/sounds/425035/ , license: CC BY 4.0
+stone_drop2.ogg - https://freesound.org/people/kernschall/sounds/425035/ , license: CC BY 4.0
+stone_drop3.og - https://freesound.org/people/Benboncan/sounds/74445/ , license: CC BY 4.0
+stone_pick_up1.ogg - https://freesound.org/people/kernschall/sounds/425035/ , license: CC BY 4.0
+stone_pick_up2.ogg - https://freesound.org/people/Benboncan/sounds/74445/ , license: CC BY 4.0
+} edited by sadboysuss
\ No newline at end of file
diff --git a/sound/items/stones/stone_drop1.ogg b/sound/items/stones/stone_drop1.ogg
new file mode 100644
index 0000000000000..a645ff7eb689f
Binary files /dev/null and b/sound/items/stones/stone_drop1.ogg differ
diff --git a/sound/items/stones/stone_drop2.ogg b/sound/items/stones/stone_drop2.ogg
new file mode 100644
index 0000000000000..3fd4415e29e69
Binary files /dev/null and b/sound/items/stones/stone_drop2.ogg differ
diff --git a/sound/items/stones/stone_drop3.ogg b/sound/items/stones/stone_drop3.ogg
new file mode 100644
index 0000000000000..650dbf8749754
Binary files /dev/null and b/sound/items/stones/stone_drop3.ogg differ
diff --git a/sound/items/stones/stone_pick_up1.ogg b/sound/items/stones/stone_pick_up1.ogg
new file mode 100644
index 0000000000000..af89dc415abdd
Binary files /dev/null and b/sound/items/stones/stone_pick_up1.ogg differ
diff --git a/sound/items/stones/stone_pick_up2.ogg b/sound/items/stones/stone_pick_up2.ogg
new file mode 100644
index 0000000000000..85b7f5a688150
Binary files /dev/null and b/sound/items/stones/stone_pick_up2.ogg differ
diff --git a/sound/items/toolbox_open.ogg b/sound/items/toolbox_open.ogg
new file mode 100644
index 0000000000000..9dea5428d048a
Binary files /dev/null and b/sound/items/toolbox_open.ogg differ
diff --git a/sound/items/toolbox_rustle.ogg b/sound/items/toolbox_rustle.ogg
new file mode 100644
index 0000000000000..939d003b18f5b
Binary files /dev/null and b/sound/items/toolbox_rustle.ogg differ
diff --git a/sound/machines/computer/attribution.txt b/sound/machines/computer/attribution.txt
new file mode 100644
index 0000000000000..ab10c922afb69
--- /dev/null
+++ b/sound/machines/computer/attribution.txt
@@ -0,0 +1,7 @@
+computer_clicks_1.ogg - made by sadboysuss, license: CC-by-SA
+computer_clicks_2.ogg - made by sadboysuss, license: CC-by-SA
+computer_clicks_3.ogg - made by sadboysuss, license: CC-by-SA
+computer_clicks_4.ogg - made by sadboysuss, license: CC-by-SA
+computer_clicks_5.ogg - made by sadboysuss, license: CC-by-SA
+computer_clicks_6.ogg - made by sadboysuss, license: CC-by-SA
+computer_clicks_7.ogg - made by sadboysuss, license: CC-by-SA
\ No newline at end of file
diff --git a/sound/machines/computer/keyboard_clicks_1.ogg b/sound/machines/computer/keyboard_clicks_1.ogg
new file mode 100644
index 0000000000000..b33c6fd56a338
Binary files /dev/null and b/sound/machines/computer/keyboard_clicks_1.ogg differ
diff --git a/sound/machines/computer/keyboard_clicks_2.ogg b/sound/machines/computer/keyboard_clicks_2.ogg
new file mode 100644
index 0000000000000..64d810753c3cb
Binary files /dev/null and b/sound/machines/computer/keyboard_clicks_2.ogg differ
diff --git a/sound/machines/computer/keyboard_clicks_3.ogg b/sound/machines/computer/keyboard_clicks_3.ogg
new file mode 100644
index 0000000000000..0e1bb3696f103
Binary files /dev/null and b/sound/machines/computer/keyboard_clicks_3.ogg differ
diff --git a/sound/machines/computer/keyboard_clicks_4.ogg b/sound/machines/computer/keyboard_clicks_4.ogg
new file mode 100644
index 0000000000000..b700393a9c38e
Binary files /dev/null and b/sound/machines/computer/keyboard_clicks_4.ogg differ
diff --git a/sound/machines/computer/keyboard_clicks_5.ogg b/sound/machines/computer/keyboard_clicks_5.ogg
new file mode 100644
index 0000000000000..d54b211da0217
Binary files /dev/null and b/sound/machines/computer/keyboard_clicks_5.ogg differ
diff --git a/sound/machines/computer/keyboard_clicks_6.ogg b/sound/machines/computer/keyboard_clicks_6.ogg
new file mode 100644
index 0000000000000..84ff3bb7f8003
Binary files /dev/null and b/sound/machines/computer/keyboard_clicks_6.ogg differ
diff --git a/sound/machines/computer/keyboard_clicks_7.ogg b/sound/machines/computer/keyboard_clicks_7.ogg
new file mode 100644
index 0000000000000..39204e360c9f7
Binary files /dev/null and b/sound/machines/computer/keyboard_clicks_7.ogg differ
diff --git a/sound/machines/gravgen/attribution.txt b/sound/machines/gravgen/attribution.txt
new file mode 100644
index 0000000000000..f4aeab2c4902a
--- /dev/null
+++ b/sound/machines/gravgen/attribution.txt
@@ -0,0 +1,6 @@
+{
+grav_gen_start.ogg
+grav_gen_mid1.ogg
+grav_gen_mid2.ogg - + Explosion 7b by LiamG_SFX -- https://freesound.org/s/322492/ -- License: Attribution NonCommercial 4.0
+grav_gen_end.ogg
+} made by sadboysuss by editing a sound made by kayozz , license: CC-by-SA
\ No newline at end of file
diff --git a/sound/machines/gravgen/grav_gen_end.ogg b/sound/machines/gravgen/grav_gen_end.ogg
new file mode 100644
index 0000000000000..a63305708d030
Binary files /dev/null and b/sound/machines/gravgen/grav_gen_end.ogg differ
diff --git a/sound/machines/gravgen/grav_gen_mid1.ogg b/sound/machines/gravgen/grav_gen_mid1.ogg
new file mode 100644
index 0000000000000..e6e38c11d467b
Binary files /dev/null and b/sound/machines/gravgen/grav_gen_mid1.ogg differ
diff --git a/sound/machines/gravgen/grav_gen_mid2.ogg b/sound/machines/gravgen/grav_gen_mid2.ogg
new file mode 100644
index 0000000000000..cf112de1885b4
Binary files /dev/null and b/sound/machines/gravgen/grav_gen_mid2.ogg differ
diff --git a/sound/machines/gravgen/grav_gen_start.ogg b/sound/machines/gravgen/grav_gen_start.ogg
new file mode 100644
index 0000000000000..4a734e5517020
Binary files /dev/null and b/sound/machines/gravgen/grav_gen_start.ogg differ
diff --git a/sound/machines/gravgen/gravgen_mid1.ogg b/sound/machines/gravgen/gravgen_mid1.ogg
deleted file mode 100644
index de2744194bdc6..0000000000000
Binary files a/sound/machines/gravgen/gravgen_mid1.ogg and /dev/null differ
diff --git a/sound/machines/gravgen/gravgen_mid2.ogg b/sound/machines/gravgen/gravgen_mid2.ogg
deleted file mode 100644
index 7b09d566e91eb..0000000000000
Binary files a/sound/machines/gravgen/gravgen_mid2.ogg and /dev/null differ
diff --git a/sound/machines/gravgen/gravgen_mid3.ogg b/sound/machines/gravgen/gravgen_mid3.ogg
deleted file mode 100644
index 6e133b5fcfe60..0000000000000
Binary files a/sound/machines/gravgen/gravgen_mid3.ogg and /dev/null differ
diff --git a/sound/machines/gravgen/gravgen_mid4.ogg b/sound/machines/gravgen/gravgen_mid4.ogg
deleted file mode 100644
index 4f08f5e6d2273..0000000000000
Binary files a/sound/machines/gravgen/gravgen_mid4.ogg and /dev/null differ
diff --git a/sound/machines/lever_start.ogg b/sound/machines/lever_start.ogg
new file mode 100644
index 0000000000000..4160f39026ac0
Binary files /dev/null and b/sound/machines/lever_start.ogg differ
diff --git a/sound/machines/lever_stop.ogg b/sound/machines/lever_stop.ogg
new file mode 100644
index 0000000000000..22f8875019dd4
Binary files /dev/null and b/sound/machines/lever_stop.ogg differ
diff --git a/sound/machines/license.txt b/sound/machines/license.txt
index 6a54969a19170..0d7de5a5dfa3d 100644
--- a/sound/machines/license.txt
+++ b/sound/machines/license.txt
@@ -7,4 +7,8 @@ coffeemaker_brew.ogg originally made by Adriana Lopez (Acekat13X31), edited to r
This is licensed under CC-BY 4.0, found at https://creativecommons.org/licenses/by/4.0/
shutter.ogg adapted from Joseph Sardin on BigSoundBank
-https://bigsoundbank.com/detail-2475-manual-roller-shutter-closing-out-2.html
\ No newline at end of file
+https://bigsoundbank.com/detail-2475-manual-roller-shutter-closing-out-2.html
+
+lever_start.ogg and lever_stop.ogg are made by A_Kuha on FreeSound
+https://freesound.org/people/A_Kuha/sounds/676412
+This is licensed under CC-0, found at https://creativecommons.org/publicdomain/zero/1.0/
diff --git a/sound/voice/breathing.ogg b/sound/voice/breathing.ogg
deleted file mode 100644
index f940a1b211a6b..0000000000000
Binary files a/sound/voice/breathing.ogg and /dev/null differ
diff --git a/sound/voice/breathing/attribution.txt b/sound/voice/breathing/attribution.txt
new file mode 100644
index 0000000000000..20f8ef5df6d1e
--- /dev/null
+++ b/sound/voice/breathing/attribution.txt
@@ -0,0 +1,10 @@
+{
+internals_breathing1.ogg
+internals_breathing2.ogg
+internals_breathing3.ogg
+internals_breathing4.ogg
+internals_breathing5.ogg
+internals_breathing6.ogg
+internals_breathing7.ogg
+internals_breathing8.ogg
+} - foley by sadboysuss, edited by Beeblie , license: CC-by-SA
\ No newline at end of file
diff --git a/sound/voice/breathing/internals_breathing1.ogg b/sound/voice/breathing/internals_breathing1.ogg
new file mode 100644
index 0000000000000..e4f1d564ad697
Binary files /dev/null and b/sound/voice/breathing/internals_breathing1.ogg differ
diff --git a/sound/voice/breathing/internals_breathing2.ogg b/sound/voice/breathing/internals_breathing2.ogg
new file mode 100644
index 0000000000000..7b09c04cc62b5
Binary files /dev/null and b/sound/voice/breathing/internals_breathing2.ogg differ
diff --git a/sound/voice/breathing/internals_breathing3.ogg b/sound/voice/breathing/internals_breathing3.ogg
new file mode 100644
index 0000000000000..0ea34b9024b67
Binary files /dev/null and b/sound/voice/breathing/internals_breathing3.ogg differ
diff --git a/sound/voice/breathing/internals_breathing4.ogg b/sound/voice/breathing/internals_breathing4.ogg
new file mode 100644
index 0000000000000..30718fab3070e
Binary files /dev/null and b/sound/voice/breathing/internals_breathing4.ogg differ
diff --git a/sound/voice/breathing/internals_breathing5.ogg b/sound/voice/breathing/internals_breathing5.ogg
new file mode 100644
index 0000000000000..c78354481955e
Binary files /dev/null and b/sound/voice/breathing/internals_breathing5.ogg differ
diff --git a/sound/voice/breathing/internals_breathing6.ogg b/sound/voice/breathing/internals_breathing6.ogg
new file mode 100644
index 0000000000000..f415845902d98
Binary files /dev/null and b/sound/voice/breathing/internals_breathing6.ogg differ
diff --git a/sound/voice/breathing/internals_breathing7.ogg b/sound/voice/breathing/internals_breathing7.ogg
new file mode 100644
index 0000000000000..946c34d45f307
Binary files /dev/null and b/sound/voice/breathing/internals_breathing7.ogg differ
diff --git a/sound/voice/breathing/internals_breathing8.ogg b/sound/voice/breathing/internals_breathing8.ogg
new file mode 100644
index 0000000000000..36f4925612542
Binary files /dev/null and b/sound/voice/breathing/internals_breathing8.ogg differ
diff --git a/strings/antagonist_flavor/traitor_flavor.json b/strings/antagonist_flavor/traitor_flavor.json
index 2eae0d17f6e60..590e4ce99e3e2 100644
--- a/strings/antagonist_flavor/traitor_flavor.json
+++ b/strings/antagonist_flavor/traitor_flavor.json
@@ -40,7 +40,7 @@
"uplink": "You have been supplied the tools for the job in the form of a standard syndicate uplink."
},
"Donk Corporation": {
- "allies": "Members of Waffle Co. are to be killed on sight; they are not allowed to be on the station while we're around.",
+ "allies": "Members of Waffle Corp. are to be killed on sight; they are not allowed to be on the station while we're around.",
"goal": "We do not approve of mindless killing of innocent workers; \"get in, get done, get out\" is our motto.",
"introduction": "You are the Donk Co. Traitor.",
"roundend_report": "was an employee from Donk Corporation.",
@@ -98,8 +98,8 @@
},
"Waffle Corporation": {
"allies": "Members of Donk Co. are to be killed on sight; they are not allowed to be on the station while we're around. Do not trust fellow members of the Waffle.co (but try not to rat them out), as they might have been assigned opposing objectives.",
- "goal": "You are not here for a station-wide demonstration. Again, other Waffle Co. Traitors may be, so watch out. Your job is to only accomplish your objectives.",
- "introduction": "You are the Waffle Co. Traitor.",
+ "goal": "You are not here for a station-wide demonstration. Again, other Waffle Corp. Traitors may be, so watch out. Your job is to only accomplish your objectives.",
+ "introduction": "You are the Waffle Corp. Traitor.",
"roundend_report": "was an employee from Waffle Corporation.",
"ui_theme": "syndicate",
"uplink": "You have been provided with a standard uplink to accomplish your task."
diff --git a/strings/crustacean_replacement.json b/strings/crustacean_replacement.json
new file mode 100644
index 0000000000000..9c1ebabcbc074
--- /dev/null
+++ b/strings/crustacean_replacement.json
@@ -0,0 +1,160 @@
+{
+
+ "crustacean": {
+ "simp": "shrimp",
+ "problem": "prawnblem",
+ "proba": "prawnba",
+ "prob": "prawn",
+ "pawn": "prawn",
+ "cool": "tenta-cool",
+ "bat": "bait",
+ "fuck": "shuck",
+ "brilliant": "gilliant",
+ "totally": "turtally",
+ "confu" : "conchfu",
+ "kungfu": "conchfu",
+ "kung fu": "conch fu",
+ " mull": " mullet",
+ "believe": "bereef",
+ "believ": "bereef",
+ "rage": "rayge",
+ "kid": "squid",
+ "mark": "shark",
+ "tray": "cray",
+ "cry": "cray",
+ "pray": "cray",
+ "comp": "clam",
+ "calm": "clam",
+ "calam": "clam",
+ "ambulance": "clambulance",
+ "bike": "pike",
+ "suspicious": "fishy",
+ " sus ": " fishy ",
+ "sussy": "sushi",
+ "tune": "tuna",
+ "opportunity": "opportunaty",
+ "got ": "cod ",
+ "god": "cod",
+ "caught": "cod",
+ "grapple": "crapple",
+ "grabb": "crappl",
+ " rue": " roe",
+ "grab": "crapple",
+ "self": "shellf",
+ "cell": "shell",
+ "come": "chum",
+ "plank ": "plankton ",
+ "meant": "manta",
+ "skill": "krill",
+ "chill": "krill",
+ "core": "coral",
+ "hell of it": "halibut",
+ "hell": "eel",
+ "whole": "whale",
+ "muscle": "mussel",
+ "cracking" : "kraken",
+ "crackin": "kraken",
+ "opinion": "octopinion",
+ "utter": "otter",
+ "neme": "nemo",
+ "real": "reel",
+ "orc ": "orca ",
+ "ork ": "orca ",
+ "macaroni": "mackarel",
+ "usurer": "loan shark",
+ "chewy": "spongey",
+ "hamburger": "crabby patty",
+ "burger": "patty",
+ "crust": "krust",
+ "offic": "ofish",
+ "outer space": "trouter space",
+ "deepspace": "trouter space",
+ "deep space": "trouter space",
+ "surgeon": "sturgeon",
+ "purpose": "porpoise",
+ "bastard": "basstard",
+ "ballock": "pollock",
+ "fist": "fish",
+ "place": "plaice",
+ "definitively" : "dolphinitely",
+ "enemy": "anemony",
+ "enemies": "anemones",
+ " mob": " lob",
+ "bitch": "beach",
+ " min ": "minnow",
+ "lemme know": "lemminnow",
+ "let me know": "let minnow",
+ "admin": "adminnow",
+ "better": "betta",
+ " ass ": " wrasse ",
+ "asshole" : "wrassehole",
+ "bond" : "pond",
+ "inc": "ink",
+ "anything": "anyfin",
+ "something": "somefin",
+ "anythin": "anyfin",
+ "somethin": "somefin",
+ "someone": "salmon",
+ "coy": "koi",
+ "earring": "herring",
+ "hearin": "herrin",
+ "celebrat": "shellebrat",
+ "santa": "sandy",
+ "claus": "claws",
+ "boss": "bass",
+ "doofus": "doofish",
+ "could": "cod",
+ "what are": "water",
+ "what're": "water",
+ "whatre": "wa'er",
+ "other": "otter",
+ "lots": "lobst",
+ "fumble": "flounder",
+ "serious": "searious",
+ "show": "shoal",
+ "miracle": "mackerel",
+ "trait": "trout",
+ "syndicate": "sea world",
+ "syndies": "fishermen",
+ "syndie": "fisherman",
+ "syndi": "fisherman",
+ "spy": "marine biologist",
+ "above": "upstream",
+ "below": "downstream",
+ "heretic": "herringtic",
+ "cult": "shoalt",
+ "nar'si": "carp'si",
+ "narsi": "carpsi",
+ "blob": "blobfish",
+ "dumbass": "dum bass",
+ "outdone": "troutdone",
+ "quintessen": "squiddessen",
+ "clos": "claws",
+ "absol": "crabsol",
+ "crap": [
+ "carp",
+ "crab"
+ ],
+ "kill": [
+ "krill",
+ "gill"
+ ],
+ "fanta": [
+ "manta",
+ "finta"
+ ],
+ "billion": [
+ "bill-ion",
+ "krillion"
+ ],
+ "click": [
+ "click",
+ "clack"
+ ],
+ "snap": [
+ "snip",
+ "snap"
+ ]
+ }
+
+}
diff --git a/strings/fishing_tips.txt b/strings/fishing_tips.txt
new file mode 100644
index 0000000000000..66e52a2ba88a9
--- /dev/null
+++ b/strings/fishing_tips.txt
@@ -0,0 +1,42 @@
+Did you know? The Freshness jar of natural baits actually contains kronkaine.
+Legends say The Dude once lost his wallet inside a toilet.
+Legends say a famous pirate once lost his precious coffer by the Beach.
+You could buy fish dirt cheap from the black market, but you probably won't get anything actually fresh.
+Rescue hooks can be used to snag in other people. Good for getting husks out of plasma rivers.
+Pufferfish are known for the slow yet lethal poison they store inside their liver.
+Magnet hooks are great to fish anything that's NOT a fish.
+You can perform scanning experiments with an experi-scanner and some fish. They'll give sci some extra techweb points and get you more modules for the fishing portal generator.
+Fish scanning experiments can be automatically performed with an advanced fishing rod. However to print one you need to have at least completed the first one.
+Advanced fishing rods come pre-equipped with a unexhaustible bait that ignores bait preferences of each fish, letting you catch'em all.
+Don't expect to be able to catch a lot of fish without a bait.
+Some fish (mostly predators) are strictly carnivorous and will ignore baits not made of meat or seafood, a few are picky eaters and will only go after the best of baits, while another smaller few are more or less strictly herbivore.
+You can fish at the holodeck beach, if you don't mind the fish being quite fake.
+You may find worms by digging through sand, ash and snow.
+You can revive fish by using a Lazarus Injector on them. However, using Strange Reagent would be a smarter option here.
+You can feed fish outside of an aquarium by tapping them with a can of fish feed.
+More fishing rods and fish cases can be printed at the autolathe.
+Seeking alternative ways to catch fish without bothering to do it yourself? Explosives can be thrown at fishing spots to get several (dead) fishes in a pinch.
+You can raise lobstrosities from chasm chrabs. However, lobstrosities can only be tamed with spare limbs or lavaloop fish while still young.
+Lavaloop fish make for dangerous yet somewhat effective throwing weapons against big fauna.
+The fishing portal generator has different modules, all of which can be unlocked by completing fish scanning experiments... except for the Syndicate one...
+A fish's traits influence how you can catch them. Carnivore fish will ignore dough balls, and herbivore fish ignore anything that's not from botany.
+Telescopic fishing rods can be bought from cargo.
+Once grown from chrabs and tamed, lobstrosities can be heeded to fish on fishing spots for you.
+Aquariums can be upgraded to bioelectricity generators can a specific kit. From there, you can add electric-generating fish like the anxious zip zap to generate power.
+Getting better at fishing will net you some small additional advantages, such as receiving more information when examining a fish or a fishing spot.
+The size and weight of a fish can influence the amount of reagents and fillets you can harvest from them, their force as a weapon and how easy it is to store them in containers.
+While most fish make for shoddy weapons, a few, like the swordfish and the chainsawfish, can be quite powerful. In general, the bigger they are, the more forceful they get.
+Fish can be sold to cargo. While most don't sell for very much, the biggest ones can be sold for a considerable bounty.
+The meat of fish like swordfish, salmon and pufferfish (weren't they poisonous) makes for an excellent ingredient that boosts the quality of the end product.
+Stingrays are known for their stinger, which they use to deliver venom to hostiles.
+Some species of fish can be bred into new species under the right conditions.
+Most fish don't survive outside water, so get them somewhere safe like an aquarium or a fish case, or even a toilet or a moisture trap!
+No matter how you look at it, most people won't care about fishing. Don't let that stop you. They're just jealous.
+To fish on ice you have to puncture the ice layer with a pick or shovel first.
+Depending on the kind of fish inside it and whether they're alive or dead, an aquarium can improve the beauty of the room or worsen it.
+Almost all fish can be ground in an All-in-one-Grinder. Don't think too hard about how you're fitting a giant fish into a blender. Nanotrasen technology is weird like that.
+The sludgefish from the toilets can be used as a steady supply of cheap fish and fillets due to its self-reproducing behaviour. However it's quite fragile.
+In a jiffy, you can scoop tadpoles from ponds with your bare hands, place them inside aquariums and quickly raise them into frogs.
+The legendary fishing hat isn't just cosmetic. Space carps (as well as young lobstrosities and frogs) do truly fear those who wear it.
+Have you ever heard a lobster or crab talk? Well, neither have I, but they say they're quite the fishy punsters.
+You can get an experiscanner from science to perform fish scanning experiments, which can unlock more modules for the fishing portal, as well as fishing technology nodes (better equipment) for research.
\ No newline at end of file
diff --git a/tgstation.dme b/tgstation.dme
index f80c5652d8048..097ef11a1b6e4 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -528,6 +528,7 @@
#include "code\_globalvars\time_vars.dm"
#include "code\_globalvars\lists\achievements.dm"
#include "code\_globalvars\lists\ambience.dm"
+#include "code\_globalvars\lists\basic_ai.dm"
#include "code\_globalvars\lists\canisters.dm"
#include "code\_globalvars\lists\cargo.dm"
#include "code\_globalvars\lists\client.dm"
@@ -624,6 +625,7 @@
#include "code\controllers\subsystem\addiction.dm"
#include "code\controllers\subsystem\admin_verbs.dm"
#include "code\controllers\subsystem\ai_controllers.dm"
+#include "code\controllers\subsystem\ai_idle_controllers.dm"
#include "code\controllers\subsystem\air.dm"
#include "code\controllers\subsystem\ambience.dm"
#include "code\controllers\subsystem\area_contents.dm"
@@ -735,6 +737,7 @@
#include "code\controllers\subsystem\persistence\counter_tram_hits.dm"
#include "code\controllers\subsystem\persistence\custom_outfits.dm"
#include "code\controllers\subsystem\persistence\engravings.dm"
+#include "code\controllers\subsystem\persistence\message_bottles.dm"
#include "code\controllers\subsystem\persistence\photo_albums.dm"
#include "code\controllers\subsystem\persistence\piggy_banks.dm"
#include "code\controllers\subsystem\persistence\recipes.dm"
@@ -744,6 +747,7 @@
#include "code\controllers\subsystem\processing\acid.dm"
#include "code\controllers\subsystem\processing\ai_basic_avoidance.dm"
#include "code\controllers\subsystem\processing\ai_behaviors.dm"
+#include "code\controllers\subsystem\processing\ai_idle_behaviors.dm"
#include "code\controllers\subsystem\processing\antag_hud.dm"
#include "code\controllers\subsystem\processing\aura.dm"
#include "code\controllers\subsystem\processing\clock_component.dm"
@@ -842,6 +846,7 @@
#include "code\datums\actions\items\cult_dagger.dm"
#include "code\datums\actions\items\hands_free.dm"
#include "code\datums\actions\items\organ_action.dm"
+#include "code\datums\actions\items\reload_rebar.dm"
#include "code\datums\actions\items\set_internals.dm"
#include "code\datums\actions\items\stealth_box.dm"
#include "code\datums\actions\items\summon_stickmen.dm"
@@ -1073,7 +1078,6 @@
#include "code\datums\components\cracked.dm"
#include "code\datums\components\crank_recharge.dm"
#include "code\datums\components\crate_carrier.dm"
-#include "code\datums\components\creamed.dm"
#include "code\datums\components\cuff_n_stun.dm"
#include "code\datums\components\cult_ritual_item.dm"
#include "code\datums\components\curse_of_hunger.dm"
@@ -1100,6 +1104,7 @@
#include "code\datums\components\evolutionary_leap.dm"
#include "code\datums\components\explodable.dm"
#include "code\datums\components\explode_on_attack.dm"
+#include "code\datums\components\face_decal.dm"
#include "code\datums\components\faction_granter.dm"
#include "code\datums\components\fertile_egg.dm"
#include "code\datums\components\fish_growth.dm"
@@ -1410,6 +1415,7 @@
#include "code\datums\elements\beauty.dm"
#include "code\datums\elements\bed_tucking.dm"
#include "code\datums\elements\befriend_petting.dm"
+#include "code\datums\elements\block_turf_fingerprints.dm"
#include "code\datums\elements\blocks_explosives.dm"
#include "code\datums\elements\body_temp_sensitive.dm"
#include "code\datums\elements\bombable_turf.dm"
@@ -1460,6 +1466,7 @@
#include "code\datums\elements\eyestab.dm"
#include "code\datums\elements\falling_hazard.dm"
#include "code\datums\elements\firestacker.dm"
+#include "code\datums\elements\fish_safe_storage.dm"
#include "code\datums\elements\floorloving.dm"
#include "code\datums\elements\footstep.dm"
#include "code\datums\elements\footstep_override.dm"
@@ -1520,6 +1527,7 @@
#include "code\datums\elements\proficient_miner.dm"
#include "code\datums\elements\projectile_drop.dm"
#include "code\datums\elements\projectile_shield.dm"
+#include "code\datums\elements\quality_food_ingredient.dm"
#include "code\datums\elements\radiation_protected_clothing.dm"
#include "code\datums\elements\radioactive.dm"
#include "code\datums\elements\ranged_armour.dm"
@@ -1839,7 +1847,6 @@
#include "code\datums\status_effects\agent_pinpointer.dm"
#include "code\datums\status_effects\buffs.dm"
#include "code\datums\status_effects\drug_effects.dm"
-#include "code\datums\status_effects\food_effects.dm"
#include "code\datums\status_effects\gas.dm"
#include "code\datums\status_effects\grouped_effect.dm"
#include "code\datums\status_effects\limited_effect.dm"
@@ -1854,9 +1861,11 @@
#include "code\datums\status_effects\buffs\bioware\cortex.dm"
#include "code\datums\status_effects\buffs\bioware\ligaments.dm"
#include "code\datums\status_effects\buffs\bioware\nerves.dm"
+#include "code\datums\status_effects\buffs\food\_food_effect.dm"
#include "code\datums\status_effects\buffs\food\chilling.dm"
-#include "code\datums\status_effects\buffs\food\food_traits.dm"
+#include "code\datums\status_effects\buffs\food\grant_trait.dm"
#include "code\datums\status_effects\buffs\food\haste.dm"
+#include "code\datums\status_effects\buffs\food\speech.dm"
#include "code\datums\status_effects\debuffs\blindness.dm"
#include "code\datums\status_effects\debuffs\choke.dm"
#include "code\datums\status_effects\debuffs\confusion.dm"
@@ -2014,6 +2023,7 @@
#include "code\game\machinery\autolathe.dm"
#include "code\game\machinery\bank_machine.dm"
#include "code\game\machinery\barsigns.dm"
+#include "code\game\machinery\big_manipulator.dm"
#include "code\game\machinery\botlaunchpad.dm"
#include "code\game\machinery\buttons.dm"
#include "code\game\machinery\cell_charger.dm"
@@ -2054,6 +2064,7 @@
#include "code\game\machinery\nebula_shielding.dm"
#include "code\game\machinery\PDApainter.dm"
#include "code\game\machinery\photobooth.dm"
+#include "code\game\machinery\portagrav.dm"
#include "code\game\machinery\prisongate.dm"
#include "code\game\machinery\prisonlabor.dm"
#include "code\game\machinery\quantum_pad.dm"
@@ -2256,6 +2267,7 @@
#include "code\game\objects\effects\landmarks\atmospherics_sanity_landmarks.dm"
#include "code\game\objects\effects\particles\acid.dm"
#include "code\game\objects\effects\particles\fire.dm"
+#include "code\game\objects\effects\particles\gravity.dm"
#include "code\game\objects\effects\particles\misc.dm"
#include "code\game\objects\effects\particles\note_particles.dm"
#include "code\game\objects\effects\particles\slime.dm"
@@ -2267,6 +2279,7 @@
#include "code\game\objects\effects\spawners\bombspawner.dm"
#include "code\game\objects\effects\spawners\costume.dm"
#include "code\game\objects\effects\spawners\gibspawner.dm"
+#include "code\game\objects\effects\spawners\message_in_a_bottle.dm"
#include "code\game\objects\effects\spawners\structure.dm"
#include "code\game\objects\effects\spawners\xeno_egg_delivery.dm"
#include "code\game\objects\effects\spawners\random\ai_module.dm"
@@ -2419,6 +2432,7 @@
#include "code\game\objects\items\devices\anomaly_releaser.dm"
#include "code\game\objects\items\devices\battle_royale.dm"
#include "code\game\objects\items\devices\beacon.dm"
+#include "code\game\objects\items\devices\broadcast_camera.dm"
#include "code\game\objects\items\devices\chameleonproj.dm"
#include "code\game\objects\items\devices\destabilizing_crystal.dm"
#include "code\game\objects\items\devices\desynchronizer.dm"
@@ -2660,6 +2674,7 @@
#include "code\game\objects\structures\curtains.dm"
#include "code\game\objects\structures\deployable_turret.dm"
#include "code\game\objects\structures\destructible_structures.dm"
+#include "code\game\objects\structures\detectiveboard.dm"
#include "code\game\objects\structures\displaycase.dm"
#include "code\game\objects\structures\divine.dm"
#include "code\game\objects\structures\door_assembly.dm"
@@ -3511,6 +3526,7 @@
#include "code\modules\awaymissions\signpost.dm"
#include "code\modules\awaymissions\super_secret_room.dm"
#include "code\modules\awaymissions\zlevel.dm"
+#include "code\modules\awaymissions\mission_code\Beach.dm"
#include "code\modules\awaymissions\mission_code\Cabin.dm"
#include "code\modules\awaymissions\mission_code\caves.dm"
#include "code\modules\awaymissions\mission_code\centcomAway.dm"
@@ -3693,6 +3709,7 @@
#include "code\modules\cargo\markets\market_items\clothing.dm"
#include "code\modules\cargo\markets\market_items\consumables.dm"
#include "code\modules\cargo\markets\market_items\hostages.dm"
+#include "code\modules\cargo\markets\market_items\local_goods.dm"
#include "code\modules\cargo\markets\market_items\misc.dm"
#include "code\modules\cargo\markets\market_items\stolen_goods.dm"
#include "code\modules\cargo\markets\market_items\tools.dm"
@@ -3756,6 +3773,7 @@
#include "code\modules\client\preferences\operative_species.dm"
#include "code\modules\client\preferences\paint_color.dm"
#include "code\modules\client\preferences\parallax.dm"
+#include "code\modules\client\preferences\paraplegic.dm"
#include "code\modules\client\preferences\pda.dm"
#include "code\modules\client\preferences\persistent_scars.dm"
#include "code\modules\client\preferences\phobia.dm"
@@ -3836,6 +3854,7 @@
#include "code\modules\clothing\gloves\costume.dm"
#include "code\modules\clothing\gloves\insulated.dm"
#include "code\modules\clothing\gloves\plasmaman.dm"
+#include "code\modules\clothing\gloves\punch_mitts.dm"
#include "code\modules\clothing\gloves\special.dm"
#include "code\modules\clothing\gloves\tacklers.dm"
#include "code\modules\clothing\head\_head.dm"
@@ -4131,6 +4150,7 @@
#include "code\modules\fishing\admin.dm"
#include "code\modules\fishing\bait.dm"
#include "code\modules\fishing\fish_catalog.dm"
+#include "code\modules\fishing\fish_movement.dm"
#include "code\modules\fishing\fishing_equipment.dm"
#include "code\modules\fishing\fishing_minigame.dm"
#include "code\modules\fishing\fishing_portal_machine.dm"
@@ -4455,7 +4475,8 @@
#include "code\modules\library\random_books.dm"
#include "code\modules\library\skill_learning\skill_station.dm"
#include "code\modules\library\skill_learning\skillchip.dm"
-#include "code\modules\library\skill_learning\generic_skillchips\matrix_flip.dm"
+#include "code\modules\library\skill_learning\generic_skillchips\matrix_taunt.dm"
+#include "code\modules\library\skill_learning\generic_skillchips\point.dm"
#include "code\modules\library\skill_learning\generic_skillchips\rod_suplex.dm"
#include "code\modules\library\skill_learning\job_skillchips\_job.dm"
#include "code\modules\library\skill_learning\job_skillchips\chef.dm"
@@ -5996,7 +6017,7 @@
#include "code\modules\surgery\organs\autosurgeon.dm"
#include "code\modules\surgery\organs\helpers.dm"
#include "code\modules\surgery\organs\organ_movement.dm"
-#include "code\modules\surgery\organs\external\_external_organ.dm"
+#include "code\modules\surgery\organs\external\_visual_organs.dm"
#include "code\modules\surgery\organs\external\restyling.dm"
#include "code\modules\surgery\organs\external\spines.dm"
#include "code\modules\surgery\organs\external\tails.dm"
@@ -6052,7 +6073,6 @@
#include "code\modules\tgui\states\notcontained.dm"
#include "code\modules\tgui\states\observer.dm"
#include "code\modules\tgui\states\physical.dm"
-#include "code\modules\tgui\states\reverse_contained.dm"
#include "code\modules\tgui\states\self.dm"
#include "code\modules\tgui\states\zlevel.dm"
#include "code\modules\tgui_input\alert.dm"
@@ -6178,6 +6198,7 @@
#include "code\modules\vending\clothesmate.dm"
#include "code\modules\vending\coffee.dm"
#include "code\modules\vending\cola.dm"
+#include "code\modules\vending\cytopro.dm"
#include "code\modules\vending\donk.dm"
#include "code\modules\vending\drinnerware.dm"
#include "code\modules\vending\engineering.dm"
diff --git a/tgui/docs/tutorial-and-examples.md b/tgui/docs/tutorial-and-examples.md
index 2e02f0e491acd..1b5ecab8968f9 100644
--- a/tgui/docs/tutorial-and-examples.md
+++ b/tgui/docs/tutorial-and-examples.md
@@ -75,7 +75,7 @@ Finally, the `ui_act` proc is called by the interface whenever the user used an
input. The input's `action` and `params` are passed to the proc.
```dm
-/obj/machinery/my_machine/ui_act(action, params)
+/obj/machinery/my_machine/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
@@ -311,7 +311,7 @@ upon code review):
data["var"] = var
return data
-/obj/copypasta/ui_act(action, params)
+/obj/copypasta/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
if(..())
return
switch(action)
diff --git a/tgui/packages/tgui-panel/chat/constants.ts b/tgui/packages/tgui-panel/chat/constants.ts
index 2efc1d0a3ec06..57ad525a9a9aa 100644
--- a/tgui/packages/tgui-panel/chat/constants.ts
+++ b/tgui/packages/tgui-panel/chat/constants.ts
@@ -60,7 +60,7 @@ export const MESSAGE_TYPES = [
name: 'Radio',
description: 'All departments of radio messages',
selector:
- '.alert, .minorannounce, .syndradio, .centcomradio, .aiprivradio, .comradio, .secradio, .gangradio, .engradio, .medradio, .sciradio, .suppradio, .servradio, .radio, .deptradio, .binarysay, .newscaster, .resonate, .abductor, .alien, .changeling',
+ '.alert, .minorannounce, .syndradio, .centcomradio, .aiprivradio, .enteradio, .comradio, .secradio, .gangradio, .engradio, .medradio, .sciradio, .suppradio, .servradio, .radio, .deptradio, .binarysay, .newscaster, .resonate, .abductor, .alien, .changeling',
},
{
type: MESSAGE_TYPE_INFO,
diff --git a/tgui/packages/tgui-panel/settings/SettingsGeneral.tsx b/tgui/packages/tgui-panel/settings/SettingsGeneral.tsx
index 3599f24e70703..f1f10ba74ae21 100644
--- a/tgui/packages/tgui-panel/settings/SettingsGeneral.tsx
+++ b/tgui/packages/tgui-panel/settings/SettingsGeneral.tsx
@@ -20,11 +20,10 @@ import { FONTS } from './constants';
import { selectSettings } from './selectors';
export function SettingsGeneral(props) {
- const { theme, fontFamily, fontSize, lineHeight, statLinked, statFontSize } =
+ const { theme, fontFamily, fontSize, lineHeight } =
useSelector(selectSettings);
const dispatch = useDispatch();
const [freeFont, setFreeFont] = useState(false);
- const [statFont, setStatFont] = useState(false);
return (