Spellcasting upgrade (#543)

* move to gurps magic types

* spell traits, categorize spells

* Update TraitSystem.cs

* magic spells item provider

* Update twoHandedStaffs.yml

* Update CP14MagicManacostModifySystem.cs

* Update CP14SpellStorageSystem.cs

* some funny shit

* fix problems 1

* FIX

* more funny broken shit

* predict slowdown, fixes funny

* EntityTarget action

* fixes

* Update T1_sphere_of_light.yml

* fix demiplan loot centering

* predict movement!
This commit is contained in:
Ed
2024-11-07 16:04:49 +03:00
committed by GitHub
parent 7e4fb90e02
commit ebac4a2eec
30 changed files with 681 additions and 451 deletions

View File

@@ -0,0 +1,198 @@
using Content.Shared._CP14.MagicSpell.Components;
using Content.Shared._CP14.MagicSpell.Events;
using Content.Shared._CP14.MagicSpell.Spells;
using Robust.Shared.Map;
namespace Content.Shared._CP14.MagicSpell;
public abstract partial class CP14SharedMagicSystem
{
private void InitializeActions()
{
SubscribeLocalEvent<CP14DelayedInstantActionEvent>(OnInstantAction);
SubscribeLocalEvent<CP14DelayedEntityWorldTargetActionEvent>(OnEntityWorldTargetAction);
SubscribeLocalEvent<CP14DelayedEntityTargetActionEvent>(OnEntityTargetAction);
SubscribeLocalEvent<CP14MagicEffectComponent, CP14DelayedInstantActionDoAfterEvent>(OnDelayedInstantActionDoAfter);
SubscribeLocalEvent<CP14MagicEffectComponent, CP14DelayedEntityWorldTargetActionDoAfterEvent>(OnDelayedEntityWorldTargetDoAfter);
SubscribeLocalEvent<CP14MagicEffectComponent, CP14DelayedEntityTargetActionDoAfterEvent>(OnDelayedEntityTargetDoAfter);
}
/// <summary>
/// Instant action used from hotkey event
/// </summary>
private void OnInstantAction(CP14DelayedInstantActionEvent args)
{
if (args.Handled)
return;
if (args is not ICP14DelayedMagicEffect delayedEffect)
return;
if (!CanCastSpell(args.Action, args.Performer))
return;
if (!TryComp<CP14MagicEffectComponent>(args.Action, out var magicEffect))
return;
if (args.CastDelay > 0)
{
var doAfter = new CP14DelayedInstantActionDoAfterEvent(args.Cooldown);
if (!TryCastSpellDelayed(delayedEffect, doAfter, args.Action, args.Performer))
return;
}
var evStart = new CP14StartCastMagicEffectEvent( args.Performer);
RaiseLocalEvent(args.Action, ref evStart);
var spellArgs =
new CP14SpellEffectBaseArgs(args.Performer, args.Performer, Transform(args.Performer).Coordinates);
CastTelegraphy((args.Action, magicEffect), spellArgs);
if (args.CastDelay == 0)
CastSpell((args.Action, magicEffect), spellArgs, args.Cooldown);
args.Handled = true;
}
/// <summary>
/// Target action used from hotkey event
/// </summary>
private void OnEntityWorldTargetAction(CP14DelayedEntityWorldTargetActionEvent args)
{
if (args.Handled)
return;
if (args is not ICP14DelayedMagicEffect delayedEffect)
return;
if (!CanCastSpell(args.Action, args.Performer))
return;
if (!TryComp<CP14MagicEffectComponent>(args.Action, out var magicEffect))
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, args.Performer))
return;
}
var evStart = new CP14StartCastMagicEffectEvent( args.Performer);
RaiseLocalEvent(args.Action, ref evStart);
var spellArgs =
new CP14SpellEffectBaseArgs(args.Performer, args.Entity, args.Coords);
CastTelegraphy((args.Action, magicEffect), spellArgs);
if (args.CastDelay <= 0)
CastSpell((args.Action, magicEffect), spellArgs, args.Cooldown);
args.Handled = true;
}
/// <summary>
/// Target action used from hotkey event
/// </summary>
private void OnEntityTargetAction(CP14DelayedEntityTargetActionEvent args)
{
if (args.Handled)
return;
if (args is not ICP14DelayedMagicEffect delayedEffect)
return;
if (!CanCastSpell(args.Action, args.Performer))
return;
if (!TryComp<CP14MagicEffectComponent>(args.Action, out var magicEffect))
return;
if (args.CastDelay > 0)
{
var doAfter = new CP14DelayedEntityTargetActionDoAfterEvent(
EntityManager.GetNetEntity(args.Target),
args.Cooldown);
if (!TryCastSpellDelayed(delayedEffect, doAfter, args.Action, args.Performer))
return;
}
var evStart = new CP14StartCastMagicEffectEvent( args.Performer);
RaiseLocalEvent(args.Action, ref evStart);
var spellArgs =
new CP14SpellEffectBaseArgs(args.Performer, 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);
args.Handled = true;
}
/// <summary>
/// Action doAfter finished or interrupted
/// </summary>
private void OnDelayedInstantActionDoAfter(Entity<CP14MagicEffectComponent> ent, ref CP14DelayedInstantActionDoAfterEvent args)
{
var endEv = new CP14EndCastMagicEffectEvent(args.User);
RaiseLocalEvent(ent, ref endEv);
if (args.Cancelled || args.Handled)
return;
CastSpell(ent, new CP14SpellEffectBaseArgs(args.User, args.User, Transform(args.User).Coordinates), args.Cooldown ?? 0);
args.Handled = true;
}
/// <summary>
/// Action doAfter finished or interrupted
/// </summary>
private void OnDelayedEntityWorldTargetDoAfter(Entity<CP14MagicEffectComponent> ent,
ref CP14DelayedEntityWorldTargetActionDoAfterEvent args)
{
var endEv = new CP14EndCastMagicEffectEvent(args.User);
RaiseLocalEvent(ent, ref endEv);
if (args.Cancelled || args.Handled)
return;
var targetPos = EntityManager.GetCoordinates(args.TargetPosition);
EntityManager.TryGetEntity(args.TargetEntity, out var targetEnt);
CastSpell(ent, new CP14SpellEffectBaseArgs(args.User, targetEnt, targetPos), args.Cooldown ?? 0);
args.Handled = true;
}
/// <summary>
/// Action doAfter finished or interrupted
/// </summary>
private void OnDelayedEntityTargetDoAfter(Entity<CP14MagicEffectComponent> ent, ref CP14DelayedEntityTargetActionDoAfterEvent args)
{
var endEv = new CP14EndCastMagicEffectEvent(args.User);
RaiseLocalEvent(ent, ref endEv);
if (args.Cancelled || args.Handled)
return;
EntityManager.TryGetEntity(args.TargetEntity, out var targetEnt);
EntityCoordinates? targetPos = null;
if (targetEnt is not null) { targetPos = Transform(targetEnt.Value).Coordinates; }
CastSpell(ent, new CP14SpellEffectBaseArgs(args.User, targetEnt, targetPos), args.Cooldown ?? 0);
args.Handled = true;
}
}

