// SPDX-FileCopyrightText: 2025 Aiden <28298836+Aidenkrz@users.noreply.github.com> // SPDX-FileCopyrightText: 2025 Aviu00 <93730715+Aviu00@users.noreply.github.com> // SPDX-FileCopyrightText: 2025 Aviu00 // SPDX-FileCopyrightText: 2025 GoobBot // SPDX-FileCopyrightText: 2025 Misandry // SPDX-FileCopyrightText: 2025 gus // // SPDX-License-Identifier: AGPL-3.0-or-later using System.Linq; using Content.Shared._White.Blink; using Content.Shared.Damage; using Content.Shared.Damage.Systems; using Content.Shared.Electrocution; using Content.Shared.Examine; using Content.Shared.Hands.EntitySystems; using Content.Shared.StatusEffect; using Content.Shared.Timing; using Content.Shared.UserInterface; using Content.Shared.Weapons.Melee; using Robust.Shared.Audio.Systems; using Robust.Shared.Prototypes; namespace Content.Shared._Shitcode.Wizard.Spellblade; public abstract class SharedSpellbladeSystem : EntitySystem { [Dependency] protected readonly UseDelaySystem UseDelay = default!; [Dependency] protected readonly SharedAudioSystem Audio = default!; [Dependency] private readonly IPrototypeManager _protoManager = default!; [Dependency] private readonly SharedHandsSystem _hands = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnMessage); SubscribeLocalEvent(OnExamine); SubscribeLocalEvent(OnOpenAttempt); SubscribeLocalEvent(OnLightning); SubscribeLocalEvent(OnBluespace); SubscribeLocalEvent(OnFire); SubscribeLocalEvent(OnSpacetime); SubscribeLocalEvent(OnForceshield); SubscribeLocalEvent(OnElectrocutionAttempt); SubscribeLocalEvent(OnBeforeStaminaDamage); SubscribeLocalEvent(OnBeforeStatusEffect); SubscribeLocalEvent(OnDamageModify); } private void OnDamageModify(Entity ent, ref DamageModifyEvent args) { args.Damage = DamageSpecifier.ApplyModifierSet(args.Damage, DamageSpecifier.PenetrateArmor(ent.Comp.Resistances, args.ArmorPenetration)); } private void OnBeforeStatusEffect(Entity ent, ref BeforeStatusEffectAddedEvent args) { if (!ent.Comp.AntiStun || args.Key is not ("Stun")) return; args.Cancelled = true; } private void OnBeforeStaminaDamage(Entity ent, ref BeforeStaminaDamageEvent args) { if (ent.Comp.AntiStun) args.Cancelled = true; } private void OnForceshield(Entity ent, ref ForceshieldSpellbladeEnchantmentEvent args) { var enchant = EnsureComp(ent); enchant.ShieldLifetime = args.ShieldLifetime; } private void OnSpacetime(Entity ent, ref SpacetimeSpellbladeEnchantmentEvent args) { EnsureComp(ent); if (!TryComp(ent, out MeleeWeaponComponent? weapon) || args.MeleeMultiplier <= 0f) return; weapon.AttackRate *= args.MeleeMultiplier; weapon.HeavyStaminaCost /= args.MeleeMultiplier; weapon.Damage /= args.MeleeMultiplier; Dirty(ent.Owner, weapon); } private void OnFire(Entity ent, ref FireSpellbladeEnchantmentEvent args) { var enchant = EnsureComp(ent); enchant.FireStacks = args.FireStacks; enchant.Range = args.Range; UseDelay.SetLength(ent.Owner, args.Delay); AddIgniteOnMeleeHitComponent(ent, args.FireStacksOnHit); } protected virtual void AddIgniteOnMeleeHitComponent(EntityUid uid, float fireStacks) { } private void OnBluespace(Entity ent, ref BluespaceSpellbladeEnchantmentEvent args) { var blink = EnsureComp(ent); blink.Distance = args.Distance; blink.KnockdownTime = args.KnockdownTime; blink.KnockdownRadius = args.KnockdownRadius; Dirty(ent.Owner, blink); UseDelay.SetLength(ent.Owner, args.ToggleDelay); UseDelay.SetLength(ent.Owner, args.BlinkDelay, blink.BlinkDelay); } private void OnLightning(Entity ent, ref LightningSpellbladeEnchantmentEvent args) { var enchant = EnsureComp(ent); enchant.ShockDamage = args.ShockDamage; enchant.ShockTime = args.ShockTime; enchant.Range = args.Range; enchant.Siemens = args.Siemens; enchant.ArcDepth = args.ArcDepth; enchant.BoltCount = args.BoltCount; enchant.LightningPrototype = args.LightningPrototype; UseDelay.SetLength(ent.Owner, args.Delay); } private void OnElectrocutionAttempt(ElectrocutionAttemptEvent ev) { if (IsHoldingItemWithComponent(ev.TargetUid)) ev.Cancel(); } private void OnOpenAttempt(Entity ent, ref ActivatableUIOpenAttemptEvent args) { if (ent.Comp.EnchantmentName == null || args.Cancelled) return; args.Cancel(); } private void OnExamine(Entity ent, ref ExaminedEvent args) { var comp = ent.Comp; if (comp.EnchantmentName == null) return; var name = Loc.GetString(comp.EnchantmentName); args.PushMarkup(Loc.GetString("spellblade-examine-enchantment", ("name", name))); } private void OnMessage(Entity ent, ref SpellbladeEnchantMessage args) { var (uid, comp) = ent; if (comp.EnchantmentName != null) return; if (!_protoManager.TryIndex(args.ProtoId, out var proto)) return; Audio.PlayPredicted(comp.EnchantSound, uid, args.Actor); comp.EnchantmentName = proto.Name; Dirty(ent); if (proto.Event != null) RaiseLocalEvent(uid, proto.Event); } public bool IsHoldingItemWithComponent(EntityUid user) where T : Component { return _hands.EnumerateHeld(user).Any(HasComp); } }