Spell scrolls (#571)

* scroll spells

* refactor magic system

* Update spawners.yml

* safe use

* Update magic-spells.ftl
This commit is contained in:
Ed
2024-11-09 17:55:16 +03:00
committed by GitHub
parent 6147740f3e
commit c8ab937cf0
17 changed files with 257 additions and 52 deletions

View File

@@ -101,7 +101,7 @@ public partial class SharedCP14MagicEnergySystem : EntitySystem
if (safe == false)
return true;
return component.Energy > energy;
return component.Energy >= energy;
}
public bool TryConsumeEnergy(EntityUid uid, FixedPoint2 energy, CP14MagicEnergyContainerComponent? component = null, bool safe = false)

View File

@@ -29,16 +29,18 @@ public abstract partial class CP14SharedMagicSystem
if (args is not ICP14DelayedMagicEffect delayedEffect)
return;
if (!CanCastSpell(args.Action, args.Performer))
if (!TryComp<CP14MagicEffectComponent>(args.Action, out var magicEffect))
return;
if (!TryComp<CP14MagicEffectComponent>(args.Action, out var magicEffect))
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, args.Performer))
if (!TryCastSpellDelayed(delayedEffect, doAfter, (args.Action, magicEffect), args.Performer))
return;
}
@@ -67,12 +69,15 @@ public abstract partial class CP14SharedMagicSystem
if (args is not ICP14DelayedMagicEffect delayedEffect)
return;
if (!CanCastSpell(args.Action, args.Performer))
return;
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(
@@ -80,7 +85,7 @@ public abstract partial class CP14SharedMagicSystem
EntityManager.GetNetEntity(args.Entity),
args.Cooldown);
if (!TryCastSpellDelayed(delayedEffect, doAfter, args.Action, args.Performer))
if (!TryCastSpellDelayed(delayedEffect, doAfter, (args.Action, magicEffect), args.Performer))
return;
}
@@ -109,10 +114,12 @@ public abstract partial class CP14SharedMagicSystem
if (args is not ICP14DelayedMagicEffect delayedEffect)
return;
if (!CanCastSpell(args.Action, args.Performer))
if (!TryComp<CP14MagicEffectComponent>(args.Action, out var magicEffect))
return;
if (!TryComp<CP14MagicEffectComponent>(args.Action, out var magicEffect))
Entity<CP14MagicEffectComponent> spell = (args.Action, magicEffect);
if (!CanCastSpell(spell, args.Performer))
return;
if (args.CastDelay > 0)
@@ -121,7 +128,7 @@ public abstract partial class CP14SharedMagicSystem
EntityManager.GetNetEntity(args.Target),
args.Cooldown);
if (!TryCastSpellDelayed(delayedEffect, doAfter, args.Action, args.Performer))
if (!TryCastSpellDelayed(delayedEffect, doAfter, (args.Action, magicEffect), args.Performer))
return;
}

View File

