using Content.Server._CP14.MagicEnergy; using Content.Server.Atmos.Components; using Content.Server.Chat.Systems; using Content.Server.Instruments; using Content.Shared._CP14.MagicEnergy.Components; using Content.Shared._CP14.MagicSpell; using Content.Shared._CP14.MagicSpell.Components; using Content.Shared._CP14.MagicSpell.Events; using Content.Shared._CP14.MagicSpell.Spells; using Content.Shared.Actions; using Content.Shared.FixedPoint; using Content.Shared.Projectiles; using Content.Shared.Throwing; using Content.Shared.Weapons.Melee.Events; using Content.Shared.Whitelist; using Robust.Server.GameObjects; using Robust.Shared.Random; namespace Content.Server._CP14.MagicSpell; public sealed partial class CP14MagicSystem : CP14SharedMagicSystem { [Dependency] private readonly ChatSystem _chat = default!; [Dependency] private readonly TransformSystem _transform = default!; [Dependency] private readonly CP14MagicEnergySystem _magicEnergy = default!; [Dependency] private readonly EntityLookupSystem _lookup = default!; [Dependency] private readonly EntityWhitelistSystem _whitelist = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly SharedActionsSystem _action = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnAoEMapInit); SubscribeLocalEvent(OnMeleeHit); SubscribeLocalEvent(OnProjectileHit); SubscribeLocalEvent(OnSpellSpoken); SubscribeLocalEvent(OnSpawnMagicVisualEffect); SubscribeLocalEvent(OnDespawnMagicVisualEffect); SubscribeLocalEvent(OnManaConsume); SubscribeLocalEvent(OnMusicCheck); } private void OnProjectileHit(Entity ent, ref ThrowDoHitEvent args) { if (!_random.Prob(ent.Comp.Prob)) return; if (ent.Comp.Whitelist is not null && !_whitelist.IsValid(ent.Comp.Whitelist, args.Target)) return; foreach (var effect in ent.Comp.Effects) { effect.Effect(EntityManager, new CP14SpellEffectBaseArgs(args.Thrown, ent, args.Target, Transform(args.Target).Coordinates)); } } private void OnMeleeHit(Entity ent, ref MeleeHitEvent args) { if (!_random.Prob(ent.Comp.Prob)) return; foreach (var entity in args.HitEntities) { if (ent.Comp.Whitelist is not null && !_whitelist.IsValid(ent.Comp.Whitelist, entity)) continue; foreach (var effect in ent.Comp.Effects) { effect.Effect(EntityManager, new CP14SpellEffectBaseArgs(args.User, ent, entity, Transform(entity).Coordinates)); } } } private void OnAoEMapInit(Entity ent, ref MapInitEvent args) { var entitiesAround = _lookup.GetEntitiesInRange(ent, ent.Comp.Range, LookupFlags.Uncontained); var count = 0; foreach (var entity in entitiesAround) { if (ent.Comp.Whitelist is not null && !_whitelist.IsValid(ent.Comp.Whitelist, entity)) continue; foreach (var effect in ent.Comp.Effects) { effect.Effect(EntityManager, new CP14SpellEffectBaseArgs(ent, null, entity, Transform(entity).Coordinates)); } count++; if (ent.Comp.MaxTargets > 0 && count >= ent.Comp.MaxTargets) break; } } private void OnSpellSpoken(Entity ent, ref CP14VerbalAspectSpeechEvent args) { if (args.Performer is not null && args.Speech is not null) _chat.TrySendInGameICMessage(args.Performer.Value, args.Speech, args.Emote ? InGameICChatType.Emote : InGameICChatType.Speak, true); } private void OnSpawnMagicVisualEffect(Entity ent, ref CP14StartCastMagicEffectEvent args) { var vfx = SpawnAttachedTo(ent.Comp.Proto, Transform(args.Performer).Coordinates); _transform.SetParent(vfx, args.Performer); ent.Comp.SpawnedEntity = vfx; } private void OnDespawnMagicVisualEffect(Entity ent, ref CP14EndCastMagicEffectEvent args) { QueueDel(ent.Comp.SpawnedEntity); ent.Comp.SpawnedEntity = null; } private void OnManaConsume(Entity ent, ref CP14MagicEffectConsumeResourceEvent args) { if (!TryComp(ent, out var magicEffect)) return; var requiredMana = CalculateManacost(ent, args.Performer); //First - used object if (magicEffect.SpellStorage is not null && TryComp(magicEffect.SpellStorage, out var magicStorage)) { var spellEv = new CP14SpellFromSpellStorageUsedEvent(args.Performer, (ent, magicEffect), requiredMana); RaiseLocalEvent(magicEffect.SpellStorage.Value, ref spellEv); _magicEnergy.ChangeEnergy(magicEffect.SpellStorage.Value, -requiredMana, out var changedEnergy, out var overloadedEnergy, magicStorage, safe: false); requiredMana -= FixedPoint2.Abs(changedEnergy + overloadedEnergy); } //Second - action user if (requiredMana > 0 && TryComp(args.Performer, out var playerMana)) { _magicEnergy.ChangeEnergy(args.Performer.Value, -requiredMana, out _, out _, playerMana, safe: false); } } private void OnMusicCheck(Entity ent, ref CP14CastMagicEffectAttemptEvent args) { var passed = false; var query = EntityQueryEnumerator(); while (query.MoveNext(out var uid, out var active, out var instrument)) { if (!instrument.Playing) continue; if (Transform(uid).ParentUid != args.Performer) continue; passed = true; break; } if (!passed) { args.PushReason(Loc.GetString("cp14-magic-music-aspect")); args.Cancel(); } } }