using System.Text; using Content.Shared._CP14.MagicEnergy; using Content.Shared._CP14.MagicEnergy.Components; using Content.Shared._CP14.MagicSpell.Components; using Content.Shared._CP14.MagicSpell.Events; using Content.Shared._CP14.MagicSpell.Spells; using Content.Shared._CP14.MagicSpellStorage; using Content.Shared.Actions; using Content.Shared.DoAfter; using Content.Shared.FixedPoint; using Content.Shared.Movement.Systems; using Content.Shared.Popups; using Robust.Shared.Network; using Robust.Shared.Prototypes; using Robust.Shared.Random; namespace Content.Shared._CP14.MagicSpell; /// /// This system handles the basic mechanics of spell use, such as doAfter, event invocation, and energy spending. /// public abstract partial class CP14SharedMagicSystem : EntitySystem { [Dependency] private readonly SharedDoAfterSystem _doAfter = default!; [Dependency] private readonly INetManager _net = default!; [Dependency] private readonly SharedCP14MagicEnergySystem _magicEnergy = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IPrototypeManager _proto = default!; [Dependency] private readonly MetaDataSystem _meta = default!; [Dependency] private readonly SharedActionsSystem _action = default!; [Dependency] private readonly MovementSpeedModifierSystem _movement = default!; public override void Initialize() { base.Initialize(); InitializeActions(); InitializeAspects(); InitializeSlowdown(); SubscribeLocalEvent(OnMagicEffectInit); SubscribeLocalEvent(OnBeforeCastMagicEffect); SubscribeLocalEvent(OnAfterCastMagicEffect); } /// /// Auto generation description for spell action /// private void OnMagicEffectInit(Entity ent, ref MapInitEvent args) { var meta = MetaData(ent); var sb = new StringBuilder(); sb.Append(meta.EntityDescription); sb.Append($"\n\n {Loc.GetString("cp14-magic-manacost")}: [color=#5da9e8]{ent.Comp.ManaCost}[/color]"); if (_proto.TryIndex(ent.Comp.MagicType, out var indexedMagic)) { sb.Append($"\n {Loc.GetString("cp14-magic-magic-type")}: [color={indexedMagic.Color.ToHex()}]{Loc.GetString(indexedMagic.Name)}[/color]"); } if (TryComp(ent, out var verbal)) { sb.Append("\n" + Loc.GetString("cp14-magic-verbal-aspect")); } if (TryComp(ent, out var somatic)) { sb.Append("\n" + Loc.GetString("cp14-magic-somatic-aspect") + " " + somatic.FreeHandRequired); } _meta.SetEntityDescription(ent, sb.ToString()); } /// /// Checking to see if the spell can be used at all /// private bool CanCastSpell(EntityUid spell, EntityUid performer) { var ev = new CP14CastMagicEffectAttemptEvent(performer); RaiseLocalEvent(spell, ref ev); if (ev.Reason != string.Empty && _net.IsServer) { _popup.PopupEntity(ev.Reason, performer, performer); } return !ev.Cancelled; } /// /// Before using a spell, a mana check is made for the amount of mana to show warnings. /// private void OnBeforeCastMagicEffect(Entity ent, ref CP14CastMagicEffectAttemptEvent args) { if (!TryComp(args.Performer, out var magicContainer)) { args.Cancel(); return; } var manaCost = CalculateManacost(ent, args.Performer); if (!_magicEnergy.HasEnergy(args.Performer, manaCost, magicContainer, ent.Comp.Safe)) { args.PushReason(Loc.GetString("cp14-magic-spell-not-enough-mana")); args.Cancel(); } else if(!_magicEnergy.HasEnergy(args.Performer, manaCost, magicContainer, true) && _net.IsServer) //фу какой некрасивый | хардкод { // \/ _popup.PopupEntity(Loc.GetString("cp14-magic-spell-not-enough-mana-cast-warning-"+_random.Next(5)), args.Performer, args.Performer, PopupType.SmallCaution); } } private void CastTelegraphy(Entity ent, CP14SpellEffectBaseArgs args) { if (!_net.IsServer) return; foreach (var effect in ent.Comp.TelegraphyEffects) { effect.Effect(EntityManager, args); } } private bool TryCastSpellDelayed(ICP14DelayedMagicEffect delayedEffect, DoAfterEvent doAfter, EntityUid action, EntityUid performer) { var doAfterEventArgs = new DoAfterArgs(EntityManager, performer, delayedEffect.CastDelay, doAfter, action) { BreakOnMove = delayedEffect.BreakOnMove, BreakOnDamage = delayedEffect.BreakOnDamage, Hidden = delayedEffect.Hidden, DistanceThreshold = 100f, CancelDuplicate = true, BlockDuplicate = true, }; return _doAfter.TryStartDoAfter(doAfterEventArgs); } private void CastSpell(Entity ent, CP14SpellEffectBaseArgs args, float cooldown) { _action.CP14StartCustomDelay(ent, TimeSpan.FromSeconds(cooldown)); if (_net.IsServer) { foreach (var effect in ent.Comp.Effects) { effect.Effect(EntityManager, args); } } var ev = new CP14AfterCastMagicEffectEvent(args.User); RaiseLocalEvent(ent, ref ev); } private void OnAfterCastMagicEffect(Entity ent, ref CP14AfterCastMagicEffectEvent args) { if (_net.IsClient) return; if (!HasComp(args.Performer)) return; var manaCost = CalculateManacost(ent, args.Performer.Value); _magicEnergy.TryConsumeEnergy(args.Performer.Value, manaCost, safe: ent.Comp.Safe); } private FixedPoint2 CalculateManacost(Entity ent, EntityUid caster) { var manaCost = ent.Comp.ManaCost; if (ent.Comp.CanModifyManacost) { var manaEv = new CP14CalculateManacostEvent(caster, ent.Comp.ManaCost, ent.Comp.MagicType); RaiseLocalEvent(caster, manaEv); if (TryComp(ent, out var provided) && provided.SpellStorage is not null) RaiseLocalEvent(provided.SpellStorage.Value, manaEv); manaCost = manaEv.GetManacost(); } return manaCost; } }