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:
Ed
2025-01-04 21:35:59 +03:00
committed by GitHub
parent a6a4a8da3f
commit 36d02fdf6e
35 changed files with 743 additions and 314 deletions

View File

@@ -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);
}
}
}

View File

@@ -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;

View File

@@ -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");
}

View File

@@ -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);
}
}

View 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);
}
}

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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
{

View File

@@ -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; }
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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 = Затраты энергии

View File

@@ -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:

View File

@@ -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:

View File

@@ -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:

View File

@@ -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:

View File

@@ -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:

View File

@@ -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:

View File

@@ -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:

View File

@@ -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:

View File

@@ -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:

View File

@@ -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

View File

@@ -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

View File

@@ -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:

View File

@@ -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:

View File

@@ -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:

View File

@@ -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:

View File

@@ -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