10 Commits

Author SHA1 Message Date
Joshua Kidder 7a3ad79506 All camelCase (Brute|Burn|Fire|Tox|Oxy|Organ|Stamina)(Loss) procs now use snake_case. UNDERSCORES RULE! (#94111)
## About The Pull Request
It's just a partial cleanup of
anti-[STYLE](https://github.com/tgstation/tgstation/blob/master/.github/guides/STYLE.md)
code from /tg/'s ancient history. I compiled & tested with my helpful
assistant and damage is still working.

<img width="1920" height="1040" alt="image"
src="https://github.com/user-attachments/assets/26dabc17-088f-4008-b299-3ff4c27142c3"
/>


I'll upload the .cs script I used to do it shortly.

## Why It's Good For The Game
Just minor code cleanup.

Script used is located at https://metek.tech/camelTo-Snake.7z

EDIT 11/23/25: Updated the script to use multithreading and sequential
scan so it works a hell of a lot faster
```
/*
//
Copyright 2025 Joshua 'Joan Metekillot' Kidder

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
//
*/
using System.Text.RegularExpressions;
class Program
{
    static async Task Main(string[] args)
    {
        var readFile = new FileStreamOptions
        {
            Access = FileAccess.Read,
            Share = FileShare.ReadWrite,
            Options = FileOptions.Asynchronous | FileOptions.SequentialScan
        };
        FileStreamOptions writeFile = new FileStreamOptions
        {
            Share = FileShare.ReadWrite,
            Access = FileAccess.ReadWrite,
            Mode = FileMode.Truncate,
            Options = FileOptions.Asynchronous
        };
        RegexOptions regexOptions = RegexOptions.Multiline | RegexOptions.Compiled;
        Dictionary<string, int> changedProcs = new();
        string regexPattern = @"(?<=\P{L})([a-z]+)([A-Z]{1,2}[a-z]+)*(Brute|Burn|Fire|Tox|Oxy|Organ|Stamina)(Loss)([A-Z]{1,2}[a-z]+)*";
        Regex camelCaseProcRegex = new(regexPattern, regexOptions);

        string snakeify(Match matchingRegex)
        {
            var vals =
            matchingRegex.Groups.Cast<Group>().SelectMany(_ => _.Captures).Select(_ => _.Value).ToArray();
            var newVal = string.Join("_", vals.Skip(1).ToArray()).ToLower();
            string logString = $"{vals[0]} => {newVal}";
            if (changedProcs.TryGetValue(logString, out int value))
            {
                changedProcs[logString] = value + 1;
            }
            else
            {
                changedProcs.Add(logString, 1);
            }
            return newVal;
        }
        var dmFiles = Directory.EnumerateFiles(".", "*.dm", SearchOption.AllDirectories).ToAsyncEnumerable<string>();

        // uses default ParallelOptions
        // https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.paralleloptions?view=net-10.0#main
        await Parallel.ForEachAsync(dmFiles, async (filePath, UnusedCancellationToken) =>
        {
            var reader = new StreamReader(filePath, readFile);
            string oldContent = await reader.ReadToEndAsync();
            string newContent = camelCaseProcRegex.Replace(oldContent, new MatchEvaluator((Func<Match, string>)snakeify));
            if (oldContent != newContent)
            {
                var writer = new StreamWriter(filePath, writeFile);
                await writer.WriteAsync(newContent);
                await writer.DisposeAsync();
            }
            reader.Dispose();
        });
        var logToList = changedProcs.Cast<KeyValuePair<string, int>>().ToList();
        foreach (var pair in logToList)
        {
            Console.WriteLine($"{pair.Key}: {pair.Value} locations");
        }
    }
}

```

## Changelog
🆑 Bisar
code: All (Brute|Burn|Fire|Tox|Oxy|Organ|Stamina)(Loss) procs now use
snake_case, in-line with the STYLE guide. Underscores rule!
/🆑
2025-11-27 15:50:23 -05:00
Jacquerel e3dee6810e Most hostile mobs can no longer be trapped by closets, chairs, and aggro grabs (#91652) 2025-06-21 03:21:22 +02:00
Bloop 3a92370673 Fixes a lot of procs not checking the return value of Life() when they should (#89542)
## About The Pull Request


![firefox_iLQqvDAiws](https://github.com/user-attachments/assets/d88c71ae-2f23-4799-865b-4b355c5bfe83)

Goal of this PR was to fix this annoying CI runtime that most likely
occurs on a Life() tick that happens on a dead or deleted mob. Ending up
finding more issues than I set out to fix.

The short of it is: the base call of `Life()` actually has a return
value of `1` if the mob is alive, or `null` if the mob is dead or
qdeleted. There are many procs which should be stopping operations once
the mob is either qdeleted or dead, but many procs were not even
checking the return value of `..()`.

This fixes that.

Note: For some procs, it _DOES_ actually matter to differentiate between
being qdeleted and being dead... `handle_organs()` comes to mind iirc.
So I was careful to respect that. That is why some are checking for `!.`
while others are checking for `QDELETED(src)`

## Why It's Good For The Game

Less spurious runtimes.

## Changelog

Not player facing

---------

Co-authored-by: SyncIt21 <110812394+SyncIt21@users.noreply.github.com>
Co-authored-by: SmArtKar <44720187+SmArtKar@users.noreply.github.com>
2025-02-20 18:20:46 +01:00
carlarctg 4eaa299c0b Cult Vs. Heretic: 7 Months Later Edition (#82877)
## About The Pull Request

This PR was originally meant as a replacement for the Bloody Bastard
blade, but then I stopped existing for 7 months. Now that I'm here
again, I'm finishing the job once and for all.

### **HERETICS VERSUS CULTISTS**

### Heretics

Heretics can now sacrifice cultists, which will give them one of three
gifts: The Cursed Blade, the Crimson Focus, and the Rusted Harvester.
The gifts given are weighted to be spread out equally with each type.
They will also gain one knowledge point.

- The Cursed Blade is a free heretic blade that is more powerful than
the normal heretic blade, including a small block chance. It can also be
used to draw heretic runes off combat mode.
- The Crimson Focus is a necklace that grants focusing and a minor
regeneration effect which also affects nearby heretics, at the cost of
gaining the BLOODY_MESS trait while wearing it. Additionally, it can be
squeezed to heal 50 points of brute/burn damage, injecting yourself with
three to six (separately) units of Eldritch ~~Water~~ Essence and Unholy
Water. Yes, this isn't good.
- The Rusted Harvester is a heretic 'monster' summon. It's a normal
Harvester, but instead of Area Conversion and Forcewall, it has
Aggressive Spread and Rust Construction (Raise Wall). It can delimb, but
only cultists, with a delay. It has an aura of decay, corroding the
environment and withering enemies near it, but it's VERY fragile.

Rusting cultist item dispensers will now cause them to turn into a
Heretic object. Altars turn into small heretic runes, Archives turn into
Codex Cicatrixi, Forges turn into Mawed Crucibles.

Ideally, Heretics would be able to gain an amount of these new powers
and use them to turn the tide against the cultists, amassing their power
and almost forming a sect of their own in turn which sweeps over and
converts the cult.

### Cultists

When a Cultist sacrifices a heretic, two things will happen:

- A new item will be available for creation at one of the dispensers.
- The Heretic will be trapped inside a powerful Haunted Blade.

`/obj/item/melee/cultblade/haunted`
`	name = "haunted longsword"`
` desc = "An eerie sword with a blade that is less 'black' than it is
'absolute nothingness'. It glows with furious, restrained green
energy."`

This blade will be stronger across-the-board than a normal cult sword,
and will even allow those who wield it to cast one heretic spell from
their previous path. The only downside? The heretic can also cast one
spell. It's up to the trapped spirit if it wants to help you, or be a
nuisance.

The unlocked items are:
- The Cursed Blade, again. For cultists, it can be used to draw runes
twice as fast as usual, and they can even right-click it to teleport to
safety, just like a heretic!
- The Crimson Focus, again. Cultists are twice as fast at carving spells
into their body, and they gain a 5th spellslot as long as they wear the
amulet. It still causes hemophilia and grants weak regeneration.
- The Proteon Orb. This orb will create a gateway to Nar'sie's own
realm, spawning one Proteon every 15 seconds, which ghosts can possess.
The gateways cannot be placed close to one another.

Originally, they were going to be able to create a Harvester Shell, but
there were some concerns of it being too OP.

The true Bastard sword has been fully deleted. The null rod conversion
has been changed to a Bloody Halberd instead.

I'm considering re-enabling Stun Hand on Heretics, with Mansus Grasp
stats.

### Other

All the items above can be used by both Heretics and Cultists, no matter
how they were first created. Hell, even normal crew can use them! This
is probably not the best idea a lot of the time, though.

There are a lot of other changes in this PR. A loooooot. I will likely
miss some in the changelog, but I'll try to be as thorough as possible.
There's probably also some leftover garbo that I didn't find and clear
out yet.

## Why It's Good For The Game

Cult and Heretics, despite being mortally opposed, have very few
interactions with eachother, especially now that the Blade's gone. The
only thing of note is just the Heretic's unfair complete resistance to
stun hand, which is only marginally better than the alternative. This PR
will reintroduce their animosity, and give both sides a very, very good
reason to fight eachother.

The Cult will gain a sick sword that keeps the heretic in the game, and
unlike with the original implementation, will recieve a cult-wide bonus
in the form of a powerful, well deserved, and fun new item to summon.

The Heretic will gain powerful trinkets and knowledge from the
sacrifices, incentivizing them to become a terrifying cult-hunter. And
if they do succeed in wiping out the cult, they will have quite the
rewards to help with their ascension.

The crew, while mostly unaffected, will have a damn good reason to not
just Side with the heretic, out of fear of what they may become after
the cult is stomped down. They can also use a few of the items here in
an attempt to get one up on either side, as long as they manage to stay
clear of the side-effects.

Let the heretics eradicate the apostates.

Let the cultists root out the heathens.

![image](https://github.com/tgstation/tgstation/assets/53100513/b43d5d94-d06d-43b8-9b10-57f5a4a32bdb)
The haunted longsword creates an aura of darkness (disabled for the
cultist for the image)
Sprites... are not great. Hopefully someone comes by and improves them.

code: Added get_inactive_hand() as an easy shortcut for carbons
code: Wall walker element can now accept a trait for wall-checking
fix: Fixed soulsword component being unable to invoke the post summon
callback
refactor: Turned Heretic rust turf healing into an element, given to
Rust Walkers and Rusted Harvesters
refactor: Converted Limb Amputation from an element to a component

Blade and Sword sprites by meyhaza!!! I did the inhands though. Cuz im
cool
2024-06-29 12:40:33 -05:00
EnterTheJake 154837240d Rust Heretic rework: THE PUKENING. (#83006)
## About The Pull Request
Turf rusting is now based on knowledge instead of RNG; toxic damage on
spells has been replaced with disgust; rust walkers are a bit easier to
summon and show up early in the tree.

Rust ascension spread has been massively increased and immunities while
on Rust have been updated.
## Why It's Good For The Game

This is a massive list of changes, but the tl:dr is Rust heretic design
is pretty barebones and dated in its current state. I'm going to try my
best to explain why that is and why it needs to change.

###  RNG on rusting is bad

**Problem** : quite a lot of turfs cannot be rusted, and reinforced
turfs rusting is tied to RNG, the emergency shuttle floors are also
unrustable, making an ascended heretic not threatening at all to an
escaping crew.

**Solution**: Heretic rusting prowess is now tied to knowledge
progression; reinf wall rusting is no longer tied to RNG; the emergency
shuttle is now rustable if you have accrued enough knowledge.

**Explanation** : I've been adopting the code from a previous PR that
sadly didn't make the light of day.

Link: https://github.com/tgstation/tgstation/pull/65361

The goal is to have Heretic rusting be more consistent, so that if you
ascend the shuttle is no longer a safe refuge.

**Grasp Of Rust**: Basic floors and walls.
**Mark Of Rust**: Reinf floors and walls (takes 3 applications of rust
to fully destroy).
**Toxic Blade** Titanium and Plastitanium( still takes 3 applications of
rust to destroy).
**Ascension**: almost everything save for admin walls, glass, and
silver.

### A territorial antagonist with no tools to defend its turf

**Problem**: Rust heretic is forced into a territorial playstyle, but
it's heavily diminished by rusted turfs not having any negative effect
on the crew whatsoever, Toxic damage on plume and blade is also kind of
bad and has no synergy with the rest of the kit.

Lastly, while fitting to the theme of Rust; mark detonation destroying
clothes and items can end up being more harmful to the heretic, as
destroying a secoff's flashbang will result in you getting stunned and
killed.

**Solution**: Rusted floors are no longer safe for the crew; walking
over Rust will add a small buildup of disgust, silicons will receive
ticking damage, Toxic damage on Rust skills has been replaced with
disgust buildup and a chem purge effect to prevent the crew from
cheesing the debuff with sol dry.

**Explaination** "The goal behind this change is to prevent the crew to
just be able to walk willy nilly into an eldritchly decayed area without
repercussions, plus I feel like disgust is a fitting debuff for Rusties
for a number of reasons.

1) Lore wise, your goal is to turn the entire station into a garbage
dump.

2) It fits for fighting a territorial antagonist, it's not immediately
threatening on its own, but if you overstay your welcome, it has dire
consequences.

3) We don't really do much with disgust as a status effect, far as i
know, this'll be the first iteration of it being used for an antagonist
toolset.

4) It gives reason to the crew to act hostile towards the Heretic, as
you are essentially making their work area inhabitable.

I've also Slightly increased the healing on leeching walk and gave it
some minor temperature regulation (you won't be able to outtemp space
cold).

### Rust Walkers 

**Problem**: Rust walkers might as well not exist in their current
state; they are one of the latest heretic unlocks, and the recipe for
summoning one is INSANE now that you cannot decapitate mobs anymore.

**Solution**: Rust walkers pop up a bit earlier in the tree; the ritual
to summon them has more reasonable reagents (wires, pools of vomit, iron
sheets) and they have increased health.

**Explanation**: : There is not a lot to add to this. without walkers,
Rust heretics are fairly slow at spreading rust, by making rust walkers
have reasonable summoning reagents, we ease that problem; lastly i've
slightly bumped their hp, as i felt 75 hp was a bit low.

### Underwhelming ascension

**Problem**: The spread rate from the ascension is downright ATROCIOUS
in its current state, i actually ran multiple tests on different maps,
on Metastation it can take up to 40 minutes for the rust to spread to
the entire station, considering an ascended heretic results in an
immediate shuttle call, it's unecceptable in its current form.

Solution: Rust spread is now a hybridization between old ascension and
Wizard tranformation ritual.

**Explanation**: The spread rate in its current form is painstakingly
slow and has a tendency to reach one corner of the map and compound on
itself, i've borrowed the code from the wizard final ritual
"transformation" and gave it my own spin so that given enough time it
will cover the station more or less evenly, it can now spread through
all z levels.

Video example: https://www.youtube.com/watch?v=jZ5zMrNM6Jw

I've also updated the immunities you gain on ascension to ignore
slowdown and stasis from Cryogelidia.

The whole point of rust ascension is to become immune to crowd control,
i've seen far too many ascended heretics die to a single bola or cryo
syringe, that's pretty lame so i fixed that.

Lastly, aggressive spread has had its radius reduced in exchange for the
spread being consistent now; cooldown is also halved when you ascend, to
better help the heretic go on the offensive.
2024-05-16 18:53:05 +00:00
Bloop e1b958c41f Removes final remnants of 'targetted' (#79626)
## About The Pull Request

Finishing what https://github.com/tgstation/tgstation/pull/79513/
started, removes 'targetted' typo from code. Also updates the basic mob
guide with the new updated var names.

## Why It's Good For The Game

Typos bad. Accurate guides good.

## Changelog

🆑
code: gets rid of the rest of the instances of 'targetted' typo from
code
/🆑
2023-11-11 07:46:02 -05:00
LemonInTheDark 9696dd1a1d Targeting Datums Renamed (and global) (#79513)
## About The Pull Request

[Implements the backend required to make targeting datums
global](https://github.com/tgstation/tgstation/commit/6901ead12e419530b7f646ea21094d4432d7385e)

It's inconsistent with the rest of basic ai for these to have a high
degree of state, plus like, such a waste yaknow?

[Implements
GET_TARGETING_STRATEGY](https://github.com/tgstation/tgstation/commit/d79c29134d03424a9f8bacd64c08cb41775fe8c0)

Regexes used:
new.*(/datum/targetting_datum[^,(]*)\(*\)* -> GET_TARGETING_STRATEGY($1)

Renamed all instances of targetting to targeting (also targetting datum
-> targeting strategy)

I've used GET_TARGETING_STRATEGY at the source where the keys are
actually used, rather then in the listing. This works out just fine.

## Why It's Good For The Game

Not a misspelled name through the whole codebase, very slightly less
memory load for basically no downside (slight cpu cost maybe but not a
significant one.

---------

Co-authored-by: John Willard <53777086+JohnFulpWillard@users.noreply.github.com>
2023-11-09 14:44:24 +00:00
san7890 e03822fe1d Standardizes Adding Datum Actions into a proc/define (Bonus AI Support) (Bonus Useless Code Cleanup) (#79389)
## About The Pull Request

The way we add multiple actions has been very unstandardized, with
several implementations of this code doing certain things wrongly (i.e.
not nullchecking `ai_controller`), so let's do something in the vein of
#74037 and just make one nice big ol' proc that catches a lot of these
cases. There are still a few things that simply can't be done here, but
this gets the most generic "give my mob some actions and also maybe tell
the AI about it" stuff done.

This is only useful in cases where we don't ever need to reference the
ability ever again when it's added. In an ideal world we would never
need to reference the ability again and it would all be self-contained,
but this is not an ideal world. However, a lot of the latticework has
been built around certain implementations of this behavior making
refactoring it just a bit easier.

I also did a lot of auditing on `Destroy()` stuff, because
`/datum/action`s listen to signals when their parent is `qdel`ing, so we
don't need to neither hold nor clear references on our mob's
`Destroy()`. This was all cleaned up now because even if we couldn't use
`grant_multiple_actions()` (the new proc I add in this PR), it's just
not useful at all and will further hinder efforts to implement this new
proc.

Also also, I noticed in some places (such as megafauna) that we were
initializing a lot of datum actions _in nullspace_. We didn't pass the
`src` argument to `New()`. I quickly fixed that, as well as got rid of
the useless types we had going on.

Also also also, I added a define macro to handle some of the cases that
melbert was speaking about in his review down below. All you need to do
is invoke the define on the typepath, and you should be good to go from
there. There's probably a better way to do it, lmk though. we do the
whole `do while` thing in order to prevent code leakages.

## Why It's Good For The Game

* Very easy to change the implementation. In case we need to do
something different in how we add actions or anything like that, we can
simply just edit instances where this proc is located.
* Standardizes addition behavior. There's a lot of cases like the
aforementioned not-null-checking `ai_controller` that we really need to
look out for, so having it all in one accessible proc ensures standard
behavior.
* Reduces copy-pasta. A lot of mobs had their own individual
implementation of this, so let's just clean up all those lines of code.
## Changelog
🆑
refactor: The way mobs get specialized actions (like revenants shocking
lights or regal rats summoning rats to their side when you slap them)
have been modified, please report any bugs.
/🆑

This doesn't touch the following case FTR:
* Instances where we need to do work on the `/datum/action` after we
`Grant()` it, like if we were to edit some variable on the action or if
we need to call procs on said action. I don't like how the current code
is so reliant on storing a variable to it, but that's a windmill to
attack another time.
2023-11-03 04:02:26 +00:00
lizardqueenlexi fc3e267c57 Heretic summon name fixes (#79055)
## About The Pull Request

Fixes #79049.

The ghost poll for heretic summons used the `real_name` field to display
the mob's name. However, for some reason, a couple of the heretic
summons have jokey nicknames as their real names ("Ashy" for ash
walkers, "Rusty" for rust walkers). I've opted to take the simple option
of making the ghost text just use the `name` field instead - it's used
for the admin logs around summoning, so it should be fine for the poll
too.

Also, I've capitalized "Fire Shark" and set its real name to also be
"Fire Shark". For consistency.

Finally, I've made heretic summon names not proper nouns, so examining
them will display "That's a Rust Walker" rather than "That's Rust
Walker". The Lord of the Night did not receive this treatment due to
being a unique thing.
## Why It's Good For The Game

It's good when ghosts know what they're actually signing up to be.

Most heretic summons aren't unique entities, so it makes sense for them
to not be proper nouns.
## Changelog
🆑
fix: Heretic summons should now display the correct name when polling
ghosts to play as them.
/🆑
2023-10-18 23:12:19 -06:00
Jacquerel 5e2c8459dd Basic Heretic Mobs: The Rest of Them (#78757)
## About The Pull Request

Raw Prophet and Armsy had fun stuff going on and merited their own PRs,
but the rest of these guys are basically just statblocks with abilities
so I converted them all at once.

Rust Walkers are present in a ruin and so have new AI which will
actually use their abilities. They rust the area around where they spawn
and throw their rust blast at people.

I also gave Flesh Stalkers AI even though nobody has put them in a map
because I thought it would be cool. This adds an AI behaviour where if
they're not doing anything else they will turn into an animal and chill
until someone's been around them for a bit, before attacking. They will
also use EMP almost immediately upon performing their ambush, which
kills the lights in that room. Spooky!
To support this I needed to make some changes to let AI continue
processing and targetting correctly while shapeshifted.

I didn't give Maids or Ash Spirits AI because they'd be really boring.

Other changes:
I made the maid in the mirror flicker when it takes examine damage
because the `visible_message` says it does but despite having the power,
nobody made it actually flicker...

## Why It's Good For The Game

No more simple mob heretic summons.

## Changelog

🆑
refactor: Rust Walkers, Ash Spirits, Flesh Stalkers, and The Maid in the
Mirror now use the basic mob framework. Please report any unusual
behaviour.
/🆑

---------

Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com>
2023-10-06 16:06:22 -06:00