2025-01-04 21:35:59 +03:00
|
|
|
using Content.Server._CP14.MagicEnergy;
|
2025-02-16 11:41:43 +03:00
|
|
|
using Content.Server.Atmos.Components;
|
2024-07-28 17:26:47 +03:00
|
|
|
using Content.Server.Chat.Systems;
|
2025-02-25 15:44:22 +03:00
|
|
|
using Content.Server.Instruments;
|
2025-01-04 21:35:59 +03:00
|
|
|
using Content.Shared._CP14.MagicEnergy.Components;
|
2024-08-01 11:52:27 +03:00
|
|
|
using Content.Shared._CP14.MagicSpell;
|
|
|
|
|
using Content.Shared._CP14.MagicSpell.Components;
|
|
|
|
|
using Content.Shared._CP14.MagicSpell.Events;
|
2025-01-17 01:01:44 +03:00
|
|
|
using Content.Shared._CP14.MagicSpell.Spells;
|
2025-03-07 14:52:43 +03:00
|
|
|
using Content.Shared.Actions;
|
2025-04-18 22:47:17 +03:00
|
|
|
using Content.Shared.CombatMode.Pacification;
|
2025-02-25 23:37:05 +03:00
|
|
|
using Content.Shared.FixedPoint;
|
2025-04-30 20:50:03 +03:00
|
|
|
using Content.Shared.Instruments;
|
2025-02-16 11:41:43 +03:00
|
|
|
using Content.Shared.Projectiles;
|
|
|
|
|
using Content.Shared.Throwing;
|
|
|
|
|
using Content.Shared.Weapons.Melee.Events;
|
2025-01-17 01:01:44 +03:00
|
|
|
using Content.Shared.Whitelist;
|
2024-08-01 11:52:27 +03:00
|
|
|
using Robust.Server.GameObjects;
|
2025-02-16 11:41:43 +03:00
|
|
|
using Robust.Shared.Random;
|
2024-07-28 17:26:47 +03:00
|
|
|
|
2024-08-01 11:52:27 +03:00
|
|
|
namespace Content.Server._CP14.MagicSpell;
|
2024-07-28 17:26:47 +03:00
|
|
|
|
2025-04-15 00:32:41 +10:00
|
|
|
public sealed class CP14MagicSystem : CP14SharedMagicSystem
|
2024-07-28 17:26:47 +03:00
|
|
|
{
|
|
|
|
|
[Dependency] private readonly ChatSystem _chat = default!;
|
2024-08-01 11:52:27 +03:00
|
|
|
[Dependency] private readonly TransformSystem _transform = default!;
|
2025-01-04 21:35:59 +03:00
|
|
|
[Dependency] private readonly CP14MagicEnergySystem _magicEnergy = default!;
|
2025-01-17 01:01:44 +03:00
|
|
|
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
|
|
|
|
[Dependency] private readonly EntityWhitelistSystem _whitelist = default!;
|
2025-02-16 11:41:43 +03:00
|
|
|
[Dependency] private readonly IRobustRandom _random = default!;
|
2024-07-28 17:26:47 +03:00
|
|
|
|
|
|
|
|
public override void Initialize()
|
|
|
|
|
{
|
2024-11-07 16:04:49 +03:00
|
|
|
base.Initialize();
|
|
|
|
|
|
2025-01-17 01:01:44 +03:00
|
|
|
SubscribeLocalEvent<CP14AreaEntityEffectComponent, MapInitEvent>(OnAoEMapInit);
|
2025-02-16 11:41:43 +03:00
|
|
|
|
|
|
|
|
SubscribeLocalEvent<CP14SpellEffectOnHitComponent, MeleeHitEvent>(OnMeleeHit);
|
|
|
|
|
SubscribeLocalEvent<CP14SpellEffectOnHitComponent, ThrowDoHitEvent>(OnProjectileHit);
|
|
|
|
|
|
2025-04-12 17:32:53 +03:00
|
|
|
SubscribeLocalEvent<CP14MagicEffectVerbalAspectComponent, CP14SpellSpeechEvent>(OnSpellSpoken);
|
2024-07-28 17:26:47 +03:00
|
|
|
|
|
|
|
|
SubscribeLocalEvent<CP14MagicEffectCastingVisualComponent, CP14StartCastMagicEffectEvent>(OnSpawnMagicVisualEffect);
|
2024-08-02 13:51:54 +03:00
|
|
|
SubscribeLocalEvent<CP14MagicEffectCastingVisualComponent, CP14EndCastMagicEffectEvent>(OnDespawnMagicVisualEffect);
|
2025-01-04 21:35:59 +03:00
|
|
|
|
|
|
|
|
SubscribeLocalEvent<CP14MagicEffectManaCostComponent, CP14MagicEffectConsumeResourceEvent>(OnManaConsume);
|
2025-02-25 15:44:22 +03:00
|
|
|
|
|
|
|
|
SubscribeLocalEvent<CP14MagicEffectRequiredMusicToolComponent, CP14CastMagicEffectAttemptEvent>(OnMusicCheck);
|
2024-07-28 17:26:47 +03:00
|
|
|
}
|
|
|
|
|
|
2025-02-16 11:41:43 +03:00
|
|
|
private void OnProjectileHit(Entity<CP14SpellEffectOnHitComponent> 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<CP14SpellEffectOnHitComponent> ent, ref MeleeHitEvent args)
|
|
|
|
|
{
|
2025-04-18 22:47:17 +03:00
|
|
|
if (HasComp<PacifiedComponent>(args.User)) //IDK how to check if the user is pacified in a better way
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (!args.IsHit)
|
|
|
|
|
return;
|
|
|
|
|
|
2025-02-16 11:41:43 +03:00
|
|
|
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));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-17 01:01:44 +03:00
|
|
|
private void OnAoEMapInit(Entity<CP14AreaEntityEffectComponent> 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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-12 17:32:53 +03:00
|
|
|
private void OnSpellSpoken(Entity<CP14MagicEffectVerbalAspectComponent> ent, ref CP14SpellSpeechEvent args)
|
2024-07-28 17:26:47 +03:00
|
|
|
{
|
|
|
|
|
if (args.Performer is not null && args.Speech is not null)
|
2025-02-06 12:38:20 +03:00
|
|
|
_chat.TrySendInGameICMessage(args.Performer.Value, args.Speech, args.Emote ? InGameICChatType.Emote : InGameICChatType.Speak, true);
|
2024-07-28 17:26:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnSpawnMagicVisualEffect(Entity<CP14MagicEffectCastingVisualComponent> ent, ref CP14StartCastMagicEffectEvent args)
|
|
|
|
|
{
|
2024-11-07 16:04:49 +03:00
|
|
|
var vfx = SpawnAttachedTo(ent.Comp.Proto, Transform(args.Performer).Coordinates);
|
|
|
|
|
_transform.SetParent(vfx, args.Performer);
|
2024-07-28 17:26:47 +03:00
|
|
|
ent.Comp.SpawnedEntity = vfx;
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-02 13:51:54 +03:00
|
|
|
private void OnDespawnMagicVisualEffect(Entity<CP14MagicEffectCastingVisualComponent> ent, ref CP14EndCastMagicEffectEvent args)
|
2024-07-28 17:26:47 +03:00
|
|
|
{
|
|
|
|
|
QueueDel(ent.Comp.SpawnedEntity);
|
|
|
|
|
ent.Comp.SpawnedEntity = null;
|
|
|
|
|
}
|
2025-01-04 21:35:59 +03:00
|
|
|
|
|
|
|
|
private void OnManaConsume(Entity<CP14MagicEffectManaCostComponent> ent, ref CP14MagicEffectConsumeResourceEvent args)
|
|
|
|
|
{
|
|
|
|
|
if (!TryComp<CP14MagicEffectComponent>(ent, out var magicEffect))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
var requiredMana = CalculateManacost(ent, args.Performer);
|
|
|
|
|
|
2025-02-25 23:37:05 +03:00
|
|
|
//First - used object
|
|
|
|
|
if (magicEffect.SpellStorage is not null && TryComp<CP14MagicEnergyContainerComponent>(magicEffect.SpellStorage, out var magicStorage))
|
2025-01-04 21:35:59 +03:00
|
|
|
{
|
|
|
|
|
var spellEv = new CP14SpellFromSpellStorageUsedEvent(args.Performer, (ent, magicEffect), requiredMana);
|
|
|
|
|
RaiseLocalEvent(magicEffect.SpellStorage.Value, ref spellEv);
|
|
|
|
|
|
2025-04-15 00:32:41 +10:00
|
|
|
_magicEnergy.ChangeEnergy((magicEffect.SpellStorage.Value, magicStorage), -requiredMana, out var changedEnergy, out var overloadedEnergy, safe: false);
|
2025-02-25 23:37:05 +03:00
|
|
|
requiredMana -= FixedPoint2.Abs(changedEnergy + overloadedEnergy);
|
2025-01-04 21:35:59 +03:00
|
|
|
}
|
|
|
|
|
|
2025-02-25 23:37:05 +03:00
|
|
|
//Second - action user
|
2025-01-04 21:35:59 +03:00
|
|
|
if (requiredMana > 0 &&
|
|
|
|
|
TryComp<CP14MagicEnergyContainerComponent>(args.Performer, out var playerMana))
|
2025-04-15 00:32:41 +10:00
|
|
|
_magicEnergy.ChangeEnergy((args.Performer.Value, playerMana), -requiredMana, out _, out _, safe: false);
|
2025-01-04 21:35:59 +03:00
|
|
|
}
|
2025-02-25 15:44:22 +03:00
|
|
|
|
|
|
|
|
private void OnMusicCheck(Entity<CP14MagicEffectRequiredMusicToolComponent> ent, ref CP14CastMagicEffectAttemptEvent args)
|
|
|
|
|
{
|
|
|
|
|
var passed = false;
|
|
|
|
|
var query = EntityQueryEnumerator<ActiveInstrumentComponent, InstrumentComponent>();
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-15 00:32:41 +10:00
|
|
|
if (passed)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
args.PushReason(Loc.GetString("cp14-magic-music-aspect"));
|
|
|
|
|
args.Cancel();
|
2025-02-25 15:44:22 +03:00
|
|
|
}
|
2024-07-28 17:26:47 +03:00
|
|
|
}
|