mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-07-13 09:05:11 +01:00
7a3ad79506
## 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! /🆑
302 lines
11 KiB
Plaintext
302 lines
11 KiB
Plaintext
|
|
/**
|
|
* Maintenance Drone
|
|
*
|
|
* Small player controlled fixer-upper
|
|
*
|
|
* The maintenace drone is a ghost role with the objective to repair and
|
|
* maintain the station.
|
|
*
|
|
* Featuring two dexterous hands, and a built in toolbox stocked with
|
|
* tools.
|
|
*
|
|
* They have laws to prevent them from doing anything else.
|
|
*
|
|
*/
|
|
/mob/living/basic/drone
|
|
name = "Drone"
|
|
desc = "A maintenance drone, an expendable robot built to perform station repairs."
|
|
icon = 'icons/mob/silicon/drone.dmi'
|
|
icon_state = "drone_maint_grey"
|
|
icon_living = "drone_maint_grey"
|
|
icon_dead = "drone_maint_dead"
|
|
health = 45
|
|
maxHealth = 45
|
|
unsuitable_atmos_damage = 0
|
|
unsuitable_cold_damage = 0
|
|
unsuitable_heat_damage = 0
|
|
speed = 0
|
|
density = FALSE
|
|
pass_flags = PASSTABLE | PASSMOB
|
|
sight = SEE_TURFS | SEE_OBJS
|
|
status_flags = (CANPUSH | CANSTUN | CANKNOCKDOWN)
|
|
gender = NEUTER
|
|
mob_biotypes = MOB_ROBOTIC
|
|
speak_emote = list("chirps")
|
|
speech_span = SPAN_ROBOT
|
|
bubble_icon = "machine"
|
|
initial_language_holder = /datum/language_holder/drone
|
|
mob_size = MOB_SIZE_SMALL
|
|
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, STAMINA = 0, OXY = 0)
|
|
hud_possible = list(DIAG_STAT_HUD, DIAG_HUD, ANTAG_HUD)
|
|
unique_name = TRUE
|
|
faction = list(FACTION_NEUTRAL,FACTION_SILICON,FACTION_TURRET)
|
|
hud_type = /datum/hud/dextrous/drone
|
|
// Going for a sort of pale green here
|
|
lighting_cutoff_red = 30
|
|
lighting_cutoff_green = 35
|
|
lighting_cutoff_blue = 25
|
|
can_be_held = TRUE
|
|
worn_slot_flags = ITEM_SLOT_HEAD
|
|
inhand_holder_type = /obj/item/mob_holder/drone
|
|
/// `TRUE` if we have picked our visual appearance, `FALSE` otherwise (default)
|
|
var/picked = FALSE
|
|
/// Stored drone color, restored when unhacked
|
|
var/colour = "grey"
|
|
var/list/drone_overlays[DRONE_TOTAL_LAYERS]
|
|
/// Drone laws announced on spawn
|
|
var/laws = \
|
|
"1. You may not involve yourself in the matters of another being, even if such matters conflict with Law Two or Law Three, unless the other being is another Drone.\n"+\
|
|
"2. You may not harm any being, regardless of intent or circumstance.\n"+\
|
|
"3. Your goals are to actively build, maintain, repair, improve, and provide power to the best of your abilities within the facility that housed your activation." //for derelict drones so they don't go to station.
|
|
/// Amount of damage sustained if hit by a heavy EMP pulse
|
|
var/heavy_emp_damage = 25
|
|
///Alarm listener datum, handes caring about alarm events and such
|
|
var/datum/alarm_listener/listener
|
|
/// Internal storage slot. Fits any item
|
|
var/obj/item/internal_storage
|
|
/// Headwear slot
|
|
var/obj/item/head
|
|
/// Default [/mob/living/basic/drone/var/internal_storage] item
|
|
var/obj/item/default_storage = /obj/item/storage/drone_tools
|
|
/// Default [/mob/living/basic/drone/var/head] item
|
|
var/obj/item/default_headwear
|
|
///The camera built into the drone which allows it to be seen through cameras.
|
|
var/obj/machinery/camera/silicon/built_in_camera
|
|
/**
|
|
* icon_state of drone from icons/mobs/drone.dmi
|
|
*
|
|
* Possible states are:
|
|
*
|
|
* - [MAINTDRONE]
|
|
* - [REPAIRDRONE]
|
|
* - [SCOUTDRONE]
|
|
* - [CLOCKDRONE]
|
|
*/
|
|
var/visualAppearance = MAINTDRONE
|
|
/// Hacked state, see [/mob/living/basic/drone/proc/update_drone_hack]
|
|
var/hacked = FALSE
|
|
/// Whether this drone can be un-hacked. Used for subtypes that cannot be meaningfully "fixed".
|
|
var/can_unhack = TRUE
|
|
/// If we have laws to minimize bothering others. Enables or disables drone laws enforcement components (use [/mob/living/basic/drone/proc/set_shy] to set)
|
|
var/shy = TRUE
|
|
/// Flavor text announced to drones on [/mob/proc/Login]
|
|
var/flavortext = \
|
|
"\n<big><span class='warning'>DO NOT INTERFERE WITH THE ROUND AS A DRONE OR YOU WILL BE DRONE BANNED</span></big>\n"+\
|
|
"<span class='notice'>Drones are a ghost role that are allowed to fix the station and build things. Interfering with the round as a drone is against the rules.</span>\n"+\
|
|
"<span class='notice'>Actions that constitute interference include, but are not limited to:</span>\n"+\
|
|
"<span class='notice'> - Interacting with round critical objects (IDs, weapons, contraband, powersinks, bombs, etc.)</span>\n"+\
|
|
"<span class='notice'> - Interacting with living beings (communication, attacking, healing, etc.)</span>\n"+\
|
|
"<span class='notice'> - Interacting with non-living beings (dragging bodies, looting bodies, etc.)</span>\n"+\
|
|
"<span class='warning'>These rules are at admin discretion and will be heavily enforced.</span>\n"+\
|
|
"<span class='warning'><u>If you do not have the regular drone laws, follow your laws to the best of your ability.</u></span>\n"+\
|
|
"<span class='notice'>Prefix your message with :b to speak in Drone Chat.</span>\n"
|
|
|
|
/mob/living/basic/drone/Initialize(mapload)
|
|
. = ..()
|
|
GLOB.drones_list += src
|
|
AddElement(/datum/element/dextrous, hud_type = hud_type)
|
|
AddComponent(/datum/component/basic_inhands, y_offset = getItemPixelShiftY())
|
|
AddComponent(/datum/component/simple_access, SSid_access.get_region_access_list(list(REGION_ALL_GLOBAL)))
|
|
AddComponent(/datum/component/personal_crafting) // Kind of hard to be a drone and not be able to make tiles
|
|
LoadComponent(/datum/component/bloodysoles/bot)
|
|
|
|
// Only station drones get a camera.
|
|
if(is_station_level(src.loc.z))
|
|
built_in_camera = new(src)
|
|
built_in_camera.c_tag = real_name
|
|
built_in_camera.network = list(CAMERANET_NETWORK_SS13)
|
|
|
|
if(default_storage)
|
|
var/obj/item/storage = new default_storage(src)
|
|
equip_to_slot_or_del(storage, ITEM_SLOT_DEX_STORAGE)
|
|
|
|
for(var/holiday_name in GLOB.holidays)
|
|
var/datum/holiday/holiday_today = GLOB.holidays[holiday_name]
|
|
var/obj/item/potential_hat = holiday_today.holiday_hat
|
|
if(!isnull(potential_hat) && isnull(default_headwear)) //If our drone type doesn't start with a hat, we take the holiday one.
|
|
default_headwear = potential_hat
|
|
|
|
if(default_headwear)
|
|
var/obj/item/new_hat = new default_headwear(src)
|
|
equip_to_slot_or_del(new_hat, ITEM_SLOT_HEAD)
|
|
|
|
shy_update()
|
|
alert_drones(DRONE_NET_CONNECT)
|
|
|
|
var/datum/atom_hud/data/diagnostic/diag_hud = GLOB.huds[DATA_HUD_DIAGNOSTIC]
|
|
diag_hud.add_atom_to_hud(src)
|
|
|
|
add_traits(list(
|
|
TRAIT_VENTCRAWLER_ALWAYS,
|
|
TRAIT_NEGATES_GRAVITY,
|
|
TRAIT_LITERATE,
|
|
TRAIT_KNOW_ENGI_WIRES,
|
|
TRAIT_ADVANCEDTOOLUSER,
|
|
TRAIT_SILICON_ACCESS,
|
|
TRAIT_REAGENT_SCANNER,
|
|
TRAIT_UNOBSERVANT,
|
|
TRAIT_SILICON_EMOTES_ALLOWED,
|
|
), INNATE_TRAIT)
|
|
|
|
listener = new(list(ALARM_ATMOS, ALARM_FIRE, ALARM_POWER), list(z))
|
|
RegisterSignal(listener, COMSIG_ALARM_LISTENER_TRIGGERED, PROC_REF(alarm_triggered))
|
|
RegisterSignal(listener, COMSIG_ALARM_LISTENER_CLEARED, PROC_REF(alarm_cleared))
|
|
listener.RegisterSignal(src, COMSIG_LIVING_DEATH, TYPE_PROC_REF(/datum/alarm_listener, prevent_alarm_changes))
|
|
listener.RegisterSignal(src, COMSIG_LIVING_REVIVE, TYPE_PROC_REF(/datum/alarm_listener, allow_alarm_changes))
|
|
|
|
/mob/living/basic/drone/med_hud_set_health()
|
|
set_hud_image_state(DIAG_HUD, "huddiag[RoundDiagBar(health/maxHealth)]")
|
|
|
|
/mob/living/basic/drone/med_hud_set_status()
|
|
if(stat == DEAD)
|
|
set_hud_image_state(DIAG_STAT_HUD, "huddead2")
|
|
return
|
|
|
|
if(incapacitated)
|
|
set_hud_image_state(DIAG_STAT_HUD, "hudoffline")
|
|
return
|
|
|
|
set_hud_image_state(DIAG_STAT_HUD, "hudstat")
|
|
|
|
/mob/living/basic/drone/Destroy()
|
|
GLOB.drones_list -= src
|
|
QDEL_NULL(listener)
|
|
QDEL_NULL(built_in_camera)
|
|
return ..()
|
|
|
|
/mob/living/basic/drone/Login()
|
|
. = ..()
|
|
if(!. || !client)
|
|
return FALSE
|
|
check_laws()
|
|
|
|
if(flavortext)
|
|
to_chat(src, "[flavortext]")
|
|
|
|
if(!picked)
|
|
pickVisualAppearance()
|
|
|
|
/mob/living/basic/drone/auto_deadmin_on_login()
|
|
if(!client?.holder)
|
|
return TRUE
|
|
if(CONFIG_GET(flag/auto_deadmin_silicons) || (client.prefs?.toggles & DEADMIN_POSITION_SILICON))
|
|
return client.holder.auto_deadmin()
|
|
return ..()
|
|
|
|
/mob/living/basic/drone/death(gibbed)
|
|
..(gibbed)
|
|
if(internal_storage)
|
|
dropItemToGround(internal_storage)
|
|
if(head)
|
|
dropItemToGround(head)
|
|
|
|
alert_drones(DRONE_NET_DISCONNECT)
|
|
|
|
/mob/living/basic/drone/gib()
|
|
dust()
|
|
|
|
/mob/living/basic/drone/get_butt_sprite()
|
|
return icon('icons/mob/butts.dmi', BUTT_SPRITE_DRONE)
|
|
|
|
/mob/living/basic/drone/examine(mob/user)
|
|
. = list()
|
|
|
|
//Hands
|
|
for(var/obj/item/held_thing in held_items)
|
|
if((held_thing.item_flags & (ABSTRACT|HAND_ITEM)) || HAS_TRAIT(held_thing, TRAIT_EXAMINE_SKIP))
|
|
continue
|
|
. += "It has [held_thing.examine_title(user)] in its [get_held_index_name(get_held_index_of_item(held_thing))]."
|
|
|
|
//Internal storage
|
|
if(internal_storage && !(internal_storage.item_flags & ABSTRACT))
|
|
. += "It is holding [internal_storage.examine_title(user)] in its internal storage."
|
|
|
|
//Cosmetic hat - provides no function other than looks
|
|
if(head && !(head.item_flags & ABSTRACT))
|
|
. += "It is wearing [head.examine_title(user)] on its head."
|
|
|
|
//Braindead
|
|
if(!client && stat != DEAD)
|
|
. += "Its status LED is blinking at a steady rate."
|
|
|
|
//Hacked
|
|
if(hacked)
|
|
. += span_warning("Its display is glowing red!")
|
|
|
|
//Damaged
|
|
if(health != maxHealth)
|
|
if(health > maxHealth * 0.33) //Between maxHealth and about a third of maxHealth, between 30 and 10 for normal drones
|
|
. += span_warning("Its screws are slightly loose.")
|
|
else //otherwise, below about 33%
|
|
. += span_boldwarning("Its screws are very loose!")
|
|
|
|
//Dead
|
|
if(stat == DEAD)
|
|
if(client)
|
|
. += span_deadsay("A message repeatedly flashes on its display: \"REBOOT -- REQUIRED\".")
|
|
else
|
|
. += span_deadsay("A message repeatedly flashes on its display: \"ERROR -- OFFLINE\".")
|
|
|
|
/mob/living/basic/drone/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null) //Secbots won't hunt maintenance drones.
|
|
return -10
|
|
|
|
/mob/living/basic/drone/emp_act(severity)
|
|
. = ..()
|
|
if(. & EMP_PROTECT_SELF)
|
|
return
|
|
Stun(70)
|
|
to_chat(src, span_danger("<b>ER@%R: MME^RY CO#RU9T!</b> R&$b@0tin)..."))
|
|
if(severity == 1)
|
|
adjust_brute_loss(heavy_emp_damage)
|
|
to_chat(src, span_userdanger("HeAV% DA%^MMA+G TO I/O CIR!%UUT!"))
|
|
|
|
/mob/living/basic/drone/proc/alarm_triggered(datum/source, alarm_type, area/source_area)
|
|
SIGNAL_HANDLER
|
|
to_chat(src, "--- [alarm_type] alarm detected in [source_area.name]!")
|
|
|
|
/mob/living/basic/drone/proc/alarm_cleared(datum/source, alarm_type, area/source_area)
|
|
SIGNAL_HANDLER
|
|
to_chat(src, "--- [alarm_type] alarm in [source_area.name] has been cleared.")
|
|
|
|
/mob/living/basic/drone/proc/set_shy(new_shy)
|
|
shy = new_shy
|
|
shy_update()
|
|
|
|
/mob/living/basic/drone/proc/shy_update()
|
|
if(shy)
|
|
REMOVE_TRAIT(src, TRAIT_CAN_STRIP, DRONE_SHY_TRAIT) // To shy to touch someone elses hat
|
|
ADD_TRAIT(src, TRAIT_PACIFISM, DRONE_SHY_TRAIT)
|
|
else
|
|
ADD_TRAIT(src, TRAIT_CAN_STRIP, DRONE_SHY_TRAIT) // ...I wonder if I can ware pants like a hat
|
|
REMOVE_TRAIT(src, TRAIT_PACIFISM, DRONE_SHY_TRAIT)
|
|
|
|
/mob/living/basic/drone/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /atom/movable/screen/fullscreen/flash, length = 25)
|
|
if(affect_silicon)
|
|
return ..()
|
|
|
|
/mob/living/basic/drone/bee_friendly()
|
|
// Why would bees pay attention to drones?
|
|
return TRUE
|
|
|
|
/mob/living/basic/drone/electrocute_act(shock_damage, source, siemens_coeff, flags = NONE)
|
|
return FALSE //So they don't die trying to fix wiring
|
|
|
|
/mob/living/basic/drone/can_track(mob/living/user)
|
|
if(built_in_camera?.can_use())
|
|
return TRUE
|
|
return ..()
|
|
|
|
/mob/living/basic/drone/hypnosis_vulnerable()
|
|
return FALSE //It obeys its laws
|