@@ -76,10 +76,10 @@ public abstract partial class CP14SharedMagicSystem : EntitySystem
/// <summary>
/// Checking to see if the spell can be used at all
/// </summary>
private bool CanCastSpell(EntityUid spell, EntityUid performer)
private bool CanCastSpell(Entity<CP14MagicEffectComponent> ent, EntityUid performer)
{
var ev = new CP14CastMagicEffectAttemptEvent(performer);
RaiseLocalEvent(spell, ref ev);
RaiseLocalEvent(ent, ref ev);
if (ev.Reason != string.Empty && _net.IsServer)
{
_popup.PopupEntity(ev.Reason, performer, performer);
@@ -92,22 +92,41 @@ public abstract partial class CP14SharedMagicSystem : EntitySystem
/// </summary>
private void OnBeforeCastMagicEffect(Entity<CP14MagicEffectComponent> ent, ref CP14CastMagicEffectAttemptEvent args)
{
if (!TryComp<CP14MagicEnergyContainerComponent>(args.Performer, out var magicContainer))
if (ent.Comp.SpellStorage is null) //Dont have spellStorage, we use mana from caster
{
args.Cancel();
return;
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);
}
}
var manaCost = CalculateManacost(ent, args.Performer);
if (!_magicEnergy.HasEnergy(args.Performer, manaCost, magicContainer, ent.Comp.Safe))
else //We HAVE SpellStorage, use mana from spellStorage
{
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);
if (!TryComp<CP14MagicEnergyContainerComponent>(ent.Comp.SpellStorage, out var magicContainer))
{
args.Cancel();
return;
}
var manaCost = CalculateManacost(ent, ent.Comp.SpellStorage.Value);
if (!_magicEnergy.HasEnergy(ent.Comp.SpellStorage.Value, manaCost, magicContainer, true))
{
args.PushReason(Loc.GetString("cp14-magic-spell-not-enough-mana-item", ("item", MetaData(ent.Comp.SpellStorage.Value).EntityName)));
args.Cancel();
}
}
}
@@ -122,9 +141,9 @@ public abstract partial class CP14SharedMagicSystem : EntitySystem
}
}
private bool TryCastSpellDelayed(ICP14DelayedMagicEffect delayedEffect, DoAfterEvent doAfter, EntityUid action, EntityUid performer)
private bool TryCastSpellDelayed(ICP14DelayedMagicEffect delayedEffect, DoAfterEvent doAfter, Entity<CP14MagicEffectComponent> action, EntityUid performer)
{
var doAfterEventArgs = new DoAfterArgs(EntityManager, performer, delayedEffect.CastDelay, doAfter, action)
var doAfterEventArgs = new DoAfterArgs(EntityManager, performer, delayedEffect.CastDelay, doAfter, action, used: action.Comp.SpellStorage)
{
BreakOnMove = delayedEffect.BreakOnMove,
BreakOnDamage = delayedEffect.BreakOnDamage,
@@ -132,6 +151,8 @@ public abstract partial class CP14SharedMagicSystem : EntitySystem
DistanceThreshold = 100f,
CancelDuplicate = true,
BlockDuplicate = true,
BreakOnDropItem = true,
NeedHand = true,
};
return _doAfter.TryStartDoAfter(doAfterEventArgs);
@@ -158,11 +179,25 @@ public abstract partial class CP14SharedMagicSystem : EntitySystem
if (_net.IsClient)
return;
if (!HasComp<CP14MagicEnergyContainerComponent>(args.Performer))
return;
if (ent.Comp.SpellStorage is null) //We pickup mana from player
{
if (!HasComp<CP14MagicEnergyContainerComponent>(args.Performer))
return;
var manaCost = CalculateManacost(ent, args.Performer.Value);
_magicEnergy.TryConsumeEnergy(args.Performer.Value, manaCost, safe: ent.Comp.Safe);
var manaCost = CalculateManacost(ent, args.Performer.Value);
_magicEnergy.TryConsumeEnergy(args.Performer.Value, manaCost, safe: ent.Comp.Safe);
}
else //We pickup mana from SpellStorage
{
if (!HasComp<CP14MagicEnergyContainerComponent>(ent.Comp.SpellStorage))
return;
var manaCost = CalculateManacost(ent, ent.Comp.SpellStorage.Value);
_magicEnergy.TryConsumeEnergy(ent.Comp.SpellStorage.Value, manaCost, safe: ent.Comp.Safe);
var spellEv = new CP14SpellFromSpellStorageUsedEvent(args.Performer, ent, manaCost);
RaiseLocalEvent(ent.Comp.SpellStorage.Value, ref spellEv);
}
}
private FixedPoint2 CalculateManacost(Entity<CP14MagicEffectComponent> ent, EntityUid caster)
@@ -174,8 +209,8 @@ public abstract partial class CP14SharedMagicSystem : EntitySystem
var manaEv = new CP14CalculateManacostEvent(caster, ent.Comp.ManaCost, ent.Comp.MagicType);
RaiseLocalEvent(caster, manaEv);
if (TryComp<CP14ProvidedBySpellStorageComponent>(ent, out var provided) && provided.SpellStorage is not null)
RaiseLocalEvent(provided.SpellStorage.Value, manaEv);
if (ent.Comp.SpellStorage is not null)
RaiseLocalEvent(ent.Comp.SpellStorage.Value, manaEv);
manaCost = manaEv.GetManacost();
}

View File

