mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-07-10 15:45:05 +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! /🆑
159 lines
6.3 KiB
Plaintext
159 lines
6.3 KiB
Plaintext
/// Checks to ensure strange reagent works as expected
|
|
/datum/unit_test/strange_reagent
|
|
priority = TEST_LONGER
|
|
|
|
var/datum/reagent/medicine/strange_reagent/instant/strange_reagent
|
|
var/target_max_health
|
|
var/amount_needed_to_full_heal
|
|
var/amount_needed_to_revive
|
|
|
|
/datum/unit_test/strange_reagent/Run()
|
|
strange_reagent = new
|
|
|
|
var/list/types_to_check = typecacheof(list(
|
|
/mob/living/carbon/human/consistent,
|
|
/mob/living/simple_animal,
|
|
/mob/living/basic,
|
|
))
|
|
types_to_check -= typesof(/mob/living/simple_animal/hostile/megafauna) // no
|
|
types_to_check -= typesof(/mob/living/basic/mouse) // qdel themselves on death; why dont they use DEL_ON_DEATH you might ask. I-unno
|
|
types_to_check -= typesof(/mob/living/basic/slime) // if they roll the 50% chance to spawn as an adult, they can just at random split and qdel themselves
|
|
|
|
for(var/mob/living/type as anything in types_to_check)
|
|
var/mob/living/target = allocate_new_target(type)
|
|
var/is_basic = istype(target, /mob/living/basic)
|
|
var/is_simple = istype(target, /mob/living/simple_animal)
|
|
// check some basic stuff
|
|
if(HAS_TRAIT(target, TRAIT_GODMODE))
|
|
continue
|
|
if(!(target.mob_biotypes & MOB_ORGANIC))
|
|
continue
|
|
|
|
if(is_simple)
|
|
var/mob/living/simple_animal/simple_animal = target
|
|
if(simple_animal.del_on_death)
|
|
continue
|
|
simple_animal.loot?.Cut()
|
|
|
|
if(is_basic)
|
|
var/mob/living/basic/basic = target
|
|
if(basic.basic_mob_flags & DEL_ON_DEATH)
|
|
continue
|
|
|
|
test_damage_but_no_death(type)
|
|
test_death_no_damage(type)
|
|
test_death_with_damage(type)
|
|
test_death_with_damage_but_not_enough_reagent(type)
|
|
if(!is_basic && !is_simple) // simple/basic mobs cannot have negative health
|
|
test_death_with_full_heal(type)
|
|
test_death_from_damage(type)
|
|
test_death_from_too_much_damage(type)
|
|
// cleanup our vars
|
|
QDEL_NULL(strange_reagent)
|
|
allocate_new_target(null)
|
|
|
|
/datum/unit_test/strange_reagent/proc/allocate_new_target(type)
|
|
// cache the last one created so that we don't create N instances of the exact same mob
|
|
var/static/mob/living/pre_allocated
|
|
if(!type)
|
|
pre_allocated = null
|
|
return
|
|
|
|
if(pre_allocated?.type == type)
|
|
pre_allocated.revive(ALL) // for some reason HEAL_ADMIN doesn't work?
|
|
return pre_allocated
|
|
|
|
pre_allocated = allocate(type)
|
|
target_max_health = pre_allocated.getMaxHealth()
|
|
update_amounts(pre_allocated)
|
|
return pre_allocated
|
|
|
|
/datum/unit_test/strange_reagent/proc/update_amounts(mob/living/target)
|
|
amount_needed_to_full_heal = strange_reagent.calculate_amount_needed_to_full_heal(target)
|
|
amount_needed_to_revive = strange_reagent.calculate_amount_needed_to_revive(target)
|
|
|
|
/datum/unit_test/strange_reagent/proc/damage_target_to_percentage(mob/living/target, percent)
|
|
var/damage = target_max_health * percent * 0.5
|
|
target.set_brute_loss(damage, updating_health=FALSE) // no point running health update logic here
|
|
target.set_fire_loss(damage, updating_health=TRUE) // since we do it here
|
|
update_amounts(target)
|
|
if(percent >= 1)
|
|
target.death()
|
|
return TRUE
|
|
|
|
/datum/unit_test/strange_reagent/proc/get_target_organic_health_manual(mob/living/target)
|
|
return target.getMaxHealth() - (target.get_brute_loss() + target.get_fire_loss())
|
|
|
|
/datum/unit_test/strange_reagent/proc/test_damage_but_no_death(target_type)
|
|
var/mob/living/target = allocate_new_target(target_type)
|
|
if(!damage_target_to_percentage(target, 0.8))
|
|
return
|
|
|
|
var/health = get_target_organic_health_manual(target)
|
|
strange_reagent.expose_mob(target, INGEST, 20)
|
|
TEST_ASSERT_EQUAL(health, get_target_organic_health_manual(target), "Strange Reagent healed a target type [target.type] that was not dead.")
|
|
|
|
/datum/unit_test/strange_reagent/proc/test_death_no_damage(target_type)
|
|
var/mob/living/target = allocate_new_target(target_type)
|
|
target.death()
|
|
if(QDELETED(target))
|
|
return
|
|
update_amounts(target)
|
|
strange_reagent.expose_mob(target, INGEST, amount_needed_to_revive)
|
|
TEST_ASSERT_NOTEQUAL(target.stat, DEAD, "Strange Reagent did not revive a dead target type [target.type].")
|
|
|
|
/datum/unit_test/strange_reagent/proc/test_death_with_damage(target_type)
|
|
var/mob/living/target = allocate_new_target(target_type)
|
|
if(!damage_target_to_percentage(target, 0.8))
|
|
return
|
|
|
|
target.death()
|
|
if(QDELETED(target))
|
|
return
|
|
update_amounts(target)
|
|
strange_reagent.expose_mob(target, INGEST, amount_needed_to_revive)
|
|
TEST_ASSERT_NOTEQUAL(target.stat, DEAD, "Strange Reagent did not revive a dead target type [target.type].")
|
|
|
|
/datum/unit_test/strange_reagent/proc/test_death_with_damage_but_not_enough_reagent(target_type)
|
|
var/mob/living/target = allocate_new_target(target_type)
|
|
if(!damage_target_to_percentage(target, 1.2))
|
|
return
|
|
|
|
update_amounts(target)
|
|
strange_reagent.expose_mob(target, INGEST, amount_needed_to_revive - 1)
|
|
TEST_ASSERT_EQUAL(target.stat, DEAD, "Strange Reagent revived a dead target type [target.type] without enough reagent.")
|
|
|
|
/datum/unit_test/strange_reagent/proc/test_death_with_full_heal(target_type)
|
|
var/mob/living/target = allocate_new_target(target_type)
|
|
if(!damage_target_to_percentage(target, 0.8))
|
|
return
|
|
|
|
target.death()
|
|
if(QDELETED(target))
|
|
return
|
|
update_amounts(target)
|
|
strange_reagent.expose_mob(target, INGEST, amount_needed_to_full_heal)
|
|
TEST_ASSERT_EQUAL(target_max_health, get_target_organic_health_manual(target), "Strange Reagent did not fully heal a dead target type [target.type] with the expected amount.")
|
|
|
|
/datum/unit_test/strange_reagent/proc/test_death_from_damage(target_type)
|
|
var/mob/living/target = allocate_new_target(target_type)
|
|
if(!damage_target_to_percentage(target, strange_reagent.max_revive_damage_ratio * 0.9)) // 10% under the damage cap
|
|
return
|
|
if(QDELETED(target))
|
|
return
|
|
|
|
update_amounts(target)
|
|
strange_reagent.expose_mob(target, INGEST, amount_needed_to_revive)
|
|
TEST_ASSERT_NOTEQUAL(target.stat, DEAD, "Strange Reagent did not revive a target type [target.type] who died from damage.")
|
|
|
|
/datum/unit_test/strange_reagent/proc/test_death_from_too_much_damage(target_type)
|
|
var/mob/living/target = allocate_new_target(target_type)
|
|
if(!damage_target_to_percentage(target, strange_reagent.max_revive_damage_ratio * 1.1)) // 10% over the damage cap
|
|
return
|
|
if(QDELETED(target))
|
|
return
|
|
|
|
update_amounts(target)
|
|
strange_reagent.expose_mob(target, INGEST, amount_needed_to_revive)
|
|
TEST_ASSERT_EQUAL(target.stat, DEAD, "Strange Reagent revived a target type [target.type] with more than double their max health in damage.")
|