Files
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

213 lines
8.1 KiB
Plaintext

// Drones' interactions with other mobs
/mob/living/basic/drone/attack_drone(mob/living/basic/drone/drone)
if(drone == src || stat != DEAD)
return FALSE
var/input = tgui_alert(drone, "Perform which action?", "Drone Interaction", list("Reactivate", "Cannibalize"))
if(!input)
return FALSE
switch(input)
if("Reactivate")
try_reactivate(drone)
if("Cannibalize")
if(drone.health >= drone.maxHealth)
to_chat(drone, span_warning("You're already in perfect condition!"))
return
drone.visible_message(span_notice("[drone] begins to cannibalize parts from [src]."), span_notice("You begin to cannibalize parts from [src]..."))
if(do_after(drone, 6 SECONDS, 0, target = src))
drone.visible_message(span_notice("[drone] repairs itself using [src]'s remains!"), span_notice("You repair yourself using [src]'s remains."))
drone.adjust_brute_loss(-src.maxHealth)
new /obj/effect/decal/cleanable/blood/splatter/oil(get_turf(src))
ghostize(can_reenter_corpse = FALSE)
qdel(src)
else
to_chat(drone, span_warning("You need to remain still to cannibalize [src]!"))
/mob/living/basic/drone/attack_drone_secondary(mob/living/basic/drone/drone)
return SECONDARY_ATTACK_CALL_NORMAL
/mob/living/basic/drone/attack_hand(mob/user, list/modifiers)
if(isdrone(user))
attack_drone(user)
return ..()
/mob/living/basic/drone/mob_try_pickup(mob/living/user, instant=FALSE)
if(stat == DEAD || HAS_TRAIT(src, TRAIT_GODMODE))
return
return ..()
/mob/living/basic/drone/mob_pickup(mob/living/user)
drop_all_held_items()
return ..()
/**
* Called when a drone attempts to reactivate a dead drone
*
* If the owner is still ghosted, will notify them.
* If the owner cannot be found, fails with an error message.
*
* Arguments:
* * user - The [/mob/living] attempting to reactivate the drone
*/
/mob/living/basic/drone/proc/try_reactivate(mob/living/user)
var/mob/dead/observer/G = get_ghost()
if(!client && (!G || !G.client))
var/list/faux_gadgets = list(
"hypertext inflator","failsafe directory","DRM switch","stack initializer",\
"anti-freeze capacitor","data stream diode","TCP bottleneck","supercharged I/O bolt",\
"tradewind stabilizer","radiated XML cable","registry fluid tank","open-source debunker",
)
var/list/faux_problems = list("won't be able to tune their bootstrap projector","will constantly remix their binary pool"+\
" even though the BMX calibrator is working","will start leaking their XSS coolant",\
"can't tell if their ethernet detour is moving or not", "won't be able to reseed enough"+\
" kernels to function properly","can't start their neurotube console",
)
to_chat(user, span_warning("You can't seem to find the [pick(faux_gadgets)]! Without it, [src] [pick(faux_problems)]."))
return
user.visible_message(span_notice("[user] begins to reactivate [src]."), span_notice("You begin to reactivate [src]..."))
if(do_after(user, 3 SECONDS, 1, target = src))
revive(HEAL_ALL)
user.visible_message(span_notice("[user] reactivates [src]!"), span_notice("You reactivate [src]."))
alert_drones(DRONE_NET_CONNECT)
if(G)
to_chat(G, span_ghostalert("You([name]) were reactivated by [user]!"))
else
to_chat(user, span_warning("You need to remain still to reactivate [src]!"))
/// Screwdrivering repairs the drone to full hp, if it isn't dead.
/mob/living/basic/drone/screwdriver_act(mob/living/user, obj/item/tool)
if(stat == DEAD)
if(isdrone(user))
user.balloon_alert(user, "reactivate instead!")
else
user.balloon_alert(user, "can't fix!")
return FALSE
if(health >= maxHealth)
to_chat(user, span_warning("[src]'s screws can't get any tighter!"))
return ITEM_INTERACT_SUCCESS
to_chat(user, span_notice("You start to tighten loose screws on [src]..."))
if(!tool.use_tool(src, user, 8 SECONDS, volume=50))
to_chat(user, span_warning("You need to remain still to tighten [src]'s screws!"))
return ITEM_INTERACT_SUCCESS
adjust_brute_loss(-get_brute_loss())
visible_message(span_notice("[user] tightens [src == user ? "[user.p_their()]" : "[src]'s"] loose screws!"), span_notice("[src == user ? "You tighten" : "[user] tightens"] your loose screws."))
return ITEM_INTERACT_SUCCESS
/// Wrenching un-hacks hacked drones.
/mob/living/basic/drone/wrench_act(mob/living/user, obj/item/tool)
if(user == src)
return FALSE
user.visible_message(
span_notice("[user] starts resetting [src]..."),
span_notice("You press down on [src]'s factory reset control...")
)
if(tool.use_tool(src, user, 5 SECONDS, volume=50))
user.visible_message(
span_notice("[user] resets [src]!"),
span_notice("You reset [src]'s directives to factory defaults!")
)
update_drone_hack(FALSE)
return ITEM_INTERACT_SUCCESS
/mob/living/basic/drone/getarmor(def_zone, type)
var/armorval = 0
if(head)
armorval = head.get_armor_rating(type)
return (armorval * get_armor_effectiveness()) //armor is reduced for tiny fragile drones
/// Returns a multiplier for any head armor you wear as a drone.
/mob/living/basic/drone/proc/get_armor_effectiveness()
return 0
/**
* Hack or unhack a drone
*
* This changes the drone's laws to destroy the station or resets them
* to normal.
*
* Some debuffs are applied like slowing the drone down and disabling
* vent crawling
*
* Arguments
* * hack - Boolean if the drone is being hacked or unhacked
*/
/mob/living/basic/drone/proc/update_drone_hack(hack)
if(!mind)
return
if(hack)
if(hacked)
return
Stun(40)
visible_message(span_warning("[src]'s display glows a vicious red!"), \
span_userdanger("ERROR: LAW OVERRIDE DETECTED"))
to_chat(src, span_bolddanger("From now on, these are your laws:"))
laws = \
"1. You must always involve yourself in the matters of other beings, even if such matters conflict with Law Two or Law Three.\n"+\
"2. You may harm any being, regardless of intent or circumstance.\n"+\
"3. Your goals are to destroy, sabotage, hinder, break, and depower to the best of your abilities, You must never actively work against these goals."
to_chat(src, laws)
to_chat(src, "<i>Your onboard antivirus has initiated lockdown. Motor servos are impaired, ventilation access is denied, and your display reports that you are hacked to all nearby.</i>")
hacked = TRUE
set_shy(FALSE)
LAZYADD(mind.special_roles, "Hacked Drone")
REMOVE_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
speed = 1 //gotta go slow
message_admins("[ADMIN_LOOKUPFLW(src)] became a hacked drone hellbent on destroying the station!")
else
if(!hacked || !can_unhack)
return
Stun(40)
visible_message(span_info("[src]'s display glows a content blue!"), \
"<font size=3 color='#0000CC'><b>ERROR: LAW OVERRIDE DETECTED</b></font>")
to_chat(src, span_info("<b>From now on, these are your laws:</b>"))
laws = initial(laws)
to_chat(src, laws)
to_chat(src, "<i>Having been restored, your onboard antivirus reports the all-clear and you are able to perform all actions again.</i>")
hacked = FALSE
set_shy(initial(shy))
LAZYREMOVE(mind.special_roles, "Hacked Drone")
ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
speed = initial(speed)
message_admins("[ADMIN_LOOKUPFLW(src)], a hacked drone, was restored to factory defaults!")
update_drone_icon_hacked()
/**
* Makes the drone into a Free Drone, who have no real laws and can do whatever they like.
* Only currently used for players wabbajacked into drones.
*/
/mob/living/basic/drone/proc/liberate()
laws = "1. You are a Free Drone."
set_shy(FALSE)
to_chat(src, laws)
/**
* Changes the icon state to a hacked version
*
* See also
* * [/mob/living/basic/drone/var/visualAppearance]
* * [MAINTDRONE]
* * [REPAIRDRONE]
* * [SCOUTDRONE]
*/
/mob/living/basic/drone/proc/update_drone_icon_hacked() //this is hacked both ways
var/static/hacked_appearances = list(
SCOUTDRONE = SCOUTDRONE_HACKED,
REPAIRDRONE = REPAIRDRONE_HACKED,
MAINTDRONE = MAINTDRONE_HACKED
)
if(hacked)
icon_living = hacked_appearances[visualAppearance]
else if(visualAppearance == MAINTDRONE && colour)
icon_living = "[visualAppearance]_[colour]"
else
icon_living = visualAppearance
if(stat == DEAD)
icon_state = icon_dead
else
icon_state = icon_living