@@ -1,5 +1,6 @@
using Content.Shared._CP14.MagicRitual.Prototypes;
using Content.Shared._CP14.MagicSpell.Spells;
using Content.Shared._CP14.MagicSpellStorage;
using Content.Shared.FixedPoint;
using Robust.Shared.Prototypes;
@@ -8,9 +9,15 @@ namespace Content.Shared._CP14.MagicSpell.Components;
/// <summary>
/// Restricts the use of this action, by spending mana or user requirements.
/// </summary>
[RegisterComponent, Access(typeof(CP14SharedMagicSystem))]
[RegisterComponent, Access(typeof(CP14SharedMagicSystem), typeof(CP14SpellStorageSystem))]
public sealed partial class CP14MagicEffectComponent : Component
{
/// <summary>
/// if this effect was provided by an spellstorage, it will be recorded here automatically.
/// </summary>
[DataField]
public Entity<CP14SpellStorageComponent>? SpellStorage;
[DataField]
public FixedPoint2 ManaCost = 0f;

View File

@@ -1,4 +1,5 @@
using Content.Shared._CP14.MagicRitual.Prototypes;
using Content.Shared._CP14.MagicSpell.Components;
using Content.Shared.FixedPoint;
using Content.Shared.Inventory;
using Robust.Shared.Prototypes;
@@ -97,3 +98,18 @@ public sealed class CP14AfterCastMagicEffectEvent : EntityEventArgs
Performer = performer;
}
}
[ByRefEvent]
public sealed class CP14SpellFromSpellStorageUsedEvent : EntityEventArgs
{
public EntityUid? Performer { get; init; }
public Entity<CP14MagicEffectComponent> Action { get; init; }
public FixedPoint2 Manacost { get; init; }
public CP14SpellFromSpellStorageUsedEvent(EntityUid? performer, Entity<CP14MagicEffectComponent> action, FixedPoint2 manacost)
{
Performer = performer;
Action = action;
Manacost = manacost;
}
}

View File

@@ -1,11 +0,0 @@
namespace Content.Shared._CP14.MagicSpellStorage;
/// <summary>
/// Located on the action entity, stores a reference to the object from which the action was created.
/// </summary>
[RegisterComponent, Access(typeof(CP14SpellStorageSystem))]
public sealed partial class CP14ProvidedBySpellStorageComponent : Component
{
[DataField]
public Entity<CP14SpellStorageComponent>? SpellStorage;
}

View File

@@ -1,7 +1,10 @@
using Content.Shared._CP14.MagicAttuning;
using Content.Shared._CP14.MagicSpell.Components;
using Content.Shared._CP14.MagicSpell.Events;
using Content.Shared.Actions;
using Content.Shared.Clothing;
using Content.Shared.Clothing.Components;
using Content.Shared.Damage;
using Content.Shared.Hands;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Mind;
@@ -20,12 +23,15 @@ public sealed partial class CP14SpellStorageSystem : EntitySystem
[Dependency] private readonly CP14SharedMagicAttuningSystem _attuning = default!;
[Dependency] private readonly SharedHandsSystem _hands = default!;
[Dependency] private readonly INetManager _net = default!;
[Dependency] private readonly DamageableSystem _damageable = default!;
public override void Initialize()
{
SubscribeLocalEvent<CP14SpellStorageComponent, MapInitEvent>(OnMagicStorageInit);
SubscribeLocalEvent<CP14SpellStorageComponent, ComponentShutdown>(OnMagicStorageShutdown);
SubscribeLocalEvent<CP14SpellStorageUseDamageComponent, CP14SpellFromSpellStorageUsedEvent>(OnSpellUsed);
SubscribeLocalEvent<CP14SpellStorageAccessHoldingComponent, GotEquippedHandEvent>(OnEquippedHand);
SubscribeLocalEvent<CP14SpellStorageAccessHoldingComponent, AddedAttuneToMindEvent>(OnHandAddedAttune);
@@ -36,6 +42,11 @@ public sealed partial class CP14SpellStorageSystem : EntitySystem
SubscribeLocalEvent<CP14SpellStorageRequireAttuneComponent, RemovedAttuneFromMindEvent>(OnRemovedAttune);
}
private void OnSpellUsed(Entity<CP14SpellStorageUseDamageComponent> ent, ref CP14SpellFromSpellStorageUsedEvent args)
{
_damageable.TryChangeDamage(ent, ent.Comp.DamagePerMana * args.Manacost);
}
/// <summary>
/// When we initialize, we create action entities, and add them to this item.
/// </summary>
@@ -50,7 +61,7 @@ public sealed partial class CP14SpellStorageSystem : EntitySystem
if (spellEnt is null)
continue;
var provided = EntityManager.EnsureComponent<CP14ProvidedBySpellStorageComponent>(spellEnt.Value);
var provided = EntityManager.EnsureComponent<CP14MagicEffectComponent>(spellEnt.Value);
provided.SpellStorage = mStorage;
mStorage.Comp.SpellEntities.Add(spellEnt.Value);

View File

