## About The Pull Request
- Afterattack is a very simple proc now: All it does is this, and all
it's used for is for having a convenient place to put effects an item
does after a successful attack (IE, the attack was not blocked)

- An overwhelming majority of afterattack implementations have been
moved to `interact_with_atom` or the new `ranged_interact_with_atom`
I have manually tested many of the refactored procs but there was 200+
so it's kinda hard
## Why It's Good For The Game
Afterattack is one of the worst parts of the attack chain, as it
simultaneously serves as a way of doing random interactions NOT AT ALL
related to attacks (despite the name) while ALSO serving as the defacto
way to do a ranged interaction with an item
This means careless coders (most of them) may throw stuff in afterattack
without realizing how wide reaching it is, which causes bugs. By making
two well defined, separate procs for handing adjacent vs ranged
interactions, it becomes WAY WAY WAY more easy to develop for.
If you want to do something when you click on something else and you're
adjacent, use `interact_with_atom`
If you want to do something when you click on something else and you're
not adjacent, use 'ranged_interact_with_atom`
This does result in some instances of boilerplate as shown here:

But I think it's acceptable, feel free to oppose if you don't I'm sure
we can think of another solution
~~Additionally it makes it easier to implement swing combat. That's a
bonus I guess~~
## Changelog
🆑 Melbert
refactor: Over 200 item interactions have been refactored to use a
newer, easier-to-use system. Report any oddities with using items on
other objects you may see (such as surgery, reagent containers like cups
and spray bottles, or construction devices), especially using something
at range (such as guns or chisels)
refactor: Item-On-Modsuit interactions have changed slightly. While on
combat mode, you will attempt to "use" the item on the suit instead of
inserting it into the suit's storage. This means being on combat mode
while the suit's panel is open will block you from inserting items
entirely via click (but other methods such as hotkey, clicking on the
storage boxes, and mousedrop will still work).
refactor: The detective's scanner will now be inserted into storage
items if clicked normally, and will scan the storage item if on combat
mode
/🆑
## About The Pull Request
This PR introduces a limited set of camera components that can be used
by surveillance security consoles and the PDA/laptop camera app.
<img width="366" alt="components"
src="https://github.com/tgstation/tgstation/assets/80724828/0e628863-9998-46d6-8822-e0a44543b4c2">
There is four camera components, each limited to a specified shell
circuit type.
Additionally, drone circuit shells can now use the recharge stations
too, much like how mobs with BCIs can recharge.
### New Components
<img width="136" alt="drone camera"
src="https://github.com/tgstation/tgstation/assets/80724828/fd045871-56bf-44a6-bb4f-ebe895d56d3d">
* Drone Camera
This camera component captures the surrounding area. It has an option to
set the camera range (near 5x5/far 14x14).
<img width="136" alt="bci camera"
src="https://github.com/tgstation/tgstation/assets/80724828/16bf2dd1-823b-4d66-8249-5d0f1bb1b779">
* BCI Camera
This camera component uses the active user's eyes as a camera function.
If the user's sights are damaged, the range will be forced to the near
setting. If the user is unconscious/dead/blinded or has no eyes, the
stream will be cut off.
It has an option to set the camera range (near 5x5/far 14x14).
<img width="136" alt="polaroid camera"
src="https://github.com/tgstation/tgstation/assets/80724828/7c4d53df-b4af-4f7c-8942-a63842510720">
* Polaroid Camera Add-On
This camera component streams to a camera network. The camera range is
hardcoded to the near setting (5x5).
<img width="136" alt="airlock camera"
src="https://github.com/tgstation/tgstation/assets/80724828/5d9e9d55-49fc-45a7-99c8-aaf1ae08f6d1">
* Airlock Camera
This camera component streams to a camera network. The camera range is
hardcoded to the near setting (5x5).
### Features
* The cameras can be EMP'd and will be disabled for 90 seconds if
successful
* When the cameras are active, they will actively drain the cell's power
per second (near range uses 3kJ & far range uses 8kJ)
* Advance camera console/AIs can use these cameras, however the camera
light is disabled (they will be useless in dark areas)
### Screenshots In Action
<details>
This is the drone camera viewed on a security camera console<br>
<img width="425" alt="near"
src="https://github.com/tgstation/tgstation/assets/80724828/e5247828-0fee-4552-9e70-5e5ee897c117"><br>
This is the same drone, now set to the far range setting<br>
<img width="425" alt="far"
src="https://github.com/tgstation/tgstation/assets/80724828/e58e3e85-aa90-4f1a-9dff-957c65764b77"><br>
</details>
## Why It's Good For The Game
This promotes emergent gameplay and improves the overall usefulness for
drones as they can be 100% used remotely.
## Changelog
🆑
add: Added new circuit camera components
qol: Circuit drones can now recharge at recharge stations
/🆑
---------
Co-authored-by: Watermelon914 <37270891+Watermelon914@users.noreply.github.com>
## About The Pull Request
This PR introduces a number of minor quality of life improvements to
already existing circuit components, and adds three new components.
<img width="600" alt="preview"
src="https://github.com/tgstation/tgstation/assets/80724828/85d39b6d-b055-430e-8996-0da088616887">
## Why It's Good For The Game
This improves the overall experience for circuits.
### UI changes
<img width="550" alt="grid aligned"
src="https://github.com/tgstation/tgstation/assets/80724828/cc7b43b5-292f-4643-beab-e01ae675fb19">
Grid align is now an option for circuit designers. It will round objects
to the nearest 10px units internally, and can be toggled on/off by the
new additional button beside the component menu button. This makes
circuits easier on the eyes as things are pixel perfect aligned.
<img width="814" alt="tooltips"
src="https://github.com/tgstation/tgstation/assets/80724828/0d31c98f-3be9-46e0-ab37-20bac3799112">
All three buttons have been given tool tips.
### Tweaked Components
<img width="136" alt="voice activator"
src="https://github.com/tgstation/tgstation/assets/80724828/21dd0f65-cb98-4bd5-aeb0-63315e842cb6">
* Adds a on/off flag to the voice activator component
-- This saves power for circuits as you're not forced to use a compare
flag check to turn off voice activation
<img width="136" alt="speech"
src="https://github.com/tgstation/tgstation/assets/80724828/9137b76c-3077-4597-8411-2d9694b39e9e">
* Adds a quiet mode flag to speech component
-- This is ideal when you want a device to speak, but don't want other
people to hear. A good example would be a handheld translator that you
only want to hear yourself.
### New Components
<img width="136" alt="ntnet list literal"
src="https://github.com/tgstation/tgstation/assets/80724828/657c851b-d442-4a63-8650-410cb8e76089">
* An NTNet Send component that allows everything to be input much like
the list literal component
-- This makes sending stuff over NTNet easier for the user, and use less
power as it won't require an additional list literal component
<img width="136" alt="compare health state"
src="https://github.com/tgstation/tgstation/assets/80724828/0bed076c-3aa1-4931-af90-2b9eb8e1ae9a">
* A health comparison component that checks the entity's health state,
and can return true or false depending if the entity is alive, sleeping,
unconscious, critical or dead
-- This could be achieved by using a health sensor and a compare
component, however it lacks the ability to know when a entity is
unconscious or sleeping
<img width="136" alt="toggle"
src="https://github.com/tgstation/tgstation/assets/80724828/7017b6bf-937a-42ad-87f3-4f1134853ac3">
* A quick toggle component to allow the switching between a true and
false state
-- This could be achieved by using a logic component and self linking,
however this makes it far easier for newcomers to make something as
simple as an on/off switch (such as a handheld translator which uses the
front button to turn on/off)
## Changelog
🆑
qol: Add tooltips to circuit editor buttons
qol: Add grid alignment mode to circuit editor
add: Added new compare health state component
add: Added new NTNet send list literal component
add: Added new toggle component
qol: Added activity toggle to voice activator component
qol: Added quiet mode to speech component
qol: NTNet send component will not use power/trigger if NTNet is offline
/🆑
## About The Pull Request
Fixes#82440
This PR just creates a new macro, `LOWER_TEXT()` (yes the irony is not
lost on me) to wrap around all calls of `lowertext()` and ensure that
whatever we input into that proc will be stringified using the `"[]"`
(or `tostring()` for the nerds) operator. very simple.
I also added a linter to enforce this (and prevent all forms of
regression) because I think that machines should do the menial work and
we shouldn't expect maintainers to remember this, let me know if you
disagree. if there is a time when it should be opted out for some
reason, the linter does respect it if you wrap your input with the
`UNLINT()` function.
## About The Pull Request
Removes all arbitrary energy and power units in the codebase. Everything
is replaced with the joule and watt, with 1 = 1 joule, or 1 watt if you
are going to multiply by time. This is a visible change, where all
arbitrary energy units you see in the game will get proper prefixed
units of energy.
With power cells being converted to the joule, charging one joule of a
power cell will require one joule of energy.
The grid will now store energy, instead of power. When an energy usage
is described as using the watt, a power to energy conversion based on
the relevant subsystem's timing (usually multiplying by seconds_per_tick
or applying power_to_energy()) is needed before adding or removing from
the grid. Power usages that are described as the watt is really anything
you would scale by time before applying the load. If it's described as a
joule, no time conversion is needed. Players will still read the grid as
power, having no visible change.
Machines that dynamically use power with the use_power() proc will
directly drain from the grid (and apc cell if there isn't enough)
instead of just tallying it up on the dynamic power usages for the area.
This should be more robust at conserving energy as the surplus is
updated on the go, preventing charging cells from nothing.
APCs no longer consume power for the dynamic power usage channels. APCs
will consume power for static power usages. Because static power usages
are added up without checking surplus, static power consumption will be
applied before any machine processes. This will give a more truthful
surplus for dynamic power consumers.
APCs will display how much power it is using for charging the cell. APC
cell charging applies power in its own channel, which gets added up to
the total. This will prevent invisible power usage you see when looking
at the power monitoring console.
After testing in MetaStation, I found roundstart power consumption to be
around 406kW after all APCs get fully charged. During the roundstart APC
charge rush, the power consumption can get as high as over 2MW (up to
25kW per roundstart APC charging) as long as there's that much
available.
Because of the absurd potential power consumption of charging APCs near
roundstart, I have changed how APCs decide to charge. APCs will now
charge only after all other machines have processed in the machines
processing subsystem. This will make sure APC charging won't disrupt
machines taking from the grid, and should stop APCs getting their power
drained due to others demanding too much power while charging. I have
removed the delays for APC charging too, so they start charging
immediately whenever there's excess power. It also stops them turning
red when a small amount of cell gets drained (airlocks opening and shit
during APC charge rush), as they immediately become fully charged
(unless too much energy got drained somehow) before changing icon.
Engineering SMES now start at 100% charge instead of 75%. I noticed
cells were draining earlier than usual after these changes, so I am
making them start maxed to try and combat that.
These changes will fix all conservation of energy issues relating to
charging powercells.
## Why It's Good For The Game
Closes#73438Closes#75789Closes#80634Closes#82031
Makes it much easier to interface with the power system in the codebase.
It's more intuitive. Removes a bunch of conservation of energy issues,
making energy and power much more meaningful. It will help the
simulation remain immersive as players won't encounter energy
duplication so easily. Arbitrary energy units getting replaced with the
joule will also tell people more meaningful information when reading it.
APC charging will feel more snappy.
## Changelog
🆑
fix: Fixes conservation of energy issues relating to charging
powercells.
qol: APCs will display how much power they are using to charge their
cell. This is accounted for in the power monitoring console.
qol: All arbitrary power cell energy units you see are replaced with
prefixed joules.
balance: As a consequence of the conservation of energy issues getting
fixed, the power consumption for charging cells is now very significant.
balance: APCs only use surplus power from the grid after every machine
processes when charging, preventing APCs from causing others to
discharge while charging.
balance: Engineering SMES start at max charge to combat the increased
energy loss due to conservation of energy fixes.
/🆑
---------
Co-authored-by: SyncIt21 <110812394+SyncIt21@users.noreply.github.com>
Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com>
## About The Pull Request
While on the floor, you can:
- Use the UIs of Atmos machinery (except thermomachine and bluespace gas
vendor), Holopads, Crayons (spray cans too), radios, and Disposal bins
- Close extinguisher cabinets with Right-Click
- Click and drag yourself onto a photocopier to climb onto it.
I also changed all instances of ``ui_status`` to have all the args it's
being passed, I was messing with it a bit but it's gonna be for a later
PR.
## Why It's Good For The Game
It's an extra layer of harmless realism, also nice QoL for people who do
not have functional legs and do not have a wheelchair.
## Changelog
🆑
qol: You can use atmos machines, holopads, crayons, spray cans, and
disposal bins while floored.
fix: You can close extinguisher cabinets while floored.
fix: You can climb onto a photocopier from the floor.
/🆑
## About The Pull Request
The parent new call is what handles showing the alt appearance to the
mob
So we add the alt appearance to our date, try to show to any mob, it
fails (there is no seer), then set seer
Fixes this by fixing the order
## Changelog
🆑 Melbert
fix: You can once again see love on Valentines Day
/🆑
## About The Pull Request
`/obj/item/circuit_component/object_overlay` handled the wrong
references when implementing `Destroy`.
## Changelog
🆑 Melbert
fix: The object overlay circuit component will no longer take things
with it.
/🆑
## About The Pull Request
get_creator() returns a printable string rather than a mob, so it
doesn't need key_name() here
## Why It's Good For The Game
Bugfixes
## Changelog
🆑
fix: Fixed integrated circuit speech logging
/🆑
Co-authored-by: Watermelon914 <3052169-Watermelon914@users.noreply.gitlab.com>
## About The Pull Request
1. Removes material breakdown flags i.e. all flags with the format
`BREAKDOWN_XXX`. These flags do nothing, there are no special checks to
transform materials based on these flags, they are passed around just
because certain procs require them for syntax purposes only.
Apparently there were plans to make these flags do something special
from the comment
302247c0d1/code/__DEFINES/construction/material.dm (L43)
But nobody got any ideas for years now. The only special thing we can do
with them now is remove them and reduce code clutter, so let's do that
The only flag that ever did something was the
`BREAKDOWN_INCLUDE_ALCHEMY` flag. This only worked when coupled together
with `TRAIT_MAT_TRANSMUTED` trait(which is only used by the reagent
metalgen) and when both this trait & flag are combined together... they
still do nothing
302247c0d1/code/game/atom/atom_materials.dm (L41-L42)
Yup they cancel out each other to prevent returning an empty list, the
traits only job was to prevent materials from being recycled (like why?
what's the benefit of that? nothing) and the flag was meant to bypass
this restriction so both the trait & the flag cancel out each other
therefore doing nothing meaningful. Best remove them both and call it a
day.
2. Fixes an error in displaying number of sheets inserted into a mat
container when that sheet is made up of alloy materials. it would count
as 2 or more because it would take the sum of total material amount
inserted and not the actual sheets. That's fixed now.
3. Remote materials now properly respect the `MATCONTAINER_NO_INSERT`
flag
4. Adds helper proc to insert materials via the remote material
component with proper context
## Changelog
🆑
fix: mat container displays correct number of sheets inserted for alloy
materials.
fix: remote materials now properly respect the `MATCONTAINER_NO_INSERT`
flag.
code: removes material breakdown flags and related traits.
code: adds helper proc to insert materials via the remote material
component with proper context.
/🆑
## About The Pull Request
This PR makes several changes to how circuit action buttons work:
- The MOD action and BCI action components have been merged into a
single component.
- MOD circuit actions can be pinned from the configuration menu. This
works the same way as pinning individual modules, and can be done both
by the wearer and a suit AI.
- Action components have an output pin for the user of the action. This
allows MOD module circuits to distinguish between the wearer and an AI.
- Creates a supertype for `/datum/action/item_action/mod/pinned_module`
named `/datum/action/item_action/mod/pinnable`, which implements common
functionality for pinned modules and pinned circuit module actions.
## Why It's Good For The Game
The prior functionality of circuit MOD actions was somewhat unintuitive,
requiring the user to select an action from a radial menu *after*
activating the module, whether from a pinned action or from the module
radial. Providing similar pinning functionality to modules themselves
makes MOD actions more readily usable.
Merging the two different types of circuit components into one was made
with the idea that adding new types of shells with equipment actions
would inflate the number of subtypes of
`/obj/item/circuit_component/equipment_action` without adding much
meaningful functionality.
## Changelog
🆑
qol: MOD wearers and internal AIs can pin the individual actions in a
MOD circuit module in a similar way to how they can pin modules. Circuit
module actions can be pinned from the configuration menu of the circuit
refactor: The MOD action and BCI action components have been merged into
one component - the Equipment Action component.
/🆑
## About The Pull Request
I've stumbled across this enough to finally go through the entire
codebase and fix it. I left out changelogs simply because rewriting
history logs is bad.
## Why It's Good For The Game
I find it pretty annoying because I stumble across words that are
misspelled for a few seconds, and I'm likely not the only one who feels
like this. Less spelling mistakes in code are better.
## Changelog
🆑
spellcheck: Occurrences of "recieve" has been changed to "receive".
/🆑
## About The Pull Request
Adds an arctangent 2 component (atan2)
## Why It's Good For The Game
It's made to convert offsets into angles, something thats pretty useful
in a coordinate based game
## Changelog
🆑
add: Adds an arctangent2 component to circuitry!
/🆑
## About The Pull Request
Added a user type to integrated circuits that can't be stored as a user
type but can be typecasted to entity. Useful for components that
directly ask for an input from the user, like the list pick component.
Refactored the list pick component to use this user port and to also
send failure signals whenever a success signal is not sent.
Removed the triggered port for the list pick component.
Also fixes a runtime that occurs with the list pick component if the
list passed in only contains null values.
## Why It's Good For The Game
Can't force a prompt onto people who haven't interacted with your
circuit.
## Changelog
🆑
add: Added a user type to integrated circuits
/🆑
---------
Co-authored-by: Watermelon914 <3052169-Watermelon914@users.noreply.gitlab.com>
## About The Pull Request
Title
## Why It's Good For The Game
Less headache in the future for a macro thats not really obvious in what
it does
## Changelog
🆑
fix: signals in circuits now actually function
/🆑
## About The Pull Request
See title.
If someone was abusing signalers previously to cause server lag, going
into list signalers would actually cause even worse lag as byond sat
there and processed thousands of items into a string over and over,
which would cause string format operations on longer and longer strings,
resulting in more and more overhead. This is bad.
So instead there is now a limit to the size of the list, currently I
have that set to 500 although I am open to increasing and even reducing
the number.
I have also made signalers slightly more intuitive by having the
cooldown actually displayed in the ui as a tooltip instead of just being
a secret feature you didnt know about unless you code dived. Also made
the cooldown actually respected by things such as circuitry where it
didnt even implement the cooldown and would happily send as many signals
as you had items connected to your proximity circuit.
## Why It's Good For The Game
Admins won't accidentally kill the server by trying to parse a lag
machines signal list. Players lagging the server? No, how about the
admins trying to fix it!
## Changelog
🆑
qol: signalers now tell you their cooldown and also use balloon alerts
/🆑
## About The Pull Request
Implements /datum/pathfind/sssp, which generates /datum/path_map
/datum/path_maps allow us to very efficently generate paths to any turf
they contain from their central point.
We're effectively running the single source shortest paths algorithm.
We expand from the center turf, adding turfs as they're found, and then
processing them in order of addition.
As we go, we remember what turf "found" us first. Reversing this chain
gives us the shortest possible path from the center turf to any turf in
its range (or the inverse).
This isn't all that useful on its own, outside of a few niche cases
(Like if we wanted to get the farthest reachable turf from the center)
but if we could reuse the map more then once, we'd be able to swarm
to/from a point very easily.
Reuse is a bit troublesome, reqiures a timeout system and a way to
compare different movables trying to get paths.
I've implemented it tho. I've refactored CanAStarPass to take a datum,
/datum/can_pass_info. This is built from a movable and a list of access,
and copies all the properties that would impact pathfinding over onto
itself.
There is one case where we don't do this, pathing over openspace
requires checking if we'd fall through the openspace, and the proc for
that takes an atom.
So instead we use the weakref to the owner that we hold onto, and hold
copies of all the values that would impact the check on the datum.
When someone requests a swarmed path their pass info is compared with
the pass info of all other path_maps centered on their target turf. If
it matches and their requested timeout isn't too short, we just reuse
the map.
Timeout is a tricky thing because the longer a map exists the more out
of date it gets.
I've added a few age defines that let you modulate your level of risk
here. We default to only allowing maps that are currently
being generated, or finished generating in our tick.
Hopefully this prevents falling into trouble, but consumers will need to
allow "failed" movements.
As a part of this datumized pass info, I've refactored pathfinding to
use access lists, rather then id cards directly. This also avoids some
dumbass harddel oppertunities, and prevents an idcard from changing mid
path.
Did a few things to the zPass procs, they took args that they did NOT
need, and I thought it'd be better to yeet em.
If you'd all like I could undo the caching/can_pass_info stuff if you'd
all like. I think it's useful generally because it avoids stuff changing
mid pathfind attempt, but if it's too clunky I could nuke it.
Oh also I added optional args to jps that constricts how it handles
diagonals. I've used this to fix bot paths.
## Why It's Good For The Game
Much of this is redundant currently. I'm adding it because it could have
saved hugglebippers, and because I get the feeling it'll be useful for
"grouping" mobs like bees and such.
We're doing more basic mob work currently and I want to provide extra
tools for that work.
https://github.com/tgstation/tgstation/assets/58055496/66aca1f9-c6e7-4173-9c38-c40516d6d853
## Changelog
🆑
add: Adds swarmed pathfinding, trading accuracy for potential
optimization of used correctly
fix: Bots will no longer take diagonal paths, preventing weirdo looking
path visuals
refactor: Refactored bits of pathfinding code, hopefully easier to add
new pathfinding strategies now
/🆑
## About The Pull Request
Fixes#76503
Probably important for this stuff to be logged.
## Why It's Good For The Game
Helps admins figure out the signallers that are signalling, and who
triggered the signaller.
## Changelog
🆑
admin: If a circuit component outputs a radio signal, it should now be
logged in list-signalers.
/🆑
## About The Pull Request
Signals were initially only usable with component listeners, which while
no longer the case has lead to outdated documentation, names, and a
similar location in code.
This pr pulls the two apart. Partially because mso thinks we should, but
also because they really aren't directly linked anymore, and having them
in this midstate just confuses people.
[Renames comp_lookup to listen_lookup, since that's what it
does](102b79694f)
[Moves signal procs over to their own
file](33d07d01fd)
[Renames the PREQDELETING and QDELETING comsigs to drop the parent bit
since they can hook to more then just comps
now](335ea4ad08)
[Does something similar to the attackby comsigs (PARENT ->
ATOM)](210e57051d)
[And finally passes over the examine
signals](65917658fb)
## Why It's Good For The Game
Code makes more sense, things are better teased apart, s just good imo
## Changelog
🆑
refactor: Pulled apart the last vestiges of names/docs directly linking
signals to components
/🆑
## About The Pull Request
See title.
In order for this change to work, these components will not work if
there is no shell, but this will change nothing user-facing because all
player-facing circuits require shells to function in the first place
anyways.
## Why It's Good For The Game
Fixes a cooldown bypass bug.
Closes#75580
## Changelog
🆑
fix: Fixed bypassing component cooldowns with module components.
/🆑
---------
Co-authored-by: Watermelon914 <3052169-Watermelon914@users.noreply.gitlab.com>
This tracks the seconds per tick of a subsystem, however note that it is
not completely accurate, as subsystems can be delayed, however it's
useful to have this number as a multiplier or ratio, so that if in
future someone changes the subsystem wait time code correctly adjusts
how fast it applies effects
regexes used
git grep --files-with-matches --name-only 'DT_PROB' | xargs -l sed -i
's/DT_PROB/SPT_PROB/g'
git grep --files-with-matches --name-only 'delta_time' | xargs -l sed -i
's/delta_time/seconds_per_tick/g'
## About The Pull Request
I underestimated SEND_GLOBAL_SIGNAL and assumed it worked differently to
SEND_SIGNAL, as in I thought it would not be sending the source as the
first arg.
Because it does, it meant that the list of data was actually just ntnet
sending circuit. This fixes it and makes the args work properly.
I've shamelessly stolen the circuit in the screenshot of the issue to
test it in-game

## Why It's Good For The Game
Closes https://github.com/tgstation/tgstation/issues/74327
## Changelog
🆑
fix: NtNet receive/send circuits should work now.
/🆑
# MAINTAINER - USE THE BUTTON THAT SAYS "MERGE MASTER" THEN SET THE PR
TO AUTO-MERGE! IT'S MUCH EASIER FOR ME TO FIX THINGS BEFORE THEY SKEW
RATHER THAN AFTER THE FACT.
## About The Pull Request
Hey there,
This took a while to do, but here's the gist:
Python file now regexes every file in `/code` except for those that have
some valid reason to be tacking on more global defines. Some of those
reasons are simply just that I don't have the time right now (doing what
you see in this PR took a few hours) to refactor and parse what should
belong and what should be thrown out. For the time being though, this PR
will at least _halt_ people making the mistake of not `#undef`ing any
files they `#define` "locally", or within the scope of a file.
Most people forget to do this and this leads to a lot of mess later on
due to how many variables can be unmanaged on the global level. I've
made this mistake, you've made this mistake, it's a common thing. Let's
automatically check for it so it can be fixed no-stress.
Scenarios this PR corrects:
* Forgetting to undef a define but undeffing others.
* Not undeffing any defines in your file.
* Earmarking a define as a "file local" define, but not defining it.
* Having a define be a "file local" define, but having it be used
elsewhere.
* Having a "local" define not even be in the file that it only shows up
in.
* Having a completely unused define*
(* I kept some of these because they seemed important... Others were
junked.)
## Why It's Good For The Game
If you wanna use it across multiple files, no reason to not make it a
global define (maybe there's a few reasons but let's assume that this is
the 95% case).
Let me know if you don't like how I re-arranged some of the defines and
how you'd rather see it be implemented, and I'd be happy to do that.
This was mostly just "eh does it need it or not" sorta stuff.
I used a pretty cool way to detect if we should use the standardized
GitHub "error" output, you can see the results of that here
https://github.com/san7890/bruhstation/actions/runs/4549766579/jobs/8022186846#step:7:792
## Changelog
Nothing that really concerns players.
(I fixed up all this stuff using vscode, no regexes beyond what you see
in the python script. sorry downstreams)
## About The Pull Request
This is a continuation of
https://github.com/tgstation/tgstation/pull/74085 - I announced in the
comments there that this would be my next PR, and this is it.
Removes SSnetwork, ``/datum/ntnet``,
``/datum/component/ntnet_interface``, ``var/network_root_id``, the
network unit test, and a lot of other things related to networks.
- NTNet circuits now check for an Ntnet relay, and uses signals to
operate.
- Logs in Wirecarp is now only for PDA and Ntnet Relay things, so you
can no longer see what ruins exist using it (why should Wirecarp know
that Oldstation spawned? The flavor is that they dont know its there).
- Removed it from MULEbots entirely, I don't think it even did anything
for them? Botkeeper seems to work without it, so it's possibly there
from pre-tgui PDAs.
- Moves assigning random names to a base proc instead of being tied to
network, this is things like random-naming scrubbers/vents. The behavior
hasn't changed at all.
- Makes Ntos work for consoles when relays are down, as the comments
said they're supposed to (because they're wired). I think this was an
accidental change on my part, so this is a revert of that.
## Why It's Good For The Game
Ntnet is ancient code that hasn't given us much that we can't do with
already existing alternatives, we've been slowly moving away from it for
init times, and though a large portion of that was limited to airlocks,
I still don't think this is a system worth keeping around.
It's way too complex to expect feature coders to do anything with it,
and too old with better alternatives for anyone to want to improve any
of it.
## Changelog
🆑
fix: Computers are now properly connected to Ethernet, and can use Ntos
when Relays are down.
refactor: Removes Ntnet and Ntnet interfaces, which was only used by
Ntnet circuits (which now directly checks for a Relay to work) and
MULEbots, which did nothing with it.
balance: Wirecarp no longer tells you what ruins spawned in a round,
instead it's limited to PDA logs, and tells you the source too. This
means the RD can catch someone running illegal programs if they don't
make any attempt at hiding it.
qol: Wirecarp logs is now set to save 300 at once, instead of 100 and
being increased to 300 by the RD during the round. This is pretty
insignificant, since there's no reason to NOT want as many logs as
possible.
/🆑
---------
Co-authored-by: Zephyr <12817816+ZephyrTFA@users.noreply.github.com>
## About The Pull Request
Once pulled, these changes will adjust how the associative list data
type is shown like on circuits and the description of the index table
component.


