* fix firewave error spamming * basic magic traces entities * Add magical vision system and mana trace entities Introduces the magical vision mechanic, including the CP14MagicVisionComponent, marker entities, and related systems for tracking and displaying magical traces. Adds new actions, skill integration, localization strings, and icons for magical vision and trace markers. Magic traces are now spawned on spell use and mob state changes, with directional pointers and localized descriptions. * Show time passed for magic vision markers Adds a display of the time elapsed since a magic vision marker was spawned, using a localized string. Updates English and Russian locale files with the new 'cp14-magic-vision-timed-past' entry. * aura imprints * Update critical and death messages for inclusivity Revised the 'critical' and 'dead' messages in both English and Russian locale files to use more inclusive language, replacing references to 'magical creature' with 'someone'. * Move magic vision spawn on mob state change to server Transferred the logic for spawning magic vision markers on mob state changes (Critical/Dead) from CP14SharedMagicVisionSystem to CP14AuraImprintSystem. This centralizes the event handling on the server side. Also increased the duration of magic vision markers for spell usage from 20 to 50 seconds. * Integrate magic vision with visibility mask system Added a CP14MagicVision flag to VisibilityFlags and updated the magic vision and religion systems to use the visibility mask system. Magic vision markers now use the Visibility component, and visibility is refreshed when relevant components are added or removed. Removed client-side toggling logic in favor of server-driven visibility. * drowsiness overlay * noir shader * sfx design
231 lines
8.3 KiB
C#
231 lines
8.3 KiB
C#
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.MagicVision;
|
|
using Content.Shared.Actions;
|
|
using Content.Shared.Actions.Components;
|
|
using Content.Shared.Damage.Systems;
|
|
using Content.Shared.DoAfter;
|
|
using Content.Shared.FixedPoint;
|
|
using Content.Shared.Movement.Systems;
|
|
using Content.Shared.Popups;
|
|
using Robust.Shared.Prototypes;
|
|
using Robust.Shared.Random;
|
|
using Robust.Shared.Timing;
|
|
|
|
namespace Content.Shared._CP14.MagicSpell;
|
|
|
|
/// <summary>
|
|
/// This system handles the basic mechanics of spell use, such as doAfter, event invocation, and energy spending.
|
|
/// </summary>
|
|
public abstract partial class CP14SharedMagicSystem : EntitySystem
|
|
{
|
|
[Dependency] private readonly SharedDoAfterSystem _doAfter = 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!;
|
|
[Dependency] private readonly SharedStaminaSystem _stamina = default!;
|
|
[Dependency] private readonly IGameTiming _timing = default!;
|
|
[Dependency] private readonly CP14SharedMagicVisionSystem _magicVision = default!;
|
|
|
|
private EntityQuery<CP14MagicEnergyContainerComponent> _magicContainerQuery;
|
|
private EntityQuery<CP14MagicEffectComponent> _magicEffectQuery;
|
|
|
|
public override void Initialize()
|
|
{
|
|
base.Initialize();
|
|
InitializeDelayedActions();
|
|
InitializeToggleableActions();
|
|
InitializeInstantActions();
|
|
InitializeChecks();
|
|
InitializeSlowdown();
|
|
|
|
_magicContainerQuery = GetEntityQuery<CP14MagicEnergyContainerComponent>();
|
|
_magicEffectQuery = GetEntityQuery<CP14MagicEffectComponent>();
|
|
|
|
SubscribeLocalEvent<CP14MagicEffectComponent, MapInitEvent>(OnMagicEffectInit);
|
|
SubscribeLocalEvent<CP14MagicEffectComponent, ComponentShutdown>(OnMagicEffectShutdown);
|
|
|
|
SubscribeLocalEvent<CP14MagicEffectComponent, CP14StartCastMagicEffectEvent>(OnStartCast);
|
|
SubscribeLocalEvent<CP14MagicEffectComponent, CP14EndCastMagicEffectEvent>(OnEndCast);
|
|
|
|
SubscribeLocalEvent<CP14MagicEffectStaminaCostComponent, CP14MagicEffectConsumeResourceEvent>(OnStaminaConsume);
|
|
}
|
|
|
|
private void OnStartCast(Entity<CP14MagicEffectComponent> ent, ref CP14StartCastMagicEffectEvent args)
|
|
{
|
|
var caster = EnsureComp<CP14MagicCasterComponent>(args.Performer);
|
|
|
|
caster.CastedSpells.Add(ent);
|
|
}
|
|
|
|
private void OnEndCast(Entity<CP14MagicEffectComponent> ent, ref CP14EndCastMagicEffectEvent args)
|
|
{
|
|
if (!TryComp<CP14MagicCasterComponent>(args.Performer, out var caster))
|
|
return;
|
|
|
|
caster.CastedSpells.Remove(ent);
|
|
|
|
//Break all casts
|
|
List<EntityUid> castedSpells = new();
|
|
foreach (var casted in caster.CastedSpells)
|
|
{
|
|
castedSpells.Add(casted);
|
|
}
|
|
|
|
foreach (var casted in castedSpells)
|
|
{
|
|
if (!_magicEffectQuery.TryComp(casted, out var castedComp))
|
|
continue;
|
|
|
|
_doAfter.Cancel(castedComp.ActiveDoAfter);
|
|
}
|
|
}
|
|
|
|
public override void Update(float frameTime)
|
|
{
|
|
base.Update(frameTime);
|
|
|
|
UpdateToggleableActions();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Auto generation description for spell action
|
|
/// </summary>
|
|
private void OnMagicEffectInit(Entity<CP14MagicEffectComponent> ent, ref MapInitEvent args)
|
|
{
|
|
var meta = MetaData(ent);
|
|
var sb = new StringBuilder();
|
|
|
|
sb.Append(meta.EntityDescription);
|
|
|
|
if (TryComp<CP14MagicEffectManaCostComponent>(ent, out var manaCost) && manaCost.ManaCost > 0)
|
|
{
|
|
sb.Append($"\n\n{Loc.GetString("cp14-magic-manacost")}: [color=#5da9e8]{manaCost.ManaCost}[/color]");
|
|
}
|
|
|
|
if (TryComp<CP14MagicEffectStaminaCostComponent>(ent, out var staminaCost) && staminaCost.Stamina > 0)
|
|
{
|
|
sb.Append($"\n\n{Loc.GetString("cp14-magic-staminacost")}: [color=#3fba54]{staminaCost.Stamina}[/color]");
|
|
}
|
|
|
|
if (_proto.TryIndex(ent.Comp.MagicType, out var indexedMagic))
|
|
{
|
|
sb.Append($"\n{Loc.GetString("cp14-magic-type")}: [color={indexedMagic.Color.ToHex()}]{Loc.GetString(indexedMagic.Name)}[/color]");
|
|
}
|
|
|
|
if (TryComp<CP14MagicEffectVerbalAspectComponent>(ent, out var verbal))
|
|
{
|
|
sb.Append("\n" + Loc.GetString("cp14-magic-verbal-aspect"));
|
|
}
|
|
|
|
if (TryComp<CP14MagicEffectSomaticAspectComponent>(ent, out var somatic))
|
|
{
|
|
sb.Append("\n" + Loc.GetString("cp14-magic-somatic-aspect") + " " + somatic.FreeHandRequired);
|
|
}
|
|
|
|
if (TryComp<CP14MagicEffectRequiredMusicToolComponent>(ent, out var music))
|
|
{
|
|
sb.Append("\n" + Loc.GetString("cp14-magic-music-aspect"));
|
|
}
|
|
|
|
_meta.SetEntityDescription(ent, sb.ToString());
|
|
}
|
|
|
|
private void OnMagicEffectShutdown(Entity<CP14MagicEffectComponent> ent, ref ComponentShutdown args)
|
|
{
|
|
if (_doAfter.IsRunning(ent.Comp.ActiveDoAfter))
|
|
_doAfter.Cancel(ent.Comp.ActiveDoAfter);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checking to see if the spell can be used at all
|
|
/// </summary>
|
|
private bool CanCastSpell(Entity<CP14MagicEffectComponent> ent, CP14SpellEffectBaseArgs args)
|
|
{
|
|
if (args.User is not { } performer)
|
|
return true;
|
|
|
|
var ev = new CP14CastMagicEffectAttemptEvent(performer, args.Used, args.Target, args.Position);
|
|
RaiseLocalEvent(ent, ev);
|
|
|
|
if (ev.Reason != string.Empty)
|
|
_popup.PopupPredicted(ev.Reason, performer, performer);
|
|
|
|
return !ev.Cancelled;
|
|
}
|
|
|
|
private void CastTelegraphy(Entity<CP14MagicEffectComponent> ent, CP14SpellEffectBaseArgs args)
|
|
{
|
|
if (!_timing.IsFirstTimePredicted)
|
|
return;
|
|
|
|
foreach (var effect in ent.Comp.TelegraphyEffects)
|
|
{
|
|
effect.Effect(EntityManager, args);
|
|
}
|
|
}
|
|
|
|
private void CastSpell(Entity<CP14MagicEffectComponent> ent, CP14SpellEffectBaseArgs args)
|
|
{
|
|
if (!_timing.IsFirstTimePredicted)
|
|
return;
|
|
|
|
var ev = new CP14MagicEffectConsumeResourceEvent(args.User);
|
|
RaiseLocalEvent(ent, ref ev);
|
|
|
|
foreach (var effect in ent.Comp.Effects)
|
|
{
|
|
effect.Effect(EntityManager, args);
|
|
}
|
|
|
|
if (args.User is not null
|
|
&& TryComp<ActionComponent>(ent, out var actionComp)
|
|
&& TryComp<CP14MagicEffectManaCostComponent>(ent, out var manaCost))
|
|
{
|
|
_magicVision.SpawnMagicVision(
|
|
Transform(args.User.Value).Coordinates,
|
|
actionComp.Icon,
|
|
Loc.GetString("cp14-magic-vision-used-spell", ("name", MetaData(ent).EntityName)),
|
|
TimeSpan.FromSeconds((float)manaCost.ManaCost * 50),
|
|
args.User,
|
|
args.Position);
|
|
}
|
|
}
|
|
|
|
protected FixedPoint2 CalculateManacost(Entity<CP14MagicEffectManaCostComponent> ent, EntityUid? caster)
|
|
{
|
|
var manaCost = ent.Comp.ManaCost;
|
|
|
|
if (ent.Comp.CanModifyManacost && _magicEffectQuery.TryComp(ent, out var magicEffect))
|
|
{
|
|
var manaEv = new CP14CalculateManacostEvent(caster, ent.Comp.ManaCost, magicEffect.MagicType);
|
|
|
|
if (caster is not null)
|
|
RaiseLocalEvent(caster.Value, manaEv);
|
|
|
|
if (magicEffect.SpellStorage is not null)
|
|
RaiseLocalEvent(magicEffect.SpellStorage.Value, manaEv);
|
|
|
|
manaCost = manaEv.GetManacost();
|
|
}
|
|
|
|
return manaCost;
|
|
}
|
|
|
|
private void OnStaminaConsume(Entity<CP14MagicEffectStaminaCostComponent> ent, ref CP14MagicEffectConsumeResourceEvent args)
|
|
{
|
|
if (args.Performer is null)
|
|
return;
|
|
|
|
_stamina.TakeStaminaDamage(args.Performer.Value, ent.Comp.Stamina, visual: false);
|
|
}
|
|
}
|