mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-23 13:10:02 +01:00
## 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! /🆑
292 lines
12 KiB
Plaintext
292 lines
12 KiB
Plaintext
GLOBAL_LIST_EMPTY(heretic_arenas)
|
|
|
|
// Invisible effect that doesnt exist outside of containing the prox monitor
|
|
/obj/effect/abstract/heretic_arena
|
|
icon = null
|
|
icon_state = null
|
|
alpha = 0
|
|
invisibility = INVISIBILITY_ABSTRACT
|
|
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
|
anchored = TRUE
|
|
resistance_flags = INDESTRUCTIBLE
|
|
/// Proximity monitor that handles the effects we are looking for
|
|
var/datum/proximity_monitor/advanced/heretic_arena/arena
|
|
|
|
/obj/effect/abstract/heretic_arena/Initialize(mapload, range, duration, caster)
|
|
. = ..()
|
|
arena = new(src, range)
|
|
QDEL_IN(src, duration)
|
|
arena.set_caster(caster)
|
|
GLOB.heretic_arenas += src
|
|
|
|
/obj/effect/abstract/heretic_arena/Destroy(force)
|
|
QDEL_NULL(arena)
|
|
GLOB.heretic_arenas -= src
|
|
. = ..()
|
|
|
|
/datum/proximity_monitor/advanced/heretic_arena
|
|
/// Reference to the caster, the spell collapses if they leave the arena
|
|
var/arena_caster
|
|
/// List of mobs inside our arena
|
|
var/list/contained_mobs = list()
|
|
/// List of border walls we have placed on the edges of the monitor
|
|
var/list/border_walls = list()
|
|
/// List of blades we've so generously handed out to the participants
|
|
var/list/welfare_blades = list()
|
|
/// List of immunities given to our combatants
|
|
var/static/list/given_immunities = list(
|
|
TRAIT_BOMBIMMUNE,
|
|
TRAIT_IGNORESLOWDOWN,
|
|
TRAIT_NO_SLIP_ALL,
|
|
TRAIT_NOBREATH,
|
|
TRAIT_PIERCEIMMUNE,
|
|
TRAIT_PUSHIMMUNE,
|
|
TRAIT_RADIMMUNE,
|
|
TRAIT_RESISTCOLD,
|
|
TRAIT_RESISTHEAT,
|
|
TRAIT_RESISTHIGHPRESSURE,
|
|
TRAIT_RESISTLOWPRESSURE,
|
|
TRAIT_SHOCKIMMUNE,
|
|
TRAIT_SLEEPIMMUNE,
|
|
TRAIT_STUNIMMUNE,
|
|
TRAIT_FORCED_GRAVITY,
|
|
)
|
|
|
|
/datum/proximity_monitor/advanced/heretic_arena/New(atom/_host, range, _ignore_if_not_on_turf)
|
|
. = ..()
|
|
recalculate_field(full_recalc = TRUE)
|
|
var/list/things_in_range = range(range)
|
|
for(var/mob/living/carbon/human/human_in_range in things_in_range)
|
|
human_in_range.add_traits(given_immunities, HERETIC_ARENA_TRAIT)
|
|
contained_mobs += human_in_range
|
|
if(!IS_HERETIC(human_in_range))
|
|
var/obj/item/melee/sickly_blade/training/new_blade = new(get_turf(human_in_range))
|
|
welfare_blades += new_blade
|
|
INVOKE_ASYNC(human_in_range, TYPE_PROC_REF(/mob, put_in_hands), new_blade)
|
|
to_chat(human_in_range, span_boldbig("Escape is impossible. The only way out is to defeat another participant in this battle to the death."))
|
|
human_in_range.balloon_alert(human_in_range, "start killing!")
|
|
human_in_range.apply_status_effect(/datum/status_effect/arena_tracker)
|
|
RegisterSignal(human_in_range, COMSIG_CAN_Z_MOVE, PROC_REF(on_try_z_move))
|
|
RegisterSignal(human_in_range, COMSIG_LADDER_TRAVEL, PROC_REF(on_try_ladder))
|
|
RegisterSignal(human_in_range, COMSIG_MOVABLE_PRE_MOVE, PROC_REF(on_pre_move))
|
|
RegisterSignal(human_in_range, COMSIG_MOVABLE_POST_TELEPORT, PROC_REF(on_teleport))
|
|
|
|
/datum/proximity_monitor/advanced/heretic_arena/Destroy()
|
|
for(var/mob/living/carbon/human/mob in contained_mobs)
|
|
mob.remove_traits(given_immunities, HERETIC_ARENA_TRAIT)
|
|
mob.remove_status_effect(/datum/status_effect/arena_tracker)
|
|
UnregisterSignal(mob, list(COMSIG_CAN_Z_MOVE, COMSIG_LADDER_TRAVEL, COMSIG_MOVABLE_PRE_MOVE, COMSIG_MOVABLE_POST_TELEPORT))
|
|
to_chat(mob, span_boldbig("Your bloodlust is sated."))
|
|
mob.balloon_alert(mob, "escape the arena!")
|
|
for(var/turf/to_restore in border_walls)
|
|
to_restore.ChangeTurf(border_walls[to_restore])
|
|
for(var/obj/to_refund as anything in welfare_blades)
|
|
qdel(to_refund)
|
|
arena_caster = null
|
|
return ..()
|
|
|
|
/datum/proximity_monitor/advanced/heretic_arena/setup_edge_turf(turf/target)
|
|
. = ..()
|
|
var/old_turf = target.type
|
|
target.ChangeTurf(/turf/closed/indestructible/heretic_wall)
|
|
border_walls += target
|
|
border_walls[target] += old_turf
|
|
|
|
/datum/proximity_monitor/advanced/heretic_arena/field_edge_uncrossed(atom/movable/movable, turf/old_location, turf/new_location)
|
|
if(!isliving(movable))
|
|
return
|
|
var/mob/living/living_mob = movable
|
|
addtimer(CALLBACK(living_mob, TYPE_PROC_REF(/mob/living, remove_status_effect), /datum/status_effect/arena_tracker), 10 SECONDS)
|
|
living_mob.remove_traits(given_immunities, HERETIC_ARENA_TRAIT)
|
|
if(living_mob == arena_caster)
|
|
QDEL_IN(host, 3 SECONDS)
|
|
|
|
/// Prevents using ladders
|
|
/datum/proximity_monitor/advanced/heretic_arena/proc/on_try_ladder(mob/climber)
|
|
SIGNAL_HANDLER
|
|
return LADDER_TRAVEL_BLOCK
|
|
|
|
/// If we try to enter a space turf that has a mirage, we will block the movement
|
|
/datum/proximity_monitor/advanced/heretic_arena/proc/on_pre_move(atom/movable/mover, atom/newloc)
|
|
if(locate(/atom/movable/mirage_holder) in newloc.contents)
|
|
return COMPONENT_MOVABLE_BLOCK_PRE_MOVE
|
|
|
|
/// Blocks Z movement to new z levels
|
|
/datum/proximity_monitor/advanced/heretic_arena/proc/on_try_z_move(atom/movable/source, turf/start, turf/destination)
|
|
SIGNAL_HANDLER
|
|
if(start.z == destination.z)
|
|
return
|
|
return COMPONENT_CANT_Z_MOVE
|
|
|
|
/// If our caster teleports away (after winning presumably) we'll collapse the arena so that it doens't needlessly linger
|
|
/datum/proximity_monitor/advanced/heretic_arena/proc/on_teleport(atom/teleportee, atom/destination, channel)
|
|
if(teleportee == arena_caster)
|
|
qdel(host)
|
|
|
|
/datum/proximity_monitor/advanced/heretic_arena/proc/set_caster(atom/caster)
|
|
arena_caster = caster
|
|
|
|
/turf/closed/indestructible/heretic_wall
|
|
name = "eldritch wall"
|
|
desc = "A wall penning in the sheep amongst the wolves. It glows with malevolent energy - prodding it is likely unwise."
|
|
icon = 'icons/turf/walls.dmi'
|
|
icon_state = "eldritch_forcewall"
|
|
opacity = FALSE
|
|
pass_flags_self = NONE // No PASSCLOSEDTURF because only arena victors are allowed to go in or out
|
|
|
|
/turf/closed/indestructible/heretic_wall/CanAllowThrough(atom/movable/mover, border_dir)
|
|
if(isliving(mover))
|
|
var/mob/living/living_mover = mover
|
|
var/datum/status_effect/arena_tracker/tracker = living_mover.has_status_effect(/datum/status_effect/arena_tracker)
|
|
if(tracker?.arena_victor)
|
|
return TRUE
|
|
return ..()
|
|
|
|
/turf/closed/indestructible/heretic_wall/Bumped(atom/movable/bumped_atom)
|
|
. = ..()
|
|
if(!isliving(bumped_atom))
|
|
return
|
|
var/mob/living/living_mob = bumped_atom
|
|
var/atom/target = get_edge_target_turf(living_mob, get_dir(src, get_step_away(living_mob, src)))
|
|
living_mob.throw_at(target, 4, 5)
|
|
to_chat(living_mob, span_userdanger("The wall repels you with tremendous force!"))
|
|
|
|
/// Called when you crit somebody to update your crown
|
|
/datum/status_effect/arena_tracker/proc/on_crit_somebody()
|
|
owner.cut_overlay(crown_overlay)
|
|
crown_overlay = mutable_appearance('icons/mob/effects/crown.dmi', "arena_victor", -HALO_LAYER)
|
|
crown_overlay.pixel_z = 24
|
|
owner.add_overlay(crown_overlay)
|
|
owner.remove_traits(list(TRAIT_ELDRITCH_ARENA_PARTICIPANT, TRAIT_NO_TELEPORT), TRAIT_STATUS_EFFECT(id))
|
|
|
|
// The mansus celebrates your efforts
|
|
if(IS_HERETIC(owner))
|
|
owner.heal_overall_damage(60, 60, 60)
|
|
owner.adjust_tox_loss(-60, forced = TRUE) // Slime heretics everywhere...
|
|
owner.adjust_oxy_loss(-60)
|
|
if(iscarbon(owner))
|
|
var/mob/living/carbon/carbon_owner = owner
|
|
for(var/datum/wound/wound as anything in carbon_owner.all_wounds)
|
|
wound.remove_wound()
|
|
|
|
if(arena_victor) // No need to spam if we've already killed at least 1 person
|
|
return
|
|
if(IS_HERETIC(owner))
|
|
to_chat(owner, span_big(span_hypnophrase("The mansus is pleased with your performance, you may leave now.")))
|
|
else
|
|
to_chat(owner, span_big(span_hypnophrase("You have done well, you may leave now.")))
|
|
arena_victor = TRUE
|
|
|
|
/**
|
|
* Status applied to every mob in the heretic arena.
|
|
* Tracks the last person to damage owner.
|
|
* When owner enters crit, we send a signal to last_attacker status so they can leave the arena
|
|
*/
|
|
|
|
/datum/status_effect/arena_tracker
|
|
id = "arena_tracker"
|
|
duration = STATUS_EFFECT_PERMANENT
|
|
tick_interval = STATUS_EFFECT_NO_TICK
|
|
status_type = STATUS_EFFECT_UNIQUE
|
|
alert_type = null
|
|
/// Tracks the last person who dealt damage to this mob
|
|
var/datum/weakref/last_attacker
|
|
/// If our mob is free to leave, set to true
|
|
var/arena_victor = FALSE
|
|
/// The overlay for our mob, changes color to indicate that they are a victor and are free to leave
|
|
var/mutable_appearance/crown_overlay
|
|
|
|
/datum/status_effect/arena_tracker/on_apply()
|
|
RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_CRITICAL_CONDITION), PROC_REF(on_enter_crit))
|
|
RegisterSignal(owner, COMSIG_MOVABLE_IMPACT_ZONE, PROC_REF(on_impact_zone))
|
|
RegisterSignal(owner, COMSIG_MOB_APPLY_DAMAGE, PROC_REF(damage_taken))
|
|
owner.add_traits(list(TRAIT_ELDRITCH_ARENA_PARTICIPANT, TRAIT_NO_TELEPORT), TRAIT_STATUS_EFFECT(id))
|
|
crown_overlay = mutable_appearance('icons/mob/effects/crown.dmi', "arena_fighter", -HALO_LAYER)
|
|
crown_overlay.pixel_z = 24
|
|
owner.add_overlay(crown_overlay)
|
|
return TRUE
|
|
|
|
/datum/status_effect/arena_tracker/on_remove()
|
|
UnregisterSignal(owner, list(SIGNAL_ADDTRAIT(TRAIT_CRITICAL_CONDITION), COMSIG_MOB_APPLY_DAMAGE))
|
|
owner.remove_traits(list(TRAIT_ELDRITCH_ARENA_PARTICIPANT, TRAIT_NO_TELEPORT), TRAIT_STATUS_EFFECT(id))
|
|
owner.cut_overlay(crown_overlay)
|
|
crown_overlay = null
|
|
|
|
// If our last attacker is an arena participant, we let them know they've scored a critical hit
|
|
/datum/status_effect/arena_tracker/proc/on_enter_crit(mob/owner)
|
|
SIGNAL_HANDLER
|
|
if(!last_attacker)
|
|
return // Safety check in case they somehow enter crit with *nobody* attacking them
|
|
var/mob/living/our_attacker = last_attacker.resolve()
|
|
if(!isliving(our_attacker) || our_attacker == owner) // We don't allow people to crit themselves as a valid way to escape
|
|
return
|
|
var/datum/status_effect/arena_tracker/their_tracker = our_attacker.has_status_effect(/datum/status_effect/arena_tracker)
|
|
if(!their_tracker)
|
|
return // Somebody killed us who isn't an arena participant
|
|
their_tracker.on_crit_somebody()
|
|
|
|
/datum/status_effect/arena_tracker/proc/damage_taken(
|
|
datum/source,
|
|
damage_amount,
|
|
damagetype,
|
|
def_zone,
|
|
blocked,
|
|
wound_bonus,
|
|
exposed_wound_bonus,
|
|
sharpness,
|
|
attack_direction,
|
|
attacking_item,
|
|
wound_clothing,
|
|
)
|
|
SIGNAL_HANDLER
|
|
if(isnull(attacking_item))
|
|
return
|
|
if(!isobj(attacking_item))
|
|
return
|
|
var/obj/attacking_object = attacking_item
|
|
|
|
// Track being hit by a mob holding a stick
|
|
if(ismob(attacking_object.loc))
|
|
last_attacker = WEAKREF(attacking_object.loc)
|
|
return
|
|
|
|
// Edge case. If our attacking_item is a gun which the owner has dropped we need to find out who shot us
|
|
// Track being hit by a mob shooting a stick
|
|
if(isprojectile(attacking_object))
|
|
var/obj/projectile/attacking_projectile = attacking_object
|
|
if(ismob(attacking_projectile.firer))
|
|
last_attacker = WEAKREF(attacking_projectile.firer)
|
|
|
|
///Called when impacted by something thrown at us, setting the last attacker to the person throwing the item.
|
|
/datum/status_effect/arena_tracker/proc/on_impact_zone(atom/source, mob/living/hitby, zone, blocked, datum/thrownthing/throwingdatum)
|
|
SIGNAL_HANDLER
|
|
// Track being hit by a mob throwing a stick
|
|
if(!isitem(throwingdatum.thrownthing))
|
|
return
|
|
var/thrown_by = throwingdatum?.get_thrower()
|
|
if(ismob(thrown_by))
|
|
last_attacker = WEAKREF(thrown_by)
|
|
|
|
/datum/antagonist/heretic_arena_participant
|
|
name = "Arena Participant"
|
|
show_in_roundend = FALSE
|
|
replace_banned = FALSE
|
|
objectives = list()
|
|
antag_hud_name = "brainwashed"
|
|
antag_flags = ANTAG_FAKE
|
|
|
|
/datum/antagonist/heretic_arena_participant/on_gain()
|
|
forge_objectives()
|
|
return ..()
|
|
|
|
/datum/antagonist/heretic_arena_participant/forge_objectives()
|
|
var/datum/objective/survive = new /datum/objective
|
|
survive.owner = owner
|
|
survive.explanation_text = "You have been trapped in an arena. The only way out is to slaughter someone else. Kill your captor, or betray your friends - the choice is yours."
|
|
objectives += survive
|
|
var/datum/objective/fight_to_escape = new /datum/objective
|
|
fight_to_escape.owner = owner
|
|
fight_to_escape.explanation_text = "Escape is impossible. The only way out is to defeat another participant in this battle to the death. \
|
|
A weapon has been bestowed unto you, granting you a fighting chance, it would be quite a shame were you to attempt to break it."
|
|
objectives += fight_to_escape
|