## Why It's Good For The Game
Given the entry difficulty level of the circuits system, some players
may find themselves overwhelmed and frustrated seeing that their index
table component's output is not connecting to the index list component's
input, despite there being an index associative list component they may
not be aware of. These changes should hopefully lead players to learn
more about associative lists and how different they are from normal
lists. Just adding "assoc." to the descriptor should lead players to
search the term in the component printer and find the index associative
table.
## Changelog
🆑
qol: Made associative lists more apparent in circuits.
/🆑
This builds on what #69790 did and improved the code even further.
Notable things:
- `Topic()` is a deprecated proc in our codebase (replaced with
Javascript tgui) so it makes sense to rename `canUseTopic` to
`can_perform_action` which is more straightforward in what it does.
- Positional and named arguments have been converted into a easier to
use `action_bitflag`
- The bitflags adds some new checks you can use like: `NEED_GRAVITY |
NEED_LITERACY | NEED_LIGHT` when you want to perform an action.
- Redundant, duplicate, or dead code has been removed.
- Fixes several runtimes where `canUseTopic` was being called without a
proper target (IV drips, gibber, food processor)
- Better documentation for the proc and bitflags with examples
## About The Pull Request
Adds the 2 new components I made in my prior PR to the basic circuit
research
also fix an issue with associative pick list
## Why It's Good For The Game
Being able to print them would be usefull
Reason I didn't notice was properly since I ran on debug station and it
never crossed my mind that they where research thingy
## Changelog
🆑
fix: You can print the new list pick and associative list pick
components
fix: Associative list pick works as intended now
/🆑
## About The Pull Request
Part of a prior PR that was closed (#72562). This version does not add
the check in CI.
## Why It's Good For The Game
The work is already done, so I figured why not.
## Changelog
N/A Nothing player facing
Co-authored-by: Jeremiah Snow <jlsnow301@pm.me>
Co-authored-by: Mothblocks <35135081+Mothblocks@users.noreply.github.com>
Hey there,
Now that every instance of `req_access` and `req_one_access` is a list
of strings, there is absolutely no reason for
req_access_txt/req_access_one_txt to exist. In fact, any instance where
they were still used in the codebase was very convoluted and was very
broken! Don't worry, I fixed it all out, and life is good.
I also dmdoc the surviving access variables, because those were missing.
I went on the side of caution and made a more verbose documentation with
an example just to have people really grasp this (it took me a while to
actually get it)
I believe that we changed _everything_ over to the
req_access/req_one_access system earlier this year in VV, but the
problem is that _new mappers don't understand the difference between the
two systems_. In fact, the "txt" system is completely redundant since
all it does is transition stuff to the "base" system. So, let's just
completely cull the one that's all but deprecated and ensure this
confusion no longer arises. The whole purpose of "txt" seemed to be to
convert the access, but it's all pointless now that we can just read the
list directly.
I'm also 99% certain that the "access check" on vending machines broke
(and didn't seem to have correct logic in the first place? I
legitimately couldn't find a case where it could fail in testing, so I
changed that up), and that's fixed up now. Let me know if I was clueless
there. I know it's short-circuiting now as opposed to "all must be
true", but it just didn't work.
Adds lints for `balloon_alert(span_xxx(...))` (which is always wrong),
and balloon alert where the first letter is a capital (which is usually
wrong). Fixes everything that failed them. As a reminder, abbreviations
like "AI" and "GPS" shouldn't be capitalized in a balloon alert.
In cases where this is intentional for flavor (there was one case), you
can `UNLINT` like so:
Co-authored-by: Zephyr <12817816+ZephyrTFA@users.noreply.github.com>
## About The Pull Request
Adds the ability to use ranges between 0 and 5 for View Sensor circuits.
Currently these nodes are locked to 5 tiles and it is rather difficult
to limit the area this circuit effects either for speed reasons or
otherwise. This PR makes it a simple variable that remains capped at 5,
admins can raise the cap by modifying a variable.
## Why It's Good For The Game
I mostly use circuits as an admin, I can't for the life of me figure out
how to make a shorter range AOE circuit although I imagine its possible
by comparing x and y coordinates of things in the list and yourself this
is far to finicky. Players can also utilize this to, for example check
all objects on the tile the view sensor is on, "possible" at the moment
but way to finicky compared to a 5 tiles.
## Changelog
🆑
qol: You can now reduce the range of View Sensor circuits.
/🆑
Co-authored-by: Mothblocks <35135081+Mothblocks@users.noreply.github.com>
<!-- 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
<!-- Describe The Pull Request. Please be sure every change is
documented or this can delay review and even discourage maintainers from
merging your PR! -->
Fixes#69798Fixes#71621
When using hypnosis on a victim, the language should be accounted for
and whether the victim can properly hear it. Before the hearing code
would magically translate any message, this is no longer the case.
This also fixes the language barrier involving hearing for:
- Mind echo trauma
- Phobia trauma
- Hypnotic trigger trauma
- Split Personality brainwashing trauma
- Codeword hearing
- Hypnotize status effect
- Impure Inacusiate reagent
## Why It's Good For The Game
<!-- 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. -->
Better consistency, improved readability, and less bugs in the future.
## 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 it's 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: Fix hypnosis, mind echo trauma, phobia trauma, hypnotic trigger
trauma, split personality brainwashing trauma, codeword hearing, and
impure inacusiate reagent all bypassing language and hearing checks. If
you try to give commands to a victim in a language they don't
understand, they will no longer magically understand the words.
fix: Fix sign language having accent modifications
refactor: Refactored saycode to be more robust, readable, and have more
unit tests.
/🆑
<!-- 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. -->
Co-authored-by: Mothblocks <35135081+Mothblocks@users.noreply.github.com>
So i left over some basic `/whatever/proc/format` uses in the original
PR this fixes it.
Notable exceptions to the rule:
- Paths in add_verb/remove_verb, we need full path instead of a name
there to access verb metadata so we can't use proc ref macros there.
- regex.Replace, found out that it does not accept call by name. Instead
i added new REGEX_REPLACE_HANDLER so we can at least try to mark these.
There's still leftover global procs that do not use GLOBAL_PROC_REF but
they functionally equivalent so that's for later.
I don't see any reasonable way to grep for this. But if you got any
ideas please share.
<!-- 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
This PR adds a reagent injector component that's exclusive to BCIs.
(Requested to be integrated into BCIs by Mothblocks.)
When outside of a circuit, the component itself stores the reagents.
However, if it's inside of a BCI, the storage is moved to the BCI. The
storage can contain up to 15u of reagents and acts like an open
container. (However, it won't spill even if you throw it, it just acts
like an open container code-wise, don't worry about it.)
You can only have one reagent injector in a circuit. Trying to insert
multiple will give you an error message.
The entire dose is administered at once. (Requirement set by
Mothblocks.)
Please don't try to dispute any of the specific limitations in the
comments as they're out of my control. They're reasonable anyways.
Reagent Injector Input/Output:
Inject (Input Signal) - Administers all reagents currently stored inside
of the BCI into the user.
Injected (Output Signal) - Triggered when reagents are injected. Not
triggered if the reagent storage is empty.
New BCI Input:
Show Charge Meter (Number) - Toggles showing the charge meter action.
(Adds some capacity for stealth.)
Install Detector Outputs: (Added following a comment about having to use
weird workarounds for proper loops.)
Current State (Number) - Outputs 1 if the BCI is implanted and 0 if it's
not.
Installed (Signal) - Triggered when the BCI is implanted into it's user.
Removed (Signal) - Triggered when the BCI is removed from it's user.
This PR also adds BCI manipulation chambers to all currently present
circuit labs. (Solution proposed by Mothblocks.)
Yes I had to do some other mapping changes to allow for this. No I don't
have any mapping experience, why do you ask?
<!-- 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
One small step for BCIs, one giant leap for circuit kind. (First
"proper" circuit to human interaction in the entire game!)
This allows for some funky stuff and also makes it less of a pain in the
ass to use BCIs. What's not to love?
<!-- 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 it's 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. -->
🆑
add: Added a reagent injector component and BCI manipulators to all
circuit labs. (+ install detector component)
/🆑
<!-- 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. -->
Co-authored-by: Mothblocks <35135081+Mothblocks@users.noreply.github.com>
Makes the code compatible with 515.1594+
Few simple changes and one very painful one.
Let's start with the easy:
* puts call behind `LIBCALL` define, so call_ext is properly used in 515
* Adds `NAMEOF_STATIC(_,X)` macro for nameof in static definitions since
src is now invalid there.
* Fixes tgui and devserver. From 515 onward the tmp3333{procid} cache
directory is not appened to base path in browser controls so we don't
check for it in base js and put the dev server dummy window file in
actual directory not the byond root.
* Renames the few things that had /final/ in typepath to ultimate since
final is a new keyword
And the very painful change:
`.proc/whatever` format is no longer valid, so we're replacing it with
new nameof() function. All this wrapped in three new macros.
`PROC_REF(X)`,`TYPE_PROC_REF(TYPE,X)`,`GLOBAL_PROC_REF(X)`. Global is
not actually necessary but if we get nameof that does not allow globals
it would be nice validation.
This is pretty unwieldy but there's no real alternative.
If you notice anything weird in the commits let me know because majority
was done with regex replace.
@tgstation/commit-access Since the .proc/stuff is pretty big change.
Co-authored-by: san7890 <the@san7890.com>
Co-authored-by: Mothblocks <35135081+Mothblocks@users.noreply.github.com>
* [s] Dead people can no longer communicate with the living
Thought listener, through chicanery, could let you still pass through valid strings (and not fail) if you were a mob/dead/observer occupying your mob/living body. god dammit. check to make sure the fucker is dead.
About The Pull Request
I've reworked multiz. This was done because our current implementation of multiz flattens planes down into just the openspace plane. This breaks any effects we attach to plane masters (including lighting), but it also totally kills the SIDE_MAP map format, which we NEED for wallening (A major 3/4ths resprite of all wall and wall adjacent things, making them more then one tile high. Without sidemap we would be unable to display things both in from of and behind objects on map. Stupid.)
This required MASSIVE changes. Both to all uses of the plane var for reasons I'll discuss later, and to a ton of different systems that interact with rendering.
I'll do my best to keep this compact, but there's only so much I can do. Sorry brother.
Core idea
OK: first thing.
vis_contents as it works now squishes the planes of everything inside it down into the plane of the vis_loc.
This is bad. But how to do better?
It's trivially easy to make copies of our existing plane masters but offset, and relay them to the bottom of the plane above. Not a problem. The issue is how to get the actual atoms on the map to "land" on them properly.
We could use FLOAT_PLANE to offset planes based off how they're being seen, in theory this would allow us to create lens for how objects are viewed.
But that's not a stable thing to do, because properly "landing" a plane on a desired plane master would require taking into account every bit of how it's being seen, would inherently break this effect.
Ok so we need to manually edit planes based off "z layer" (IE: what layer of a z stack are you on).
That's the key conceit of this pr. Implementing the plane cube, and ensuring planes are always offset properly.
Everything else is just gravy.
About the Plane Cube
Each plane master (except ones that opt out) is copied down by some constant value equal to the max absolute change between the first and the last plane.
We do this based off the max z stack size detected by SSmapping. This is also where updates come from, and where all our updating logic will live.
As mentioned, plane masters can choose to opt out of being mirrored down. In this case, anything that interacts with them assuming that they'll be offset will instead just get back the valid plane value. This works for render targets too, since I had to work them into the system as well.
Plane masters can also be temporarily hidden from the client's screen. This is done as an attempt at optimization, and applies to anything used in niche cases, or planes only used if there's a z layer below you.
About Plane Master Groups
BYOND supports having different "maps" on screen at once (IE: groups of items/turfs/etc)
Plane masters cannot cover 2 maps at once, since their location is determined by their screen_loc.
So we need to maintain a mirror of each plane for every map we have open.
This was quite messy, so I've refactored it (and maps too) to be a bit more modular.
Rather then storing a list of plane masters, we store a list of plane master group datums.
Each datum is in charge of the plane masters for its particular map, both creating them, and managing them.
Like I mentioned, I also refactored map views. Adding a new mapview is now as simple as newing a /atom/movable/screen/map_view, calling generate_view with the appropriate map id, setting things you want to display in its vis_contents, and then calling display_to on it, passing in the mob to show ourselves to.
Much better then the hardcoded pattern we used to use. So much duplicated code man.
Oh and plane master controllers, that system we have that allows for applying filters to sets of plane masters? I've made it use lookups on plane master groups now, rather then hanging references to all impacted planes. This makes logic easier, and prevents the need to manage references and update the controllers.
image
In addition, I've added a debug ui for plane masters.
It allows you to view all of your own plane masters and short descriptions of what they do, alongside tools for editing them and their relays.
It ALSO supports editing someone elses plane masters, AND it supports (in a very fragile and incomplete manner) viewing literally through someone else's eyes, including their plane masters. This is very useful, because it means you can debug "hey my X is yorked" issues yourself, on live.
In order to accomplish this I have needed to add setters for an ungodly amount of visual impacting vars. Sight flags, eye, see_invis, see_in_dark, etc.
It also comes with an info dump about the ui, and plane masters/relays in general.
Sort of on that note. I've documented everything I know that's niche/useful about our visual effects and rendering system. My hope is this will serve to bring people up to speed on what can be done more quickly, alongside making my sin here less horrible.
See https://github.com/LemonInTheDark/tgstation/blob/multiz-hell/.github/guides/VISUALS.md.
"Landing" planes
Ok so I've explained the backend, but how do we actually land planes properly?
Most of the time this is really simple. When a plane var is set, we need to provide some spokesperson for the appearance's z level. We can use this to derive their z layer, and thus what offset to use.
This is just a lot of gruntwork, but it's occasionally more complex.
Sometimes we need to cache a list of z layer -> effect, and then use that.
Also a LOT of updating on z move. So much z move shit.
Oh. and in order to make byond darkness work properly, I needed to add SEE_BLACKNESS to all sight flags.
This draws darkness to plane 0, which means I'm able to relay it around and draw it on different z layers as is possible. fun darkness ripple effects incoming someday
I also need to update mob overlays on move.
I do this by realiizing their appearances, mutating their plane, and then readding the overlay in the correct order.
The cost of this is currently 3N. I'm convinced this could be improved, but I've not got to it yet.
It can also occasionally cause overlays to corrupt. This is fixed by laying a protective ward of overlays.Copy in the sand, but that spell makes the compiler confused, so I'll have to bully lummy about fixing it at some point.
Behavior changes
We've had to give up on the already broken gateway "see through" effect. Won't work without managing gateway plane masters or something stupid. Not worth it.
So instead we display the other side as a ui element. It's worse, but not that bad.
Because vis_contents no longer flattens planes (most of the time), some uses of it now have interesting behavior.
The main thing that comes to mind is alert popups that display mobs. They can impact the lighting plane.
I don't really care, but it should be fixable, I think, given elbow grease.
Ah and I've cleaned up layers and plane defines to make them a bit easier to read/reason about, at least I think.
Why It's Good For The Game
<visual candy>
Fixes#65800Fixes#68461
Changelog
cl
refactor: Refactored... well a lot really. Map views, anything to do with planes, multiz, a shit ton of rendering stuff. Basically if you see anything off visually report it
admin: VV a mob, and hit View/Edit Planes in the dropdown to steal their view, and modify it as you like. You can do the same to yourself using the Edit/Debug Planes verb
/cl
Changes components\atom\reagentscanner to use table list from Assoc list.
Added purity output to components\atom\reagentscanner.
At time of making this its impossible to iterate through the output of reagentscanner via loops or numerical index and to determine the amount or the reagent scanned you needed to know its associated value which is less than idea.
Queried this issue on coderbus meeting 3 then asked Watermelon and he agreed that a change would be good.
Added a "purity" to the table outputs to make shells of this component "desirable" to chemistry who need to use Ph_meter to check exact purity. If this not allowed I’m willing to make an \atom\reagentscanner\adv variant that will comparable to Ph_meter.
I intend to give the same treatment to materialscanner.
* Optimizes away /obj/Initialize
We were spending like 0.15 seconds just checking for blueprints, obj
flags and network ids
All these things can just be applied where they're wanted, saves time
Oh and I replaced object flags with an emag injector. I'll give it a
sprite and name later I promise
* Requires a GenerateTag() call to set DF_USE_TAG, rather then doing a check in atom New
This is technically harder to use, but I don't really want people using
tags, and it saves 0.15 seconds
* Moves generatetag to /datum
* I am dumb
* Saves 0.5 seconds, makes init emissive blockers actually work
Ok so background. If an overlay is added with add_overlay, and not
"managed" somehow, it will effectively never be removed, because
nothing's tracking it.
Update_overlays uses the managed_overlays list/var (one of those) to do
this.
I'm gonna piggyback off this to make emissive overlays actually like,
respect overlay updates.
Oh and uh, I've saved maybe 0.5 seconds by caching the new emissive, and
not using add_overlay. There's a chance this will lead to overlay
corruption, but since we never readd the flattened, I think we'll be
safe
* Fixes plane not being set right, changes color logic too, since alpha will override past color sets
* Makes it actually work. also makes rand posters update appearance to clear away the overlay, since it shows on right click and looks bad
* Fixes blockers showing as emissives. It turns out alpha sets override the color list we use. Not sure why we pretend to support them
* Makes the injector support traits, adds an amazing sprite
Moves singulo and supermatter dmis into obj/engine, renamed from obj/tesla_engine
Moves Halloween, Christmas, and misc holiday items to obj/holiday
Moves lollipops to obj/food
Moves crates, closets, and storage to obj/storage
Moves assemblies to obj/assemblies
Renames decals.dmi to signs.dmi ...because they're signs and not decals
Moves statues, cutouts, instruments, art supplies, and crayons to obj/art
Moves balloons, plushes, toys, cards, dice, the hourglass, and TCG to obj/toys
Moves guns, swords, shields to obj/weapons
See title, these checks are based on those used by set_turf_examine_tab for the statpanel.
Fixes#68596 (in the specific case of the plasma image holder in the bug, it has MOUSE_OPACITY_TRANSPARENT)
* Refactored fundamental circuit components that have varying inputs. Made the integrated circuit UI slightly better.
* Fixes with UI
* Removes logger
* Ran prettier
* Fixed documentation
* Rebalances drone circuit
* Drones can now charge in chargers
Co-authored-by: Watermelon914 <hidden@hidden.com>
About The Pull Request
Fixes some cases in which actual references were used in trait sources instead of keys (or ref() keys).
This can cause some rare and difficult to find hard deletes.
Trait sources should be a string key relating to the source of it, not an actual reference to what added it. References within trait sources are never handled in Destroy(), because it's not expected behavior, meaning it can cause hanging references.
So, I went through with a regex to find some cases and replaced them.
I used the following and just picked through the few by hand to find erroneous ones.
ADD_TRAIT\(.+, .+, [a-z]+\)
REMOVE_TRAIT_TRAIT\(.+, .+, [a-z]+\)
Why It's Good For The Game
Less hard deletes, probably.
Changelog
cl Melbert
code: Some traits which mistakenly were sourced from a hard reference are no longer.
/cl
Fixes#67885.
I don't know if this works because I can't reproduce locally, but I can reproduce on servers so I'll let you know next Sybil round It works