Magic spells code expansion (#692)
* split manacost in separate component * stamina spells * toggleable actions * swap activeCasting on ActiveDoAfter * remove dublication * Update CP14SharedMagicSystem.ToggleableActions.cs * EntityWoldTarget * mana glove done * fix spell scrolls interrupting * fix cooldown problem * clean up, edit stamina system
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
using Content.Server._CP14.MagicEnergy;
|
||||
using Content.Server.Chat.Systems;
|
||||
using Content.Shared._CP14.MagicEnergy.Components;
|
||||
using Content.Shared._CP14.MagicSpell;
|
||||
using Content.Shared._CP14.MagicSpell.Components;
|
||||
using Content.Shared._CP14.MagicSpell.Events;
|
||||
@@ -10,6 +12,7 @@ public sealed partial class CP14MagicSystem : CP14SharedMagicSystem
|
||||
{
|
||||
[Dependency] private readonly ChatSystem _chat = default!;
|
||||
[Dependency] private readonly TransformSystem _transform = default!;
|
||||
[Dependency] private readonly CP14MagicEnergySystem _magicEnergy = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -19,6 +22,8 @@ public sealed partial class CP14MagicSystem : CP14SharedMagicSystem
|
||||
|
||||
SubscribeLocalEvent<CP14MagicEffectCastingVisualComponent, CP14StartCastMagicEffectEvent>(OnSpawnMagicVisualEffect);
|
||||
SubscribeLocalEvent<CP14MagicEffectCastingVisualComponent, CP14EndCastMagicEffectEvent>(OnDespawnMagicVisualEffect);
|
||||
|
||||
SubscribeLocalEvent<CP14MagicEffectManaCostComponent, CP14MagicEffectConsumeResourceEvent>(OnManaConsume);
|
||||
}
|
||||
|
||||
private void OnSpellSpoken(Entity<CP14MagicEffectVerbalAspectComponent> ent, ref CP14VerbalAspectSpeechEvent args)
|
||||
@@ -39,4 +44,33 @@ public sealed partial class CP14MagicSystem : CP14SharedMagicSystem
|
||||
QueueDel(ent.Comp.SpawnedEntity);
|
||||
ent.Comp.SpawnedEntity = null;
|
||||
}
|
||||
|
||||
private void OnManaConsume(Entity<CP14MagicEffectManaCostComponent> ent, ref CP14MagicEffectConsumeResourceEvent args)
|
||||
{
|
||||
if (!TryComp<CP14MagicEffectComponent>(ent, out var magicEffect))
|
||||
return;
|
||||
|
||||
var requiredMana = CalculateManacost(ent, args.Performer);
|
||||
|
||||
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);
|
||||
|
||||
if (magicStorage.Energy > 0)
|
||||
{
|
||||
//TODO: FIX THIS SHIT
|
||||
var cashedEnergy = magicStorage.Energy;
|
||||
_magicEnergy.TryConsumeEnergy(magicEffect.SpellStorage.Value, requiredMana, magicStorage, false);
|
||||
requiredMana = MathF.Max(0, (float)(requiredMana - cashedEnergy));
|
||||
}
|
||||
}
|
||||
|
||||
if (requiredMana > 0 &&
|
||||
TryComp<CP14MagicEnergyContainerComponent>(args.Performer, out var playerMana))
|
||||
{
|
||||
_magicEnergy.TryConsumeEnergy(args.Performer.Value, requiredMana, safe: false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -716,7 +716,7 @@ public abstract class SharedActionsSystem : EntitySystem
|
||||
action.Enabled = false;
|
||||
}
|
||||
|
||||
action.Cooldown = null;
|
||||
//action.Cooldown = null; //CP14 - disabling auto cooldown after using
|
||||
if (action is { UseDelay: not null, Charges: null or < 1 })
|
||||
{
|
||||
dirty = true;
|
||||
|
||||
@@ -382,10 +382,13 @@ public sealed partial class StaminaSystem : EntitySystem
|
||||
}
|
||||
|
||||
component.Critical = false;
|
||||
component.StaminaDamage = 0f;
|
||||
//CP14 Stamina edit
|
||||
//component.StaminaDamage = 0f;
|
||||
component.StaminaDamage = component.CritThreshold * 0.8f;
|
||||
//CP14 stamina edit end
|
||||
component.NextUpdate = _timing.CurTime;
|
||||
SetStaminaAlert(uid, component);
|
||||
RemComp<ActiveStaminaComponent>(uid);
|
||||
//RemComp<ActiveStaminaComponent>(uid); //CP14
|
||||
Dirty(uid, component);
|
||||
_adminLogger.Add(LogType.Stamina, LogImpact.Low, $"{ToPrettyString(uid):user} recovered from stamina crit");
|
||||
}
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
using Content.Shared._CP14.MagicSpell.Components;
|
||||
using Content.Shared._CP14.MagicSpell.Events;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Speech.Muting;
|
||||
|
||||
namespace Content.Shared._CP14.MagicSpell;
|
||||
|
||||
public abstract partial class CP14SharedMagicSystem
|
||||
{
|
||||
private void InitializeAspects()
|
||||
{
|
||||
SubscribeLocalEvent<CP14MagicEffectSomaticAspectComponent, CP14CastMagicEffectAttemptEvent>(OnSomaticAspectBeforeCast);
|
||||
|
||||
SubscribeLocalEvent<CP14MagicEffectVerbalAspectComponent, CP14CastMagicEffectAttemptEvent>(OnVerbalAspectBeforeCast);
|
||||
SubscribeLocalEvent<CP14MagicEffectVerbalAspectComponent, CP14StartCastMagicEffectEvent>(OnVerbalAspectStartCast);
|
||||
SubscribeLocalEvent<CP14MagicEffectVerbalAspectComponent, CP14AfterCastMagicEffectEvent>(OnVerbalAspectAfterCast);
|
||||
}
|
||||
|
||||
private void OnSomaticAspectBeforeCast(Entity<CP14MagicEffectSomaticAspectComponent> ent, ref CP14CastMagicEffectAttemptEvent args)
|
||||
{
|
||||
if (TryComp<HandsComponent>(args.Performer, out var hands) || hands is not null)
|
||||
{
|
||||
var freeHand = 0;
|
||||
foreach (var hand in hands.Hands)
|
||||
{
|
||||
if (hand.Value.IsEmpty)
|
||||
freeHand++;
|
||||
}
|
||||
if (freeHand >= ent.Comp.FreeHandRequired)
|
||||
return;
|
||||
}
|
||||
args.PushReason(Loc.GetString("cp14-magic-spell-need-somatic-component"));
|
||||
args.Cancel();
|
||||
}
|
||||
|
||||
private void OnVerbalAspectBeforeCast(Entity<CP14MagicEffectVerbalAspectComponent> ent, ref CP14CastMagicEffectAttemptEvent args)
|
||||
{
|
||||
if (HasComp<MutedComponent>(args.Performer))
|
||||
{
|
||||
args.PushReason(Loc.GetString("cp14-magic-spell-need-verbal-component"));
|
||||
args.Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnVerbalAspectStartCast(Entity<CP14MagicEffectVerbalAspectComponent> ent, ref CP14StartCastMagicEffectEvent args)
|
||||
{
|
||||
var ev = new CP14VerbalAspectSpeechEvent
|
||||
{
|
||||
Performer = args.Performer,
|
||||
Speech = ent.Comp.StartSpeech,
|
||||
};
|
||||
RaiseLocalEvent(ent, ref ev);
|
||||
}
|
||||
|
||||
private void OnVerbalAspectAfterCast(Entity<CP14MagicEffectVerbalAspectComponent> ent, ref CP14AfterCastMagicEffectEvent args)
|
||||
{
|
||||
if (_net.IsClient)
|
||||
return;
|
||||
|
||||
var ev = new CP14VerbalAspectSpeechEvent
|
||||
{
|
||||
Performer = args.Performer,
|
||||
Speech = ent.Comp.EndSpeech,
|
||||
};
|
||||
RaiseLocalEvent(ent, ref ev);
|
||||
}
|
||||
|
||||
}
|
||||
111
Content.Shared/_CP14/MagicSpell/CP14SharedMagicSystem.Checks.cs
Normal file
111
Content.Shared/_CP14/MagicSpell/CP14SharedMagicSystem.Checks.cs
Normal file
@@ -0,0 +1,111 @@
|
||||
using Content.Shared._CP14.MagicSpell.Components;
|
||||
using Content.Shared._CP14.MagicSpell.Events;
|
||||
using Content.Shared.Damage.Components;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Speech.Muting;
|
||||
|
||||
namespace Content.Shared._CP14.MagicSpell;
|
||||
|
||||
public abstract partial class CP14SharedMagicSystem
|
||||
{
|
||||
private void InitializeChecks()
|
||||
{
|
||||
SubscribeLocalEvent<CP14MagicEffectSomaticAspectComponent, CP14CastMagicEffectAttemptEvent>(OnSomaticCheck);
|
||||
SubscribeLocalEvent<CP14MagicEffectVerbalAspectComponent, CP14CastMagicEffectAttemptEvent>(OnVerbalCheck);
|
||||
SubscribeLocalEvent<CP14MagicEffectManaCostComponent, CP14CastMagicEffectAttemptEvent>(OnManaCheck);
|
||||
SubscribeLocalEvent<CP14MagicEffectStaminaCostComponent, CP14CastMagicEffectAttemptEvent>(OnStaminaCheck);
|
||||
|
||||
//Verbal speaking
|
||||
SubscribeLocalEvent<CP14MagicEffectVerbalAspectComponent, CP14StartCastMagicEffectEvent>(OnVerbalAspectStartCast);
|
||||
SubscribeLocalEvent<CP14MagicEffectVerbalAspectComponent, CP14MagicEffectConsumeResourceEvent>(OnVerbalAspectAfterCast);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Before using a spell, a mana check is made for the amount of mana to show warnings.
|
||||
/// </summary>
|
||||
private void OnManaCheck(Entity<CP14MagicEffectManaCostComponent> ent, ref CP14CastMagicEffectAttemptEvent args)
|
||||
{
|
||||
var requiredMana = CalculateManacost(ent, args.Performer);
|
||||
|
||||
if (!_magicEffectQuery.TryComp(ent, out var magicEffect))
|
||||
return;
|
||||
|
||||
if (magicEffect.SpellStorage is not null)
|
||||
{
|
||||
if (_magicContainerQuery.TryComp(magicEffect.SpellStorage, out var magicContainer)) // We have item that provides this spell
|
||||
requiredMana = MathF.Max(0, (float)(requiredMana - magicContainer.Energy));
|
||||
}
|
||||
|
||||
if (requiredMana > 0 && _magicContainerQuery.TryComp(args.Performer, out var playerMana))
|
||||
{
|
||||
if (!_magicEnergy.HasEnergy(args.Performer, requiredMana, playerMana, true) && _net.IsServer)
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("cp14-magic-spell-not-enough-mana-cast-warning-"+_random.Next(5)), args.Performer, args.Performer, PopupType.SmallCaution);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnStaminaCheck(Entity<CP14MagicEffectStaminaCostComponent> ent, ref CP14CastMagicEffectAttemptEvent args)
|
||||
{
|
||||
if (!TryComp<StaminaComponent>(args.Performer, out var staminaComp))
|
||||
return;
|
||||
|
||||
if (staminaComp.Critical)
|
||||
{
|
||||
args.PushReason(Loc.GetString("cp14-magic-spell-stamina-not-enough"));
|
||||
args.Cancel();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSomaticCheck(Entity<CP14MagicEffectSomaticAspectComponent> ent, ref CP14CastMagicEffectAttemptEvent args)
|
||||
{
|
||||
if (TryComp<HandsComponent>(args.Performer, out var hands) || hands is not null)
|
||||
{
|
||||
var freeHand = 0;
|
||||
foreach (var hand in hands.Hands)
|
||||
{
|
||||
if (hand.Value.IsEmpty)
|
||||
freeHand++;
|
||||
}
|
||||
if (freeHand >= ent.Comp.FreeHandRequired)
|
||||
return;
|
||||
}
|
||||
args.PushReason(Loc.GetString("cp14-magic-spell-need-somatic-component"));
|
||||
args.Cancel();
|
||||
}
|
||||
|
||||
private void OnVerbalCheck(Entity<CP14MagicEffectVerbalAspectComponent> ent, ref CP14CastMagicEffectAttemptEvent args)
|
||||
{
|
||||
if (HasComp<MutedComponent>(args.Performer))
|
||||
{
|
||||
args.PushReason(Loc.GetString("cp14-magic-spell-need-verbal-component"));
|
||||
args.Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnVerbalAspectStartCast(Entity<CP14MagicEffectVerbalAspectComponent> ent, ref CP14StartCastMagicEffectEvent args)
|
||||
{
|
||||
var ev = new CP14VerbalAspectSpeechEvent
|
||||
{
|
||||
Performer = args.Performer,
|
||||
Speech = ent.Comp.StartSpeech,
|
||||
};
|
||||
RaiseLocalEvent(ent, ref ev);
|
||||
}
|
||||
|
||||
private void OnVerbalAspectAfterCast(Entity<CP14MagicEffectVerbalAspectComponent> ent, ref CP14MagicEffectConsumeResourceEvent args)
|
||||
{
|
||||
if (_net.IsClient)
|
||||
return;
|
||||
|
||||
var ev = new CP14VerbalAspectSpeechEvent
|
||||
{
|
||||
Performer = args.Performer,
|
||||
Speech = ent.Comp.EndSpeech,
|
||||
};
|
||||
RaiseLocalEvent(ent, ref ev);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,13 +1,14 @@
|
||||
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 InitializeActions()
|
||||
private void InitializeDelayedActions()
|
||||
{
|
||||
SubscribeLocalEvent<CP14DelayedInstantActionEvent>(OnInstantAction);
|
||||
SubscribeLocalEvent<CP14DelayedEntityWorldTargetActionEvent>(OnEntityWorldTargetAction);
|
||||
@@ -18,6 +19,65 @@ public abstract partial class CP14SharedMagicSystem
|
||||
SubscribeLocalEvent<CP14MagicEffectComponent, CP14DelayedEntityTargetActionDoAfterEvent>(OnDelayedEntityTargetDoAfter);
|
||||
}
|
||||
|
||||
private bool TryStartDelayedAction(ICP14DelayedMagicEffect delayedEffect, DoAfterEvent doAfter, Entity<CP14MagicEffectComponent> action, EntityUid performer)
|
||||
{
|
||||
if (_doAfter.IsRunning(action.Comp.ActiveDoAfter))
|
||||
return false;
|
||||
|
||||
var fromItem = action.Comp.SpellStorage is not null;
|
||||
|
||||
var doAfterEventArgs = new DoAfterArgs(EntityManager, performer, MathF.Max(delayedEffect.CastDelay, 1f), doAfter, action, used: action.Comp.SpellStorage)
|
||||
{
|
||||
BreakOnMove = delayedEffect.BreakOnMove,
|
||||
BreakOnDamage = delayedEffect.BreakOnDamage,
|
||||
Hidden = delayedEffect.Hidden,
|
||||
DistanceThreshold = 100f,
|
||||
CancelDuplicate = true,
|
||||
BlockDuplicate = true,
|
||||
BreakOnDropItem = fromItem,
|
||||
NeedHand = fromItem,
|
||||
};
|
||||
|
||||
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.CP14StartCustomDelay(action, TimeSpan.FromSeconds(cooldown.Value));
|
||||
}
|
||||
|
||||
private void UseDelayedAction(ICP14DelayedMagicEffect delayedEffect, Entity<CP14MagicEffectComponent> action, DoAfterEvent doAfter, EntityUid performer)
|
||||
{
|
||||
if (!CanCastSpell(action, performer))
|
||||
return;
|
||||
|
||||
if (_doAfter.IsRunning(action.Comp.ActiveDoAfter))
|
||||
_doAfter.Cancel(action.Comp.ActiveDoAfter);
|
||||
else
|
||||
{
|
||||
if (TryStartDelayedAction(delayedEffect, doAfter, action, performer))
|
||||
{
|
||||
var evStart = new CP14StartCastMagicEffectEvent(performer);
|
||||
RaiseLocalEvent(action, ref evStart);
|
||||
|
||||
var spellArgs =
|
||||
new CP14SpellEffectBaseArgs(performer, action.Comp.SpellStorage, performer, Transform(performer).Coordinates);
|
||||
|
||||
CastTelegraphy(action, spellArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Instant action used from hotkey event
|
||||
/// </summary>
|
||||
@@ -32,28 +92,8 @@ public abstract partial class CP14SharedMagicSystem
|
||||
if (!TryComp<CP14MagicEffectComponent>(args.Action, out var magicEffect))
|
||||
return;
|
||||
|
||||
Entity<CP14MagicEffectComponent> spell = (args.Action, magicEffect);
|
||||
|
||||
if (!CanCastSpell(spell, args.Performer))
|
||||
return;
|
||||
|
||||
if (args.CastDelay > 0)
|
||||
{
|
||||
var doAfter = new CP14DelayedInstantActionDoAfterEvent(args.Cooldown);
|
||||
if (!TryCastSpellDelayed(delayedEffect, doAfter, (args.Action, magicEffect), args.Performer))
|
||||
return;
|
||||
}
|
||||
|
||||
var evStart = new CP14StartCastMagicEffectEvent( args.Performer);
|
||||
RaiseLocalEvent(args.Action, ref evStart);
|
||||
|
||||
var spellArgs =
|
||||
new CP14SpellEffectBaseArgs(args.Performer, magicEffect.SpellStorage, args.Performer, Transform(args.Performer).Coordinates);
|
||||
|
||||
CastTelegraphy((args.Action, magicEffect), spellArgs);
|
||||
|
||||
if (args.CastDelay == 0)
|
||||
CastSpell((args.Action, magicEffect), spellArgs, args.Cooldown);
|
||||
var doAfter = new CP14DelayedInstantActionDoAfterEvent(args.Cooldown);
|
||||
UseDelayedAction(delayedEffect, (args.Action, magicEffect), doAfter, args.Performer);
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
@@ -72,33 +112,11 @@ public abstract partial class CP14SharedMagicSystem
|
||||
if (!TryComp<CP14MagicEffectComponent>(args.Action, out var magicEffect))
|
||||
return;
|
||||
|
||||
Entity<CP14MagicEffectComponent> spell = (args.Action, magicEffect);
|
||||
|
||||
if (!CanCastSpell(spell, args.Performer))
|
||||
return;
|
||||
|
||||
|
||||
if (args.CastDelay > 0)
|
||||
{
|
||||
var doAfter = new CP14DelayedEntityWorldTargetActionDoAfterEvent(
|
||||
EntityManager.GetNetCoordinates(args.Coords),
|
||||
EntityManager.GetNetEntity(args.Entity),
|
||||
args.Cooldown);
|
||||
|
||||
if (!TryCastSpellDelayed(delayedEffect, doAfter, (args.Action, magicEffect), args.Performer))
|
||||
return;
|
||||
}
|
||||
|
||||
var evStart = new CP14StartCastMagicEffectEvent( args.Performer);
|
||||
RaiseLocalEvent(args.Action, ref evStart);
|
||||
|
||||
var spellArgs =
|
||||
new CP14SpellEffectBaseArgs(args.Performer, magicEffect.SpellStorage, args.Entity, args.Coords);
|
||||
|
||||
CastTelegraphy((args.Action, magicEffect), spellArgs);
|
||||
|
||||
if (args.CastDelay <= 0)
|
||||
CastSpell((args.Action, magicEffect), spellArgs, args.Cooldown);
|
||||
var doAfter = new CP14DelayedEntityWorldTargetActionDoAfterEvent(
|
||||
EntityManager.GetNetCoordinates(args.Coords),
|
||||
EntityManager.GetNetEntity(args.Entity),
|
||||
args.Cooldown);
|
||||
UseDelayedAction(delayedEffect, (args.Action, magicEffect), doAfter, args.Performer);
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
@@ -117,32 +135,8 @@ public abstract partial class CP14SharedMagicSystem
|
||||
if (!TryComp<CP14MagicEffectComponent>(args.Action, out var magicEffect))
|
||||
return;
|
||||
|
||||
Entity<CP14MagicEffectComponent> spell = (args.Action, magicEffect);
|
||||
|
||||
if (!CanCastSpell(spell, args.Performer))
|
||||
return;
|
||||
|
||||
if (args.CastDelay > 0)
|
||||
{
|
||||
var doAfter = new CP14DelayedEntityTargetActionDoAfterEvent(
|
||||
EntityManager.GetNetEntity(args.Target),
|
||||
args.Cooldown);
|
||||
|
||||
if (!TryCastSpellDelayed(delayedEffect, doAfter, (args.Action, magicEffect), args.Performer))
|
||||
return;
|
||||
}
|
||||
|
||||
var evStart = new CP14StartCastMagicEffectEvent( args.Performer);
|
||||
RaiseLocalEvent(args.Action, ref evStart);
|
||||
|
||||
var spellArgs =
|
||||
new CP14SpellEffectBaseArgs(args.Performer, magicEffect.SpellStorage, args.Target, Transform(args.Target).Coordinates);
|
||||
|
||||
CastTelegraphy((args.Action, magicEffect), spellArgs);
|
||||
|
||||
//TODO: Bug! If CastDelay = 0, cooldown dont want apply to spell aftercast
|
||||
if (args.CastDelay <= 0)
|
||||
CastSpell((args.Action, magicEffect), spellArgs, args.Cooldown);
|
||||
var doAfter = new CP14DelayedEntityTargetActionDoAfterEvent(EntityManager.GetNetEntity(args.Target), args.Cooldown);
|
||||
UseDelayedAction(delayedEffect, (args.Action, magicEffect), doAfter, args.Performer);
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
@@ -152,13 +146,12 @@ public abstract partial class CP14SharedMagicSystem
|
||||
/// </summary>
|
||||
private void OnDelayedInstantActionDoAfter(Entity<CP14MagicEffectComponent> ent, ref CP14DelayedInstantActionDoAfterEvent args)
|
||||
{
|
||||
var endEv = new CP14EndCastMagicEffectEvent(args.User);
|
||||
RaiseLocalEvent(ent, ref endEv);
|
||||
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.Cooldown ?? 0);
|
||||
CastSpell(ent, new CP14SpellEffectBaseArgs(args.User, args.Used, args.User, Transform(args.User).Coordinates));
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
@@ -169,8 +162,7 @@ public abstract partial class CP14SharedMagicSystem
|
||||
private void OnDelayedEntityWorldTargetDoAfter(Entity<CP14MagicEffectComponent> ent,
|
||||
ref CP14DelayedEntityWorldTargetActionDoAfterEvent args)
|
||||
{
|
||||
var endEv = new CP14EndCastMagicEffectEvent(args.User);
|
||||
RaiseLocalEvent(ent, ref endEv);
|
||||
EndDelayedAction(ent, args.User, args.Cooldown);
|
||||
|
||||
if (args.Cancelled || args.Handled)
|
||||
return;
|
||||
@@ -178,7 +170,7 @@ public abstract partial class CP14SharedMagicSystem
|
||||
var targetPos = EntityManager.GetCoordinates(args.TargetPosition);
|
||||
EntityManager.TryGetEntity(args.TargetEntity, out var targetEnt);
|
||||
|
||||
CastSpell(ent, new CP14SpellEffectBaseArgs(args.User, args.Used, targetEnt, targetPos), args.Cooldown ?? 0);
|
||||
CastSpell(ent, new CP14SpellEffectBaseArgs(args.User, args.Used, targetEnt, targetPos));
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
@@ -188,8 +180,7 @@ public abstract partial class CP14SharedMagicSystem
|
||||
/// </summary>
|
||||
private void OnDelayedEntityTargetDoAfter(Entity<CP14MagicEffectComponent> ent, ref CP14DelayedEntityTargetActionDoAfterEvent args)
|
||||
{
|
||||
var endEv = new CP14EndCastMagicEffectEvent(args.User);
|
||||
RaiseLocalEvent(ent, ref endEv);
|
||||
EndDelayedAction(ent, args.User, args.Cooldown);
|
||||
|
||||
if (args.Cancelled || args.Handled)
|
||||
return;
|
||||
@@ -198,7 +189,7 @@ public abstract partial class CP14SharedMagicSystem
|
||||
EntityCoordinates? targetPos = null;
|
||||
if (targetEnt is not null) { targetPos = Transform(targetEnt.Value).Coordinates; }
|
||||
|
||||
CastSpell(ent, new CP14SpellEffectBaseArgs(args.User, args.Used, targetEnt, targetPos), args.Cooldown ?? 0);
|
||||
CastSpell(ent, new CP14SpellEffectBaseArgs(args.User, args.Used, targetEnt, targetPos));
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
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 InitializeToggleableActions()
|
||||
{
|
||||
SubscribeLocalEvent<CP14ToggleableInstantActionEvent>(OnInstantAction);
|
||||
SubscribeLocalEvent<CP14ToggleableEntityWorldTargetActionEvent>(OnEntityWorldTargetAction);
|
||||
SubscribeLocalEvent<CP14ToggleableEntityTargetActionEvent>(OnEntityTargetAction);
|
||||
|
||||
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), toggled.Performer.Value))
|
||||
{
|
||||
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;
|
||||
|
||||
var evStart = new CP14StartCastMagicEffectEvent(performer);
|
||||
RaiseLocalEvent(action, ref evStart);
|
||||
|
||||
var fromItem = action.Comp.SpellStorage is not null;
|
||||
|
||||
var doAfterEventArgs = new DoAfterArgs(EntityManager, performer, toggleable.CastTime, doAfter, action, used: action.Comp.SpellStorage)
|
||||
{
|
||||
BreakOnMove = toggleable.BreakOnMove,
|
||||
BreakOnDamage = toggleable.BreakOnDamage,
|
||||
Hidden = toggleable.Hidden,
|
||||
DistanceThreshold = 100f,
|
||||
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 = entityTarget;
|
||||
toggled.WorldTarget = worldTarget;
|
||||
|
||||
action.Comp.ActiveDoAfter = doAfterId;
|
||||
}
|
||||
}
|
||||
|
||||
private void EndToggleableAction(Entity<CP14MagicEffectComponent> action, EntityUid performer, float? cooldown = null)
|
||||
{
|
||||
if (cooldown is not null)
|
||||
_action.CP14StartCustomDelay(action, 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 (!CanCastSpell(action, performer))
|
||||
return;
|
||||
|
||||
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 OnInstantAction(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 OnEntityWorldTargetAction(CP14ToggleableEntityWorldTargetActionEvent 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.Coords),
|
||||
EntityManager.GetNetEntity(args.Entity),
|
||||
args.Cooldown);
|
||||
ToggleToggleableAction(toggleable, doAfter, (args.Action, magicEffect), args.Performer, args.Entity, args.Coords);
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Entity target action used from hotkey event
|
||||
/// </summary>
|
||||
private void OnEntityTargetAction(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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using Content.Shared._CP14.MagicSpell.Events;
|
||||
using Content.Shared._CP14.MagicSpell.Spells;
|
||||
using Content.Shared._CP14.MagicSpellStorage;
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.Damage.Systems;
|
||||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Movement.Systems;
|
||||
@@ -13,6 +14,7 @@ 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;
|
||||
|
||||
@@ -30,21 +32,34 @@ public abstract partial class CP14SharedMagicSystem : EntitySystem
|
||||
[Dependency] private readonly MetaDataSystem _meta = default!;
|
||||
[Dependency] private readonly SharedActionsSystem _action = default!;
|
||||
[Dependency] private readonly MovementSpeedModifierSystem _movement = default!;
|
||||
[Dependency] private readonly StaminaSystem _stamina = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
|
||||
private EntityQuery<CP14MagicEnergyContainerComponent> _magicContainerQuery;
|
||||
private EntityQuery<CP14MagicEffectComponent> _magicEffectQuery;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
InitializeActions();
|
||||
InitializeAspects();
|
||||
InitializeDelayedActions();
|
||||
InitializeToggleableActions();
|
||||
InitializeChecks();
|
||||
InitializeSlowdown();
|
||||
|
||||
_magicContainerQuery = GetEntityQuery<CP14MagicEnergyContainerComponent>();
|
||||
_magicEffectQuery = GetEntityQuery<CP14MagicEffectComponent>();
|
||||
|
||||
SubscribeLocalEvent<CP14MagicEffectComponent, MapInitEvent>(OnMagicEffectInit);
|
||||
SubscribeLocalEvent<CP14MagicEffectComponent, CP14CastMagicEffectAttemptEvent>(OnBeforeCastMagicEffect);
|
||||
SubscribeLocalEvent<CP14MagicEffectComponent, ComponentShutdown>(OnMagicEffectShutdown);
|
||||
|
||||
SubscribeLocalEvent<CP14MagicEffectComponent, CP14AfterCastMagicEffectEvent>(OnAfterCastMagicEffect);
|
||||
SubscribeLocalEvent<CP14MagicEffectStaminaCostComponent, CP14MagicEffectConsumeResourceEvent>(OnStaminaConsume);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
UpdateToggleableActions();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -56,11 +71,20 @@ public abstract partial class CP14SharedMagicSystem : EntitySystem
|
||||
var sb = new StringBuilder();
|
||||
|
||||
sb.Append(meta.EntityDescription);
|
||||
sb.Append($"\n\n {Loc.GetString("cp14-magic-manacost")}: [color=#5da9e8]{ent.Comp.ManaCost}[/color]");
|
||||
|
||||
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-magic-type")}: [color={indexedMagic.Color.ToHex()}]{Loc.GetString(indexedMagic.Name)}[/color]");
|
||||
sb.Append($"\n{Loc.GetString("cp14-magic-magic-type")}: [color={indexedMagic.Color.ToHex()}]{Loc.GetString(indexedMagic.Name)}[/color]");
|
||||
}
|
||||
|
||||
if (TryComp<CP14MagicEffectVerbalAspectComponent>(ent, out var verbal))
|
||||
@@ -76,6 +100,12 @@ public abstract partial class CP14SharedMagicSystem : EntitySystem
|
||||
_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>
|
||||
@@ -90,36 +120,6 @@ public abstract partial class CP14SharedMagicSystem : EntitySystem
|
||||
return !ev.Cancelled;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Before using a spell, a mana check is made for the amount of mana to show warnings.
|
||||
/// </summary>
|
||||
private void OnBeforeCastMagicEffect(Entity<CP14MagicEffectComponent> ent, ref CP14CastMagicEffectAttemptEvent args)
|
||||
{
|
||||
var requiredMana = CalculateManacost(ent, args.Performer);
|
||||
|
||||
if (ent.Comp.SpellStorage is not null)
|
||||
{
|
||||
if (_magicContainerQuery.TryComp(ent.Comp.SpellStorage, out var magicContainer)) // We have item that provides this spell
|
||||
requiredMana = MathF.Max(0, (float)(requiredMana - magicContainer.Energy));
|
||||
|
||||
if (!ent.Comp.SpellStorage.Value.Comp.CanUseCasterMana && requiredMana > 0)
|
||||
{
|
||||
args.PushReason(Loc.GetString("cp14-magic-spell-not-enough-mana-item"));
|
||||
args.Cancel();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (requiredMana > 0 && _magicContainerQuery.TryComp(args.Performer, out var playerMana))
|
||||
{
|
||||
if (!_magicEnergy.HasEnergy(args.Performer, requiredMana, playerMana, true) && _net.IsServer)
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("cp14-magic-spell-not-enough-mana-cast-warning-"+_random.Next(5)), args.Performer, args.Performer, PopupType.SmallCaution);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CastTelegraphy(Entity<CP14MagicEffectComponent> ent, CP14SpellEffectBaseArgs args)
|
||||
{
|
||||
if (!_net.IsServer)
|
||||
@@ -131,28 +131,10 @@ public abstract partial class CP14SharedMagicSystem : EntitySystem
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryCastSpellDelayed(ICP14DelayedMagicEffect delayedEffect, DoAfterEvent doAfter, Entity<CP14MagicEffectComponent> action, EntityUid performer)
|
||||
private void CastSpell(Entity<CP14MagicEffectComponent> ent, CP14SpellEffectBaseArgs args)
|
||||
{
|
||||
var fromItem = action.Comp.SpellStorage is not null;
|
||||
|
||||
var doAfterEventArgs = new DoAfterArgs(EntityManager, performer, delayedEffect.CastDelay, doAfter, action, used: action.Comp.SpellStorage)
|
||||
{
|
||||
BreakOnMove = delayedEffect.BreakOnMove,
|
||||
BreakOnDamage = delayedEffect.BreakOnDamage,
|
||||
Hidden = delayedEffect.Hidden,
|
||||
DistanceThreshold = 100f,
|
||||
CancelDuplicate = true,
|
||||
BlockDuplicate = true,
|
||||
BreakOnDropItem = fromItem,
|
||||
NeedHand = fromItem,
|
||||
};
|
||||
|
||||
return _doAfter.TryStartDoAfter(doAfterEventArgs);
|
||||
}
|
||||
|
||||
private void CastSpell(Entity<CP14MagicEffectComponent> ent, CP14SpellEffectBaseArgs args, float cooldown)
|
||||
{
|
||||
_action.CP14StartCustomDelay(ent, TimeSpan.FromSeconds(cooldown));
|
||||
var ev = new CP14MagicEffectConsumeResourceEvent(args.User);
|
||||
RaiseLocalEvent(ent, ref ev);
|
||||
|
||||
if (_net.IsServer)
|
||||
{
|
||||
@@ -161,57 +143,33 @@ public abstract partial class CP14SharedMagicSystem : EntitySystem
|
||||
effect.Effect(EntityManager, args);
|
||||
}
|
||||
}
|
||||
|
||||
var ev = new CP14AfterCastMagicEffectEvent(args.User);
|
||||
RaiseLocalEvent(ent, ref ev);
|
||||
}
|
||||
|
||||
private void OnAfterCastMagicEffect(Entity<CP14MagicEffectComponent> ent, ref CP14AfterCastMagicEffectEvent args)
|
||||
{
|
||||
if (_net.IsClient)
|
||||
return;
|
||||
|
||||
var requiredMana = CalculateManacost(ent, args.Performer);
|
||||
|
||||
if (ent.Comp.SpellStorage is not null &&
|
||||
_magicContainerQuery.TryComp(ent.Comp.SpellStorage, out var magicStorage))
|
||||
{
|
||||
var spellEv = new CP14SpellFromSpellStorageUsedEvent(args.Performer, ent, requiredMana);
|
||||
RaiseLocalEvent(ent.Comp.SpellStorage.Value, ref spellEv);
|
||||
|
||||
if (magicStorage.Energy > 0)
|
||||
{
|
||||
//TODO: FIX THIS SHIT
|
||||
var cashedEnergy = magicStorage.Energy;
|
||||
_magicEnergy.TryConsumeEnergy(ent.Comp.SpellStorage.Value, requiredMana, magicStorage, false);
|
||||
requiredMana = MathF.Max(0, (float)(requiredMana - cashedEnergy));
|
||||
}
|
||||
}
|
||||
|
||||
if (requiredMana > 0 &&
|
||||
_magicContainerQuery.TryComp(args.Performer, out var playerMana))
|
||||
{
|
||||
_magicEnergy.TryConsumeEnergy(args.Performer.Value, requiredMana, safe: false);
|
||||
}
|
||||
}
|
||||
|
||||
private FixedPoint2 CalculateManacost(Entity<CP14MagicEffectComponent> ent, EntityUid? caster)
|
||||
protected FixedPoint2 CalculateManacost(Entity<CP14MagicEffectManaCostComponent> ent, EntityUid? caster)
|
||||
{
|
||||
var manaCost = ent.Comp.ManaCost;
|
||||
|
||||
if (ent.Comp.CanModifyManacost)
|
||||
if (ent.Comp.CanModifyManacost && _magicEffectQuery.TryComp(ent, out var magicEffect))
|
||||
{
|
||||
var manaEv = new CP14CalculateManacostEvent(caster, ent.Comp.ManaCost, ent.Comp.MagicType);
|
||||
var manaEv = new CP14CalculateManacostEvent(caster, ent.Comp.ManaCost, magicEffect.MagicType);
|
||||
|
||||
if (caster is not null)
|
||||
RaiseLocalEvent(caster.Value, manaEv);
|
||||
|
||||
if (ent.Comp.SpellStorage is not null)
|
||||
RaiseLocalEvent(ent.Comp.SpellStorage.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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
using Content.Shared._CP14.MagicRitual.Prototypes;
|
||||
using Content.Shared._CP14.MagicSpell.Spells;
|
||||
using Content.Shared._CP14.MagicSpellStorage;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.DoAfter;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.MagicSpell.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Restricts the use of this action, by spending mana or user requirements.
|
||||
/// Stores the results and appearance of the magic effect
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14SharedMagicSystem), typeof(CP14SpellStorageSystem))]
|
||||
public sealed partial class CP14MagicEffectComponent : Component
|
||||
@@ -18,18 +18,9 @@ public sealed partial class CP14MagicEffectComponent : Component
|
||||
[DataField]
|
||||
public Entity<CP14SpellStorageComponent>? SpellStorage;
|
||||
|
||||
[DataField]
|
||||
public FixedPoint2 ManaCost = 0f;
|
||||
|
||||
[DataField]
|
||||
public ProtoId<CP14MagicTypePrototype>? MagicType = null;
|
||||
|
||||
/// <summary>
|
||||
/// Can the cost of casting this magic effect be changed from clothing or other sources?
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool CanModifyManacost = true;
|
||||
|
||||
/// <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>
|
||||
@@ -38,4 +29,7 @@ public sealed partial class CP14MagicEffectComponent : Component
|
||||
|
||||
[DataField]
|
||||
public List<CP14SpellEffect> Effects = new();
|
||||
|
||||
[DataField]
|
||||
public DoAfterId? ActiveDoAfter;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
using Content.Shared._CP14.MagicSpellStorage;
|
||||
using Content.Shared.FixedPoint;
|
||||
|
||||
namespace Content.Shared._CP14.MagicSpell.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Restricts the use of this action, by spending mana or user requirements.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14SharedMagicSystem), typeof(CP14SpellStorageSystem))]
|
||||
public sealed partial class CP14MagicEffectManaCostComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public FixedPoint2 ManaCost = 0f;
|
||||
|
||||
/// <summary>
|
||||
/// Can the cost of casting this magic effect be changed from clothing or other sources?
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool CanModifyManacost = true;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using Content.Shared._CP14.MagicSpellStorage;
|
||||
|
||||
namespace Content.Shared._CP14.MagicSpell.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Restricts the use of this action, by spending stamina.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14SharedMagicSystem), typeof(CP14SpellStorageSystem))]
|
||||
public sealed partial class CP14MagicEffectStaminaCostComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public float Stamina = 0f;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
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;
|
||||
}
|
||||
@@ -89,11 +89,11 @@ public sealed class CP14EndCastMagicEffectEvent : EntityEventArgs
|
||||
/// is invoked only if the spell has been successfully cast
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public sealed class CP14AfterCastMagicEffectEvent : EntityEventArgs
|
||||
public sealed class CP14MagicEffectConsumeResourceEvent : EntityEventArgs
|
||||
{
|
||||
public EntityUid? Performer { get; init; }
|
||||
|
||||
public CP14AfterCastMagicEffectEvent(EntityUid? performer)
|
||||
public CP14MagicEffectConsumeResourceEvent(EntityUid? performer)
|
||||
{
|
||||
Performer = performer;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,21 @@ 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 bool Hidden{ get; }
|
||||
|
||||
public float EntityDistance { get; }
|
||||
}
|
||||
|
||||
public sealed partial class CP14DelayedEntityWorldTargetActionEvent : EntityWorldTargetActionEvent,
|
||||
ICP14DelayedMagicEffect
|
||||
{
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
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 bool Hidden{ get; }
|
||||
|
||||
public float EntityDistance { get; }
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
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 bool Hidden{ get; }
|
||||
|
||||
public float EntityDistance { 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 bool Hidden { get; private set; } = false;
|
||||
|
||||
[DataField]
|
||||
public float EntityDistance { get; private set; } = 100f;
|
||||
}
|
||||
|
||||
public sealed partial class CP14ToggleableEntityWorldTargetActionEvent : EntityWorldTargetActionEvent, 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 bool Hidden { get; private set; } = false;
|
||||
|
||||
[DataField]
|
||||
public float EntityDistance { get; private set; } = 100f;
|
||||
}
|
||||
|
||||
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 bool Hidden { get; private set; } = false;
|
||||
|
||||
[DataField]
|
||||
public float EntityDistance { get; private set; } = 100f;
|
||||
}
|
||||
|
||||
[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;
|
||||
}
|
||||
@@ -19,10 +19,4 @@ public sealed partial class CP14SpellStorageComponent : Component
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public List<EntityUid> SpellEntities = new();
|
||||
|
||||
/// <summary>
|
||||
/// allows you to use an caster's mana to create spells.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool CanUseCasterMana = true;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
cp14-magic-spell-not-enough-mana = Not enough mana!
|
||||
cp14-magic-spell-not-enough-mana-item = Not enough mana in {$item}!
|
||||
|
||||
|
||||
cp14-magic-spell-not-enough-mana-cast-warning-0 = Everything inside you starts to whine unpleasantly...
|
||||
cp14-magic-spell-not-enough-mana-cast-warning-1 = Your head starts to buzz...
|
||||
@@ -13,4 +11,7 @@ cp14-magic-energy-damage-overload = You can't hold that much mana!
|
||||
cp14-magic-energy-damage-burn-out-fall = You pass out from the intense pain!
|
||||
|
||||
cp14-magic-spell-need-verbal-component = You can't cast the spell out loud.
|
||||
cp14-magic-spell-need-somatic-component = You don't have your hands free.
|
||||
cp14-magic-spell-need-somatic-component = You don't have your hands free.
|
||||
|
||||
cp14-magic-spell-stamina-not-enough = You don't have the energy to do it.
|
||||
cp14-magic-staminacost = Stamina cost
|
||||
@@ -1,5 +1,4 @@
|
||||
cp14-magic-spell-not-enough-mana = Недостаточно магической энергии!
|
||||
cp14-magic-spell-not-enough-mana-item = Недостаточно магической энергии в {$item}!
|
||||
|
||||
cp14-magic-spell-not-enough-mana-cast-warning-0 = Внутри вас все начинает неприятно ныть...
|
||||
cp14-magic-spell-not-enough-mana-cast-warning-1 = Голова начинает шуметь...
|
||||
@@ -12,4 +11,7 @@ cp14-magic-energy-damage-overload = Вы не можете удержать ст
|
||||
cp14-magic-energy-damage-burn-out-fall = Вы теряете сознание от сильной боли!
|
||||
|
||||
cp14-magic-spell-need-verbal-component = Вы не можете произнести заклинание вслух.
|
||||
cp14-magic-spell-need-somatic-component = Вам не хватает свободных рук.
|
||||
cp14-magic-spell-need-somatic-component = Вам не хватает свободных рук.
|
||||
|
||||
cp14-magic-spell-stamina-not-enough = Вам не хватает сил, чтобы сделать это.
|
||||
cp14-magic-staminacost = Затраты энергии
|
||||
@@ -8,9 +8,10 @@
|
||||
state: earth_wall
|
||||
- type: CP14MagicEffectCastSlowdown
|
||||
speedMultiplier: 0.3
|
||||
- type: CP14MagicEffectManaCost
|
||||
manaCost: 15
|
||||
- type: CP14MagicEffect
|
||||
magicType: Earth
|
||||
manaCost: 15
|
||||
telegraphyEffects:
|
||||
- !type:CP14SpellSpawnEntityOnTarget
|
||||
spawns:
|
||||
|
||||
@@ -6,9 +6,10 @@
|
||||
- type: Sprite
|
||||
sprite: _CP14/Effects/Magic/spells_icons.rsi
|
||||
state: flame_creation
|
||||
- type: CP14MagicEffectManaCost
|
||||
manaCost: 5
|
||||
- type: CP14MagicEffect
|
||||
magicType: Fire
|
||||
manaCost: 5
|
||||
effects:
|
||||
- !type:CP14SpellSpawnEntityOnTarget
|
||||
spawns:
|
||||
|
||||
@@ -8,9 +8,10 @@
|
||||
state: fireball
|
||||
- type: CP14MagicEffectCastSlowdown
|
||||
speedMultiplier: 0.3
|
||||
- type: CP14MagicEffectManaCost
|
||||
manaCost: 20
|
||||
- type: CP14MagicEffect
|
||||
magicType: Fire
|
||||
manaCost: 20
|
||||
effects:
|
||||
- !type:CP14SpellSpawnEntityOnUser
|
||||
spawns:
|
||||
|
||||
@@ -8,9 +8,10 @@
|
||||
state: shadow_step
|
||||
- type: CP14MagicEffectCastSlowdown
|
||||
speedMultiplier: 0.8
|
||||
- type: CP14MagicEffectManaCost
|
||||
manaCost: 20
|
||||
- type: CP14MagicEffect
|
||||
magicType: Gate
|
||||
manaCost: 20
|
||||
telegraphyEffects:
|
||||
- !type:CP14SpellSpawnEntityOnTarget
|
||||
spawns:
|
||||
|
||||
@@ -8,9 +8,10 @@
|
||||
state: cure_burn
|
||||
- type: CP14MagicEffectCastSlowdown
|
||||
speedMultiplier: 0.5
|
||||
- type: CP14MagicEffectManaCost
|
||||
manaCost: 10
|
||||
- type: CP14MagicEffect
|
||||
magicType: Healing
|
||||
manaCost: 10
|
||||
telegraphyEffects:
|
||||
- !type:CP14SpellSpawnEntityOnTarget
|
||||
spawns:
|
||||
|
||||
@@ -8,9 +8,10 @@
|
||||
state: cure_poison
|
||||
- type: CP14MagicEffectCastSlowdown
|
||||
speedMultiplier: 0.5
|
||||
- type: CP14MagicEffectManaCost
|
||||
manaCost: 10
|
||||
- type: CP14MagicEffect
|
||||
magicType: Healing
|
||||
manaCost: 10
|
||||
telegraphyEffects:
|
||||
- !type:CP14SpellSpawnEntityOnTarget
|
||||
spawns:
|
||||
|
||||
@@ -8,9 +8,10 @@
|
||||
state: cure_wounds
|
||||
- type: CP14MagicEffectCastSlowdown
|
||||
speedMultiplier: 0.5
|
||||
- type: CP14MagicEffectManaCost
|
||||
manaCost: 10
|
||||
- type: CP14MagicEffect
|
||||
magicType: Healing
|
||||
manaCost: 10
|
||||
telegraphyEffects:
|
||||
- !type:CP14SpellSpawnEntityOnTarget
|
||||
spawns:
|
||||
|
||||
@@ -6,9 +6,10 @@
|
||||
- type: Sprite
|
||||
sprite: _CP14/Effects/Magic/spells_icons.rsi
|
||||
state: sphere_of_light
|
||||
- type: CP14MagicEffectManaCost
|
||||
manaCost: 10
|
||||
- type: CP14MagicEffect
|
||||
magicType: LightDarkness
|
||||
manaCost: 10
|
||||
effects:
|
||||
- !type:CP14SpellSpawnEntityOnTarget
|
||||
spawns:
|
||||
|
||||
@@ -6,9 +6,10 @@
|
||||
- type: Sprite
|
||||
sprite: _CP14/Effects/Magic/spells_icons.rsi
|
||||
state: flash_light
|
||||
- type: CP14MagicEffectManaCost
|
||||
manaCost: 10
|
||||
- type: CP14MagicEffect
|
||||
magicType: LightDarkness
|
||||
manaCost: 10
|
||||
telegraphyEffects:
|
||||
- !type:CP14SpellSpawnEntityOnTarget
|
||||
spawns:
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
state: mana_consume
|
||||
- type: CP14MagicEffect
|
||||
magicType: Meta
|
||||
manaCost: 0
|
||||
canModifyManacost: false
|
||||
telegraphyEffects:
|
||||
- !type:CP14SpellSpawnEntityOnTarget
|
||||
spawns:
|
||||
@@ -34,9 +32,9 @@
|
||||
icon:
|
||||
sprite: _CP14/Effects/Magic/spells_icons.rsi
|
||||
state: mana_consume
|
||||
event: !type:CP14DelayedEntityTargetActionEvent
|
||||
cooldown: 1
|
||||
castDelay: 2
|
||||
event: !type:CP14ToggleableEntityTargetActionEvent
|
||||
cooldown: 5
|
||||
castTime: 10
|
||||
breakOnMove: true
|
||||
|
||||
- type: entity
|
||||
|
||||
@@ -6,10 +6,11 @@
|
||||
- type: Sprite
|
||||
sprite: _CP14/Effects/Magic/spells_icons.rsi
|
||||
state: mana_gift
|
||||
- type: CP14MagicEffect
|
||||
magicType: Meta
|
||||
- type: CP14MagicEffectManaCost
|
||||
manaCost: 12
|
||||
canModifyManacost: false
|
||||
- type: CP14MagicEffect
|
||||
magicType: Meta
|
||||
telegraphyEffects:
|
||||
- !type:CP14SpellSpawnEntityOnTarget
|
||||
spawns:
|
||||
@@ -39,9 +40,9 @@
|
||||
icon:
|
||||
sprite: _CP14/Effects/Magic/spells_icons.rsi
|
||||
state: mana_gift
|
||||
event: !type:CP14DelayedEntityTargetActionEvent
|
||||
cooldown: 1
|
||||
castDelay: 1
|
||||
event: !type:CP14ToggleableEntityTargetActionEvent
|
||||
cooldown: 5
|
||||
castTime: 10
|
||||
|
||||
- type: entity
|
||||
id: CP14RuneManaGift
|
||||
|
||||
@@ -6,9 +6,10 @@
|
||||
- type: Sprite
|
||||
sprite: _CP14/Effects/Magic/spells_icons.rsi
|
||||
state: shadow_grab
|
||||
- type: CP14MagicEffectManaCost
|
||||
manaCost: 10
|
||||
- type: CP14MagicEffect
|
||||
magicType: Movement
|
||||
manaCost: 10
|
||||
telegraphyEffects:
|
||||
- !type:CP14SpellSpawnEntityOnTarget
|
||||
spawns:
|
||||
|
||||
@@ -8,9 +8,10 @@
|
||||
state: resurrection
|
||||
- type: CP14MagicEffectCastSlowdown
|
||||
speedMultiplier: 0.2
|
||||
- type: CP14MagicEffectManaCost
|
||||
manaCost: 100
|
||||
- type: CP14MagicEffect
|
||||
magicType: Necromancy
|
||||
manaCost: 100
|
||||
telegraphyEffects:
|
||||
- !type:CP14SpellSpawnEntityOnTarget
|
||||
spawns:
|
||||
|
||||
@@ -6,9 +6,10 @@
|
||||
- type: Sprite
|
||||
sprite: _CP14/Effects/Magic/spells_icons.rsi
|
||||
state: water_creation
|
||||
- type: CP14MagicEffectManaCost
|
||||
manaCost: 10
|
||||
- type: CP14MagicEffect
|
||||
magicType: Water
|
||||
manaCost: 10
|
||||
effects:
|
||||
- !type:CP14SpellSpawnEntityOnTarget
|
||||
spawns:
|
||||
|
||||
@@ -6,9 +6,10 @@
|
||||
- type: Sprite
|
||||
sprite: _CP14/Effects/Magic/spells_icons.rsi
|
||||
state: beer_creation
|
||||
- type: CP14MagicEffectManaCost
|
||||
manaCost: 50
|
||||
- type: CP14MagicEffect
|
||||
magicType: Water
|
||||
manaCost: 50
|
||||
effects:
|
||||
- !type:CP14SpellSpawnEntityOnTarget
|
||||
spawns:
|
||||
|
||||
@@ -8,9 +8,10 @@
|
||||
state: ice_shards
|
||||
- type: CP14MagicEffectCastSlowdown
|
||||
speedMultiplier: 0.75
|
||||
- type: CP14MagicEffectManaCost
|
||||
manaCost: 5
|
||||
- type: CP14MagicEffect
|
||||
magicType: Water
|
||||
manaCost: 5
|
||||
effects:
|
||||
- !type:CP14SpellProjectile
|
||||
prototype: CP14IceShard
|
||||
|
||||
Reference in New Issue
Block a user