Magic spell refactor part 2 (#1757)
* DoAfter support for Actions (#38253) * Adds Action DoAfter Events * Adds DoAfterArgs fields to DoAfterComp * Adds a base doafter action * Adds Attempt action doafter logic * Adds doafter logic to actions * Changes Action Attempt Doafter and action doafter to take in Performer and the original use delay. Use delay now triggers when a repeated action is cancelled. * Readds the TryPerformAction method and readds request perform action into the action doafter events * Adds a force skip to DoAfter Cancel so we can skip the complete check * Adds a Delay Reduction field to the comp and to the comp state * Fixes doafter mispredict, changes doafter comp check to a guard clause, sets delay reduction if it exists. * Cancels ActionDoAfter if charges is 0 * Serializes Attempt Frequency * Comment for rework * Changes todo into a comment * Moves doafterargs to doafterargscomp * Adds DoAfterArgs comp to BaseDoAfterAction * Removes unused trycomp with actionDoAfter * Replaces DoAfterRepateUseDelay const with timespan.zero * Removes unused usings * Makes SharedActionsSystem partial, adds DoAfter partial class to ActionSystem, moves ActionDoAfter logic to the SharedActionsSystem.DoAfter class * Cleanup and prediction * Renames OnActionDoAfterAttempt to OnActionDoAfter, moves both to Shared Action DoAfter * Removes ActionAttemptDoAfterEvent and moves its summaries to ActionDoAfterEvent. Converts OnActionDoAfterAttempt into TryStartActionDoAfter * Removes Extra check for charges and actiondoafters * Sloptimization * Cleanup * Cleanup * Adds param descs --------- Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com> * Refactor CP14 action emote and speech handling Moved emote and speech logic from magic spell components to dedicated CP14 action components and systems. Removed CP14MagicEffectEmotingComponent and related event handling, introducing CP14ActionEmotingComponent and updating event subscriptions. Updated resource consumption and performed logic to use new action-based components. Adjusted affected prototypes and removed obsolete code. * kicking in * Refactor athletic spell actions and remove mana cost calc Reworked dash and sprint spell YAMLs to use modular effect events and updated their action properties. Removed the unused CalculateManacost method from CP14SharedMagicSystem.cs. Also removed the startDelay property from the kick action. * fix cooldown and resource cost * casting visuals adapt * telegraphy adapt * slowdown adaption * Remove Lumera and Merkas demigod spells and skills Deleted all spell and skill prototypes related to the Lumera and Merkas demigods, including their actions, effects, and skill trees. Updated athletic sprint and second wind spells, and refactored portal_to_city spell to use modular effects. Also added a debug category to the admin skill reset verb. * fuck... * done * some refactor hell * light + lurker process * meta process * mobs process * vampire * finish * no clientside * Update water_creation.yml * fixes * Update ice_ghost.yml * а * viator review * fix lurker --------- Co-authored-by: keronshb <54602815+keronshb@users.noreply.github.com> Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using Content.Shared.Actions.Events;
|
||||
using Content.Shared._CP14.Actions;
|
||||
using Content.Shared.Actions.Events;
|
||||
using Content.Shared.DoAfter;
|
||||
|
||||
namespace Content.Shared.Actions;
|
||||
@@ -20,6 +21,11 @@ public abstract partial class SharedActionsSystem
|
||||
|
||||
var netEnt = GetNetEntity(performer);
|
||||
|
||||
//CP14 doAfter start event
|
||||
var cp14StartEv = new CP14ActionStartDoAfterEvent(netEnt, input);
|
||||
RaiseLocalEvent(ent, cp14StartEv);
|
||||
//CP14 end
|
||||
|
||||
var actionDoAfterEvent = new ActionDoAfterEvent(netEnt, originalUseDelay, input);
|
||||
|
||||
var doAfterArgs = new DoAfterArgs(EntityManager, performer, delay, actionDoAfterEvent, ent.Owner, performer)
|
||||
|
||||
@@ -1,34 +1,24 @@
|
||||
using System.Linq;
|
||||
using Content.Shared._CP14.Actions.Components;
|
||||
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.Religion.Components;
|
||||
using Content.Shared._CP14.Religion.Systems;
|
||||
using Content.Shared._CP14.Skill.Components;
|
||||
using Content.Shared.Actions.Components;
|
||||
using Content.Shared.Actions.Events;
|
||||
using Content.Shared.CombatMode.Pacification;
|
||||
using Content.Shared.Damage.Components;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Mobs;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Speech.Muting;
|
||||
using Content.Shared.SSDIndicator;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Shared._CP14.Actions;
|
||||
|
||||
public abstract partial class CP14SharedActionSystem
|
||||
{
|
||||
[Dependency] private readonly SharedHandsSystem _hand = default!;
|
||||
[Dependency] private readonly CP14SharedMagicEnergySystem _magicEnergy = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly CP14SharedReligionGodSystem _god = default!;
|
||||
private void InitializeAttempts()
|
||||
{
|
||||
SubscribeLocalEvent<CP14ActionFreeHandsRequiredComponent, ActionAttemptEvent>(OnSomaticActionAttempt);
|
||||
@@ -52,9 +42,10 @@ public abstract partial class CP14SharedActionSystem
|
||||
if (args.Cancelled)
|
||||
return;
|
||||
|
||||
TryComp<CP14MagicEffectComponent>(ent, out var magicEffect);
|
||||
if (!TryComp<ActionComponent>(ent, out var action))
|
||||
return;
|
||||
|
||||
//Total man required
|
||||
//Total mana required
|
||||
var requiredMana = ent.Comp.ManaCost;
|
||||
|
||||
if (ent.Comp.CanModifyManacost)
|
||||
@@ -63,15 +54,15 @@ public abstract partial class CP14SharedActionSystem
|
||||
|
||||
RaiseLocalEvent(args.User, manaEv);
|
||||
|
||||
if (magicEffect?.SpellStorage is not null)
|
||||
RaiseLocalEvent(magicEffect.SpellStorage.Value, manaEv);
|
||||
if (action.Container is not null)
|
||||
RaiseLocalEvent(action.Container.Value, manaEv);
|
||||
|
||||
requiredMana = manaEv.GetManacost();
|
||||
}
|
||||
|
||||
//First - trying get mana from item
|
||||
if (magicEffect is not null && magicEffect.SpellStorage is not null &&
|
||||
TryComp<CP14MagicEnergyContainerComponent>(magicEffect.SpellStorage, out var magicContainer))
|
||||
if (action.Container is not null &&
|
||||
TryComp<CP14MagicEnergyContainerComponent>(action.Container, out var magicContainer))
|
||||
requiredMana = MathF.Max(0, (float)(requiredMana - magicContainer.Energy));
|
||||
|
||||
if (requiredMana <= 0)
|
||||
|
||||
55
Content.Shared/_CP14/Actions/CP14ActionSystem.DoAfters.cs
Normal file
55
Content.Shared/_CP14/Actions/CP14ActionSystem.DoAfters.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using Content.Shared._CP14.Actions.Components;
|
||||
using Content.Shared.Actions.Events;
|
||||
using Content.Shared.Movement.Systems;
|
||||
|
||||
namespace Content.Shared._CP14.Actions;
|
||||
|
||||
public abstract partial class CP14SharedActionSystem
|
||||
{
|
||||
private void InitializeDoAfter()
|
||||
{
|
||||
SubscribeLocalEvent<CP14ActionDoAfterSlowdownComponent, CP14ActionStartDoAfterEvent>(OnStartDoAfter);
|
||||
SubscribeLocalEvent<CP14ActionDoAfterSlowdownComponent, ActionDoAfterEvent>(OnEndDoAfter);
|
||||
SubscribeLocalEvent<CP14SlowdownFromActionsComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovespeed);
|
||||
}
|
||||
|
||||
private void OnStartDoAfter(Entity<CP14ActionDoAfterSlowdownComponent> ent, ref CP14ActionStartDoAfterEvent args)
|
||||
{
|
||||
var performer = GetEntity(args.Performer);
|
||||
EnsureComp<CP14SlowdownFromActionsComponent>(performer, out var slowdown);
|
||||
|
||||
slowdown.SpeedAffectors.TryAdd(GetNetEntity(ent), ent.Comp.SpeedMultiplier);
|
||||
Dirty(performer, slowdown);
|
||||
_movement.RefreshMovementSpeedModifiers(performer);
|
||||
}
|
||||
|
||||
private void OnEndDoAfter(Entity<CP14ActionDoAfterSlowdownComponent> ent, ref ActionDoAfterEvent args)
|
||||
{
|
||||
if (args.Repeat)
|
||||
return;
|
||||
|
||||
var performer = GetEntity(args.Performer);
|
||||
if (!TryComp<CP14SlowdownFromActionsComponent>(performer, out var slowdown))
|
||||
return;
|
||||
|
||||
slowdown.SpeedAffectors.Remove(GetNetEntity(ent));
|
||||
Dirty(performer, slowdown);
|
||||
|
||||
_movement.RefreshMovementSpeedModifiers(performer);
|
||||
|
||||
if (slowdown.SpeedAffectors.Count == 0)
|
||||
RemCompDeferred<CP14SlowdownFromActionsComponent>(performer);
|
||||
}
|
||||
|
||||
private void OnRefreshMovespeed(Entity<CP14SlowdownFromActionsComponent> ent, ref RefreshMovementSpeedModifiersEvent args)
|
||||
{
|
||||
var targetSpeedModifier = 1f;
|
||||
|
||||
foreach (var (_, affector) in ent.Comp.SpeedAffectors)
|
||||
{
|
||||
targetSpeedModifier *= affector;
|
||||
}
|
||||
|
||||
args.ModifySpeed(targetSpeedModifier);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
using System.Linq;
|
||||
using Content.Shared._CP14.Actions.Components;
|
||||
using Content.Shared._CP14.MagicSpell.Components;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Mobs;
|
||||
|
||||
|
||||
97
Content.Shared/_CP14/Actions/CP14ActionSystem.Performed.cs
Normal file
97
Content.Shared/_CP14/Actions/CP14ActionSystem.Performed.cs
Normal file
@@ -0,0 +1,97 @@
|
||||
using Content.Shared._CP14.Actions.Components;
|
||||
using Content.Shared._CP14.MagicEnergy.Components;
|
||||
using Content.Shared._CP14.MagicSpell.Events;
|
||||
using Content.Shared.Actions.Events;
|
||||
using Content.Shared.FixedPoint;
|
||||
|
||||
namespace Content.Shared._CP14.Actions;
|
||||
|
||||
public abstract partial class CP14SharedActionSystem
|
||||
{
|
||||
private void InitializePerformed()
|
||||
{
|
||||
SubscribeLocalEvent<CP14ActionMaterialCostComponent, ActionPerformedEvent>(OnMaterialCostActionPerformed);
|
||||
SubscribeLocalEvent<CP14ActionStaminaCostComponent, ActionPerformedEvent>(OnStaminaCostActionPerformed);
|
||||
SubscribeLocalEvent<CP14ActionManaCostComponent, ActionPerformedEvent>(OnManaCostActionPerformed);
|
||||
SubscribeLocalEvent<CP14ActionSkillPointCostComponent, ActionPerformedEvent>(OnSkillPointCostActionPerformed);
|
||||
}
|
||||
|
||||
private void OnMaterialCostActionPerformed(Entity<CP14ActionMaterialCostComponent> ent, ref ActionPerformedEvent args)
|
||||
{
|
||||
if (ent.Comp.Requirement is null)
|
||||
return;
|
||||
|
||||
HashSet<EntityUid> heldedItems = new();
|
||||
|
||||
foreach (var hand in _hand.EnumerateHands(args.Performer))
|
||||
{
|
||||
var helded = _hand.GetHeldItem(args.Performer, hand);
|
||||
if (helded is not null)
|
||||
heldedItems.Add(helded.Value);
|
||||
}
|
||||
|
||||
ent.Comp.Requirement.PostCraft(EntityManager, _proto, heldedItems);
|
||||
}
|
||||
|
||||
private void OnStaminaCostActionPerformed(Entity<CP14ActionStaminaCostComponent> ent, ref ActionPerformedEvent args)
|
||||
{
|
||||
_stamina.TakeStaminaDamage(args.Performer, ent.Comp.Stamina, visual: false);
|
||||
}
|
||||
|
||||
private void OnManaCostActionPerformed(Entity<CP14ActionManaCostComponent> ent, ref ActionPerformedEvent args)
|
||||
{
|
||||
if (!_actionQuery.TryComp(ent, out var action))
|
||||
return;
|
||||
|
||||
if (action.Container is null)
|
||||
return;
|
||||
|
||||
var innate = action.Container == args.Performer;
|
||||
|
||||
var manaCost = ent.Comp.ManaCost;
|
||||
|
||||
if (ent.Comp.CanModifyManacost)
|
||||
{
|
||||
var manaEv = new CP14CalculateManacostEvent(args.Performer, ent.Comp.ManaCost);
|
||||
|
||||
RaiseLocalEvent(args.Performer, manaEv);
|
||||
|
||||
if (!innate)
|
||||
RaiseLocalEvent(action.Container.Value, manaEv);
|
||||
|
||||
manaCost = manaEv.GetManacost();
|
||||
}
|
||||
|
||||
//First - try to take mana from container
|
||||
if (!innate && TryComp<CP14MagicEnergyContainerComponent>(action.Container, out var magicStorage))
|
||||
{
|
||||
var spellEv = new CP14SpellFromSpellStorageUsedEvent(args.Performer, ent, manaCost);
|
||||
RaiseLocalEvent(action.Container.Value, ref spellEv);
|
||||
|
||||
_magicEnergy.ChangeEnergy((action.Container.Value, magicStorage), -manaCost, out var changedEnergy, out var overloadedEnergy, safe: false);
|
||||
manaCost -= FixedPoint2.Abs(changedEnergy + overloadedEnergy);
|
||||
}
|
||||
|
||||
//Second - action user
|
||||
if (manaCost > 0 &&
|
||||
TryComp<CP14MagicEnergyContainerComponent>(args.Performer, out var playerMana))
|
||||
_magicEnergy.ChangeEnergy((args.Performer, playerMana), -manaCost, out _, out _, safe: false);
|
||||
|
||||
//And spawn mana trace
|
||||
_magicVision.SpawnMagicTrace(
|
||||
Transform(args.Performer).Coordinates,
|
||||
action.Icon,
|
||||
Loc.GetString("cp14-magic-vision-used-spell", ("name", MetaData(ent).EntityName)),
|
||||
TimeSpan.FromSeconds((float)ent.Comp.ManaCost * 50),
|
||||
args.Performer,
|
||||
null); //TODO: We need a way to pass spell target here
|
||||
}
|
||||
|
||||
private void OnSkillPointCostActionPerformed(Entity<CP14ActionSkillPointCostComponent> ent, ref ActionPerformedEvent args)
|
||||
{
|
||||
if (ent.Comp.SkillPoint is null)
|
||||
return;
|
||||
|
||||
_skill.RemoveSkillPoints(args.Performer, ent.Comp.SkillPoint.Value, ent.Comp.Count);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
using Content.Shared._CP14.MagicSpell.Spells;
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.Actions.Components;
|
||||
|
||||
namespace Content.Shared._CP14.Actions;
|
||||
|
||||
public abstract partial class CP14SharedActionSystem
|
||||
{
|
||||
private void InitializeModularEffects()
|
||||
{
|
||||
SubscribeLocalEvent<TransformComponent, CP14ActionStartDoAfterEvent>(OnActionTelegraphy);
|
||||
|
||||
SubscribeLocalEvent<TransformComponent, CP14InstantModularEffectEvent>(OnInstantCast);
|
||||
SubscribeLocalEvent<TransformComponent, CP14WorldTargetModularEffectEvent>(OnWorldTargetCast);
|
||||
SubscribeLocalEvent<TransformComponent, CP14EntityTargetModularEffectEvent>(OnEntityTargetCast);
|
||||
}
|
||||
|
||||
private void OnActionTelegraphy(Entity<TransformComponent> ent, ref CP14ActionStartDoAfterEvent args)
|
||||
{
|
||||
if (!_timing.IsFirstTimePredicted)
|
||||
return;
|
||||
|
||||
var performer = GetEntity(args.Performer);
|
||||
var action = GetEntity(args.Input.Action);
|
||||
var target = GetEntity(args.Input.EntityTarget);
|
||||
var targetPosition = GetCoordinates(args.Input.EntityCoordinatesTarget);
|
||||
|
||||
if (!TryComp<ActionComponent>(action, out var actionComp))
|
||||
return;
|
||||
|
||||
//Instant
|
||||
if (TryComp<InstantActionComponent>(action, out var instant) && instant.Event is CP14InstantModularEffectEvent instantModular)
|
||||
{
|
||||
var spellArgs = new CP14SpellEffectBaseArgs(performer, actionComp.Container, performer, Transform(performer).Coordinates);
|
||||
|
||||
foreach (var effect in instantModular.TelegraphyEffects)
|
||||
{
|
||||
effect.Effect(EntityManager, spellArgs);
|
||||
}
|
||||
}
|
||||
|
||||
//World Target
|
||||
if (TryComp<WorldTargetActionComponent>(action, out var worldTarget) && worldTarget.Event is CP14WorldTargetModularEffectEvent worldModular && targetPosition is not null)
|
||||
{
|
||||
var spellArgs = new CP14SpellEffectBaseArgs(performer, actionComp.Container, null, targetPosition.Value);
|
||||
|
||||
foreach (var effect in worldModular.TelegraphyEffects)
|
||||
{
|
||||
effect.Effect(EntityManager, spellArgs);
|
||||
}
|
||||
}
|
||||
|
||||
//Entity Target
|
||||
if (TryComp<EntityTargetActionComponent>(action, out var entityTarget) && entityTarget.Event is CP14EntityTargetModularEffectEvent entityModular && target is not null)
|
||||
{
|
||||
var spellArgs = new CP14SpellEffectBaseArgs(performer, actionComp.Container, target, Transform(target.Value).Coordinates);
|
||||
|
||||
foreach (var effect in entityModular.TelegraphyEffects)
|
||||
{
|
||||
effect.Effect(EntityManager, spellArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnInstantCast(Entity<TransformComponent> ent, ref CP14InstantModularEffectEvent args)
|
||||
{
|
||||
if (!_timing.IsFirstTimePredicted)
|
||||
return;
|
||||
|
||||
var spellArgs = new CP14SpellEffectBaseArgs(args.Performer, args.Action.Comp.Container, args.Performer, Transform(args.Performer).Coordinates);
|
||||
|
||||
foreach (var effect in args.Effects)
|
||||
{
|
||||
effect.Effect(EntityManager, spellArgs);
|
||||
}
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnWorldTargetCast(Entity<TransformComponent> ent, ref CP14WorldTargetModularEffectEvent args)
|
||||
{
|
||||
if (!_timing.IsFirstTimePredicted)
|
||||
return;
|
||||
|
||||
var spellArgs = new CP14SpellEffectBaseArgs(args.Performer, args.Action.Comp.Container, null, args.Target);
|
||||
|
||||
foreach (var effect in args.Effects)
|
||||
{
|
||||
effect.Effect(EntityManager, spellArgs);
|
||||
}
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnEntityTargetCast(Entity<TransformComponent> ent, ref CP14EntityTargetModularEffectEvent args)
|
||||
{
|
||||
if (!_timing.IsFirstTimePredicted)
|
||||
return;
|
||||
|
||||
var spellArgs = new CP14SpellEffectBaseArgs(args.Performer, args.Action.Comp.Container, args.Target, Transform(args.Target).Coordinates);
|
||||
|
||||
foreach (var effect in args.Effects)
|
||||
{
|
||||
effect.Effect(EntityManager, spellArgs);
|
||||
}
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed partial class CP14InstantModularEffectEvent : InstantActionEvent
|
||||
{
|
||||
/// <summary>
|
||||
/// Effects that will trigger at the beginning of the cast, before mana is spent. Should have no gameplay importance, just special effects, popups and sounds.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public List<CP14SpellEffect> TelegraphyEffects = new();
|
||||
|
||||
[DataField]
|
||||
public List<CP14SpellEffect> Effects = new();
|
||||
}
|
||||
|
||||
public sealed partial class CP14WorldTargetModularEffectEvent : WorldTargetActionEvent
|
||||
{
|
||||
/// <summary>
|
||||
/// Effects that will trigger at the beginning of the cast, before mana is spent. Should have no gameplay importance, just special effects, popups and sounds.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public List<CP14SpellEffect> TelegraphyEffects = new();
|
||||
|
||||
[DataField]
|
||||
public List<CP14SpellEffect> Effects = new();
|
||||
}
|
||||
|
||||
public sealed partial class CP14EntityTargetModularEffectEvent : EntityTargetActionEvent
|
||||
{
|
||||
/// <summary>
|
||||
/// Effects that will trigger at the beginning of the cast, before mana is spent. Should have no gameplay importance, just special effects, popups and sounds.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public List<CP14SpellEffect> TelegraphyEffects = new();
|
||||
|
||||
[DataField]
|
||||
public List<CP14SpellEffect> Effects = new();
|
||||
}
|
||||
@@ -1,5 +1,16 @@
|
||||
using Content.Shared._CP14.MagicEnergy;
|
||||
using Content.Shared._CP14.MagicVision;
|
||||
using Content.Shared._CP14.Religion.Systems;
|
||||
using Content.Shared._CP14.Skill;
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.Actions.Components;
|
||||
using Content.Shared.Damage.Systems;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
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.Actions;
|
||||
|
||||
@@ -7,11 +18,37 @@ public abstract partial class CP14SharedActionSystem : EntitySystem
|
||||
{
|
||||
[Dependency] protected readonly SharedPopupSystem Popup = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _hand = default!;
|
||||
[Dependency] private readonly CP14SharedMagicEnergySystem _magicEnergy = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly CP14SharedReligionGodSystem _god = default!;
|
||||
[Dependency] private readonly SharedStaminaSystem _stamina = default!;
|
||||
[Dependency] private readonly CP14SharedSkillSystem _skill = default!;
|
||||
[Dependency] private readonly CP14SharedMagicVisionSystem _magicVision = default!;
|
||||
[Dependency] private readonly MovementSpeedModifierSystem _movement = default!;
|
||||
|
||||
private EntityQuery<ActionComponent> _actionQuery;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
_actionQuery = GetEntityQuery<ActionComponent>();
|
||||
|
||||
InitializeAttempts();
|
||||
InitializeExamine();
|
||||
InitializePerformed();
|
||||
InitializeModularEffects();
|
||||
InitializeDoAfter();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called on an action when an attempt to start doAfter using this action begins.
|
||||
/// </summary>
|
||||
public sealed class CP14ActionStartDoAfterEvent(NetEntity performer, RequestPerformActionEvent input) : EntityEventArgs
|
||||
{
|
||||
public NetEntity Performer = performer;
|
||||
public readonly RequestPerformActionEvent Input = input;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace Content.Shared._CP14.Actions.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Slows the caster while using action
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14SharedActionSystem))]
|
||||
public sealed partial class CP14ActionDoAfterSlowdownComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public float SpeedMultiplier = 1f;
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.MagicSpell.Components;
|
||||
namespace Content.Shared._CP14.Actions.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a temporary entity that exists while the spell is cast, and disappears at the end. For visual special effects.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14SharedMagicSystem))]
|
||||
public sealed partial class CP14MagicEffectCastingVisualComponent : Component
|
||||
[RegisterComponent, Access(typeof(CP14SharedActionSystem))]
|
||||
public sealed partial class CP14ActionDoAfterVisualsComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public EntityUid? SpawnedEntity;
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace Content.Shared._CP14.Actions.Components;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class CP14ActionEmotingComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public string StartEmote = string.Empty; //Not LocId!
|
||||
|
||||
[DataField]
|
||||
public string EndEmote = string.Empty; //Not LocId!
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
namespace Content.Shared._CP14.MagicSpell.Components;
|
||||
namespace Content.Shared._CP14.Actions.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Requires the user to have at least one free hand to use this spell
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14SharedMagicSystem))]
|
||||
[RegisterComponent]
|
||||
public sealed partial class CP14ActionFreeHandsRequiredComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
using Content.Shared._CP14.MagicSpell;
|
||||
|
||||
namespace Content.Shared._CP14.Actions.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Requires the user to play music to use this spell
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14SharedMagicSystem))]
|
||||
[RegisterComponent]
|
||||
public sealed partial class CP14ActionRequiredMusicToolComponent : Component
|
||||
{
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Content.Shared._CP14.Actions.Components;
|
||||
/// <summary>
|
||||
/// Blocks the user from using action against target target in SSD.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14SharedMagicSystem))]
|
||||
[RegisterComponent]
|
||||
public sealed partial class CP14ActionSSDBlockComponent : Component
|
||||
{
|
||||
}
|
||||
|
||||
@@ -11,17 +11,7 @@ public sealed partial class CP14ActionSpeakingComponent : Component
|
||||
|
||||
[DataField]
|
||||
public string EndSpeech = string.Empty; //Not LocId!
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// patch to send an event to the server for saying a phrase out loud
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public sealed class CP14ActionSpeechEvent : EntityEventArgs
|
||||
{
|
||||
public EntityUid? Performer { get; init; }
|
||||
|
||||
public string? Speech { get; init; }
|
||||
|
||||
public bool Emote { get; init; }
|
||||
|
||||
[DataField]
|
||||
public bool Whisper = false;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Content.Shared._CP14.Actions.Components;
|
||||
/// <summary>
|
||||
/// Restricts the use of this action, by spending stamina.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14SharedMagicSystem))]
|
||||
[RegisterComponent]
|
||||
public sealed partial class CP14ActionStaminaCostComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared._CP14.Actions.Components;
|
||||
|
||||
/// <summary>
|
||||
/// apply slowdown effect from casting spells
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(CP14SharedActionSystem))]
|
||||
public sealed partial class CP14SlowdownFromActionsComponent : Component
|
||||
{
|
||||
[DataField, AutoNetworkedField]
|
||||
public Dictionary<NetEntity, float> SpeedAffectors = new();
|
||||
}
|
||||
@@ -1,136 +0,0 @@
|
||||
using Content.Shared._CP14.Actions.Components;
|
||||
using Content.Shared._CP14.MagicEnergy.Components;
|
||||
using Content.Shared._CP14.MagicSpell.Components;
|
||||
using Content.Shared._CP14.MagicSpell.Events;
|
||||
using Content.Shared._CP14.Religion.Systems;
|
||||
using Content.Shared._CP14.Skill;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
|
||||
namespace Content.Shared._CP14.MagicSpell;
|
||||
|
||||
public abstract partial class CP14SharedMagicSystem
|
||||
{
|
||||
[Dependency] private readonly CP14SharedReligionGodSystem _god = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _hand = default!;
|
||||
[Dependency] private readonly CP14SharedSkillSystem _skill = default!;
|
||||
|
||||
private void InitializeChecks()
|
||||
{
|
||||
//Verbal speaking
|
||||
SubscribeLocalEvent<CP14ActionSpeakingComponent, CP14StartCastMagicEffectEvent>(OnVerbalAspectStartCast);
|
||||
SubscribeLocalEvent<CP14ActionSpeakingComponent, CP14MagicEffectConsumeResourceEvent>(OnVerbalAspectAfterCast);
|
||||
|
||||
SubscribeLocalEvent<CP14MagicEffectEmotingComponent, CP14StartCastMagicEffectEvent>(OnEmoteStartCast);
|
||||
SubscribeLocalEvent<CP14MagicEffectEmotingComponent, CP14MagicEffectConsumeResourceEvent>(OnEmoteEndCast);
|
||||
|
||||
//Consuming resources
|
||||
SubscribeLocalEvent<CP14ActionMaterialCostComponent, CP14MagicEffectConsumeResourceEvent>(OnMaterialAspectEndCast);
|
||||
SubscribeLocalEvent<CP14ActionStaminaCostComponent, CP14MagicEffectConsumeResourceEvent>(OnStaminaConsume);
|
||||
SubscribeLocalEvent<CP14ActionManaCostComponent, CP14MagicEffectConsumeResourceEvent>(OnManaConsume);
|
||||
SubscribeLocalEvent<CP14ActionSkillPointCostComponent, CP14MagicEffectConsumeResourceEvent>(OnSkillPointConsume);
|
||||
}
|
||||
|
||||
private void OnVerbalAspectStartCast(Entity<CP14ActionSpeakingComponent> ent,
|
||||
ref CP14StartCastMagicEffectEvent args)
|
||||
{
|
||||
var ev = new CP14ActionSpeechEvent
|
||||
{
|
||||
Performer = args.Performer,
|
||||
Speech = Loc.GetString(ent.Comp.StartSpeech),
|
||||
Emote = false,
|
||||
};
|
||||
RaiseLocalEvent(ent, ref ev);
|
||||
}
|
||||
|
||||
private void OnVerbalAspectAfterCast(Entity<CP14ActionSpeakingComponent> ent,
|
||||
ref CP14MagicEffectConsumeResourceEvent args)
|
||||
{
|
||||
var ev = new CP14ActionSpeechEvent
|
||||
{
|
||||
Performer = args.Performer,
|
||||
Speech = Loc.GetString(ent.Comp.EndSpeech),
|
||||
Emote = false
|
||||
};
|
||||
RaiseLocalEvent(ent, ref ev);
|
||||
}
|
||||
|
||||
private void OnEmoteStartCast(Entity<CP14MagicEffectEmotingComponent> ent, ref CP14StartCastMagicEffectEvent args)
|
||||
{
|
||||
var ev = new CP14ActionSpeechEvent
|
||||
{
|
||||
Performer = args.Performer,
|
||||
Speech = Loc.GetString(ent.Comp.StartEmote),
|
||||
Emote = true,
|
||||
};
|
||||
RaiseLocalEvent(ent, ref ev);
|
||||
}
|
||||
|
||||
|
||||
private void OnEmoteEndCast(Entity<CP14MagicEffectEmotingComponent> ent, ref CP14MagicEffectConsumeResourceEvent args)
|
||||
{
|
||||
var ev = new CP14ActionSpeechEvent
|
||||
{
|
||||
Performer = args.Performer,
|
||||
Speech = Loc.GetString(ent.Comp.EndEmote),
|
||||
Emote = true
|
||||
};
|
||||
RaiseLocalEvent(ent, ref ev);
|
||||
}
|
||||
|
||||
private void OnMaterialAspectEndCast(Entity<CP14ActionMaterialCostComponent> ent, ref CP14MagicEffectConsumeResourceEvent args)
|
||||
{
|
||||
if (ent.Comp.Requirement is null || args.Performer is null)
|
||||
return;
|
||||
|
||||
HashSet<EntityUid> heldedItems = new();
|
||||
|
||||
foreach (var hand in _hand.EnumerateHands(args.Performer.Value))
|
||||
{
|
||||
var helded = _hand.GetHeldItem(args.Performer.Value, hand);
|
||||
if (helded is not null)
|
||||
heldedItems.Add(helded.Value);
|
||||
}
|
||||
|
||||
ent.Comp.Requirement.PostCraft(EntityManager, _proto, heldedItems);
|
||||
}
|
||||
|
||||
private void OnStaminaConsume(Entity<CP14ActionStaminaCostComponent> ent, ref CP14MagicEffectConsumeResourceEvent args)
|
||||
{
|
||||
if (args.Performer is null)
|
||||
return;
|
||||
|
||||
_stamina.TakeStaminaDamage(args.Performer.Value, ent.Comp.Stamina, visual: false);
|
||||
}
|
||||
|
||||
private void OnManaConsume(Entity<CP14ActionManaCostComponent> ent, ref CP14MagicEffectConsumeResourceEvent args)
|
||||
{
|
||||
if (!TryComp<CP14MagicEffectComponent>(ent, out var magicEffect))
|
||||
return;
|
||||
|
||||
var requiredMana = CalculateManacost(ent, args.Performer);
|
||||
|
||||
//First - used object
|
||||
if (magicEffect.SpellStorage is not null && TryComp<CP14MagicEnergyContainerComponent>(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, magicStorage), -requiredMana, out var changedEnergy, out var overloadedEnergy, safe: false);
|
||||
requiredMana -= FixedPoint2.Abs(changedEnergy + overloadedEnergy);
|
||||
}
|
||||
|
||||
//Second - action user
|
||||
if (requiredMana > 0 &&
|
||||
TryComp<CP14MagicEnergyContainerComponent>(args.Performer, out var playerMana))
|
||||
_magicEnergy.ChangeEnergy((args.Performer.Value, playerMana), -requiredMana, out _, out _, safe: false);
|
||||
}
|
||||
|
||||
private void OnSkillPointConsume(Entity<CP14ActionSkillPointCostComponent> ent, ref CP14MagicEffectConsumeResourceEvent args)
|
||||
{
|
||||
if (ent.Comp.SkillPoint is null || args.Performer is null)
|
||||
return;
|
||||
|
||||
_skill.RemoveSkillPoints(args.Performer.Value, ent.Comp.SkillPoint.Value, ent.Comp.Count);
|
||||
}
|
||||
}
|
||||
@@ -1,205 +0,0 @@
|
||||
using Content.Shared._CP14.MagicSpell.Components;
|
||||
using Content.Shared._CP14.MagicSpell.Events;
|
||||
using Content.Shared._CP14.MagicSpell.Spells;
|
||||
using Content.Shared.DoAfter;
|
||||
using Robust.Shared.Map;
|
||||
|
||||
namespace Content.Shared._CP14.MagicSpell;
|
||||
|
||||
public abstract partial class CP14SharedMagicSystem
|
||||
{
|
||||
private void InitializeDelayedActions()
|
||||
{
|
||||
SubscribeLocalEvent<CP14DelayedInstantActionEvent>(OnInstantAction);
|
||||
SubscribeLocalEvent<CP14DelayedWorldTargetActionEvent>(OnWorldTargetAction);
|
||||
SubscribeLocalEvent<CP14DelayedEntityTargetActionEvent>(OnEntityTargetAction);
|
||||
|
||||
SubscribeLocalEvent<CP14MagicEffectComponent, CP14DelayedInstantActionDoAfterEvent>(OnDelayedInstantActionDoAfter);
|
||||
SubscribeLocalEvent<CP14MagicEffectComponent, CP14DelayedEntityWorldTargetActionDoAfterEvent>(OnDelayedEntityWorldTargetDoAfter);
|
||||
SubscribeLocalEvent<CP14MagicEffectComponent, CP14DelayedEntityTargetActionDoAfterEvent>(OnDelayedEntityTargetDoAfter);
|
||||
}
|
||||
|
||||
private bool TryStartDelayedAction(ICP14DelayedMagicEffect delayedEffect, DoAfterEvent doAfter, Entity<CP14MagicEffectComponent> action, EntityUid? target, EntityUid performer)
|
||||
{
|
||||
if (_doAfter.IsRunning(action.Comp.ActiveDoAfter))
|
||||
return false;
|
||||
|
||||
var fromItem = action.Comp.SpellStorage is not null && action.Comp.SpellStorage.Value != performer;
|
||||
|
||||
var doAfterEventArgs = new DoAfterArgs(EntityManager, performer, MathF.Max(delayedEffect.CastDelay, 0.3f), doAfter, action, used: action.Comp.SpellStorage, target: target)
|
||||
{
|
||||
BreakOnMove = delayedEffect.BreakOnMove,
|
||||
BreakOnDamage = delayedEffect.BreakOnDamage,
|
||||
Hidden = delayedEffect.Hidden,
|
||||
DistanceThreshold = delayedEffect.DistanceThreshold,
|
||||
CancelDuplicate = true,
|
||||
BlockDuplicate = true,
|
||||
BreakOnDropItem = fromItem,
|
||||
NeedHand = fromItem,
|
||||
RequireCanInteract = delayedEffect.RequireCanInteract,
|
||||
};
|
||||
|
||||
if (_doAfter.TryStartDoAfter(doAfterEventArgs, out var doAfterId))
|
||||
{
|
||||
action.Comp.ActiveDoAfter = doAfterId;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void EndDelayedAction(Entity<CP14MagicEffectComponent> action, EntityUid performer, float? cooldown = null)
|
||||
{
|
||||
var endEv = new CP14EndCastMagicEffectEvent(performer);
|
||||
RaiseLocalEvent(action, ref endEv);
|
||||
|
||||
if (cooldown is not null)
|
||||
_action.SetCooldown(action.Owner, TimeSpan.FromSeconds(cooldown.Value));
|
||||
}
|
||||
|
||||
private bool UseDelayedAction(ICP14DelayedMagicEffect delayedEffect, Entity<CP14MagicEffectComponent> action, DoAfterEvent doAfter, EntityUid performer, EntityUid? target = null, EntityCoordinates? worldTarget = null)
|
||||
{
|
||||
// Event may return an empty entity with id = 0, which causes bugs
|
||||
var currentTarget = target;
|
||||
if (currentTarget is not null && currentTarget == EntityUid.Invalid)
|
||||
currentTarget = null;
|
||||
|
||||
if (_doAfter.IsRunning(action.Comp.ActiveDoAfter))
|
||||
{
|
||||
_doAfter.Cancel(action.Comp.ActiveDoAfter);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!TryStartDelayedAction(delayedEffect, doAfter, action, currentTarget, performer))
|
||||
return false;
|
||||
|
||||
var evStart = new CP14StartCastMagicEffectEvent(performer);
|
||||
RaiseLocalEvent(action, ref evStart);
|
||||
|
||||
var spellArgs = new CP14SpellEffectBaseArgs(performer, action.Comp.SpellStorage, currentTarget, worldTarget);
|
||||
CastTelegraphy(action, spellArgs);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Instant action used from hotkey event
|
||||
/// </summary>
|
||||
private void OnInstantAction(CP14DelayedInstantActionEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
if (args is not ICP14DelayedMagicEffect delayedEffect)
|
||||
return;
|
||||
|
||||
if (!TryComp<CP14MagicEffectComponent>(args.Action, out var magicEffect))
|
||||
return;
|
||||
|
||||
var doAfter = new CP14DelayedInstantActionDoAfterEvent(args.Cooldown);
|
||||
|
||||
if (!UseDelayedAction(delayedEffect, (args.Action, magicEffect), doAfter, args.Performer, args.Performer))
|
||||
return;
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Target action used from hotkey event
|
||||
/// </summary>
|
||||
private void OnWorldTargetAction(CP14DelayedWorldTargetActionEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
if (args is not ICP14DelayedMagicEffect delayedEffect)
|
||||
return;
|
||||
|
||||
if (!TryComp<CP14MagicEffectComponent>(args.Action, out var magicEffect))
|
||||
return;
|
||||
|
||||
var doAfter = new CP14DelayedEntityWorldTargetActionDoAfterEvent(
|
||||
EntityManager.GetNetCoordinates(args.Target),
|
||||
EntityManager.GetNetEntity(args.Entity),
|
||||
args.Cooldown);
|
||||
|
||||
if (!UseDelayedAction(delayedEffect, (args.Action, magicEffect), doAfter, args.Performer, args.Entity, args.Target))
|
||||
return;
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Target action used from hotkey event
|
||||
/// </summary>
|
||||
private void OnEntityTargetAction(CP14DelayedEntityTargetActionEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
if (args is not ICP14DelayedMagicEffect delayedEffect)
|
||||
return;
|
||||
|
||||
if (!TryComp<CP14MagicEffectComponent>(args.Action, out var magicEffect))
|
||||
return;
|
||||
|
||||
var doAfter = new CP14DelayedEntityTargetActionDoAfterEvent(EntityManager.GetNetEntity(args.Target), args.Cooldown);
|
||||
|
||||
if (!UseDelayedAction(delayedEffect, (args.Action, magicEffect), doAfter, args.Performer, args.Target))
|
||||
return;
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Action doAfter finished or interrupted
|
||||
/// </summary>
|
||||
private void OnDelayedInstantActionDoAfter(Entity<CP14MagicEffectComponent> ent, ref CP14DelayedInstantActionDoAfterEvent args)
|
||||
{
|
||||
EndDelayedAction(ent, args.User, args.Cooldown);
|
||||
|
||||
if (args.Cancelled || args.Handled)
|
||||
return;
|
||||
|
||||
CastSpell(ent, new CP14SpellEffectBaseArgs(args.User, args.Used, args.User, Transform(args.User).Coordinates));
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Action doAfter finished or interrupted
|
||||
/// </summary>
|
||||
private void OnDelayedEntityWorldTargetDoAfter(Entity<CP14MagicEffectComponent> ent,
|
||||
ref CP14DelayedEntityWorldTargetActionDoAfterEvent args)
|
||||
{
|
||||
EndDelayedAction(ent, args.User, args.Cooldown);
|
||||
|
||||
if (args.Cancelled || args.Handled)
|
||||
return;
|
||||
|
||||
var targetPos = EntityManager.GetCoordinates(args.TargetPosition);
|
||||
EntityManager.TryGetEntity(args.TargetEntity, out var targetEnt);
|
||||
|
||||
CastSpell(ent, new CP14SpellEffectBaseArgs(args.User, args.Used, targetEnt, targetPos));
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Action doAfter finished or interrupted
|
||||
/// </summary>
|
||||
private void OnDelayedEntityTargetDoAfter(Entity<CP14MagicEffectComponent> ent, ref CP14DelayedEntityTargetActionDoAfterEvent args)
|
||||
{
|
||||
EndDelayedAction(ent, args.User, args.Cooldown);
|
||||
|
||||
if (args.Cancelled || args.Handled)
|
||||
return;
|
||||
|
||||
EntityManager.TryGetEntity(args.TargetEntity, out var targetEnt);
|
||||
EntityCoordinates? targetPos = null;
|
||||
if (targetEnt is not null) { targetPos = Transform(targetEnt.Value).Coordinates; }
|
||||
|
||||
CastSpell(ent, new CP14SpellEffectBaseArgs(args.User, args.Used, targetEnt, targetPos));
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
using Content.Shared._CP14.MagicSpell.Components;
|
||||
using Content.Shared._CP14.MagicSpell.Events;
|
||||
using Content.Shared._CP14.MagicSpell.Spells;
|
||||
|
||||
namespace Content.Shared._CP14.MagicSpell;
|
||||
|
||||
public abstract partial class CP14SharedMagicSystem
|
||||
{
|
||||
private void InitializeInstantActions()
|
||||
{
|
||||
SubscribeLocalEvent<CP14InstantActionEvent>(OnMagicInstantAction);
|
||||
SubscribeLocalEvent<CP14WorldTargetActionEvent>(OnMagicWorldTargetAction);
|
||||
SubscribeLocalEvent<CP14EntityTargetActionEvent>(OnMagicEntityTargetAction);
|
||||
}
|
||||
|
||||
private void OnMagicInstantAction(CP14InstantActionEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
if (!TryComp<CP14MagicEffectComponent>(args.Action, out var magicEffect))
|
||||
return;
|
||||
|
||||
var spellArgs = new CP14SpellEffectBaseArgs(args.Performer, magicEffect.SpellStorage, args.Performer, Transform(args.Performer).Coordinates);
|
||||
CastSpell((args.Action, magicEffect), spellArgs);
|
||||
|
||||
_action.SetCooldown(args.Action.Owner, args.Cooldown);
|
||||
}
|
||||
|
||||
private void OnMagicWorldTargetAction(CP14WorldTargetActionEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
if (!TryComp<CP14MagicEffectComponent>(args.Action, out var magicEffect))
|
||||
return;
|
||||
|
||||
var spellArgs = new CP14SpellEffectBaseArgs(args.Performer, magicEffect.SpellStorage, null, args.Target);
|
||||
CastSpell((args.Action, magicEffect), spellArgs);
|
||||
|
||||
_action.SetCooldown(args.Action.Owner, args.Cooldown);
|
||||
}
|
||||
|
||||
private void OnMagicEntityTargetAction(CP14EntityTargetActionEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
if (!TryComp<CP14MagicEffectComponent>(args.Action, out var magicEffect))
|
||||
return;
|
||||
|
||||
var spellArgs = new CP14SpellEffectBaseArgs(args.Performer, magicEffect.SpellStorage, args.Target, Transform(args.Target).Coordinates);
|
||||
CastSpell((args.Action, magicEffect), spellArgs);
|
||||
|
||||
_action.SetCooldown(args.Action.Owner, args.Cooldown);
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
using Content.Shared._CP14.MagicSpell.Components;
|
||||
using Content.Shared._CP14.MagicSpell.Events;
|
||||
using Content.Shared.Movement.Systems;
|
||||
|
||||
namespace Content.Shared._CP14.MagicSpell;
|
||||
|
||||
public abstract partial class CP14SharedMagicSystem
|
||||
{
|
||||
private void InitializeSlowdown()
|
||||
{
|
||||
SubscribeLocalEvent<CP14MagicEffectCastSlowdownComponent, CP14StartCastMagicEffectEvent>(OnSlowdownCaster);
|
||||
SubscribeLocalEvent<CP14MagicEffectCastSlowdownComponent, CP14EndCastMagicEffectEvent>(OnUnslowdownCaster);
|
||||
SubscribeLocalEvent<CP14MagicCasterSlowdownComponent, RefreshMovementSpeedModifiersEvent>(OnCasterRefreshMovespeed);
|
||||
}
|
||||
|
||||
private void OnSlowdownCaster(Entity<CP14MagicEffectCastSlowdownComponent> ent, ref CP14StartCastMagicEffectEvent args)
|
||||
{
|
||||
if (!TryComp<CP14MagicCasterSlowdownComponent>(args.Performer, out var caster))
|
||||
return;
|
||||
|
||||
caster.SpeedModifier = ent.Comp.SpeedMultiplier;
|
||||
_movement.RefreshMovementSpeedModifiers(args.Performer);
|
||||
}
|
||||
|
||||
private void OnUnslowdownCaster(Entity<CP14MagicEffectCastSlowdownComponent> ent, ref CP14EndCastMagicEffectEvent args)
|
||||
{
|
||||
if (!TryComp<CP14MagicCasterSlowdownComponent>(args.Performer, out var caster))
|
||||
return;
|
||||
|
||||
caster.SpeedModifier = 1f;
|
||||
|
||||
_movement.RefreshMovementSpeedModifiers(args.Performer);
|
||||
}
|
||||
|
||||
private void OnCasterRefreshMovespeed(Entity<CP14MagicCasterSlowdownComponent> ent, ref RefreshMovementSpeedModifiersEvent args)
|
||||
{
|
||||
args.ModifySpeed(ent.Comp.SpeedModifier);
|
||||
}
|
||||
}
|
||||
@@ -1,199 +0,0 @@
|
||||
using Content.Shared._CP14.MagicSpell.Components;
|
||||
using Content.Shared._CP14.MagicSpell.Events;
|
||||
using Content.Shared._CP14.MagicSpell.Spells;
|
||||
using Content.Shared.DoAfter;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Shared._CP14.MagicSpell;
|
||||
|
||||
public abstract partial class CP14SharedMagicSystem
|
||||
{
|
||||
private void InitializeToggleableActions()
|
||||
{
|
||||
SubscribeLocalEvent<CP14ToggleableInstantActionEvent>(OnToggleableInstantAction);
|
||||
SubscribeLocalEvent<CP14ToggleableWorldTargetActionEvent>(OnToggleableEntityWorldTargetAction);
|
||||
SubscribeLocalEvent<CP14ToggleableEntityTargetActionEvent>(OnToggleableEntityTargetAction);
|
||||
|
||||
SubscribeLocalEvent<CP14MagicEffectComponent, CP14ToggleableInstantActionDoAfterEvent>(OnToggleableInstantActionDoAfterEvent);
|
||||
SubscribeLocalEvent<CP14MagicEffectComponent, CP14ToggleableEntityWorldTargetActionDoAfterEvent>(OnToggleableEntityWorldTargetActionDoAfterEvent);
|
||||
SubscribeLocalEvent<CP14MagicEffectComponent, CP14ToggleableEntityTargetActionDoAfterEvent>(OnToggleableEntityTargetActionDoAfterEvent);
|
||||
}
|
||||
|
||||
private void UpdateToggleableActions()
|
||||
{
|
||||
var query = EntityQueryEnumerator<CP14MagicEffectComponent, CP14MagicEffectToggledComponent>();
|
||||
|
||||
while (query.MoveNext(out var uid, out var effect, out var toggled))
|
||||
{
|
||||
if (toggled.NextTick > _timing.CurTime)
|
||||
continue;
|
||||
|
||||
if (toggled.Performer is null)
|
||||
continue;
|
||||
|
||||
toggled.NextTick = _timing.CurTime + TimeSpan.FromSeconds(toggled.Frequency);
|
||||
|
||||
var spellArgs =
|
||||
new CP14SpellEffectBaseArgs(toggled.Performer, effect.SpellStorage, toggled.EntityTarget, toggled.WorldTarget);
|
||||
|
||||
//if (!CanCastSpell((uid, effect), spellArgs))
|
||||
//{
|
||||
// if (_doAfter.IsRunning(toggled.DoAfterId))
|
||||
// _doAfter.Cancel(toggled.DoAfterId);
|
||||
// continue;
|
||||
//}
|
||||
|
||||
CastSpell((uid, effect), spellArgs);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnToggleableInstantActionDoAfterEvent(Entity<CP14MagicEffectComponent> ent, ref CP14ToggleableInstantActionDoAfterEvent args)
|
||||
{
|
||||
EndToggleableAction(ent, args.User, args.Cooldown);
|
||||
}
|
||||
|
||||
private void OnToggleableEntityWorldTargetActionDoAfterEvent(Entity<CP14MagicEffectComponent> ent, ref CP14ToggleableEntityWorldTargetActionDoAfterEvent args)
|
||||
{
|
||||
EndToggleableAction(ent, args.User, args.Cooldown);
|
||||
}
|
||||
|
||||
private void OnToggleableEntityTargetActionDoAfterEvent(Entity<CP14MagicEffectComponent> ent, ref CP14ToggleableEntityTargetActionDoAfterEvent args)
|
||||
{
|
||||
EndToggleableAction(ent, args.User, args.Cooldown);
|
||||
}
|
||||
|
||||
private void StartToggleableAction(ICP14ToggleableMagicEffect toggleable, DoAfterEvent doAfter, Entity<CP14MagicEffectComponent> action, EntityUid performer, EntityUid? entityTarget = null, EntityCoordinates? worldTarget = null)
|
||||
{
|
||||
if (_doAfter.IsRunning(action.Comp.ActiveDoAfter))
|
||||
return;
|
||||
|
||||
// event may return an empty entity with id = 0, which causes bugs
|
||||
var _target = entityTarget;
|
||||
if (_target is not null && _target.Value.Id == 0)
|
||||
_target = null;
|
||||
|
||||
var evStart = new CP14StartCastMagicEffectEvent(performer);
|
||||
RaiseLocalEvent(action, ref evStart);
|
||||
|
||||
var fromItem = action.Comp.SpellStorage is not null && action.Comp.SpellStorage.Value != performer;
|
||||
|
||||
var doAfterEventArgs = new DoAfterArgs(EntityManager, performer, toggleable.CastTime, doAfter, action, used: action.Comp.SpellStorage, target: _target)
|
||||
{
|
||||
BreakOnMove = toggleable.BreakOnMove,
|
||||
BreakOnDamage = toggleable.BreakOnDamage,
|
||||
Hidden = toggleable.Hidden,
|
||||
DistanceThreshold = toggleable.DistanceThreshold,
|
||||
CancelDuplicate = true,
|
||||
BlockDuplicate = true,
|
||||
BreakOnDropItem = fromItem,
|
||||
NeedHand = fromItem,
|
||||
};
|
||||
|
||||
if (_doAfter.TryStartDoAfter(doAfterEventArgs, out var doAfterId))
|
||||
{
|
||||
EnsureComp<CP14MagicEffectToggledComponent>(action, out var toggled);
|
||||
toggled.Frequency = toggleable.EffectFrequency;
|
||||
toggled.Performer = performer;
|
||||
toggled.DoAfterId = doAfterId;
|
||||
toggled.Cooldown = toggleable.Cooldown;
|
||||
|
||||
toggled.EntityTarget = _target;
|
||||
toggled.WorldTarget = worldTarget;
|
||||
|
||||
action.Comp.ActiveDoAfter = doAfterId;
|
||||
}
|
||||
}
|
||||
|
||||
private void EndToggleableAction(Entity<CP14MagicEffectComponent> action, EntityUid performer, float? cooldown = null)
|
||||
{
|
||||
//This is an extremely dirty hack. I added it only because I know that in the coming weeks we will be rewriting this entire system.
|
||||
// But until then, the game just needs to work as intended. The refactoring of actions hit us all hard...
|
||||
//The main problem is that my stupid spell system has its own separate cooldown, which works independently of the official system (to support doAfters).
|
||||
//And at this point in the code, the cooldown was first set by my system, and then reset to 0 by the official system.
|
||||
//Previously, I edited the official system a little so that it would not reset the cooldowns, but I don't want to repeat this after refactoring the actions.
|
||||
//So I just delay installing the cooldown from my fucked-up system for a split second. This is evil! And we will destroy this evil!
|
||||
Timer.Spawn(50,
|
||||
() =>
|
||||
{
|
||||
if (cooldown is not null)
|
||||
_action.SetCooldown(action.Owner, TimeSpan.FromSeconds(cooldown.Value));
|
||||
});
|
||||
RemCompDeferred<CP14MagicEffectToggledComponent>(action);
|
||||
|
||||
var endEv = new CP14EndCastMagicEffectEvent(performer);
|
||||
RaiseLocalEvent(action, ref endEv);
|
||||
}
|
||||
|
||||
private void ToggleToggleableAction(ICP14ToggleableMagicEffect toggleable, DoAfterEvent doAfter, Entity<CP14MagicEffectComponent> action, EntityUid performer, EntityUid? entityTarget = null, EntityCoordinates? worldTarget = null)
|
||||
{
|
||||
if (_doAfter.IsRunning(action.Comp.ActiveDoAfter))
|
||||
_doAfter.Cancel(action.Comp.ActiveDoAfter);
|
||||
else
|
||||
StartToggleableAction(toggleable, doAfter, action, performer, entityTarget, worldTarget);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Instant action used from hotkey event
|
||||
/// </summary>
|
||||
private void OnToggleableInstantAction(CP14ToggleableInstantActionEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
if (args is not ICP14ToggleableMagicEffect toggleable)
|
||||
return;
|
||||
|
||||
if (!TryComp<CP14MagicEffectComponent>(args.Action, out var magicEffect))
|
||||
return;
|
||||
|
||||
var doAfter = new CP14ToggleableInstantActionDoAfterEvent(args.Cooldown);
|
||||
ToggleToggleableAction(toggleable, doAfter, (args.Action, magicEffect), args.Performer, args.Performer, Transform(args.Performer).Coordinates);
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Target action used from hotkey event
|
||||
/// </summary>
|
||||
private void OnToggleableEntityWorldTargetAction(CP14ToggleableWorldTargetActionEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
if (args is not ICP14ToggleableMagicEffect toggleable)
|
||||
return;
|
||||
|
||||
if (!TryComp<CP14MagicEffectComponent>(args.Action, out var magicEffect))
|
||||
return;
|
||||
|
||||
var doAfter = new CP14ToggleableEntityWorldTargetActionDoAfterEvent(
|
||||
EntityManager.GetNetCoordinates(args.Target),
|
||||
EntityManager.GetNetEntity(args.Entity),
|
||||
args.Cooldown);
|
||||
ToggleToggleableAction(toggleable, doAfter, (args.Action, magicEffect), args.Performer, args.Entity, args.Target);
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Entity target action used from hotkey event
|
||||
/// </summary>
|
||||
private void OnToggleableEntityTargetAction(CP14ToggleableEntityTargetActionEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
if (args is not ICP14ToggleableMagicEffect toggleable)
|
||||
return;
|
||||
|
||||
if (!TryComp<CP14MagicEffectComponent>(args.Action, out var magicEffect))
|
||||
return;
|
||||
|
||||
var doAfter = new CP14ToggleableEntityTargetActionDoAfterEvent(EntityManager.GetNetEntity(args.Target), args.Cooldown);
|
||||
ToggleToggleableAction(toggleable, doAfter, (args.Action, magicEffect), args.Performer, args.Target, Transform(args.Target).Coordinates);
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,165 +0,0 @@
|
||||
using System.Text;
|
||||
using Content.Shared._CP14.Actions.Components;
|
||||
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.Network;
|
||||
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 CP14SharedMagicEnergySystem _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!;
|
||||
[Dependency] private readonly INetManager _net = 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, ComponentShutdown>(OnMagicEffectShutdown);
|
||||
|
||||
SubscribeLocalEvent<CP14MagicEffectComponent, CP14StartCastMagicEffectEvent>(OnStartCast);
|
||||
SubscribeLocalEvent<CP14MagicEffectComponent, CP14EndCastMagicEffectEvent>(OnEndCast);
|
||||
}
|
||||
|
||||
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 (!_net.IsServer)
|
||||
return;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
private void OnMagicEffectShutdown(Entity<CP14MagicEffectComponent> ent, ref ComponentShutdown args)
|
||||
{
|
||||
if (_doAfter.IsRunning(ent.Comp.ActiveDoAfter))
|
||||
_doAfter.Cancel(ent.Comp.ActiveDoAfter);
|
||||
}
|
||||
|
||||
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<CP14ActionManaCostComponent>(ent, out var manaCost))
|
||||
{
|
||||
_magicVision.SpawnMagicTrace(
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
public FixedPoint2 CalculateManacost(Entity<CP14ActionManaCostComponent> 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);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
namespace Content.Shared._CP14.MagicSpell.Components;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14SharedMagicSystem))]
|
||||
public sealed partial class CP14MagicCasterComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public List<EntityUid> CastedSpells = new();
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
namespace Content.Shared._CP14.MagicSpell.Components;
|
||||
|
||||
/// <summary>
|
||||
/// apply slowdown effect from casting spells
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14SharedMagicSystem))]
|
||||
public sealed partial class CP14MagicCasterSlowdownComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public float SpeedModifier = 1f;
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
namespace Content.Shared._CP14.MagicSpell.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Slows the caster while using this spell
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14SharedMagicSystem))]
|
||||
public sealed partial class CP14MagicEffectCastSlowdownComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public float SpeedMultiplier = 1f;
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
using Content.Shared._CP14.MagicRitual.Prototypes;
|
||||
using Content.Shared._CP14.MagicSpell.Spells;
|
||||
using Content.Shared._CP14.MagicSpellStorage;
|
||||
using Content.Shared.DoAfter;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.MagicSpell.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Stores the results and appearance of the magic effect
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14SharedMagicSystem), typeof(CP14SharedSpellStorageSystem))]
|
||||
public sealed partial class CP14MagicEffectComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// if this effect was provided by an spellstorage, it will be recorded here automatically.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public EntityUid? SpellStorage;
|
||||
|
||||
/// <summary>
|
||||
/// Effects that will trigger at the beginning of the cast, before mana is spent. Should have no gameplay importance, just special effects, popups and sounds.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public List<CP14SpellEffect> TelegraphyEffects = new();
|
||||
|
||||
[DataField]
|
||||
public List<CP14SpellEffect> Effects = new();
|
||||
|
||||
[DataField]
|
||||
public DoAfterId? ActiveDoAfter;
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
namespace Content.Shared._CP14.MagicSpell.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Requires the user to be able to speak in order to use this spell. Also forces the user to use certain phrases at the beginning and end of a spell cast
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14SharedMagicSystem))]
|
||||
public sealed partial class CP14MagicEffectEmotingComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public string StartEmote = string.Empty; //Not LocId!
|
||||
|
||||
[DataField]
|
||||
public string EndEmote = string.Empty; //Not LocId!
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
using Content.Shared.DoAfter;
|
||||
using Robust.Shared.Map;
|
||||
|
||||
namespace Content.Shared._CP14.MagicSpell.Components;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[RegisterComponent, AutoGenerateComponentPause, Access(typeof(CP14SharedMagicSystem))]
|
||||
public sealed partial class CP14MagicEffectToggledComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public float Cooldown = 1f;
|
||||
|
||||
[DataField, AutoPausedField]
|
||||
public TimeSpan NextTick = TimeSpan.Zero;
|
||||
|
||||
[DataField]
|
||||
public float Frequency = 0f;
|
||||
|
||||
[DataField]
|
||||
public EntityUid? Performer;
|
||||
|
||||
public DoAfterId? DoAfterId;
|
||||
|
||||
[DataField]
|
||||
public EntityUid? EntityTarget;
|
||||
|
||||
[DataField]
|
||||
public EntityCoordinates? WorldTarget;
|
||||
}
|
||||
@@ -1,10 +1,5 @@
|
||||
using Content.Shared._CP14.MagicRitual.Prototypes;
|
||||
using Content.Shared._CP14.MagicSpell.Components;
|
||||
using Content.Shared._CP14.MagicSpell.Spells;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Inventory;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.MagicSpell.Events;
|
||||
|
||||
@@ -33,59 +28,14 @@ public sealed class CP14CalculateManacostEvent : EntityEventArgs, IInventoryRela
|
||||
public SlotFlags TargetSlots { get; } = SlotFlags.All;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// is invoked if all conditions are met and the spell has begun to be cast (doAfter start moment)
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public sealed class CP14StartCastMagicEffectEvent : EntityEventArgs
|
||||
public sealed class CP14SpellFromSpellStorageUsedEvent(
|
||||
EntityUid? performer,
|
||||
EntityUid? action,
|
||||
FixedPoint2 manacost)
|
||||
: EntityEventArgs
|
||||
{
|
||||
public EntityUid Performer { get; init; }
|
||||
|
||||
public CP14StartCastMagicEffectEvent(EntityUid performer)
|
||||
{
|
||||
Performer = performer;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// is invoked on the spell itself when the spell process has been completed or interrupted (doAfter end moment)
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public sealed class CP14EndCastMagicEffectEvent : EntityEventArgs
|
||||
{
|
||||
public EntityUid Performer { get; init; }
|
||||
|
||||
public CP14EndCastMagicEffectEvent(EntityUid performer)
|
||||
{
|
||||
Performer = performer;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// is invoked only if the spell has been successfully cast
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public sealed class CP14MagicEffectConsumeResourceEvent : EntityEventArgs
|
||||
{
|
||||
public EntityUid? Performer { get; init; }
|
||||
|
||||
public CP14MagicEffectConsumeResourceEvent(EntityUid? performer)
|
||||
{
|
||||
Performer = performer;
|
||||
}
|
||||
}
|
||||
|
||||
[ByRefEvent]
|
||||
public sealed class CP14SpellFromSpellStorageUsedEvent : EntityEventArgs
|
||||
{
|
||||
public EntityUid? Performer { get; init; }
|
||||
public Entity<CP14MagicEffectComponent> Action { get; init; }
|
||||
public FixedPoint2 Manacost { get; init; }
|
||||
|
||||
public CP14SpellFromSpellStorageUsedEvent(EntityUid? performer, Entity<CP14MagicEffectComponent> action, FixedPoint2 manacost)
|
||||
{
|
||||
Performer = performer;
|
||||
Action = action;
|
||||
Manacost = manacost;
|
||||
}
|
||||
public EntityUid? Performer { get; init; } = performer;
|
||||
public EntityUid? Action { get; init; } = action;
|
||||
public FixedPoint2 Manacost { get; init; } = manacost;
|
||||
}
|
||||
|
||||
@@ -1,149 +0,0 @@
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.DoAfter;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._CP14.MagicSpell.Events;
|
||||
|
||||
public interface ICP14DelayedMagicEffect
|
||||
{
|
||||
public float Cooldown { get; }
|
||||
|
||||
public float CastDelay { get; }
|
||||
|
||||
public bool BreakOnMove { get; }
|
||||
|
||||
public bool BreakOnDamage { get; }
|
||||
|
||||
public float DistanceThreshold { get; }
|
||||
|
||||
public bool Hidden { get; }
|
||||
|
||||
public bool RequireCanInteract { get; }
|
||||
}
|
||||
|
||||
public sealed partial class CP14DelayedWorldTargetActionEvent : WorldTargetActionEvent,
|
||||
ICP14DelayedMagicEffect
|
||||
{
|
||||
[DataField]
|
||||
public float Cooldown { get; private set; } = 1f;
|
||||
|
||||
[DataField]
|
||||
public float CastDelay { get; private set; } = 1f;
|
||||
|
||||
[DataField]
|
||||
public bool BreakOnMove { get; private set; } = true;
|
||||
|
||||
[DataField]
|
||||
public bool BreakOnDamage { get; private set; } = true;
|
||||
|
||||
[DataField]
|
||||
public float DistanceThreshold { get; private set; } = 100f;
|
||||
|
||||
[DataField]
|
||||
public bool Hidden { get; private set; } = false;
|
||||
|
||||
[DataField]
|
||||
public bool RequireCanInteract { get; private set; } = true;
|
||||
}
|
||||
|
||||
//Entity Target
|
||||
public sealed partial class CP14DelayedEntityTargetActionEvent : EntityTargetActionEvent,
|
||||
ICP14DelayedMagicEffect
|
||||
{
|
||||
[DataField]
|
||||
public float Cooldown { get; private set; } = 1f;
|
||||
|
||||
[DataField]
|
||||
public float CastDelay { get; private set; } = 1f;
|
||||
|
||||
[DataField]
|
||||
public bool BreakOnMove { get; private set; } = true;
|
||||
|
||||
[DataField]
|
||||
public bool BreakOnDamage { get; private set; } = true;
|
||||
|
||||
[DataField]
|
||||
public float DistanceThreshold { get; private set; } = 100f;
|
||||
|
||||
[DataField]
|
||||
public bool Hidden { get; private set; } = false;
|
||||
|
||||
[DataField]
|
||||
public bool RequireCanInteract { get; private set; } = true;
|
||||
}
|
||||
|
||||
public sealed partial class CP14DelayedInstantActionEvent : InstantActionEvent, ICP14DelayedMagicEffect
|
||||
{
|
||||
[DataField]
|
||||
public float Cooldown { get; private set; } = 3f;
|
||||
|
||||
[DataField]
|
||||
public float CastDelay { get; private set; } = 1f;
|
||||
|
||||
[DataField]
|
||||
public bool BreakOnMove { get; private set; } = true;
|
||||
|
||||
[DataField]
|
||||
public bool BreakOnDamage { get; private set; } = true;
|
||||
|
||||
[DataField]
|
||||
public float DistanceThreshold { get; private set; } = 100f;
|
||||
|
||||
[DataField]
|
||||
public bool Hidden { get; private set; } = false;
|
||||
|
||||
[DataField]
|
||||
public bool RequireCanInteract { get; private set; } = true;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class CP14DelayedEntityWorldTargetActionDoAfterEvent : DoAfterEvent
|
||||
{
|
||||
[DataField]
|
||||
public NetCoordinates? TargetPosition;
|
||||
[DataField]
|
||||
public NetEntity? TargetEntity;
|
||||
[DataField]
|
||||
public float? Cooldown;
|
||||
|
||||
public CP14DelayedEntityWorldTargetActionDoAfterEvent(NetCoordinates? targetPos, NetEntity? targetEntity, float cooldown)
|
||||
{
|
||||
TargetPosition = targetPos;
|
||||
TargetEntity = targetEntity;
|
||||
Cooldown = cooldown;
|
||||
}
|
||||
|
||||
public override DoAfterEvent Clone() => this;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class CP14DelayedEntityTargetActionDoAfterEvent : DoAfterEvent
|
||||
{
|
||||
[DataField]
|
||||
public NetEntity? TargetEntity;
|
||||
[DataField]
|
||||
public float? Cooldown;
|
||||
|
||||
public CP14DelayedEntityTargetActionDoAfterEvent(NetEntity? targetEntity, float cooldown)
|
||||
{
|
||||
TargetEntity = targetEntity;
|
||||
Cooldown = cooldown;
|
||||
}
|
||||
|
||||
public override DoAfterEvent Clone() => this;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class CP14DelayedInstantActionDoAfterEvent : DoAfterEvent
|
||||
{
|
||||
[DataField]
|
||||
public float? Cooldown;
|
||||
|
||||
public CP14DelayedInstantActionDoAfterEvent(float cooldown)
|
||||
{
|
||||
Cooldown = cooldown;
|
||||
}
|
||||
|
||||
public override DoAfterEvent Clone() => this;
|
||||
}
|
||||
@@ -1,147 +0,0 @@
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.DoAfter;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._CP14.MagicSpell.Events;
|
||||
|
||||
public interface ICP14ToggleableMagicEffect
|
||||
{
|
||||
public float EffectFrequency { get; }
|
||||
|
||||
public float CastTime { get; }
|
||||
|
||||
public float Cooldown { get; }
|
||||
|
||||
public bool BreakOnMove { get; }
|
||||
|
||||
public bool BreakOnDamage { get; }
|
||||
|
||||
public float DistanceThreshold { get; }
|
||||
|
||||
public bool Hidden{ get; }
|
||||
}
|
||||
|
||||
public sealed partial class CP14ToggleableInstantActionEvent : InstantActionEvent, ICP14ToggleableMagicEffect
|
||||
{
|
||||
[DataField]
|
||||
public float EffectFrequency { get; private set; } = 1f;
|
||||
|
||||
[DataField]
|
||||
public float Cooldown { get; private set; } = 3f;
|
||||
|
||||
[DataField]
|
||||
public float CastTime { get; private set; } = 10f;
|
||||
|
||||
[DataField]
|
||||
public bool BreakOnMove { get; private set; } = false;
|
||||
|
||||
[DataField]
|
||||
public bool BreakOnDamage { get; private set; } = true;
|
||||
|
||||
[DataField]
|
||||
public float DistanceThreshold { get; private set; } = 100f;
|
||||
|
||||
[DataField]
|
||||
public bool Hidden { get; private set; } = false;
|
||||
}
|
||||
|
||||
public sealed partial class CP14ToggleableWorldTargetActionEvent : WorldTargetActionEvent, ICP14ToggleableMagicEffect
|
||||
{
|
||||
[DataField]
|
||||
public float EffectFrequency { get; private set; } = 1f;
|
||||
|
||||
[DataField]
|
||||
public float Cooldown { get; private set; } = 3f;
|
||||
|
||||
[DataField]
|
||||
public float CastTime { get; private set; } = 10f;
|
||||
|
||||
[DataField]
|
||||
public bool BreakOnMove { get; private set; } = false;
|
||||
|
||||
[DataField]
|
||||
public bool BreakOnDamage { get; private set; } = true;
|
||||
|
||||
[DataField]
|
||||
public float DistanceThreshold { get; private set; } = 100f;
|
||||
|
||||
[DataField]
|
||||
public bool Hidden { get; private set; } = false;
|
||||
}
|
||||
|
||||
public sealed partial class CP14ToggleableEntityTargetActionEvent : EntityTargetActionEvent, ICP14ToggleableMagicEffect
|
||||
{
|
||||
[DataField]
|
||||
public float EffectFrequency { get; private set; } = 1f;
|
||||
|
||||
[DataField]
|
||||
public float Cooldown { get; private set; } = 3f;
|
||||
|
||||
[DataField]
|
||||
public float CastTime { get; private set; } = 10f;
|
||||
|
||||
[DataField]
|
||||
public bool BreakOnMove { get; private set; } = false;
|
||||
|
||||
[DataField]
|
||||
public bool BreakOnDamage { get; private set; } = true;
|
||||
|
||||
[DataField]
|
||||
public float DistanceThreshold { get; private set; } = 100f;
|
||||
|
||||
[DataField]
|
||||
public bool Hidden { get; private set; } = false;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class CP14ToggleableInstantActionDoAfterEvent : DoAfterEvent
|
||||
{
|
||||
[DataField]
|
||||
public float? Cooldown;
|
||||
|
||||
public CP14ToggleableInstantActionDoAfterEvent(float cooldown)
|
||||
{
|
||||
Cooldown = cooldown;
|
||||
}
|
||||
|
||||
public override DoAfterEvent Clone() => this;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class CP14ToggleableEntityWorldTargetActionDoAfterEvent : DoAfterEvent
|
||||
{
|
||||
[DataField]
|
||||
public NetCoordinates? TargetPosition;
|
||||
[DataField]
|
||||
public NetEntity? TargetEntity;
|
||||
[DataField]
|
||||
public float? Cooldown;
|
||||
|
||||
public CP14ToggleableEntityWorldTargetActionDoAfterEvent(NetCoordinates? targetPos, NetEntity? targetEntity, float cooldown)
|
||||
{
|
||||
TargetPosition = targetPos;
|
||||
TargetEntity = targetEntity;
|
||||
Cooldown = cooldown;
|
||||
}
|
||||
|
||||
public override DoAfterEvent Clone() => this;
|
||||
}
|
||||
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class CP14ToggleableEntityTargetActionDoAfterEvent : DoAfterEvent
|
||||
{
|
||||
[DataField]
|
||||
public NetEntity? TargetEntity;
|
||||
[DataField]
|
||||
public float? Cooldown;
|
||||
|
||||
public CP14ToggleableEntityTargetActionDoAfterEvent(NetEntity? targetEntity, float cooldown)
|
||||
{
|
||||
TargetEntity = targetEntity;
|
||||
Cooldown = cooldown;
|
||||
}
|
||||
|
||||
public override DoAfterEvent Clone() => this;
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
using Content.Shared._CP14.Actions.Components;
|
||||
using Content.Shared._CP14.MagicSpell.Components;
|
||||
using Content.Shared.Electrocution;
|
||||
|
||||
namespace Content.Shared._CP14.MagicSpell.Spells;
|
||||
|
||||
public sealed partial class CP14SpellInterruptSpell : CP14SpellEffect
|
||||
{
|
||||
[DataField]
|
||||
public TimeSpan Duration = TimeSpan.FromSeconds(5);
|
||||
|
||||
[DataField]
|
||||
public int Damage = 10;
|
||||
|
||||
public override void Effect(EntityManager entManager, CP14SpellEffectBaseArgs args)
|
||||
{
|
||||
if (args.Target is null)
|
||||
return;
|
||||
|
||||
if (!entManager.TryGetComponent<CP14MagicCasterComponent>(args.Target.Value, out var caster))
|
||||
return;
|
||||
|
||||
var interrupt = false;
|
||||
foreach (var spell in caster.CastedSpells)
|
||||
{
|
||||
if (entManager.HasComponent<CP14ActionManaCostComponent>(spell))
|
||||
{
|
||||
interrupt = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!interrupt)
|
||||
return;
|
||||
|
||||
var electrocutionSystem = entManager.System<SharedElectrocutionSystem>();
|
||||
|
||||
electrocutionSystem.TryDoElectrocution(args.Target.Value, args.User, Damage, Duration, true, ignoreInsulation: true );
|
||||
}
|
||||
}
|
||||
@@ -56,6 +56,7 @@ public abstract partial class CP14SharedSkillSystem
|
||||
{
|
||||
Text = "Reset skills",
|
||||
Message = "Remove all learned skills",
|
||||
Category = VerbCategory.Debug,
|
||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/_CP14/Interface/Misc/reroll.rsi"), "reroll"),
|
||||
Act = () =>
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user