This PR replaces our current NPC AI with a [behavior tree
system](https://en.wikipedia.org/wiki/Behavior_tree_(artificial_intelligence,_robotics_and_control)).
Behavior trees are a common way of creating AI in which you place nodes
in a tree structure to define what actions an AI should take.
AI controllers defined a list of /datum/ai_planning_subtree types in
behavior_nodes. Each subtree was a self-contained unit that could call
queue_behavior() to fire off /datum/ai_behavior actions. The controller
iterated subtrees in order, each one deciding independently whether to
queue something and deciding whether the next subtree would run.
This has a few issues:
1. There's no real structure; you are just defining a list of things to
try in order.
2. There was a loooot of subtrees that were basically the same as
another but with some slight modification
3. It was hard to understand.
Controllers now define a single json file describing a tree of nodes.
The tree is composed of structural composites:
Sequence - do A, then B, then C (and so on)
Selector - try A, if it fails try B, then C (and so on)
Parallel - run A and B simultaneously, with configurable failure/success
policies and or looping behavior
Subplan - loop a child continiously
Along that we also have "Decorators". These are nodes that basically
check a condition (E.g.; do we have a combat target). These decorators
can be used to gate behavior and are re-useable across behavior trees.
They also have a concept known as "Observers". Which lets them cancel
lower priority behavior in case their condition changes (Which we check
whenever a signal fires that fits that specific decorator). This makes
the AI much more responsive to change in environment.
For behaviors, we still use the ai_behavior datums. These are the actual
behaviors such as "Move to X", "Attack X". The only major change is that
these can no longer sleep() since they now run in the ai_controller.
Lastly, we now also have subtrees, except now they are essentially
pieces of behavior tree that can be re-used, or even overriden at
runtime or as a variable. Allowing for making modular AI made out of
several smaller trees.
You can set variables on these nodes directly via the extension (see
below), which should reduce the need to make subtypes of behaviors by a
lot. All of these vars are saved on the JSON and will be applied at
runtime.
If you are using subtrees, you can also assign "bindings" to these
variables, which will allow instances of the subtree to override those
variables.
Since a tree structure with variables becomes hard to parse in a JSON,
I've made a VSCode extension to edit these JSONs:
https://marketplace.visualstudio.com/items?itemName=BehaviorTreeG.behaviortreeghttps://github.com/CabinetOnFire/BehaviorTreeG
<img width="1795" height="1268" alt="image"
src="https://github.com/user-attachments/assets/56aa2f0b-3cf9-449f-bca4-8281fca82db6"
/>
This extension allows you to edit the behavior tree JSONs, and browse
through all the behaviors/decorators/subtrees we have
If you'd like more info on how to build these AI check out the
learn_ai.md. I will also make a tutorial to go over more depth on what
the system offers because I kind of suck at doing technical write-ups.
Targetting has been changed to. I've made a new acquire_targets behavior
that takes a target_source (what am I targetting) and
targetting_strategy (what does the candidate need to fulfill to be
considered a target). This allows us to make composites targetting
combinations to reduce the amount of specific find_and_set esque
behaviors we had before. Not everything is ported to this system but
that would be a longer term goal.
I've added a new build_bt script that converts all the behavior tree
JSONs into compiled versions. Why is this needed? Because I wanted to
keep using defines in behavior trees, so we need a way to convert this
into literal values before we send it to DM. This script runs on compile
and should also run in CI (If I didn't fuck that up!). This saves to a
new build/ folder.
I've ported every single AI in the game to this system (except raptors,
Kobsa is working on those so should be in soon!), so I do expect some
bugs to come out of this. But I also fixed some issues that have
probably been in the game for a long time such as:
- Fixed penguins being unable to fish
- Fixed bileworms not being able to devour people
- Fixes goldgrubs not grubbing gold (they could not mine!)
- Lizards actually eat food they find
Either way, I'd reccomend a long TM on this.
1. (Hopefully) a better development experience for making AI
2. Less copy-paste for behaviors, we should be able to re-use more
pieces to make behavior
3. Behavior trees is a more common pattern in making AI, so it should be
easier to find resources to find out how to do things.
🆑 CabinetOnFire, Iamgoofball, SmartKar, Ben10omintrix
refactor: Replaces our AI system with behavior trees, porting all
datum/ai to it
/🆑
I will add this PR with more details down the line. I think I got the
big picture but its a big PR, so sorry if I missed something important.
---------
Co-authored-by: Iamgoofball <iamgoofball@gmail.com>
Co-authored-by: SmArtKar <44720187+SmArtKar@users.noreply.github.com>
Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com>
Co-authored-by: Ben10Omintrix <138636438+Ben10Omintrix@users.noreply.github.com>
Co-authored-by: SyncIt21 <110812394+SyncIt21@users.noreply.github.com>
## About The Pull Request
### Summary
This PR changes internal structure of `/datum/gas_mixture`:
`gases[gas_id][MOLES]` refactored into `moles[gas_id]`,
`gases[gas_id][ARCHIVE]` into `moles_archive[gas_id]` and
`gases[gas_id][GAS_META]` into `gas_meta` static variable. This allows
us to use BYOND 516 vector functions for calculating total moles and
heat capacity. Also it simplifies some parts of the code, allowing us to
get rid of macros `ADD_GAS` and `ASSERT_GAS`. According to the profiler
`/turf/open/process_cell` time is reduced by ~20%.
### Details
`gas_mixture.gases` was a nested 2d-list with MOLES, ARCHIVE and
GAS_META for each gas_id. For example, to get gas moles you had to do
`gases[gas_id][MOLES]`. I've changed this structure to be as follows:
`moles[gas_id]` - moles for the gas, `moles_archive[gas_id]` - archived
version of moles, `gas_meta[KEY][gas_id]` - static var with meta
information for the gas.
Since I removed key GAS_META from the gases, `gas_meta` was moved to the
static variable and the order of keys in the array was changed from
`gas_meta[gas_id][META_KEY]' to 'gas_meta[META_KEY][gas_id]`. This was
done to allow using it in vector calculations (for example heat capacity
or fusion power). Static variable access is very fast and it is
considered as accessing a global in the bytecode.
Byond 516 introduced new vector functions: `values_sum`, `values_dot`
and others. These functions are very fast, but operate only on
associative lists. This allows us to change the way we calculate
total_moles and heat_capacity - very hot and heavily used functions.
`total_moles()` became just `values_sum(moles)`, and `heat_capacity` is
just a dot product: `values_dot(moles,
gas_meta[META_GAS_SPECIFIC_HEAT])`.
As a side bonus, since `moles` is just an associative list, you don't
really need old macros `ADD_GAS` and `ASSERT_GAS` - all they did was to
make a copy of a list[3] with default value [0, 0, gas_meta] for
specific gas. Now when you're adding gas you can just use `moles[gas_id]
+= amount` and when you query amount of gas you can just query the key
(for example `moles[/datum/gas/oxygen]`) if the key does not exist, it
returns null and works as 0 for all arithmetic and logic operations. For
example, old code would be `if (!air.gases[/datum/gas/oxygen] ||
air.gases[/datum/gas/oxygen][MOLES] < 1)` and now it is `if
(moles[/datum/gas/oxygen] < 1)`. This simplifies some parts of the code
and also speeds things up.
For the performance comparison I used Tracy profiler. I've done many
different tests, and they all show slightly different numbers, but
overall speedup for `process_cell` is about 20%. (-20% to average time
per call from ). My testing setup was as follows:
Load Icebox, drop 30/60/90 radius bomb in the middle of the bridge, set
code to blue, wait 10 minutes until the round ends.
Also I fixed random seed in the master controller and in the planetary
gas randomization so generated maps are the same between tests.
Althought it's not very realistic, it generates a lot of samples for the
`process_cell` (around ~3.5M per 10 minutes).
Another test I did was a plasmafire in an 8x8 space, on runtime station,
it showed (-24% time on process_cell).
Another test was a emagged holodeck burn test, it showed (-13% time)
As for other functions of gas_mixture: `total_moles`: -50%(2x speedup),
`heat_capacity`: -65%(3x speedup), `share`: -30%, `react`: -20%. Timings
of all those functions is in microseconds range and they are very hot
(call count is in the same order as process_cell)
<details><summary>Some pictures from profiler</summary>
<img width="569" height="642" alt="process_cell"
src="https://github.com/user-attachments/assets/76fa0c27-719d-485d-9bfc-859fef788999"
/>
<img width="572" height="315" alt="image"
src="https://github.com/user-attachments/assets/f68497e9-4db8-4a9c-b43f-ad04e6dc5cac"
/>
<img width="569" height="317" alt="image"
src="https://github.com/user-attachments/assets/d7249e7b-f344-47a6-8b39-1bab0521182d"
/>
<img width="541" height="316" alt="image"
src="https://github.com/user-attachments/assets/1bef71fd-533d-40fa-a85e-7a803ad322f7"
/>
<img width="519" height="409" alt="image"
src="https://github.com/user-attachments/assets/51165289-174e-403d-a09c-787dd9af136a"
/>
<img width="523" height="318" alt="image"
src="https://github.com/user-attachments/assets/fe4b1db0-17d8-47f9-8fd0-e2ecef2ee66a"
/>
</details>
<details><summary>Setting up a profiler</summary>
If you wanna to reproduce my results here is a list of steps
1. download: https://github.com/goonstation/byond-tracy-writer (this one
has offsets for my version 1677)
2. build the dll, drop in the tgstation/ folder
3. download rtracy https://github.com/Dimach/rtracy
4. download Tracy profiler (0.13.1) https://github.com/wolfpld/tracy
5. uncomment `#define USE_BYOND_TRACY` in `_compile_options.dm`
6. build tgstation
7. open dream daemon, run the desired test, after round end dream daemon
closes
8. navigate to tgstation/data/profiler, find the `123412341234.utracy`
file
9. run `rtracty 123412341234.utracy`
10. open tracy-profiler.exe, press Connect, save the profiler data
11. repeat steps 5-10 with another branch, save another profiler data
12. open tracy-profiler, open first data, press compare, open second
data
</details>
## Why It's Good For The Game
## Changelog
🆑
refactor: Atmos refactor & speedup by utilizing BYOND 516 vector
functions
/🆑
---------
Co-authored-by: san7890 <the@san7890.com>
## About The Pull Request
Error from #96917 (cb535cdfa6)
We shouldn't be calling `mob_try_pickup` on the other pathways, that's
the responsibility of the mousedrop proc. The other two signal handling
procs on this element exist only to block storage dumping/stripping when
the mousedrop proc is working. I think I didn't catch this in testing
because it's an invisible bug that gets obfuscated by the `do_after()`
but I pretty obviously fell asleep at the wheel here and added this
extra code when it's definitely not meant to work that way.
I'm gonna do a CL because I forgot to mention something in the original
refactor's changelog so people might be more aware of the new mechanic
that I forgot to mention (implemented to better reliably parse intent
and be less ambiguous)
🆑
refactor: Picking up your pets (or any holdable mob) requires an
aggressive grab now.
/🆑
## About The Pull Request
We were doing a lot of mental gymnastics in a bunch of other places, so
let's change this wonky var to a streamlined element that will rely on
the same signals that a lot of stuff was already using/accounting for in
its own signal handling pathways, instead of being a weird coverage gap.
This patch should also make the whole "checking if someone is attempting
to pick a mob up" thing make a lot more sense and use a unified proc
instead of spot-checking whatever random things it wants to spot-check.
## Why It's Good For The Game
I didn't know this was a thing until I looked at #96873 and it made me
sad because literally everything else involving mob drag-and-drop is
already signal-based except this weird stinker that relied on proc
overrides. Never mind that now, let's use nice traits to avoid
typecasting and elements to avoid duplicating code. It should also be
much cleaner to add holdability to a mob isntead of having to do
`can_be_held = FALSE` as a weird behavior (at least one instance had
this non-necessarily). All this really is is just middleware on the
extant /mob/living code but still making it in proper lockstep with the
other signalling procs.
I did port over raptor code faithfully but I'm not 100% sure if it was
meant to be like this? Regardless, that's how it is.
## Changelog
🆑
refactor: Picking up mobs has been altered a bit, please report any bugs
or glitches.
/🆑
## About The Pull Request
Title. I'm moving a few monkey features away from the species and into
its bodyparts and organs. I plan on following up with another PR for the
various `ismonkey()` in the code, as these are necessary changes for a
niche thing I'm ultimately working on.
Also one carp organ and one stoat organ both had bits of code made
redundant by available traits. This takes care of them.
Also removed the passwindow_on/off and passtable_on/off procs. We can
just register the associated trait signals on init for living mobs (plus
they were being misused on non-mobs).
## Why It's Good For The Game
Less code associated directly to the species and more to its body parts
and organs, which is basically something we've been doing for a few
years ~~(also I need it for skeletonized monkeys)~~.
## Changelog
N/A
## About The Pull Request
resolves: https://github.com/tgstation/tgstation/issues/56396
Modifies `atoms_movable.dm` and `skittish.md`, as a subscriber to the
`COMSIG_MOVABLE_BUMP` signal, to allow the latter to bubble up an
intercept flag to `living.dm`, so that it can cancel a shove and
function properly.
I looked at every other registered `COMSIG_MOVABLE_BUMP` signal receiver
and found that only one ever possibly returns non-zero, and that is
`/obj/item/clothing/gloves/gauntlets/proc/rocksmash`. However, when
`rocksmash` is called via a bump signal, it will return `NONE` because
the `proximity` parameter will not be set. Therefore, unless I missed
something, there should be no collateral damage from this change.
## Why It's Good For The Game
Skittish has been broken seemingly since its addition to the game. This
fixes that.
<img width="640" height="480" alt="crate"
src="https://github.com/user-attachments/assets/0ce01c07-0e44-498b-aac0-02c448a6d379"
/>
<img width="640" height="480" alt="locker"
src="https://github.com/user-attachments/assets/6fc946fb-e953-43d0-9bd3-9d958a3d9744"
/>
## Changelog
🆑
fix: Fixed Skittish behaving strangely with lockers not against a wall,
and crates in general.
/🆑
<!-- Write **BELOW** The Headers and **ABOVE** The comments else it may
not be viewable. -->
<!-- You can view Contributing.MD for a detailed description of the pull
request process. -->
## About The Pull Request
Extension to #96385
I added `/datum/element/pressure_sensitive` for making mobs sensitive to
low/high pressure limits, then implemented it for blood worms so they
take damage from low pressure. The element also has the same
`/proc/check_safe_environment` setup that
`/datum/element/body_temp_sensitive` has, for future-proofing in case
pressure sensitivity is expanded to all basic mobs.
I also did some message fixes for the pressure and temperature alerts.
The temperature alert no longer breaks if the damage being dealt is
below 1 but above 0. Also, the check for more severe alerts is now
effectively `>=` instead of `>`, meaning that 5 damage is now considered
high severity.
Hatchlings take 0.5 DPS from low pressure and 0.5 DPS from cold
temperatures. All blood worms have low absolute values for minimum
pressure and minimum temperature, but they're still reliably screwed
over by space which is what I want.
Lastly, I made blood worms breathless again.
EDIT: I also updated the antag info panel to match #95920.
<!-- Describe The Pull Request. Please be sure every change is
documented or this can delay review and even discourage maintainers from
merging your PR! -->
## Why It's Good For The Game
Blood worm hatchlings are highly dependent on vents for being able to
play the game. I don't want distro losing pressure or an atmos tech
optimizing distro density with low temperature to be a gotcha for blood
worms. Those happen coincidentally pretty often with no intention to
kill blood worms behind them and losing to something like that right
after you spawn just feels bad.
The pressure and cold damage in general is meant to prevent blood worms
from spacewalking and breaking every window in sight to expand their
effective domain. They can still get hosts with space suits to
circumvent this.
<!-- Argue for the merits of your changes and how they benefit the game,
especially if they are controversial and/or far reaching. If you can't
actually explain WHY what you are doing will improve the game, then it
probably isn't good for the game in the first place. -->
## Changelog
<!-- If your PR modifies aspects of the game that can be concretely
observed by players or admins you should add a changelog. If your change
does NOT meet this description, remove this section. Be sure to properly
mark your PRs to prevent unnecessary GBP loss. You can read up on GBP
and its effects on PRs in the tgstation guides for contributors. Please
note that maintainers freely reserve the right to remove and add tags
should they deem it appropriate. You can attempt to finagle the system
all you want, but it's best to shoot for clear communication right off
the bat. -->
🆑
fix: Low temperature alerts now appear for basic mobs when the damage
being dealt is below 1 but above 0 (e.g. 0.5 DPS).
balance: Blood worms are now breathless again.
balance: Blood worms take damage from low pressures now (increases with
growth stage).
/🆑
<!-- Both 🆑's are required for the changelog to work! You can put
your name to the right of the first 🆑 if you want to overwrite your
GitHub username as author ingame. -->
<!-- You can use multiple of the same prefix (they're only used for the
icon ingame) and delete the unneeded ones. Despite some of the tags,
changelogs should generally represent how a player might be affected by
the changes rather than a summary of the PR's contents. -->
## About The Pull Request
This PR moves out hud offsets into a separate proc on atom level, which
lets mobs override it as to control their atom HUD positioning. This
fixes weird hud offsets on mobs who are located in files larger than
their own icon, or have a very offset but small/detached detail on their
sprite (blood-drunk miner, raptors, megacarps)
This also lets humans adjust their HUDs based on their height, which
should prevent hud clipping for spacers.
<img width="93" height="88" alt="dreamseeker_iBapCH9y5a"
src="https://github.com/user-attachments/assets/f429d4d9-6e1f-451e-9908-54c8a1373f1a"
/>
Main reason behind this change is to allow humans to override their
sprite width/height according to their bodypart overlays, which fixes
immerse and brimdust sac inlaid overlays being shorter/thinner than
expected.
Before & after:
<img width="172" height="188" alt="dreamseeker_5l78R30uLI"
src="https://github.com/user-attachments/assets/0b62ac27-71e6-4b3b-92d0-cf3e73eb458d"
/>
<img width="222" height="189" alt="dreamseeker_9hX6FXLvK9"
src="https://github.com/user-attachments/assets/ab36bc36-abd5-4bdf-965d-ee3951ce9b11"
/>
These values are cached and only updated on ``update_body_parts`` as to
save on a bit of performance.
## Why It's Good For The Game
Fixes jank visuals
## Changelog
🆑
fix: Brimdust sac and fluid immersion overlays no longer look weird on
humans with extra-wide or tall bodyparts or organs
fix: Some mobs now have more sensible health HUD positions
fix: Health and security HUD now scales with player height, no more huds
clipping into spacer hair
/🆑
## About The Pull Request
Fixes#96687
Basically, /datum/element/climb_walkable makes it so that if you share a
turf with this object, you can keep walking onto other objects with that
component. so if you're on a crate you can step onto tables for example.
Issue was, if an with /datum/element/climb_walkable gets initialized it
would give itself this trait via
COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZED_ON, and if it then moved and
would be blocked by a crate, it would instead move "onto" the crate.
This is not a perfect fix, I think in general this is not an ideal way
to handle elevation movement, but fixing that would turn this into a big
refactor.
## Why It's Good For The Game
Prevents roundstart crates from clipping into the backrooms
## Changelog
🆑
fix: Fixes crates not respecting density in all cases and being able to
move into other crates or tables
/🆑
## About The Pull Request
### Main changes
Height is no longer applied in `apply_overlay`
There is now a proc titled `apply_height()` which is passed an
appearance and a body area, and handles either applying a filter or
adjusting the offset of the appearance up or down
`apply_height` is now called directly when applying item appearances
(ie, `update_worn_x`)
`apply_height` is also called directly in `get_limb_icon` (as height is
included in limb render keys).
### Other changes
Bodypart overlays were cleaned up a bit. You can now apply and remove
bodypart overlays directly with just the typepath, which is a bit more
convenient.
Bodypart textures were split into a separate type. Previously, textures
relied on insertion order to be "correctly" added (any bodypart overlays
added later would not be modified by the bodypart texture). Now
Fixed a bug with cybernetics while I was there. They reskin by changing
DMI so they needed to have their DMI included in their render keys.
## Why It's Good For The Game
This allows us to be more specific and less wasteful about applying
height filters and whatnot - We can now specify whether certain overlays
are offset or given a filter.
For example: In the past, horns and frills were filtered solely because
they were attached to the head and the head was filtered.
We couldn't independently say "Offsets the horns and frills, they don't
need filters".
But now, not only are we able to say "rather than filter the head, just
apply an offset", we can also say "horns and frills should be offset
rather than filtered".
TL;DR fixes the issue where horns or cat ears are cut off by height
filters, yippee.
## Changelog
🆑 Melbert
fix: Cybernetic reskinning should break less.
fix: Horns and cat ears should be cut off less by height.
fix: Bodypart textures should apply more consistently.
refactor: Mutant parts like moth wings, lizard tails, cat eats, etc.
have been refactored a tiny bit, report any oddities.
refactor: Bodypart textures were refactored a tiny bit, report any
oddities.
refactor: Refactored the way height works, report anything weird looking
things involving that.
/🆑
## About The Pull Request
Every standing overlay layer that wasn't actually a standing overlay
layer is now a "sub-standing layer", denoted with a decimal
Total number of standing overlay layers reduced from 39 to 23
Small refactors to mutation overlay/species handling and cult halo.
## Why It's Good For The Game
Makes it easier to work with mob overlays.
You can see at a glance which layers are applied with standing overlays
and which layers are manually handled, and more importantly you can see
how the layers sort themselves out by just looking at them. Very
convenient.
## Changelog
🆑 Melbert
code: Reorganized human layering, report any oddities with sprites, such
as mislayered equipment.
refactor: Refactored cult halos, report any oddities like them not
appearing when they should.
refactor: Refactored mutation visuals, they're now affected by height!
Report any oddities like them disappearing.
refactor: Refactored mutation species handling, report any oddities like
lizards with hulk.
/🆑
---------
Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com>
## About The Pull Request
De-hardcodes food/crafting complexity (the stuff responsible for food
buffs) from food items and gives the var to the edible component, so
that objects crafted with pizza or meat sheets can have it as well.
Renamed TRAIT_FOOD_CHEF_MADE to TRAIT_HANDMADE now that it's also given
to the item when crafted through either the stack recipe UI or crafting
UI.
## Why It's Good For The Game
See title. In all seriousness though, it's more flexible code.
## Changelog
🆑
refactor: Refactored a couple things around food/recipe complexity (what
food buffs depend on). Technically, you can now kiss that pizza toilet,
which you crafted (right?), with the chef kiss skillchip enabled to add
"love" to its reagents.
/🆑
## About The Pull Request
Being muzzles prevents you from casting verbal spells, like it used to
pre-rework.
## Why It's Good For The Game
Feels like an oversight from when rework.
## Changelog
🆑 Melbert
balance: Muzzles prevent verbal spellcasting
/🆑
## About The Pull Request
Slightly refactor the code to include heat/cold/breathing checks inside
the atmos elements.
Fun fact: there doesn't appear to be any way for basic/simple mobs to
take pressure damage, but I still went ahead and added the relevant
pressure protection just in case it changes in the future.
## Why It's Good For The Game
Better code.
## Changelog
🆑
code: Add immunity checks for atmos traits for simple/basic mobs
/🆑
## About The Pull Request
Add a buckled check to the waddling element.
## Why It's Good For The Game
Waddling is supposed to represent, well, waddling, like how you walk
funny when you're wearing big, clumsy clown shoes. If you're riding an
ATV, you aren't actually walking with those big clumsy clown shoes,
therefore, you shouldn't be waddling (also because waddling looks too
jittery at higher speeds).
## Changelog
🆑
fix: You no longer waddle when buckled to something.
/🆑
## About The Pull Request
Fixes#96244.
Problem was that when you use last item in the stack, the stack gets
qdel'd and the destructor is called. The destructor sets `mats_per_unit
= null` for the object, and when custom materials applied to tile/wall
it is null.
Bug was caused by #92620. I'm not gonna review 272 files from that PR to
see if I can delete that destructor, potentially breaking something
else, so this is a lazy fix for the annoying bug which is 6 months old.
## Changelog
🆑
fix: fixed material tiles and walls not having material when constructed
from last item in the stack
/🆑
## About The Pull Request
Title.
Its now 2x damage, via burn. Additionally, all silver items are baned
against lycan.
## Why It's Good For The Game
One, bugs bad.
Two, I didnt mean for it to be 3x at first.
Three, burn bypasses the lycan brute resistance.
Four, its more flavorful.
## Proof Of Testing
<details>
<summary>Screenshots/Videos</summary>
<img width="674" height="185" alt="image"
src="https://github.com/user-attachments/assets/3b4a27dd-feb5-40b1-9b84-aca24aa133b0"
/>
</details>
## Changelog
🆑
add: All silver weapons bane lycans
add: Silver weapons now burn lycans
balance: Silver weapons now only bane lycans by 2x
/🆑
## Interface Science
You know what the problem is with our features? They're all too easy,
too optimized to use. Look at Genetics; we went from a confusing UI that
a 14 year old hardcoded with html into byond to a polished UI using
tgui, optimized for player comfort, and gameplay has suffered. Too long
we have coddled players with fun and easy content, no more I say!!!
To fix ss13, I have added a feature with the most awful, unusable UI
ever. It's just wires with random sequences that may or may not do
something. And yet, you will use it till your fingers bleed and your
eyes go white, and you will be grateful. "Thank you coder daddy", you
say as you sacrifice yourself to a display of unending, procedurally
generated dogshit.
<img width="563" height="294" alt="image"
src="https://github.com/user-attachments/assets/e56c947f-a40c-4df9-beed-672812357576"
/>
Or maybe you're a sick little deviant, and you don't respect me. Instead
of using my awful UI, you start optimizing. You've forced the secret
pulse code, and you're not going to pulse them again and again. You make
your own interface by connecting it with signallers, or integrated
circuits. Ahhh, you beat me! Damn it, and you're gonna get away with it
too.
## About the Pull Request
Adds new job content to science. Science spawns with a few "gizmo"
devices and can order more through cargo. These gizmo's have random
functionalities, like the strange objects you can find in maintenance.
These functionalities come with different settings to change how they
operate.
However, there are no buttons, just wires or a voice interface. You need
to solve, for example, a wire puzzle. You just pulse the wires, and if
you hear ping the sequence is good, if you hear buzz its bad. Just keep
going till you hear a creak sound.
If you do a sequence correctly, there are a bunch of randomly generated
ways this interacts with the functionality, mimicking real life settings
and interactions. Imagine a TV remote with randomized buttons, and you
have to map them out again.
Once you've mapped the sequences, you can make an interface. For simple
ones, you can just make some signaller assemblies. For the best control,
you could connect it with a bunch of integrated circuit signallers, and
program sequences into an integrated circuit machine.
Below is a short video of how the puzzle solving works. (I can't be
arsed to figure out how to record tgui, here's a video I made with my
phone. Also I had the sequences written down, which I STRONGLY recommend
you do.)
https://github.com/user-attachments/assets/93f79f0f-df14-4ff9-8096-f079ebae7e91
<details>
<summary>Actual details</summary>
I have hidden the details to make exploring the feature itself more fun.
The whole thing was written to be convoluted, but intuitive. You should
be able to hit it with a multitool, and figure out everything from
there. It will take a bit to get the gist of it.
Nonetheless, for review purposes I have written down the details here.
If you're reading this for non-review purposes, you should know I have
embedded an internet curse that will at some point in 2026 teleport you
2 meters in a random direction. Continue reading at your own discretion.
The gizmo objects is usually generated with 1 or 2 'gizmodes'.
'Gizmodes' contains the fun-ctionality, and holds different operating
modes (so dubbed 'gizpulse'). You can't directly select a gizpulse, but
instead it generates a bunch of mode selections.
For example, a function that toggles lights has two gizpulses: toggle_on
and toggle_off. There are four different mode selects:
Cycle mode: Adds signal to cycle to the next gizpulse, and to activate
the current gizpulse
Select mode: Adds a signal for selecting every gizpulse, and a signal to
activate whatever the activate gizpulse is
Direct activate mode: Adds a signal for selecting every gizpulse, and
also immediately activates that gizpulse
Cycle-active mode: Cycles to the next mode, and activates it
(inconvenient but only has 1 signal to worry about)
So a light gizmode with the randomly selected 'select mode' has three
signals: select toggle_on, select toggle_off and trigger the currently
selected gizpulse.
Currently implemented gizmodes:
- Lights: toggle on, toggle off
- Move: start moving, stop moving
- Food printer (its filled with the spongebob grey goop thing): print
food (donut or burger)
- Mood pulser (AOE): happy pulse, sad pulse, radiation pulse
- Mopper: select different reagent, dump onto tile (1/2/3 range), make
smoke cloud
- Teleporter (5 to 15 tiles, random dir): Teleport self, teleport mobs
in range 1, do both
- Electric: charge from nearest cell (looks into objects and stuff),
magically gain some charge, make lightning, make emp, charge nearby
object, defibrillate in an area
- Copier (makes fake copies of mobs and objects, visual copy only): scan
objects, print objects, erase all copies
- Sputter: dump oil and shake, throw self
- Bad: explode, explode, explode harder, explode with fire, stab you,
warning, make robot spider, breaks your bones, throws a grenade at you,
radiation pulses
- Some behind the scenes gizmodes (language toggle for voice interface,
for example)
The voice interface starts with wires, with signals to toggle the
language or dump the code words. After that, you can talk to it using
the code words similarly to the wire sequence to solve the rest of the
gizmodes.
</details>
I've added two to every map, somewhere in or near the experimentor room.
They may ocassionally spawn from a maintenance crate spawner
<img width="611" height="331" alt="image"
src="https://github.com/user-attachments/assets/3782700f-57d3-4591-9282-e0de590056e1"
/>
## Why It's Good For The Game
It's really difficult to have "experimentation" type features in the
game. It all has to fit into 1h rounds, and people get used to it real
quick. The experimentor and strange objects kinda try, but it's just one
button and praying a bear doesnt spawn you explodes you.
I don't claim to have solved this perfectly, but I think this is fun.
You truly have to start experimenting, be systematic and write things
down. If you figure out how something works, you can go to the next
stage of making it more convenient to use. I think it's really fun to
mess around with integrated circuits and USB's, and make, for example, a
BCI controlled bluespace launchpad.
So I lean into it! There's different settings to account for, and its up
to you to make it usable! If you like integrated circuits, you'll love
this (maybe).
The gizmo functions are aimed at benefiting the station as a whole in
some ways, to motivate people to make some fun systems for these to get
maximum benefit! A mood pulser near a busy area will make everyone
happier! (I do need to add more like these, I got distracted doing
stupid shit.)
## About The Pull Request
Goliaths no longer instantly stun the mobs they hit with their tentacle
for full 10 seconds, instead leashing them to the spot they were grabbed
at or dragging them towards themselves. The ranged tetris-piece attack
has been changed to a full cross which tethers the target preventing
them from moving away more than 1 tile, while the line and the ring
attacks tether the mob directly to the goliath itself and drag them in.
https://github.com/user-attachments/assets/0b566a12-17ae-4a8a-97ac-5734c89c83d4
The tentacles can be manually removed after standing for 6 seconds, or
by hitting them for 75 damage total (3 PKC swings, or 5 bayonet hits).
They also naturally retract after 10/15 (cross/line and ring) seconds
like before.
Goliaths themselves have received a massive speed boost, going from 3
second movement delay to 1.2 seconds (150% buff) and no longer can
friendly fire with their tentacles (and ancient goliaths have their
trophy drop guaranteed)
Brimdemons, lobstrocities, watchers and legions also received some
changes:
- Brimdemons no longer can wound with their beams (they were basically
guaranteed to land a nasty burn wound with the initial blast), but are
now affected by laser armor and their beam DOT (not the initial 25 burn
damage upon firing) has been increased from 5 to 7. Their blasts can now
be interrupted by hitting them from their side or from their back
- Lobstrocities have had their retreat distance decreased from 8 to 6,
making them much less likely to randomly lose aggro on the miner (their
aggro range is 9 tiles, meaning that even a single tile of movement on
miner's part will result in lobsters losing interest in them when on CD)
- Watchers now try to stick to 3-5 (previously 4-6) tiles of distance
between themselves and their target, and legions try to maintain 4-6
tiles of distance as opposed to running away completely. This should
make fighting both of them more interesting and engaging, and make
dealing with them during vents less cancerous.
Sprites for the tentacle item and mob overlay are by thgvr from
https://github.com/shiptest-ss13/Shiptest/pull/2432
## Why It's Good For The Game
Goliaths are extremely outdated in their attack design, 10 second
hardstuns are basically a guaranteed death if there are any other mobs
around and aren't very engaging to fight on their own as they are very
easy to evade with 3 second movement delays.
Change to lobstrocities should just make their AI less jank, and
watcher/legion range changes should make them less slippery when
fighting with PKC or zero range PKA, or during vent defense.
## Changelog
🆑 SmArtKar, thgvr
balance: Goliaths no longer hardstun, but instead bind and drag their
targets in with their tentacles. They are, however, much faster now.
balance: Brimdemon beams can no longer wound, but deal a bit more DOT
damage. Their beams can also be interrupted by hitting them from the
side or back in melee.
balance: Watchers and legions now try to maintain a few tiles of
distance from their targets instead of retreating.
fix: Lobstrocity AI should no longer sometimes flee out of their aggro
range when retreating.
/🆑
## About The Pull Request
Fixes#96042Fixes#96041
Simply stops two people from cuffing to the same item
We could add support for this behavior later, but we'd need to sort out
how that behavior should work
## Changelog
🆑 Melbert
fix: Blocks two people cuffing to one item
/🆑
## About The Pull Request
Introduces a new targeting priority strategy system for basicmob AIs,
which allows controllers to decide which mob to prioritize over others.
Mining mobs will now focus on the NODE drone unless hit, and will pursue
the attacker for 25 seconds before dropping the aggro. They also get
increased aggro if you've attacked other mobs in their view recently,
and after a few hits will have enough aggro to swap to you from the NODE
drone. Ashwalkers get a reduction in aggro because they live there.
Legion broods and brimdemons will immediately target anyone who attacks
their allies rather than waiting for multiple hits. Broods also now
inherit their parent's targets and retaliation/reinforcements lists.
https://github.com/user-attachments/assets/6baaba8a-8b3c-4b2f-ae8b-842f0b1f2b6d
#### This is a bounty for ArcaneMusic
## Why It's Good For The Game
Makes vent defense mob behavior more predictable and easier for players
to manipulate, allowing them to draw aggro from the NODE drone should
make vents more engaging and less of an AI rng fest
## Changelog
🆑
add: Mining mobs now use priority when choosing their target,
prioritizing NODE drones over miners who haven't attacked them or their
allies
/🆑
## About The Pull Request
i ll be honest i dont know know if the number 7 is there for a
particular reason. i put it to 12 globally because of this, but it s
probably best to just do hiero. Close#95799
## Why It's Good For The Game
currently obtaining the hierophant crusher kill achievement forces you
to tank at least a portion of it s deathrattle attack so this makes it
so that you can get the cheevo (currently of any megafauna) obtainable
from 12 tiles (1 tile away from hiero final blast). would fix the
underlaying issue pointed in #95799
## Changelog
🆑
fix: hierophant achievement can now be obtained from 1 tile away of it s
final blast
/🆑
Requires #5420 to be merged.
## About The Pull Request
See changelog
## Why It's Good For The Game
Bug fixes are good. Especially fixing bugs that brick you.
## Proof Of Testing

## Changelog
🆑
fix: Click dragging a protean modsuit onto yourself no longer unequips
it, bricking you.
del: Removed the Control Click Stripping functionality from Protean
modsuits. It's now only click dragging.
/🆑
## About The Pull Request
Refactor the majority of the current gasmix mole change use cases into a
proc called adjust_gas which simply adds the designated mole count of
the species into the gas mix while also handling asserting the gas and
garbage_collect()
I also added adjust_multiple_gases and convert_gas() for modifying
multiple gases and within a gasmix
## Why It's Good For The Game
Lemon wanted this to be done as part of the air group refactor
## Changelog
🆑
refactor: refactored majority of gas_mix mole change into adjust_gas()
proc
/🆑
## About The Pull Request
Removes a lot of cargo cult copypasta with
`default_deconstruction_screwdriver`, `default_deconstruction_crowbar`,
and to a lesser extent `default_pry_open` and
`default_change_direction_wrench`
ALL you gotta do now if you want your machine to have an openable panel
or be deconstructible with a crowbar is this
```dm
/obj/machinery/dish_drive/screwdriver_act(mob/living/user, obj/item/tool)
return default_deconstruction_screwdriver(user, tool)
/obj/machinery/dish_drive/crowbar_act(mob/living/user, obj/item/tool)
return default_deconstruction_crowbar(user, tool)
```
`default_deconstruction_screwdriver` no longer directly sets
`icon_state`, requiring the user pass in the open and closed icon
states. Now, it just calls `update_appearance`, and everything that once
passed the icon state now uses `base_icon_state` and
`update_icon_state`.
## Why It's Good For The Game
Many of these procs were terribly overcomplicated and difficult to work
with for what should be a relatively simple action
Streamlining it makes it easier for coders to understand and work with
## Changelog
🆑 Melbert
refactor: A majority of machines had their screwdriver/crowbar/wrench
interactions rewritten, report any oddities like being unable to open a
machine's panel or deconstruct a machine
/🆑
## About The Pull Request
this translates some various
- `FLOOR(x, 1)` -> `floor(x)`
- `CEILING(x, 1)` -> `ceil(x)`
- `SIGN(x)` define is gone, just uses the native BYOND `sign()` now.
Also, the `MODULUS` define is just a wrapper for the [BYOND `%%`
operator](https://ref.harry.live/operator/modulomodulo) now.
would be nice if someone double checked to make sure there's no
potential subtle oddities resulting from this.
## Why It's Good For The Game
These procs presumably did not exist whenever the defines were written -
and they are BYOND builtins, meaning it will just be, say, one `sign`
instruction, instead of two comparisons and a subtraction.
## Changelog
no player-facing changes
## About The Pull Request
Continues the work of #94761 by adding an analog for virus references
It contains a majority of viruses - including some that are
not-quite-viruses like parrot possession
Some are excluded, some are combined into others
It also contains all advanced virus symptoms
<img width="859" height="509" alt="image"
src="https://github.com/user-attachments/assets/c73f56c0-5a11-4643-9a97-1e2a06ade0c1"
/>
Other changes
- Refactored the SDSM to have use a generic "PaginatedBook" component
for reuse
- Adjusted flavor of all of the diseases
- Flu / Spanish Flu and Cold / Cold 9 now properly act as antibodies for
one another as implied by cure text
## Why It's Good For The Game
Refer to #94761 : De-wikification and larp. This one is a reference to
the IDC-11.
## Changelog
🆑 Melbert
refactor: Refactored the SDSM-35 to allow for new books of similar
styles, report any oddities with it.
fix: Fixes the broken image(s) in the SDSM-35.
add: Adds the IDC-27 in Medbay, the CMO's office, Virology, and possibly
the Library. It's a reference book to all viruses you may experience,
similar to the SDSM-35.
add: Several diseases/viruses received minor flavor adjustments,
primarily to cure text, agent, description, and form.
add: Getting cured of the Flu provides immunity to Spanish Flu (and visa
versa) as implied in cure text.
add: Getting cured of a Cold provides immunity to Cold-9 (and visa
versa) as implied in cure text.
/🆑
---------
Co-authored-by: Time-Green <7501474+Time-Green@users.noreply.github.com>
## About The Pull Request
If you orbit a recovered crewmember or thanatorenasia body situated in a
morgue, the indicated will change from red to green, indicating the body
is revivable
Additionally, orbiting a recovered crewmember or thanatorenasia body
will cause morgues or bodybags to shake. This is an extension of the
existing behavior where orbiting the body causes it to twitch.
## Why It's Good For The Game
Allows doctors to store bodies in a safe place while they wait for a
ghost to occupy it, also means you don't have to repeatedly defib them.
## Changelog
🆑 Melbert
qol: Recovered crew/Thanatorenasia bodies in morgue trays change the
indicator to green when a ghost is orbiting them (to allow ghosts to
signal they want it to be revived)
qol: Recovered crew/Thanatorenasia bodies now cause morgue trays /
bodybags to shake when orbited, much like how the body itself shakes
when orbited (to allow ghosts to signal they want it to be revived)
/🆑
## About The Pull Request
This is a port/revival of Kapu's
https://github.com/DaedalusDock/daedalusdock/pull/883
By god, please TM this for a while, as HUDs are rather volatile and I
might've missed something (also the original PR had harddel issues, so
we should probably be on the lookout for those)
Instead of being stored in a metric ton of separate variables, all HUD
elements are now kept in a ``key -> element`` assoc list, and separate
category lists have been turned into a single ``group_key -> list of
elements`` assoc list for easier management.
This massively simplifies HUD creation and management, and allows us to
sanely dynamically modify HUDs without having to keep track of our
elements ourselves (harddel fuel)
I've also noticed that plasma vessels had... interesting, to say the
least, way of managing their HUD and in humans were unable to display
it, which I've changed (the element itself is displayed below stamina in
non-aliens, as latter occupies the spot where you'd normally see it)
Also fixes a bunch of minor unlikely to occur issues with HUD not
updating when it should've sometimes.
## Why It's Good For The Game
The two most important results of this is that A) we can fix the issue
with items larger than 32x32 not displaying properly in inventories (in
a separate PR) and B) this paves the way for datumized inventory slots,
although that is a separate nightmare
Some of this code is also actually over a decade old, and is an absolute
nightmare to work with.
## Changelog
🆑
qol: Non-aliens with an implanted plasma vessel now see their plasma
level in their HUD instead of just the stat panel
refactor: Refactored the entirety of HUD management code, report if
anything breaks!
/🆑
---------
Co-authored-by: John Willard <53777086+JohnFulpWillard@users.noreply.github.com>
## About The Pull Request
`/datum/element/foodlike_drink` was not updated in the reagent
refactors, still called `attack` directly. Rather than patch it I
figured it was better to just integrate it into `/cup`, to make less
jank in general.
## Changelog
🆑 Melbert
fix: Drinking soup will loop until it's empty or you cancel it (as it
used to)
/🆑
## About The Pull Request
- The `prosthetic replacement` surgical operation has been reverted to
be closer to how it used to work: The operation is done targeting the
limb that's missing
The change was made out of necessity, as surgical state was tied to
limbs - you had to operate on the chest to re-attach limbs because there
was no limb to operate on.
To circumvent that, I have done the unthinkable of adding stumps when
you are dismembered.
- Missing limbs are now represented as an invisible, un-removable,
un-interactable limb.
Making this change was not as difficult as originally anticipated, and
(at least surface level) seems to have broken very little.
Surprisingly little had to change to make this work.
Direct accesses to `mob.bodyparts` was changed to `mob.get_bodyparts()`
with an optional `include_stumps` argument.
Similarly, `get_bodypart()` had an optional `include_stumps` added.
This means we ultimately barely needed to change anything, and in fact,
some loops/checks were able to be streamlined.
## Why It's Good For The Game
- As mentioned, this change was out of necessity and was easily the
least intuitive part of the broader changes. Reverting it back to how it
used to work should make it far easier for people to pick up on, and
means we can cut out a bunch of bespoke instruction sets that I had to
include.
- The addition of stumps also adds a ton of future potential - code wise
it allows for stuff like better damage tracking (we can transfer damage
between limb <-> stump rather than limb <-> chest), and feature we can
do "fun" stuff like have stumps bleed on dismemberment that you can
bandage.
## Changelog
🆑 Melbert
del: "Add prosthetic limb" surgical operation has been reverted to be a
bit closer to how it used to work - you operate on the missing limb /
limb stump, rather than on the chest.
refactor: Missing limbs are now represented as limb stumps. In practice
this should change nothing (for now), as no features were rewritten to
make use of these besides surgery. Please report any oddities with
missing limbs, however.
/🆑
## About The Pull Request
Cybernetic/Cortical brain touch-up. Discuss.
Also because vox use cortical brains, we touched their code a little.
Tangent: I wish there was a way to make the brain restore surgery
capable of taking a multitool without being a separate op :\
# But why?
It's been noticed that people are using cortical brains to shoot up some
meth without consequences. This was a) not originally intended b)
genuine power creep, as previously the only way to be able to process
chems without the brain damage was to be a vox, who do start with
robotic-only brains. So, this PR is to address it. Sure you get an EMP
weakness, but this server has a soft-stigmatization against using EMPs
so that's leery on the social contract.
Fret not! You'll still have the option of a roundstart brain which
doesn't take meth damage. It just also takes slightly more EMP damage,
has less health than an ordinary brain, and if it ever gets removed, it
explodes as the other prosthetics do (but doesn't qdel). So really,
there's not much of a consequence.
## Proof Of Testing
https://github.com/user-attachments/assets/f48efc8b-9f4b-4fd1-b71f-145a1d4b63c5
<img width="255" height="167" alt="Screenshot_10"
src="https://github.com/user-attachments/assets/0334b931-0593-4721-9de2-a02211253e28"
/>
yeah i flipped it on the below one. it's correct now though
<img width="661" height="171" alt="Screenshot_11"
src="https://github.com/user-attachments/assets/554eaf09-8ee4-4a1a-a95b-c7332a078610"
/>
## Changelog
🆑
add: Previously-unobtainable surplus-cybernetic brain added to
Prosthetic Organ quirk
add: Cybernetic brains given the ORGAN_PROMINENT trait, following normal
brains.
add: Vox Primalis unique cybernetic brain has been finally added to
their species descriptions. (Bet you didn't know they had one)
balance: (Roundstart) Cortical brains given ORGAN_ORGANIC, so they can
be fixed with both mannitol and a multitool. Vox brains are excluded
balance: Brain options in character prefs have been given a 1
quirkiness-point cost.
fix: Cybernetic/Cortical brains have their repair hints updated to
reflect what they can actually be repaired by
code: Prosthetic Organ quirk moved to modular_zubbers
code: 'Vox Primalis' now considered a collective noun
code: dangerous_organ_removal has a new variable to toggle between organ
qdel or having its damage set to max health.
/🆑