View File

@@ -0,0 +1,68 @@
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,39 @@
using Content.Shared._CP14.MagicSpell.Components;
using Content.Shared._CP14.MagicSpell.Events;
using Content.Shared.Movement.Systems;
namespace Content.Shared._CP14.MagicSpell;
public abstract partial class CP14SharedMagicSystem
{
private void InitializeSlowdown()
{
SubscribeLocalEvent<CP14MagicEffectCastSlowdownComponent, CP14StartCastMagicEffectEvent>(OnSlowdownCaster);
SubscribeLocalEvent<CP14MagicEffectCastSlowdownComponent, CP14EndCastMagicEffectEvent>(OnUnslowdownCaster);
SubscribeLocalEvent<CP14MagicCasterSlowdownComponent, RefreshMovementSpeedModifiersEvent>(OnCasterRefreshMovespeed);
}
private void OnSlowdownCaster(Entity<CP14MagicEffectCastSlowdownComponent> ent, ref CP14StartCastMagicEffectEvent args)
{
if (!TryComp<CP14MagicCasterSlowdownComponent>(args.Performer, out var caster))
return;
caster.SpeedModifier = ent.Comp.SpeedMultiplier;
_movement.RefreshMovementSpeedModifiers(args.Performer);
}
private void OnUnslowdownCaster(Entity<CP14MagicEffectCastSlowdownComponent> ent, ref CP14EndCastMagicEffectEvent args)
{
if (!TryComp<CP14MagicCasterSlowdownComponent>(args.Performer, out var caster))
return;
caster.SpeedModifier = 1f;
_movement.RefreshMovementSpeedModifiers(args.Performer);
}
private void OnCasterRefreshMovespeed(Entity<CP14MagicCasterSlowdownComponent> ent, ref RefreshMovementSpeedModifiersEvent args)
{
args.ModifySpeed(ent.Comp.SpeedModifier);
}
}

