Magic spells backend (#358)
* add EntityEffect aability support * delayed actions * renaming * delayed projectile spells * spawn on self + entityEffect on self spells * spawn on point spell * rename * clean up base species components * magic alert * move magic energy to Shared, add manacost to spells * magic recoil * improve magic recoil * verbal aspect * somatic aspect * add simple vfx proto and sprites * add casting VFX * add TODO
37
Content.Server/_CP14/Magic/CP14MagicSystem.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using Content.Server.Chat.Systems;
|
||||
using Content.Shared._CP14.Magic;
|
||||
using Content.Shared._CP14.Magic.Components;
|
||||
using Content.Shared._CP14.Magic.Events;
|
||||
|
||||
namespace Content.Server._CP14.Magic;
|
||||
|
||||
public sealed partial class CP14MagicSystem : CP14SharedMagicSystem
|
||||
{
|
||||
[Dependency] private readonly ChatSystem _chat = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<CP14MagicEffectVerbalAspectComponent, CP14VerbalAspectSpeechEvent>(OnSpellSpoken);
|
||||
|
||||
SubscribeLocalEvent<CP14MagicEffectCastingVisualComponent, CP14StartCastMagicEffectEvent>(OnSpawnMagicVisualEffect);
|
||||
SubscribeLocalEvent<CP14MagicEffectCastingVisualComponent, CP14StopCastMagicEffectEvent>(OnDespawnMagicVisualEffect);
|
||||
}
|
||||
|
||||
private void OnSpellSpoken(Entity<CP14MagicEffectVerbalAspectComponent> ent, ref CP14VerbalAspectSpeechEvent args)
|
||||
{
|
||||
if (args.Performer is not null && args.Speech is not null)
|
||||
_chat.TrySendInGameICMessage(args.Performer.Value, args.Speech, InGameICChatType.Speak, false);
|
||||
}
|
||||
|
||||
private void OnSpawnMagicVisualEffect(Entity<CP14MagicEffectCastingVisualComponent> ent, ref CP14StartCastMagicEffectEvent args)
|
||||
{
|
||||
var vfx = SpawnAttachedTo(ent.Comp.Proto, Transform(args.Performer).Coordinates);
|
||||
ent.Comp.SpawnedEntity = vfx;
|
||||
}
|
||||
|
||||
private void OnDespawnMagicVisualEffect(Entity<CP14MagicEffectCastingVisualComponent> ent, ref CP14StopCastMagicEffectEvent args)
|
||||
{
|
||||
QueueDel(ent.Comp.SpawnedEntity);
|
||||
ent.Comp.SpawnedEntity = null;
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@ using Content.Server._CP14.MagicEnergy.Components;
|
||||
using Content.Shared._CP14.MagicEnergy;
|
||||
using Content.Shared._CP14.MagicEnergy.Components;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Inventory;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Timing;
|
||||
@@ -18,6 +17,7 @@ public sealed partial class CP14MagicEnergySystem : SharedCP14MagicEnergySystem
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<CP14MagicEnergyDrawComponent, MapInitEvent>(OnMapInit);
|
||||
|
||||
SubscribeLocalEvent<CP14MagicEnergyPointLightControllerComponent, CP14MagicEnergyLevelChangeEvent>(OnEnergyChange);
|
||||
|
||||
SubscribeLocalEvent<CP14MagicEnergyExaminableComponent, ExaminedEvent>(OnExamined);
|
||||
@@ -58,8 +58,6 @@ public sealed partial class CP14MagicEnergySystem : SharedCP14MagicEnergySystem
|
||||
args.PushMarkup(GetEnergyExaminedText(ent, magicContainer));
|
||||
}
|
||||
|
||||
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
@@ -92,61 +90,4 @@ public sealed partial class CP14MagicEnergySystem : SharedCP14MagicEnergySystem
|
||||
ChangeEnergy(energyEnt.Value, energyComp, draw.Energy, draw.Safe);
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryConsumeEnergy(EntityUid uid, FixedPoint2 energy, CP14MagicEnergyContainerComponent? component = null, bool safe = false)
|
||||
{
|
||||
if (!Resolve(uid, ref component))
|
||||
return false;
|
||||
|
||||
if (energy <= 0)
|
||||
return true;
|
||||
|
||||
// Attempting to absorb more energy than is contained in the carrier will still waste all the energy
|
||||
if (component.Energy < energy)
|
||||
{
|
||||
ChangeEnergy(uid, component, -component.Energy);
|
||||
return false;
|
||||
}
|
||||
|
||||
ChangeEnergy(uid, component, -energy, safe);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void ChangeEnergy(EntityUid uid, CP14MagicEnergyContainerComponent component, FixedPoint2 energy, bool safe = false)
|
||||
{
|
||||
if (!safe)
|
||||
{
|
||||
//Overload
|
||||
if (component.Energy + energy > component.MaxEnergy)
|
||||
{
|
||||
RaiseLocalEvent(uid, new CP14MagicEnergyOverloadEvent()
|
||||
{
|
||||
OverloadEnergy = (component.Energy + energy) - component.MaxEnergy,
|
||||
});
|
||||
}
|
||||
|
||||
//Burn out
|
||||
if (component.Energy + energy < 0)
|
||||
{
|
||||
RaiseLocalEvent(uid, new CP14MagicEnergyBurnOutEvent()
|
||||
{
|
||||
BurnOutEnergy = -energy - component.Energy
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var oldEnergy = component.Energy;
|
||||
var newEnergy = Math.Clamp((float)component.Energy + (float)energy, 0, (float)component.MaxEnergy);
|
||||
component.Energy = newEnergy;
|
||||
|
||||
if (oldEnergy != newEnergy)
|
||||
{
|
||||
RaiseLocalEvent(uid, new CP14MagicEnergyLevelChangeEvent()
|
||||
{
|
||||
OldValue = component.Energy,
|
||||
NewValue = newEnergy,
|
||||
MaxValue = component.MaxEnergy,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
13
Content.Shared/_CP14/Magic/CP14IDelayedMagicEffect.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace Content.Shared._CP14.Magic;
|
||||
|
||||
public interface ICP14DelayedMagicEffect // The speak n spell interface
|
||||
{
|
||||
/// <summary>
|
||||
/// Localized string spoken by the caster when casting this spell.
|
||||
/// </summary>
|
||||
public float Delay { get; }
|
||||
|
||||
public bool BreakOnMove { get; }
|
||||
|
||||
public bool BreakOnDamage { get; }
|
||||
}
|
||||
130
Content.Shared/_CP14/Magic/CP14SharedMagicSystem.Spells.cs
Normal file
@@ -0,0 +1,130 @@
|
||||
using Content.Shared._CP14.Magic.Components.Spells;
|
||||
using Content.Shared._CP14.Magic.Events;
|
||||
using Content.Shared.EntityEffects;
|
||||
|
||||
namespace Content.Shared._CP14.Magic;
|
||||
|
||||
public partial class CP14SharedMagicSystem
|
||||
{
|
||||
private void InitializeSpells()
|
||||
{
|
||||
// Instants
|
||||
SubscribeLocalEvent<CP14DelayedSpawnEntitiesSpellComponent, CP14DelayedInstantActionDoAfterEvent>(OnCastEntitiesSpawn);
|
||||
SubscribeLocalEvent<CP14DelayedSelfEntityEffectSpellComponent, CP14DelayedInstantActionDoAfterEvent>(OnCastSelfEntityEffects);
|
||||
//Entity Target
|
||||
SubscribeLocalEvent<CP14DelayedApplyEntityEffectsSpellComponent, CP14DelayedEntityTargetActionDoAfterEvent>(OnCastApplyEntityEffects);
|
||||
//World Target
|
||||
SubscribeLocalEvent<CP14DelayedProjectileSpellComponent, CP14DelayedWorldTargetActionDoAfterEvent>(OnCastProjectileSpell);
|
||||
SubscribeLocalEvent<CP14DelayedSpawnOnWorldTargetSpellComponent, CP14DelayedWorldTargetActionDoAfterEvent>(OnCastSpawnOnPoint);
|
||||
}
|
||||
|
||||
//TODO: Fuck,there's a lot of code repetition here that needs to be squeezed together somehow. Event calls, checks, and all this stuff
|
||||
private void OnCastEntitiesSpawn(Entity<CP14DelayedSpawnEntitiesSpellComponent> spell, ref CP14DelayedInstantActionDoAfterEvent args)
|
||||
{
|
||||
var stopEv = new CP14StopCastMagicEffectEvent();
|
||||
RaiseLocalEvent(spell, ref stopEv);
|
||||
|
||||
if (args.Cancelled || args.Handled || !_net.IsServer)
|
||||
return;
|
||||
|
||||
args.Handled = true;
|
||||
|
||||
foreach (var spawn in spell.Comp.Spawns)
|
||||
{
|
||||
SpawnAtPosition(spawn, Transform(args.User).Coordinates);
|
||||
}
|
||||
|
||||
var ev = new CP14AfterCastMagicEffectEvent {Performer = args.User};
|
||||
RaiseLocalEvent(spell, ref ev);
|
||||
}
|
||||
|
||||
private void OnCastSelfEntityEffects(Entity<CP14DelayedSelfEntityEffectSpellComponent> spell, ref CP14DelayedInstantActionDoAfterEvent args)
|
||||
{
|
||||
var stopEv = new CP14StopCastMagicEffectEvent();
|
||||
RaiseLocalEvent(spell, ref stopEv);
|
||||
|
||||
if (args.Cancelled || args.Handled)
|
||||
return;
|
||||
|
||||
args.Handled = true;
|
||||
|
||||
foreach (var effect in spell.Comp.Effects)
|
||||
{
|
||||
effect.Effect(new EntityEffectBaseArgs(args.User, EntityManager));
|
||||
}
|
||||
|
||||
var ev = new CP14AfterCastMagicEffectEvent {Performer = args.User};
|
||||
RaiseLocalEvent(spell, ref ev);
|
||||
}
|
||||
|
||||
private void OnCastApplyEntityEffects(Entity<CP14DelayedApplyEntityEffectsSpellComponent> spell, ref CP14DelayedEntityTargetActionDoAfterEvent args)
|
||||
{
|
||||
var stopEv = new CP14StopCastMagicEffectEvent();
|
||||
RaiseLocalEvent(spell, ref stopEv);
|
||||
|
||||
if (args.Cancelled || args.Handled || args.Target == null)
|
||||
return;
|
||||
|
||||
args.Handled = true;
|
||||
|
||||
foreach (var effect in spell.Comp.Effects)
|
||||
{
|
||||
effect.Effect(new EntityEffectBaseArgs(args.Target.Value, EntityManager));
|
||||
}
|
||||
|
||||
var ev = new CP14AfterCastMagicEffectEvent {Performer = args.User};
|
||||
RaiseLocalEvent(spell, ref ev);
|
||||
}
|
||||
|
||||
private void OnCastProjectileSpell(Entity<CP14DelayedProjectileSpellComponent> spell, ref CP14DelayedWorldTargetActionDoAfterEvent args)
|
||||
{
|
||||
var stopEv = new CP14StopCastMagicEffectEvent();
|
||||
RaiseLocalEvent(spell, ref stopEv);
|
||||
|
||||
if (args.Cancelled || args.Handled || !_net.IsServer)
|
||||
return;
|
||||
|
||||
args.Handled = true;
|
||||
|
||||
var xform = Transform(args.User);
|
||||
var fromCoords = xform.Coordinates;
|
||||
var toCoords = GetCoordinates(args.Target);
|
||||
var userVelocity = _physics.GetMapLinearVelocity(args.User);
|
||||
|
||||
// If applicable, this ensures the projectile is parented to grid on spawn, instead of the map.
|
||||
var fromMap = fromCoords.ToMap(EntityManager, _transform);
|
||||
var spawnCoords = _mapManager.TryFindGridAt(fromMap, out var gridUid, out _)
|
||||
? fromCoords.WithEntityId(gridUid, EntityManager)
|
||||
: new(_mapManager.GetMapEntityId(fromMap.MapId), fromMap.Position);
|
||||
|
||||
var ent = Spawn(spell.Comp.Prototype, spawnCoords);
|
||||
var direction = toCoords.ToMapPos(EntityManager, _transform) -
|
||||
spawnCoords.ToMapPos(EntityManager, _transform);
|
||||
_gunSystem.ShootProjectile(ent, direction, userVelocity, args.User, args.User);
|
||||
|
||||
var ev = new CP14AfterCastMagicEffectEvent {Performer = args.User};
|
||||
RaiseLocalEvent(spell, ref ev);
|
||||
}
|
||||
|
||||
private void OnCastSpawnOnPoint(Entity<CP14DelayedSpawnOnWorldTargetSpellComponent> spell, ref CP14DelayedWorldTargetActionDoAfterEvent args)
|
||||
{
|
||||
var stopEv = new CP14StopCastMagicEffectEvent();
|
||||
RaiseLocalEvent(spell, ref stopEv);
|
||||
|
||||
if (args.Cancelled || args.Handled || !_net.IsServer)
|
||||
return;
|
||||
|
||||
args.Handled = true;
|
||||
|
||||
var xform = Transform(args.User);
|
||||
var toCoords = GetCoordinates(args.Target);
|
||||
|
||||
foreach (var spawn in spell.Comp.Spawns)
|
||||
{
|
||||
SpawnAtPosition(spawn, toCoords);
|
||||
}
|
||||
|
||||
var ev = new CP14AfterCastMagicEffectEvent {Performer = args.User};
|
||||
RaiseLocalEvent(spell, ref ev);
|
||||
}
|
||||
}
|
||||
219
Content.Shared/_CP14/Magic/CP14SharedMagicSystem.cs
Normal file
@@ -0,0 +1,219 @@
|
||||
using Content.Shared._CP14.Magic.Components;
|
||||
using Content.Shared._CP14.Magic.Events;
|
||||
using Content.Shared._CP14.MagicEnergy;
|
||||
using Content.Shared._CP14.MagicEnergy.Components;
|
||||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Speech.Muting;
|
||||
using Content.Shared.Weapons.Ranged.Systems;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Physics.Systems;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Shared._CP14.Magic;
|
||||
|
||||
public partial class CP14SharedMagicSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
||||
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
|
||||
[Dependency] private readonly INetManager _net = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
[Dependency] private readonly SharedGunSystem _gunSystem = default!;
|
||||
[Dependency] private readonly SharedCP14MagicEnergySystem _magicEnergy = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _hands = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<CP14MagicEffectComponent, CP14BeforeCastMagicEffectEvent>(OnBeforeCastMagicEffect);
|
||||
|
||||
SubscribeLocalEvent<CP14MagicEffectSomaticAspectComponent, CP14BeforeCastMagicEffectEvent>(OnSomaticAspectBeforeCast);
|
||||
|
||||
SubscribeLocalEvent<CP14MagicEffectVerbalAspectComponent, CP14BeforeCastMagicEffectEvent>(OnVerbalAspectBeforeCast);
|
||||
SubscribeLocalEvent<CP14MagicEffectVerbalAspectComponent, CP14AfterCastMagicEffectEvent>(OnVerbalAspectAfterCast);
|
||||
|
||||
SubscribeLocalEvent<CP14MagicEffectComponent, CP14AfterCastMagicEffectEvent>(OnAfterCastMagicEffect);
|
||||
|
||||
SubscribeLocalEvent<CP14DelayedInstantActionEvent>(OnInstantAction);
|
||||
SubscribeLocalEvent<CP14DelayedEntityTargetActionEvent>(OnEntityTargetAction);
|
||||
SubscribeLocalEvent<CP14DelayedWorldTargetActionEvent>(OnWorldTargetAction);
|
||||
|
||||
InitializeSpells();
|
||||
}
|
||||
|
||||
private void OnSomaticAspectBeforeCast(Entity<CP14MagicEffectSomaticAspectComponent> ent, ref CP14BeforeCastMagicEffectEvent args)
|
||||
{
|
||||
if (TryComp<HandsComponent>(args.Performer, out var hands) || hands is not null)
|
||||
{
|
||||
foreach (var hand in hands.Hands)
|
||||
{
|
||||
if (hand.Value.IsEmpty)
|
||||
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.Performer))
|
||||
{
|
||||
args.PushReason(Loc.GetString("cp14-magic-spell-need-verbal-component"));
|
||||
args.Cancel();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!args.Cancelled)
|
||||
{
|
||||
var ev = new CP14VerbalAspectSpeechEvent
|
||||
{
|
||||
Performer = args.Performer,
|
||||
Speech = ent.Comp.StartSpeech,
|
||||
};
|
||||
RaiseLocalEvent(ent, ref ev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnVerbalAspectAfterCast(Entity<CP14MagicEffectVerbalAspectComponent> ent, ref CP14AfterCastMagicEffectEvent args)
|
||||
{
|
||||
var ev = new CP14VerbalAspectSpeechEvent
|
||||
{
|
||||
Performer = args.Performer,
|
||||
Speech = ent.Comp.EndSpeech,
|
||||
};
|
||||
RaiseLocalEvent(ent, ref ev);
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
_doAfter.TryStartDoAfter(doAfterEventArgs);
|
||||
}
|
||||
|
||||
private void OnWorldTargetAction(CP14DelayedWorldTargetActionEvent 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 CP14DelayedWorldTargetActionDoAfterEvent()
|
||||
{
|
||||
Target = EntityManager.GetNetCoordinates(args.Target)
|
||||
};
|
||||
|
||||
var doAfterEventArgs = new DoAfterArgs(EntityManager, args.Performer, delayedEffect.Delay, doAfter, args.Action)
|
||||
{
|
||||
BreakOnMove = delayedEffect.BreakOnMove,
|
||||
BreakOnDamage = delayedEffect.BreakOnDamage,
|
||||
};
|
||||
|
||||
_doAfter.TryStartDoAfter(doAfterEventArgs);
|
||||
}
|
||||
|
||||
private void OnEntityTargetAction(CP14DelayedEntityTargetActionEvent 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 CP14DelayedEntityTargetActionDoAfterEvent(), args.Action, args.Target)
|
||||
{
|
||||
BreakOnMove = delayedEffect.BreakOnMove,
|
||||
BreakOnDamage = delayedEffect.BreakOnDamage,
|
||||
};
|
||||
|
||||
_doAfter.TryStartDoAfter(doAfterEventArgs);
|
||||
}
|
||||
|
||||
private bool TryCastSpell(EntityUid spell, EntityUid performer)
|
||||
{
|
||||
var ev = new CP14BeforeCastMagicEffectEvent
|
||||
{
|
||||
Performer = 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 = performer,
|
||||
};
|
||||
RaiseLocalEvent(spell, ref evStart);
|
||||
}
|
||||
return !ev.Cancelled;
|
||||
}
|
||||
|
||||
private void OnBeforeCastMagicEffect(Entity<CP14MagicEffectComponent> ent, ref CP14BeforeCastMagicEffectEvent args)
|
||||
{
|
||||
if (!TryComp<CP14MagicEnergyContainerComponent>(args.Performer, out var magicContainer))
|
||||
{
|
||||
args.Cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_magicEnergy.HasEnergy(args.Performer, ent.Comp.ManaCost, magicContainer, ent.Comp.Safe))
|
||||
{
|
||||
args.PushReason(Loc.GetString("cp14-magic-spell-not-enough-mana"));
|
||||
args.Cancel();
|
||||
}
|
||||
else if(!_magicEnergy.HasEnergy(args.Performer, ent.Comp.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 OnAfterCastMagicEffect(Entity<CP14MagicEffectComponent> ent, ref CP14AfterCastMagicEffectEvent args)
|
||||
{
|
||||
if (_net.IsClient)
|
||||
return;
|
||||
|
||||
if (!HasComp<CP14MagicEnergyContainerComponent>(args.Performer))
|
||||
return;
|
||||
|
||||
_magicEnergy.TryConsumeEnergy(args.Performer.Value, ent.Comp.ManaCost, safe: ent.Comp.Safe);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Magic.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a temporary entity that exists while the spell is cast, and disappears at the end. For visual special effects.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14SharedMagicSystem))]
|
||||
public sealed partial class CP14MagicEffectCastingVisualComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public EntityUid? SpawnedEntity;
|
||||
|
||||
[DataField(required: true)]
|
||||
public EntProtoId Proto = default!;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using Content.Shared.FixedPoint;
|
||||
|
||||
namespace Content.Shared._CP14.Magic.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Restricts the use of this action, by spending mana or user requirements.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14SharedMagicSystem))]
|
||||
public sealed partial class CP14MagicEffectComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public FixedPoint2 ManaCost = 0f;
|
||||
|
||||
[DataField]
|
||||
public bool Safe = false;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Content.Shared._CP14.Magic.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Requires the user to have at least one free hand to use this spell
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14SharedMagicSystem))]
|
||||
public sealed partial class CP14MagicEffectSomaticAspectComponent : Component
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using Content.Shared.FixedPoint;
|
||||
|
||||
namespace Content.Shared._CP14.Magic.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Requires the user to be able to speak in order to use this spell. Also forces the user to use certain phrases at the beginning and end of a spell cast
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14SharedMagicSystem))]
|
||||
public sealed partial class CP14MagicEffectVerbalAspectComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public string StartSpeech = string.Empty;
|
||||
|
||||
[DataField]
|
||||
public string EndSpeech = string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// patch to send an event to the server for saying a phrase out loud
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public sealed class CP14VerbalAspectSpeechEvent : EntityEventArgs
|
||||
{
|
||||
public EntityUid? Performer { get; init; }
|
||||
|
||||
public string? Speech { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using Content.Shared.EntityEffects;
|
||||
|
||||
namespace Content.Shared._CP14.Magic.Components.Spells;
|
||||
|
||||
/// <summary>
|
||||
/// Stores a list of effects for delayed actions.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14SharedMagicSystem))]
|
||||
public sealed partial class CP14DelayedApplyEntityEffectsSpellComponent : Component
|
||||
{
|
||||
[DataField(required: true, serverOnly: true)]
|
||||
public List<EntityEffect> Effects = new();
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Magic.Components.Spells;
|
||||
|
||||
/// <summary>
|
||||
/// Stores a list of effects for delayed actions.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14SharedMagicSystem))]
|
||||
public sealed partial class CP14DelayedProjectileSpellComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// What entity should be spawned.
|
||||
/// </summary>
|
||||
[DataField(required: true)]
|
||||
public EntProtoId Prototype;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using Content.Shared.EntityEffects;
|
||||
|
||||
namespace Content.Shared._CP14.Magic.Components.Spells;
|
||||
|
||||
/// <summary>
|
||||
/// Stores a list of effects for delayed actions.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14SharedMagicSystem))]
|
||||
public sealed partial class CP14DelayedSelfEntityEffectSpellComponent : Component
|
||||
{
|
||||
[DataField(required: true, serverOnly: true)]
|
||||
public List<EntityEffect> Effects = new();
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Magic.Components.Spells;
|
||||
|
||||
/// <summary>
|
||||
/// Stores a list of effects for delayed actions.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14SharedMagicSystem))]
|
||||
public sealed partial class CP14DelayedSpawnEntitiesSpellComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// What entities should be spawned.
|
||||
/// </summary>
|
||||
[DataField(required: true)]
|
||||
public HashSet<EntProtoId> Spawns = new();
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Magic.Components.Spells;
|
||||
|
||||
/// <summary>
|
||||
/// Stores a list of effects for delayed actions.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14SharedMagicSystem))]
|
||||
public sealed partial class CP14DelayedSpawnOnWorldTargetSpellComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// What entities should be spawned.
|
||||
/// </summary>
|
||||
[DataField(required: true)]
|
||||
public HashSet<EntProtoId> Spawns = new();
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
namespace Content.Shared._CP14.Magic.Events;
|
||||
|
||||
[ByRefEvent]
|
||||
public sealed class CP14BeforeCastMagicEffectEvent : CancellableEntityEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// The Performer of the event, to check if they meet the requirements.
|
||||
/// </summary>
|
||||
public EntityUid Performer { get; init; }
|
||||
|
||||
public string Reason = string.Empty;
|
||||
|
||||
public void PushReason(string reason)
|
||||
{
|
||||
Reason += $"{reason}\n";
|
||||
}
|
||||
}
|
||||
|
||||
[ByRefEvent]
|
||||
public sealed class CP14AfterCastMagicEffectEvent : EntityEventArgs
|
||||
{
|
||||
public EntityUid? Performer { get; init; }
|
||||
}
|
||||
/// <summary>
|
||||
/// is invoked if all conditions are met and the spell has begun to be cast
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public sealed class CP14StartCastMagicEffectEvent : EntityEventArgs
|
||||
{
|
||||
public EntityUid Performer { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// is invoked on the spell itself when the spell process has been completed or interrupted
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public sealed class CP14StopCastMagicEffectEvent : EntityEventArgs
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
64
Content.Shared/_CP14/Magic/Events/CP14DelayedActionEvents.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.DoAfter;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._CP14.Magic.Events;
|
||||
|
||||
//World target
|
||||
public sealed partial class CP14DelayedWorldTargetActionEvent : WorldTargetActionEvent, ICP14DelayedMagicEffect
|
||||
{
|
||||
[DataField]
|
||||
public float Delay { get; private set; } = 1f;
|
||||
|
||||
[DataField]
|
||||
public bool BreakOnMove { get; private set; } = true;
|
||||
|
||||
[DataField]
|
||||
public bool BreakOnDamage { get; private set; } = true;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class CP14DelayedWorldTargetActionDoAfterEvent : DoAfterEvent
|
||||
{
|
||||
[DataField]
|
||||
public NetCoordinates Target;
|
||||
public override DoAfterEvent Clone() => this;
|
||||
}
|
||||
|
||||
|
||||
//Entity Target
|
||||
public sealed partial class CP14DelayedEntityTargetActionEvent : EntityTargetActionEvent, ICP14DelayedMagicEffect
|
||||
{
|
||||
[DataField]
|
||||
public float Delay { get; private set; } = 1f;
|
||||
|
||||
[DataField]
|
||||
public bool BreakOnMove { get; private set; } = true;
|
||||
|
||||
[DataField]
|
||||
public bool BreakOnDamage { get; private set; } = true;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class CP14DelayedEntityTargetActionDoAfterEvent : SimpleDoAfterEvent
|
||||
{
|
||||
}
|
||||
|
||||
//Instant
|
||||
public sealed partial class CP14DelayedInstantActionEvent : InstantActionEvent, ICP14DelayedMagicEffect
|
||||
{
|
||||
[DataField]
|
||||
public float Delay { get; private set; } = 1f;
|
||||
|
||||
[DataField]
|
||||
public bool BreakOnMove { get; private set; } = true;
|
||||
|
||||
[DataField]
|
||||
public bool BreakOnDamage { get; private set; } = true;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class CP14DelayedInstantActionDoAfterEvent : SimpleDoAfterEvent
|
||||
{
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.MagicEnergy.Components;
|
||||
|
||||
@@ -13,4 +15,7 @@ public sealed partial class CP14MagicEnergyContainerComponent : Component
|
||||
|
||||
[DataField]
|
||||
public FixedPoint2 MaxEnergy = 100f;
|
||||
|
||||
[DataField]
|
||||
public ProtoId<AlertPrototype>? MagicAlert = null;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,34 @@
|
||||
using Content.Shared._CP14.MagicEnergy.Components;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Rounding;
|
||||
|
||||
namespace Content.Shared._CP14.MagicEnergy;
|
||||
|
||||
public partial class SharedCP14MagicEnergySystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly AlertsSystem _alerts = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<CP14MagicEnergyContainerComponent, ComponentStartup>(OnComponentStartup);
|
||||
SubscribeLocalEvent<CP14MagicEnergyContainerComponent, ComponentShutdown>(OnComponentShutdown);
|
||||
}
|
||||
|
||||
private void OnComponentStartup(Entity<CP14MagicEnergyContainerComponent> ent, ref ComponentStartup args)
|
||||
{
|
||||
UpdateMagicAlert(ent);
|
||||
}
|
||||
|
||||
private void OnComponentShutdown(Entity<CP14MagicEnergyContainerComponent> ent, ref ComponentShutdown args)
|
||||
{
|
||||
if (ent.Comp.MagicAlert == null)
|
||||
return;
|
||||
|
||||
_alerts.ClearAlert(ent, ent.Comp.MagicAlert.Value);
|
||||
}
|
||||
|
||||
public string GetEnergyExaminedText(EntityUid uid, CP14MagicEnergyContainerComponent ent)
|
||||
{
|
||||
var power = (int)((ent.Energy / ent.MaxEnergy) * 100);
|
||||
@@ -22,6 +44,92 @@ public partial class SharedCP14MagicEnergySystem : EntitySystem
|
||||
("power", power),
|
||||
("color", color));
|
||||
}
|
||||
|
||||
public void ChangeEnergy(EntityUid uid, CP14MagicEnergyContainerComponent component, FixedPoint2 energy, bool safe = false)
|
||||
{
|
||||
if (!safe)
|
||||
{
|
||||
//Overload
|
||||
if (component.Energy + energy > component.MaxEnergy)
|
||||
{
|
||||
RaiseLocalEvent(uid, new CP14MagicEnergyOverloadEvent()
|
||||
{
|
||||
OverloadEnergy = (component.Energy + energy) - component.MaxEnergy,
|
||||
});
|
||||
}
|
||||
|
||||
//Burn out
|
||||
if (component.Energy + energy < 0)
|
||||
{
|
||||
RaiseLocalEvent(uid, new CP14MagicEnergyBurnOutEvent()
|
||||
{
|
||||
BurnOutEnergy = -energy - component.Energy
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var oldEnergy = component.Energy;
|
||||
var newEnergy = Math.Clamp((float)component.Energy + (float)energy, 0, (float)component.MaxEnergy);
|
||||
component.Energy = newEnergy;
|
||||
|
||||
if (oldEnergy != newEnergy)
|
||||
{
|
||||
RaiseLocalEvent(uid, new CP14MagicEnergyLevelChangeEvent()
|
||||
{
|
||||
OldValue = component.Energy,
|
||||
NewValue = newEnergy,
|
||||
MaxValue = component.MaxEnergy,
|
||||
});
|
||||
}
|
||||
|
||||
UpdateMagicAlert((uid, component));
|
||||
}
|
||||
|
||||
public bool HasEnergy(EntityUid uid, FixedPoint2 energy, CP14MagicEnergyContainerComponent? component = null, bool safe = false)
|
||||
{
|
||||
if (!Resolve(uid, ref component))
|
||||
return false;
|
||||
|
||||
if (safe == false)
|
||||
return true;
|
||||
|
||||
return component.Energy > energy;
|
||||
}
|
||||
|
||||
public bool TryConsumeEnergy(EntityUid uid, FixedPoint2 energy, CP14MagicEnergyContainerComponent? component = null, bool safe = false)
|
||||
{
|
||||
if (!Resolve(uid, ref component))
|
||||
return false;
|
||||
|
||||
if (energy <= 0)
|
||||
return true;
|
||||
|
||||
// Attempting to absorb more energy than is contained in the container available only in non-safe methods (with container destruction)
|
||||
if (component.Energy < energy)
|
||||
{
|
||||
if (safe)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
ChangeEnergy(uid, component, -energy, safe);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
ChangeEnergy(uid, component, -energy, safe);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void UpdateMagicAlert(Entity<CP14MagicEnergyContainerComponent> ent)
|
||||
{
|
||||
if (ent.Comp.MagicAlert == null)
|
||||
return;
|
||||
|
||||
var level = ContentHelpers.RoundToLevels(MathF.Max(0f, (float) ent.Comp.Energy), (float) ent.Comp.MaxEnergy, 10);
|
||||
_alerts.ShowAlert(ent, ent.Comp.MagicAlert.Value, (short)level);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.FixedPoint;
|
||||
|
||||
namespace Content.Shared._CP14.MagicWeakness;
|
||||
|
||||
/// <summary>
|
||||
/// imposes damage on excessive use of magic
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14MagicWeaknessSystem))]
|
||||
public sealed partial class CP14MagicUnsafeDamageComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public DamageSpecifier DamagePerEnergy = new()
|
||||
{
|
||||
DamageDict = new Dictionary<string, FixedPoint2>
|
||||
{
|
||||
{"Blunt", 0.5},
|
||||
{"Heat", 0.5},
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.FixedPoint;
|
||||
|
||||
namespace Content.Shared._CP14.MagicWeakness;
|
||||
|
||||
/// <summary>
|
||||
/// imposes debuffs on excessive use of magic
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14MagicWeaknessSystem))]
|
||||
public sealed partial class CP14MagicUnsafeSleepComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public float SleepPerEnergy = 0.5f;
|
||||
|
||||
/// <summary>
|
||||
/// At the specified amount of extra mana expenditure, the character falls asleep.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public FixedPoint2 SleepThreshold = 20f;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using Content.Shared._CP14.MagicEnergy;
|
||||
using Content.Shared.Bed.Sleep;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.StatusEffect;
|
||||
|
||||
namespace Content.Shared._CP14.MagicWeakness;
|
||||
|
||||
public partial class CP14MagicWeaknessSystem : EntitySystem
|
||||
{
|
||||
[ValidatePrototypeId<StatusEffectPrototype>]
|
||||
private const string StatusEffectKey = "ForcedSleep";
|
||||
|
||||
[Dependency] private readonly StatusEffectsSystem _statusEffects = default!;
|
||||
[Dependency] private readonly DamageableSystem _damageable = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<CP14MagicUnsafeDamageComponent, CP14MagicEnergyBurnOutEvent>(OnMagicEnergyBurnOutDamage);
|
||||
SubscribeLocalEvent<CP14MagicUnsafeSleepComponent, CP14MagicEnergyBurnOutEvent>(OnMagicEnergyBurnOutSleep);
|
||||
}
|
||||
|
||||
private void OnMagicEnergyBurnOutSleep(Entity<CP14MagicUnsafeSleepComponent> ent, ref CP14MagicEnergyBurnOutEvent args)
|
||||
{
|
||||
if (args.BurnOutEnergy > ent.Comp.SleepThreshold)
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("cp14-magic-energy-damage-burn-out-fall"), ent, ent, PopupType.LargeCaution);
|
||||
_statusEffects.TryAddStatusEffect<ForcedSleepingComponent>(ent,
|
||||
StatusEffectKey,
|
||||
TimeSpan.FromSeconds(ent.Comp.SleepPerEnergy * (float)args.BurnOutEnergy),
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnMagicEnergyBurnOutDamage(Entity<CP14MagicUnsafeDamageComponent> ent, ref CP14MagicEnergyBurnOutEvent args)
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("cp14-magic-energy-damage-burn-out"), ent, ent, PopupType.LargeCaution);
|
||||
_damageable.TryChangeDamage(ent, ent.Comp.DamagePerEnergy * args.BurnOutEnergy);
|
||||
}
|
||||
}
|
||||
2
Resources/Locale/en-US/_CP14/alerts/alerts.ftl
Normal file
@@ -0,0 +1,2 @@
|
||||
cp14-alerts-magic-energy-name = Magic energy
|
||||
cp14-alerts-magic-energy-desc = A reserve of your internal magic power that allows you to use spells.
|
||||
@@ -4,4 +4,4 @@ cp14-magic-energy-crystal-slot-name = Energy crystal
|
||||
|
||||
cp14-magic-energy-no-crystal = No energy crystal!
|
||||
cp14-magic-energy-insufficient = Not enough energy!
|
||||
cp14-magic-energy-insufficient-unsafe = Crystal cracks from lack of energy!
|
||||
cp14-magic-energy-insufficient-unsafe = Crystal cracks from lack of energy!
|
||||
|
||||
10
Resources/Locale/en-US/_CP14/magicEnergy/magic-spells.ftl
Normal file
@@ -0,0 +1,10 @@
|
||||
cp14-magic-spell-not-enough-mana = Not enough mana!
|
||||
|
||||
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...
|
||||
cp14-magic-spell-not-enough-mana-cast-warning-2 = Your hands are shaking...
|
||||
cp14-magic-spell-not-enough-mana-cast-warning-3 = Your throat starts to lump...
|
||||
cp14-magic-spell-not-enough-mana-cast-warning-4 = Your head becomes heavy...
|
||||
|
||||
cp14-magic-energy-damage-burn-out = The pain is piercing your body!
|
||||
cp14-magic-energy-damage-burn-out-fall = You pass out from the intense pain!
|
||||
2
Resources/Locale/ru-RU/_CP14/alerts/alerts.ftl
Normal file
@@ -0,0 +1,2 @@
|
||||
cp14-alerts-magic-energy-name = Магическая энергия
|
||||
cp14-alerts-magic-energy-desc = Запас вашей внутренней магической силы, позволяющий вам использовать заклинания.
|
||||
@@ -4,4 +4,4 @@ cp14-magic-energy-crystal-slot-name = Энергокристалл
|
||||
|
||||
cp14-magic-energy-no-crystal = Отсутствует энергокристалл!
|
||||
cp14-magic-energy-insufficient = Не достаточно энергии!
|
||||
cp14-magic-energy-insufficient-unsafe = Кристалл трескается от нехватки энергии!
|
||||
cp14-magic-energy-insufficient-unsafe = Кристалл трескается от нехватки энергии!
|
||||
|
||||
13
Resources/Locale/ru-RU/_CP14/magicEnergy/magic-spells.ftl
Normal file
@@ -0,0 +1,13 @@
|
||||
cp14-magic-spell-not-enough-mana = Недостаточно магической энергии!
|
||||
|
||||
cp14-magic-spell-not-enough-mana-cast-warning-0 = Внутри вас все начинает неприятно ныть...
|
||||
cp14-magic-spell-not-enough-mana-cast-warning-1 = Голова начинает шуметь...
|
||||
cp14-magic-spell-not-enough-mana-cast-warning-2 = Ваши руки дрожат...
|
||||
cp14-magic-spell-not-enough-mana-cast-warning-3 = К горлу подступает ком...
|
||||
cp14-magic-spell-not-enough-mana-cast-warning-4 = Голова наливается свинцом...
|
||||
|
||||
cp14-magic-energy-damage-burn-out = Боль пронзает ваше тело!
|
||||
cp14-magic-energy-damage-burn-out-fall = Вы теряете сознание от сильной боли!
|
||||
|
||||
cp14-magic-spell-need-verbal-component = Вы не можете произнести заклинание вслух.
|
||||
cp14-magic-spell-need-somatic-component = Вам нужна свободная рука.
|
||||
@@ -5,6 +5,7 @@
|
||||
id: BaseAlertOrder
|
||||
order:
|
||||
- category: Health
|
||||
- alertType: CP14MagicEnergy
|
||||
- category: Stamina
|
||||
- alertType: SuitPower
|
||||
- category: Internals
|
||||
|
||||
@@ -207,7 +207,7 @@
|
||||
id: MobRespirator
|
||||
abstract: true
|
||||
components:
|
||||
- type: Internals
|
||||
#- type: Internals #CP14 dont need this
|
||||
- type: Respirator
|
||||
damage:
|
||||
types:
|
||||
|
||||
29
Resources/Prototypes/_CP14/Alerts/alerts.yml
Normal file
@@ -0,0 +1,29 @@
|
||||
- type: alert
|
||||
id: CP14MagicEnergy
|
||||
icons:
|
||||
- sprite: /Textures/_CP14/Interface/Alerts/magic_energy.rsi
|
||||
state: mana_0
|
||||
- sprite: /Textures/_CP14/Interface/Alerts/magic_energy.rsi
|
||||
state: mana_1
|
||||
- sprite: /Textures/_CP14/Interface/Alerts/magic_energy.rsi
|
||||
state: mana_2
|
||||
- sprite: /Textures/_CP14/Interface/Alerts/magic_energy.rsi
|
||||
state: mana_3
|
||||
- sprite: /Textures/_CP14/Interface/Alerts/magic_energy.rsi
|
||||
state: mana_4
|
||||
- sprite: /Textures/_CP14/Interface/Alerts/magic_energy.rsi
|
||||
state: mana_5
|
||||
- sprite: /Textures/_CP14/Interface/Alerts/magic_energy.rsi
|
||||
state: mana_6
|
||||
- sprite: /Textures/_CP14/Interface/Alerts/magic_energy.rsi
|
||||
state: mana_7
|
||||
- sprite: /Textures/_CP14/Interface/Alerts/magic_energy.rsi
|
||||
state: mana_8
|
||||
- sprite: /Textures/_CP14/Interface/Alerts/magic_energy.rsi
|
||||
state: mana_9
|
||||
- sprite: /Textures/_CP14/Interface/Alerts/magic_energy.rsi
|
||||
state: mana_10
|
||||
name: cp14-alerts-magic-energy-name
|
||||
description: cp14-alerts-magic-energy-desc
|
||||
minSeverity: 0
|
||||
maxSeverity: 10
|
||||
153
Resources/Prototypes/_CP14/Entities/Actions/test_spell.yml
Normal file
@@ -0,0 +1,153 @@
|
||||
- type: entity
|
||||
id: CP14ActionSpellHealingWord
|
||||
name: Healing word
|
||||
description: bruh
|
||||
components:
|
||||
- type: CP14MagicEffect
|
||||
manaCost: 10
|
||||
- type: EntityTargetAction
|
||||
useDelay: 1
|
||||
itemIconStyle: BigAction
|
||||
interactOnMiss: true
|
||||
sound: !type:SoundPathSpecifier
|
||||
path: /Audio/Magic/rumble.ogg
|
||||
icon:
|
||||
sprite: Objects/Magic/magicactions.rsi
|
||||
state: gib
|
||||
event: !type:CP14DelayedEntityTargetActionEvent
|
||||
- type: CP14DelayedApplyEntityEffectsSpell
|
||||
effects:
|
||||
- !type:HealthChange
|
||||
damage:
|
||||
types:
|
||||
Slash: -5
|
||||
Blunt: -5
|
||||
Piercing: -5
|
||||
Heat: -10
|
||||
- !type:Jitter
|
||||
|
||||
- type: entity
|
||||
id: CP14ActionSpellFireball
|
||||
name: Fireball
|
||||
description: Fires an explosive fireball towards the clicked location.
|
||||
components:
|
||||
- type: CP14MagicEffect
|
||||
manaCost: 70
|
||||
- type: CP14MagicEffectVerbalAspect
|
||||
startSpeech: "O tenebrae, ubi lux non penetrat..."
|
||||
endSpeech: "Quaeso, quemdam inter vos quaero!"
|
||||
- type: CP14MagicEffectSomaticAspect
|
||||
- type: CP14MagicEffectCastingVisual
|
||||
proto: CP14FireballRune
|
||||
- type: WorldTargetAction
|
||||
useDelay: 3
|
||||
itemIconStyle: BigAction
|
||||
checkCanAccess: false
|
||||
raiseOnUser: true
|
||||
range: 60
|
||||
sound: !type:SoundPathSpecifier
|
||||
path: /Audio/Magic/fireball.ogg
|
||||
icon:
|
||||
sprite: Objects/Magic/magicactions.rsi
|
||||
state: fireball
|
||||
event: !type:CP14DelayedWorldTargetActionEvent
|
||||
delay: 3
|
||||
- type: CP14DelayedProjectileSpell
|
||||
prototype: ProjectileFireball
|
||||
|
||||
- type: entity
|
||||
id: CP14ActionSpellSelfHeal
|
||||
name: Self Heal
|
||||
description: Toggles your suit's phase cloak. Beware that if you are hit, all abilities are disabled for 5 seconds, including your cloak!
|
||||
components:
|
||||
- type: InstantAction
|
||||
# have to plan (un)cloaking ahead of time
|
||||
useDelay: 5
|
||||
priority: -9
|
||||
event: !type:CP14DelayedInstantActionEvent
|
||||
- type: CP14DelayedSelfEntityEffectSpell
|
||||
effects:
|
||||
- !type:HealthChange
|
||||
damage:
|
||||
types:
|
||||
Slash: -5
|
||||
Blunt: -5
|
||||
Piercing: -5
|
||||
Heat: -10
|
||||
- !type:Jitter
|
||||
|
||||
- type: entity
|
||||
id: CP14ActionSpelldaggerSpawn
|
||||
name: Gravity well
|
||||
description: Toggles your suit's phase cloak. Beware that if you are hit, all abilities are disabled for 5 seconds, including your cloak!
|
||||
components:
|
||||
- type: CP14MagicEffect
|
||||
manaCost: 20
|
||||
- type: WorldTargetAction
|
||||
useDelay: 1
|
||||
itemIconStyle: BigAction
|
||||
checkCanAccess: false
|
||||
raiseOnUser: true
|
||||
range: 4
|
||||
sound: !type:SoundPathSpecifier
|
||||
path: /Audio/Magic/fireball.ogg
|
||||
icon:
|
||||
sprite: Objects/Magic/magicactions.rsi
|
||||
state: fireball
|
||||
event: !type:CP14DelayedWorldTargetActionEvent
|
||||
- type: CP14DelayedSpawnOnWorldTargetSpell
|
||||
spawns:
|
||||
- AdminInstantEffectGravityWell
|
||||
|
||||
- type: listing
|
||||
id: CP14SpellbookJutter
|
||||
name: jit
|
||||
description: jit
|
||||
productAction: CP14ActionSpellHealingWord
|
||||
cost:
|
||||
WizCoin: 1
|
||||
categories:
|
||||
- SpellbookOffensive
|
||||
conditions:
|
||||
- !type:ListingLimitedStockCondition
|
||||
stock: 1
|
||||
|
||||
|
||||
- type: listing
|
||||
id: CP14SpellbookFireball
|
||||
name: fifire
|
||||
description: fifire
|
||||
productAction: CP14ActionSpellFireball
|
||||
cost:
|
||||
WizCoin: 1
|
||||
categories:
|
||||
- SpellbookOffensive
|
||||
conditions:
|
||||
- !type:ListingLimitedStockCondition
|
||||
stock: 1
|
||||
|
||||
- type: listing
|
||||
id: CP14SpellbookFireball3
|
||||
name: selfheal
|
||||
description: selfheal
|
||||
productAction: CP14ActionSpellSelfHeal
|
||||
cost:
|
||||
WizCoin: 1
|
||||
categories:
|
||||
- SpellbookOffensive
|
||||
conditions:
|
||||
- !type:ListingLimitedStockCondition
|
||||
stock: 1
|
||||
|
||||
- type: listing
|
||||
id: CP14SpellbookFireball33
|
||||
name: Gravity Well
|
||||
description: well...
|
||||
productAction: CP14ActionSpelldaggerSpawn
|
||||
cost:
|
||||
WizCoin: 1
|
||||
categories:
|
||||
- SpellbookOffensive
|
||||
conditions:
|
||||
- !type:ListingLimitedStockCondition
|
||||
stock: 1
|
||||
31
Resources/Prototypes/_CP14/Entities/Effects/cast_vfx.yml
Normal file
@@ -0,0 +1,31 @@
|
||||
- type: entity
|
||||
id: CP14BaseMagicRune
|
||||
name: magic rune
|
||||
description: manifestation of magical energy in the physical plane
|
||||
abstract: true
|
||||
components:
|
||||
- type: Sprite
|
||||
drawDepth: FloorTiles
|
||||
sprite: _CP14/Effects/Magic/cast_rune.rsi
|
||||
- type: Tag
|
||||
tags:
|
||||
- HideContextMenu
|
||||
- type: PointLight
|
||||
radius: 1.5
|
||||
energy: 2.5
|
||||
netsync: false
|
||||
|
||||
- type: entity
|
||||
id: CP14FireballRune
|
||||
parent: CP14BaseMagicRune
|
||||
components:
|
||||
- type: PointLight
|
||||
color: "#d47d26"
|
||||
- type: Sprite
|
||||
layers:
|
||||
- state: medium_circle
|
||||
color: "#d47d26"
|
||||
shader: unshaded
|
||||
- state: sun
|
||||
color: "#d47d26"
|
||||
shader: unshaded
|
||||
@@ -54,10 +54,6 @@
|
||||
sprite: Objects/Misc/handcuffs.rsi
|
||||
state: body-overlay-2
|
||||
visible: false
|
||||
- map: [ "clownedon" ] # Dynamically generated
|
||||
sprite: "Effects/creampie.rsi"
|
||||
state: "creampie_human"
|
||||
visible: false
|
||||
- type: DamageVisuals
|
||||
thresholds: [ 10, 20, 30, 50, 70, 100 ]
|
||||
targetLayers:
|
||||
@@ -144,9 +140,7 @@
|
||||
prototype: CP14Human
|
||||
requiredLegs: 2
|
||||
- type: Identity
|
||||
- type: IdExaminable
|
||||
- type: Hands
|
||||
- type: Internals
|
||||
- type: Inventory
|
||||
- type: InventorySlots
|
||||
- type: FloatingVisuals
|
||||
@@ -171,8 +165,6 @@
|
||||
- type: SleepEmitSound
|
||||
- type: SSDIndicator
|
||||
- type: StandingState
|
||||
- type: Fingerprint
|
||||
- type: Dna
|
||||
- type: MindContainer
|
||||
showExamineInfo: true
|
||||
- type: InteractionPopup
|
||||
@@ -180,11 +172,9 @@
|
||||
interactSuccessString: hugging-success-generic
|
||||
interactSuccessSound: /Audio/Effects/thudswoosh.ogg
|
||||
messagePerceivedByOthers: hugging-success-generic-others
|
||||
- type: CanHostGuardian
|
||||
- type: NpcFactionMember
|
||||
factions:
|
||||
- NanoTrasen
|
||||
- type: CreamPied
|
||||
- type: Stripping
|
||||
- type: Strippable
|
||||
- type: UserInterface
|
||||
@@ -215,9 +205,16 @@
|
||||
deathPenalty: 0.01 # However they really ought to be living and intact, otherwise they're worth 100x less.
|
||||
- type: Tag
|
||||
tags:
|
||||
- CanPilot
|
||||
- FootstepSound
|
||||
- DoorBumpOpener
|
||||
- type: CP14MagicEnergyContainer
|
||||
magicAlert: CP14MagicEnergy
|
||||
maxEnergy: 100
|
||||
energy: 100
|
||||
- type: CP14MagicEnergyDraw
|
||||
energy: 5
|
||||
delay: 5
|
||||
- type: CP14MagicUnsafeDamage
|
||||
- type: CP14MagicUnsafeSleep
|
||||
|
||||
|
||||
- type: entity
|
||||
@@ -342,10 +339,6 @@
|
||||
sprite: Objects/Misc/handcuffs.rsi
|
||||
state: body-overlay-2
|
||||
visible: false
|
||||
- map: [ "clownedon" ] # Dynamically generated
|
||||
sprite: "Effects/creampie.rsi"
|
||||
state: "creampie_human"
|
||||
visible: false
|
||||
- type: Appearance
|
||||
- type: HumanoidAppearance
|
||||
species: CP14Human
|
||||
|
||||
@@ -77,4 +77,3 @@
|
||||
32:
|
||||
sprite: _CP14/Mobs/Species/Human/displacement.rsi
|
||||
state: female_shirt
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 7.8 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
@@ -0,0 +1,71 @@
|
||||
{
|
||||
"version": 1,
|
||||
"size": {
|
||||
"x": 48,
|
||||
"y": 48
|
||||
},
|
||||
"license": "All rights reserved for the CrystallPunk14 project only",
|
||||
"copyright": "Created by TheShuEd for CrystallPunk",
|
||||
"states": [
|
||||
{
|
||||
"name": "double_outer",
|
||||
"delays": [
|
||||
[
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "medium_circle",
|
||||
"delays": [
|
||||
[
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "medium_line",
|
||||
"delays": [
|
||||
[
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "sun",
|
||||
"delays": [
|
||||
[
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2,
|
||||
0.2
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
Resources/Textures/_CP14/Effects/Magic/cast_rune.rsi/sun.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 413 B |
|
After Width: | Height: | Size: 466 B |
|
After Width: | Height: | Size: 467 B |
|
After Width: | Height: | Size: 503 B |
|
After Width: | Height: | Size: 499 B |
|
After Width: | Height: | Size: 507 B |
|
After Width: | Height: | Size: 517 B |
|
After Width: | Height: | Size: 557 B |
|
After Width: | Height: | Size: 525 B |
|
After Width: | Height: | Size: 541 B |
|
After Width: | Height: | Size: 523 B |
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"version": 1,
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"copyright": "Created by TheShuEd (Github) for CrystallPunk",
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 32
|
||||
},
|
||||
"states": [
|
||||
{
|
||||
"name": "mana_0"
|
||||
},
|
||||
{
|
||||
"name": "mana_1"
|
||||
},
|
||||
{
|
||||
"name": "mana_2"
|
||||
},
|
||||
{
|
||||
"name": "mana_3"
|
||||
},
|
||||
{
|
||||
"name": "mana_4"
|
||||
},
|
||||
{
|
||||
"name": "mana_5"
|
||||
},
|
||||
{
|
||||
"name": "mana_6"
|
||||
},
|
||||
{
|
||||
"name": "mana_7"
|
||||
},
|
||||
{
|
||||
"name": "mana_8"
|
||||
},
|
||||
{
|
||||
"name": "mana_9"
|
||||
},
|
||||
{
|
||||
"name": "mana_10"
|
||||
}
|
||||
]
|
||||
}
|
||||