@@ -0,0 +1,16 @@
using Content.Shared.Damage;
namespace Content.Shared._CP14.MagicSpellStorage;
/// <summary>
/// Causes damage to the Spell storage when spells from it are used
/// </summary>
[RegisterComponent, Access(typeof(CP14SpellStorageSystem))]
public sealed partial class CP14SpellStorageUseDamageComponent : Component
{
/// <summary>
/// the amount of damage this entity will take per unit manacost of the spell used
/// </summary>
[DataField(required: true)]
public DamageSpecifier DamagePerMana = default!;
}

View File

@@ -1,4 +1,6 @@
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...

View File

@@ -1,4 +1,5 @@
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 = Голова начинает шуметь...

View File

@@ -39,8 +39,8 @@
sprite: _CP14/Effects/Magic/spells_icons.rsi
state: mana_gift
event: !type:CP14DelayedEntityTargetActionEvent
cooldown: 5
castDelay: 2
cooldown: 1
castDelay: 1
- type: entity
id: CP14RuneManaGift

View File

@@ -11,6 +11,11 @@
- ring
- type: Sprite
sprite: _CP14/Clothing/Rings/rings.rsi
- type: CP14MagicEnergyExaminable
- type: CP14MagicEnergyContainer
energy: 50
maxEnergy: 50
- type: CP14MagicUnsafeDamage
- type: entity
id: CP14ClothingRingIceDagger

View File

@@ -32,6 +32,12 @@
weight: 0.5
- id: CP14CopperCoin1
weight: 1
- !type:GroupSelector
children:
- id: CP14SpellScrollFireball
- id: CP14SpellScrollCureWounds
- id: CP14SpellScrollIceShards
- id: CP14SpellScrollManaGift
- !type:GroupSelector
children:
- id: CP14DyeRed

View File

@@ -0,0 +1,103 @@
- type: entity
parent: BaseItem
id: CP14BaseSpellScroll
categories: [ ForkFiltered ]
name: spell scroll
description: A piece of paper with a spell embedded in it. The use of magic destroys the fragile paper, making these scrolls short-lived consumables.
abstract: true
components:
- type: Sprite
sprite: _CP14/Objects/Bureaucracy/paper.rsi
layers:
- state: paper_filled
- state: magic
shader: unshaded
- type: Item
size: Tiny
- type: Flammable
fireSpread: true
alwaysCombustible: true
damage:
types:
Heat: 1
- type: FireVisuals
sprite: Effects/fire.rsi
normalState: fire
- type: Damageable
- type: Destructible
thresholds:
- trigger:
!type:DamageTrigger
damage: 1
behaviors:
- !type:SpawnEntitiesBehavior
spawn:
Ash:
min: 1
max: 1
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: Food
solution: food
delay: 7
forceFeedDelay: 7
- type: FlavorProfile
flavors:
- paper
- CP14Magic
- type: BadFood
- type: SolutionContainerManager
solutions:
food:
maxVol: 1
reagents:
- ReagentId: Fiber
Quantity: 1
- type: Tag
tags:
- Document
- type: CP14SpellStorageAccessHolding
- type: CP14SpellStorageUseDamage
damagePerMana:
types:
Heat: 1
- type: CP14MagicEnergyContainer
energy: 30
maxEnergy: 50
- type: CP14MagicUnsafeDamage
- type: entity
parent: CP14BaseSpellScroll
id: CP14SpellScrollFireball
name: fireball spell scroll
components:
- type: CP14SpellStorage
spells:
- CP14ActionSpellFireball
- type: entity
parent: CP14BaseSpellScroll
id: CP14SpellScrollCureWounds
name: cure wound spell scroll
components:
- type: CP14SpellStorage
spells:
- CP14ActionSpellCureWounds
- type: entity
parent: CP14BaseSpellScroll
id: CP14SpellScrollIceShards
name: ice shards spell scroll
components:
- type: CP14SpellStorage
spells:
- CP14ActionSpellIceShards
- type: entity
parent: CP14BaseSpellScroll
id: CP14SpellScrollManaGift
name: mana gift spell scroll
components:
- type: CP14SpellStorage
spells:
- CP14ActionSpellManaGift

View File

@@ -44,6 +44,10 @@
- type: CP14SpellStorage
spells:
- CP14ActionSpellCureWounds
- type: CP14MagicManacostModify
modifiers:
Healing: 1.1
#- type: CP14MagicManacostModify
# modifiers:
# Healing: 1.1
- type: CP14MagicEnergyExaminable
- type: CP14MagicEnergyContainer
energy: 80
maxEnergy: 80

Binary file not shown.

After

Width:  |  Height:  |  Size: 270 B

View File

@@ -38,6 +38,9 @@
},
{
"name": "paper_stamp-generic"
},
{
"name": "magic"
}
]
}