View File

@@ -5,11 +5,11 @@ using Content.Shared._CP14.MagicSpell.Components;
using Content.Shared._CP14.MagicSpell.Events;
using Content.Shared._CP14.MagicSpell.Spells;
using Content.Shared._CP14.MagicSpellStorage;
using Content.Shared.Actions;
using Content.Shared.DoAfter;
using Content.Shared.FixedPoint;
using Content.Shared.Hands.Components;
using Content.Shared.Movement.Systems;
using Content.Shared.Popups;
using Content.Shared.Speech.Muting;
using Robust.Shared.Network;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
@@ -19,7 +19,7 @@ namespace Content.Shared._CP14.MagicSpell;
/// <summary>
/// This system handles the basic mechanics of spell use, such as doAfter, event invocation, and energy spending.
/// </summary>
public partial class CP14SharedMagicSystem : EntitySystem
public abstract partial class CP14SharedMagicSystem : EntitySystem
{
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
[Dependency] private readonly INetManager _net = default!;
@@ -28,28 +28,25 @@ public partial class CP14SharedMagicSystem : EntitySystem
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly MetaDataSystem _meta = default!;
[Dependency] private readonly SharedActionsSystem _action = default!;
[Dependency] private readonly MovementSpeedModifierSystem _movement = default!;
public override void Initialize()
{
base.Initialize();
InitializeActions();
InitializeAspects();
InitializeSlowdown();
SubscribeLocalEvent<CP14MagicEffectComponent, MapInitEvent>(OnMagicEffectInit);
SubscribeLocalEvent<CP14MagicEffectComponent, CP14BeforeCastMagicEffectEvent>(OnBeforeCastMagicEffect);
SubscribeLocalEvent<CP14DelayedInstantActionEvent>(OnInstantAction);
SubscribeLocalEvent<CP14DelayedEntityWorldTargetActionEvent>(OnEntityWorldTargetAction);
SubscribeLocalEvent<CP14MagicEffectComponent, CP14DelayedInstantActionDoAfterEvent>(OnDelayedInstantActionDoAfter);
SubscribeLocalEvent<CP14MagicEffectComponent, CP14DelayedEntityWorldTargetActionDoAfterEvent>(OnDelayedEntityWorldTargetDoAfter);
SubscribeLocalEvent<CP14MagicEffectSomaticAspectComponent, CP14BeforeCastMagicEffectEvent>(OnSomaticAspectBeforeCast);
SubscribeLocalEvent<CP14MagicEffectVerbalAspectComponent, CP14BeforeCastMagicEffectEvent>(OnVerbalAspectBeforeCast);
SubscribeLocalEvent<CP14MagicEffectVerbalAspectComponent, CP14AfterCastMagicEffectEvent>(OnVerbalAspectAfterCast);
SubscribeLocalEvent<CP14MagicEffectComponent, CP14CastMagicEffectAttemptEvent>(OnBeforeCastMagicEffect);
SubscribeLocalEvent<CP14MagicEffectComponent, CP14AfterCastMagicEffectEvent>(OnAfterCastMagicEffect);
}
/// <summary>
/// Auto generation description for spell action
/// </summary>
private void OnMagicEffectInit(Entity<CP14MagicEffectComponent> ent, ref MapInitEvent args)
{
var meta = MetaData(ent);
@@ -76,219 +73,96 @@ public partial class CP14SharedMagicSystem : EntitySystem
_meta.SetEntityDescription(ent, sb.ToString());
}
private void OnBeforeCastMagicEffect(Entity<CP14MagicEffectComponent> ent, ref CP14BeforeCastMagicEffectEvent args)
/// <summary>
/// Checking to see if the spell can be used at all
/// </summary>
private bool CanCastSpell(EntityUid spell, EntityUid performer)
{
if (!TryComp<CP14MagicEnergyContainerComponent>(args.Caster, out var magicContainer))
{
args.Cancel();
return;
}
var manaCost = CalculateManacost(ent, args.Caster);
if (!_magicEnergy.HasEnergy(args.Caster, manaCost, magicContainer, ent.Comp.Safe))
{
args.PushReason(Loc.GetString("cp14-magic-spell-not-enough-mana"));
args.Cancel();
}
else if(!_magicEnergy.HasEnergy(args.Caster, manaCost, magicContainer, true) && _net.IsServer)
{
_popup.PopupEntity(Loc.GetString("cp14-magic-spell-not-enough-mana-cast-warning-"+_random.Next(5)), args.Caster, args.Caster, PopupType.SmallCaution);
}
}
private void OnInstantAction(CP14DelayedInstantActionEvent args)
{
if (args.Handled)
return;
args.Handled = true;
if (args is not ICP14DelayedMagicEffect delayedEffect)
return;
if (!TryCastSpell(args.Action, args.Performer))
return;
var doAfterEventArgs = new DoAfterArgs(EntityManager, args.Performer, delayedEffect.Delay, new CP14DelayedInstantActionDoAfterEvent(), args.Action)
{
BreakOnMove = delayedEffect.BreakOnMove,
BreakOnDamage = delayedEffect.BreakOnDamage,
Hidden = delayedEffect.Hidden,
BlockDuplicate = true,
DistanceThreshold = 100f,
};
_doAfter.TryStartDoAfter(doAfterEventArgs);
//Telegraphy effects
if (_net.IsServer && TryComp<CP14MagicEffectComponent>(args.Action, out var magicEffect))
{
foreach (var effect in magicEffect.TelegraphyEffects)
{
effect.Effect(EntityManager, new CP14SpellEffectBaseArgs(args.Performer, args.Performer, Transform(args.Performer).Coordinates));
}
}
}
private void OnEntityWorldTargetAction(CP14DelayedEntityWorldTargetActionEvent args)
{
if (args.Handled)
return;
args.Handled = true;
if (args is not ICP14DelayedMagicEffect delayedEffect)
return;
if (!TryCastSpell(args.Action, args.Performer))
return;
var doAfter = new CP14DelayedEntityWorldTargetActionDoAfterEvent(
EntityManager.GetNetCoordinates(args.Coords),
EntityManager.GetNetEntity(args.Entity));
var doAfterEventArgs = new DoAfterArgs(EntityManager, args.Performer, delayedEffect.Delay, doAfter, args.Action)
{
BreakOnMove = delayedEffect.BreakOnMove,
BreakOnDamage = delayedEffect.BreakOnDamage,
Hidden = delayedEffect.Hidden,
BlockDuplicate = true,
DistanceThreshold = 100f
};
_doAfter.TryStartDoAfter(doAfterEventArgs);
//Telegraphy effects
if (_net.IsServer && TryComp<CP14MagicEffectComponent>(args.Action, out var magicEffect))
{
foreach (var effect in magicEffect.TelegraphyEffects)
{
effect.Effect(EntityManager, new CP14SpellEffectBaseArgs(args.Performer, args.Entity, args.Coords));
}
}
}
private void OnDelayedEntityWorldTargetDoAfter(Entity<CP14MagicEffectComponent> ent,
ref CP14DelayedEntityWorldTargetActionDoAfterEvent args)
{
var endEv = new CP14EndCastMagicEffectEvent(args.User);
RaiseLocalEvent(ent, ref endEv);
if (args.Cancelled || !_net.IsServer)
return;
var targetPos = EntityManager.GetCoordinates(args.TargetPosition);
EntityUid? targetEnt;
EntityManager.TryGetEntity(args.TargetEntity, out targetEnt);
var effectArgs = new CP14SpellEffectBaseArgs(args.User, targetEnt, targetPos);
foreach (var effect in ent.Comp.Effects)
{
effect.Effect(EntityManager, effectArgs);
}
var ev = new CP14AfterCastMagicEffectEvent(args.User);
RaiseLocalEvent(ent, ref ev);
}
private void OnDelayedInstantActionDoAfter(Entity<CP14MagicEffectComponent> ent, ref CP14DelayedInstantActionDoAfterEvent args)
{
var endEv = new CP14EndCastMagicEffectEvent(args.User);
RaiseLocalEvent(ent, ref endEv);
if (args.Cancelled || !_net.IsServer)
return;
foreach (var effect in ent.Comp.Effects)
{
effect.Effect(EntityManager, new CP14SpellEffectBaseArgs(args.User, args.User, Transform(args.User).Coordinates));
}
var ev = new CP14AfterCastMagicEffectEvent(args.User);
RaiseLocalEvent(ent, ref ev);
}
private void OnSomaticAspectBeforeCast(Entity<CP14MagicEffectSomaticAspectComponent> ent, ref CP14BeforeCastMagicEffectEvent args)
{
if (TryComp<HandsComponent>(args.Caster, 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 CP14BeforeCastMagicEffectEvent args)
{
if (HasComp<MutedComponent>(args.Caster))
{
args.PushReason(Loc.GetString("cp14-magic-spell-need-verbal-component"));
args.Cancel();
}
else
{
if (!args.Cancelled)
{
var ev = new CP14VerbalAspectSpeechEvent
{
Performer = args.Caster,
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.Caster,
Speech = ent.Comp.EndSpeech,
};
RaiseLocalEvent(ent, ref ev);
}
private bool TryCastSpell(EntityUid spell, EntityUid performer)
{
var ev = new CP14BeforeCastMagicEffectEvent(performer);
var ev = new CP14CastMagicEffectAttemptEvent(performer);
RaiseLocalEvent(spell, ref ev);
if (ev.Reason != string.Empty && _net.IsServer)
{
_popup.PopupEntity(ev.Reason, performer, performer);
}
if (!ev.Cancelled)
{
var evStart = new CP14StartCastMagicEffectEvent(performer);
RaiseLocalEvent(spell, ref evStart);
}
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)
{
if (!TryComp<CP14MagicEnergyContainerComponent>(args.Performer, out var magicContainer))
{
args.Cancel();
return;
}
var manaCost = CalculateManacost(ent, args.Performer);
if (!_magicEnergy.HasEnergy(args.Performer, manaCost, magicContainer, ent.Comp.Safe))
{
args.PushReason(Loc.GetString("cp14-magic-spell-not-enough-mana"));
args.Cancel();
}
else if(!_magicEnergy.HasEnergy(args.Performer, manaCost, magicContainer, 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)
return;
foreach (var effect in ent.Comp.TelegraphyEffects)
{
effect.Effect(EntityManager, args);
}
}
private bool TryCastSpellDelayed(ICP14DelayedMagicEffect delayedEffect, DoAfterEvent doAfter, EntityUid action, EntityUid performer)
{
var doAfterEventArgs = new DoAfterArgs(EntityManager, performer, delayedEffect.CastDelay, doAfter, action)
{
BreakOnMove = delayedEffect.BreakOnMove,
BreakOnDamage = delayedEffect.BreakOnDamage,
Hidden = delayedEffect.Hidden,
DistanceThreshold = 100f,
CancelDuplicate = true,
BlockDuplicate = true,
};
return _doAfter.TryStartDoAfter(doAfterEventArgs);
}
private void CastSpell(Entity<CP14MagicEffectComponent> ent, CP14SpellEffectBaseArgs args, float cooldown)
{
_action.CP14StartCustomDelay(ent, TimeSpan.FromSeconds(cooldown));
if (_net.IsServer)
{
foreach (var effect in ent.Comp.Effects)
{
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;
if (!HasComp<CP14MagicEnergyContainerComponent>(args.Caster))
if (!HasComp<CP14MagicEnergyContainerComponent>(args.Performer))
return;
var manaCost = CalculateManacost(ent, args.Caster.Value);
_magicEnergy.TryConsumeEnergy(args.Caster.Value, manaCost, safe: ent.Comp.Safe);
var manaCost = CalculateManacost(ent, args.Performer.Value);
_magicEnergy.TryConsumeEnergy(args.Performer.Value, manaCost, safe: ent.Comp.Safe);
}
private FixedPoint2 CalculateManacost(Entity<CP14MagicEffectComponent> ent, EntityUid caster)

View File

@@ -7,5 +7,5 @@ namespace Content.Shared._CP14.MagicSpell.Components;
public sealed partial class CP14MagicCasterSlowdownComponent : Component
{
[DataField]
public List<float> SpeedModifiers = new();
public float SpeedModifier = 1f;
}

View File

@@ -5,19 +5,22 @@ using Robust.Shared.Prototypes;
namespace Content.Shared._CP14.MagicSpell.Events;
/// <summary>
/// Called first to verify that all conditions are met and the spell can be performed.
/// </summary>
[ByRefEvent]
public sealed class CP14BeforeCastMagicEffectEvent : CancellableEntityEventArgs
public sealed class CP14CastMagicEffectAttemptEvent : CancellableEntityEventArgs
{
/// <summary>
/// The Performer of the event, to check if they meet the requirements.
/// </summary>
public EntityUid Caster { get; init; }
public EntityUid Performer { get; init; }
public string Reason = string.Empty;
public CP14BeforeCastMagicEffectEvent(EntityUid caster)
public CP14CastMagicEffectAttemptEvent(EntityUid performer)
{
Caster = caster;
Performer = performer;
}
public void PushReason(string reason)
@@ -26,56 +29,21 @@ public sealed class CP14BeforeCastMagicEffectEvent : CancellableEntityEventArgs
}
}
[ByRefEvent]
public sealed class CP14AfterCastMagicEffectEvent : EntityEventArgs
{
public EntityUid? Caster { get; init; }
public CP14AfterCastMagicEffectEvent(EntityUid caster)
{
Caster = caster;
}
}
/// <summary>
/// is invoked if all conditions are met and the spell has begun to be cast
/// An event that checks all sorts of conditions, and calculates the total cost of casting a spell. Called before the spell is cast.
/// </summary>
[ByRefEvent]
public sealed class CP14StartCastMagicEffectEvent : EntityEventArgs
{
public EntityUid Caster { get; init; }
public CP14StartCastMagicEffectEvent(EntityUid caster)
{
Caster = caster;
}
}
/// <summary>
/// is invoked on the spell itself when the spell process has been completed or interrupted
/// </summary>
[ByRefEvent]
public sealed class CP14EndCastMagicEffectEvent : EntityEventArgs
{
public EntityUid Caster { get; init; }
public CP14EndCastMagicEffectEvent(EntityUid caster)
{
Caster = caster;
}
}
/// <remarks>TODO: This call is duplicated at the beginning of the cast for checks, and at the end of the cast for mana subtraction.</remarks>
public sealed class CP14CalculateManacostEvent : EntityEventArgs, IInventoryRelayEvent
{
public FixedPoint2 Manacost = 0f;
public float Multiplier = 1f;
public EntityUid Caster;
public EntityUid Performer;
public ProtoId<CP14MagicTypePrototype>? MagicType;
public CP14CalculateManacostEvent(EntityUid caster, FixedPoint2 initialManacost, ProtoId<CP14MagicTypePrototype>? magicType)
public CP14CalculateManacostEvent(EntityUid performer, FixedPoint2 initialManacost, ProtoId<CP14MagicTypePrototype>? magicType)
{
Caster = caster;
Performer = performer;
Manacost = initialManacost;
MagicType = magicType;
}
@@ -87,3 +55,45 @@ public sealed class CP14CalculateManacostEvent : EntityEventArgs, IInventoryRela
public SlotFlags TargetSlots { get; } = SlotFlags.All;
}
/// <summary>
/// is invoked if all conditions are met and the spell has begun to be cast (doAfter start moment)
/// </summary>
[ByRefEvent]
public sealed class CP14StartCastMagicEffectEvent : EntityEventArgs
{
public EntityUid Performer { get; init; }
public CP14StartCastMagicEffectEvent(EntityUid performer)
{
Performer = performer;
}
}
/// <summary>
/// is invoked on the spell itself when the spell process has been completed or interrupted (doAfter end moment)
/// </summary>
[ByRefEvent]
public sealed class CP14EndCastMagicEffectEvent : EntityEventArgs
{
public EntityUid Performer { get; init; }
public CP14EndCastMagicEffectEvent(EntityUid performer)
{
Performer = performer;
}
}
/// <summary>
/// is invoked only if the spell has been successfully cast
/// </summary>
[ByRefEvent]
public sealed class CP14AfterCastMagicEffectEvent : EntityEventArgs
{
public EntityUid? Performer { get; init; }
public CP14AfterCastMagicEffectEvent(EntityUid? performer)
{
Performer = performer;
}
}

View File

@@ -9,7 +9,54 @@ public sealed partial class CP14DelayedEntityWorldTargetActionEvent : EntityWorl
ICP14DelayedMagicEffect
{
[DataField]
public float Delay { get; private set; } = 1f;
public float Cooldown { get; private set; } = 1f;
[DataField]
public float CastDelay { get; private set; } = 1f;
[DataField]
public bool BreakOnMove { get; private set; } = true;
[DataField]
public bool BreakOnDamage { get; private set; } = true;
[DataField]
public bool Hidden { get; private set; } = false;
[DataField]
public float EntityDistance { get; private set; } = 100f;
}
//Entity Target
public sealed partial class CP14DelayedEntityTargetActionEvent : EntityTargetActionEvent,
ICP14DelayedMagicEffect
{
[DataField]
public float Cooldown { get; private set; } = 1f;
[DataField]
public float CastDelay { get; private set; } = 1f;
[DataField]
public bool BreakOnMove { get; private set; } = true;
[DataField]
public bool BreakOnDamage { get; private set; } = true;
[DataField]
public bool Hidden { get; private set; } = false;
[DataField]
public float EntityDistance { get; private set; } = 100f;
}
public sealed partial class CP14DelayedInstantActionEvent : InstantActionEvent, ICP14DelayedMagicEffect
{
[DataField]
public float Cooldown { get; private set; } = 3f;
[DataField]
public float CastDelay { get; private set; } = 1f;
[DataField]
public bool BreakOnMove { get; private set; } = true;
@@ -31,36 +78,46 @@ public sealed partial class CP14DelayedEntityWorldTargetActionDoAfterEvent : DoA
public NetCoordinates? TargetPosition;
[DataField]
public NetEntity? TargetEntity;
[DataField]
public float? Cooldown;
public CP14DelayedEntityWorldTargetActionDoAfterEvent(NetCoordinates? targetPos, NetEntity? targetEntity)
public CP14DelayedEntityWorldTargetActionDoAfterEvent(NetCoordinates? targetPos, NetEntity? targetEntity, float cooldown)
{
TargetPosition = targetPos;
TargetEntity = targetEntity;
Cooldown = cooldown;
}
public override DoAfterEvent Clone() => this;
}
//Instant
public sealed partial class CP14DelayedInstantActionEvent : InstantActionEvent, ICP14DelayedMagicEffect
[Serializable, NetSerializable]
public sealed partial class CP14DelayedEntityTargetActionDoAfterEvent : DoAfterEvent
{
[DataField]
public float Delay { get; private set; } = 1f;
public NetEntity? TargetEntity;
[DataField]
public bool BreakOnMove { get; private set; } = true;
public float? Cooldown;
[DataField]
public bool BreakOnDamage { get; private set; } = true;
public CP14DelayedEntityTargetActionDoAfterEvent(NetEntity? targetEntity, float cooldown)
{
TargetEntity = targetEntity;
Cooldown = cooldown;
}
[DataField]
public bool Hidden { get; private set; } = false;
[DataField]
public float EntityDistance { get; private set; } = 100f;
public override DoAfterEvent Clone() => this;
}
[Serializable, NetSerializable]
public sealed partial class CP14DelayedInstantActionDoAfterEvent : SimpleDoAfterEvent
public sealed partial class CP14DelayedInstantActionDoAfterEvent : DoAfterEvent
{
[DataField]
public float? Cooldown;
public CP14DelayedInstantActionDoAfterEvent(float cooldown)
{
Cooldown = cooldown;
}
public override DoAfterEvent Clone() => this;
}

View File

@@ -1,11 +1,10 @@
namespace Content.Shared._CP14.MagicSpell.Events;
public interface ICP14DelayedMagicEffect // The speak n spell interface
public interface ICP14DelayedMagicEffect
{
/// <summary>
/// Localized string spoken by the caster when casting this spell.
/// </summary>
public float Delay { get; }
public float Cooldown { get; }
public float CastDelay { get; }
public bool BreakOnMove { get; }