From 11f729d02494727b0c95f79d824bad9743c2d7a1 Mon Sep 17 00:00:00 2001 From: keronshb <54602815+keronshb@users.noreply.github.com> Date: Sun, 29 May 2022 02:29:10 -0400 Subject: [PATCH] Simple Magic Spellbook System (#7823) Co-authored-by: metalgearsloth --- .../ActiveTriggerOnTimedCollideComponent.cs | 4 + .../Components/TriggerOnActivateComponent.cs | 7 + .../TriggerOnTimedCollideComponent.cs | 18 + .../TriggerSystem.TimedCollide.cs | 55 +++ .../Explosion/EntitySystems/TriggerSystem.cs | 10 + .../Magic/Components/SpellbookComponent.cs | 36 ++ .../Magic/Events/InstantSpawnSpellEvent.cs | 42 +++ .../Magic/Events/KnockSpellEvent.cs | 24 ++ .../Magic/Events/TeleportSpellEvent.cs | 10 + .../Magic/Events/WorldSpawnSpellEvent.cs | 29 ++ Content.Server/Magic/MagicSystem.cs | 317 ++++++++++++++++++ .../Components/TimedDespawnComponent.cs | 15 + .../EntitySystems/TimedDespawnSystem.cs | 19 ++ .../Physics/PreventCollideComponent.cs | 24 ++ .../Physics/SharedPreventCollideSystem.cs | 38 +++ Content.Shared/Sound/SoundSpecifier.cs | 5 +- Resources/Audio/Magic/blink.ogg | Bin 0 -> 13201 bytes Resources/Audio/Magic/forcewall.ogg | Bin 0 -> 24301 bytes Resources/Audio/Magic/knock.ogg | Bin 0 -> 28179 bytes Resources/Audio/Magic/licenses.txt | 5 + .../Locale/en-US/magic/spells-actions.ftl | 17 + .../Entities/Objects/Magic/books.yml | 65 ++++ .../Entities/Structures/Walls/walls.yml | 28 ++ Resources/Prototypes/Magic/Fixtures/runes.yml | 141 ++++++++ .../Prototypes/Magic/forcewall_spells.yml | 15 + Resources/Prototypes/Magic/knock_spell.yml | 11 + Resources/Prototypes/Magic/rune_spells.yml | 11 + Resources/Prototypes/Magic/spawn_spells.yml | 16 + .../Prototypes/Magic/teleport_spells.yml | 14 + .../Objects/Magic/magicactions.rsi/blink.png | Bin 0 -> 547 bytes .../Objects/Magic/magicactions.rsi/knock.png | Bin 0 -> 225 bytes .../Objects/Magic/magicactions.rsi/meta.json | 23 ++ .../Objects/Magic/magicactions.rsi/shield.png | Bin 0 -> 398 bytes .../Magic/magicactions.rsi/spell_default.png | Bin 0 -> 633 bytes .../Magic/spellbooks.rsi/bookfireball.png | Bin 0 -> 652 bytes .../Magic/spellbooks.rsi/bookforcewall.png | Bin 0 -> 532 bytes .../Magic/spellbooks.rsi/bookknock.png | Bin 0 -> 693 bytes .../Objects/Magic/spellbooks.rsi/meta.json | 47 +++ .../Magic/spellbooks.rsi/spellbook.png | Bin 0 -> 743 bytes .../Structures/Magic/Cult/rune.rsi/cult1.png | Bin 0 -> 648 bytes .../Structures/Magic/Cult/rune.rsi/cult2.png | Bin 0 -> 668 bytes .../Structures/Magic/Cult/rune.rsi/cult3.png | Bin 0 -> 637 bytes .../Structures/Magic/Cult/rune.rsi/cult4.png | Bin 0 -> 621 bytes .../Structures/Magic/Cult/rune.rsi/cult5.png | Bin 0 -> 652 bytes .../Structures/Magic/Cult/rune.rsi/cult6.png | Bin 0 -> 640 bytes .../Structures/Magic/Cult/rune.rsi/cult7.png | Bin 0 -> 671 bytes .../Structures/Magic/Cult/rune.rsi/meta.json | 32 ++ .../Structures/Magic/Cult/trap.rsi/meta.json | 14 + .../Structures/Magic/Cult/trap.rsi/trap.png | Bin 0 -> 640 bytes .../Magic/forcewall.rsi/forcewall.png | Bin 0 -> 661 bytes .../Magic/forcewall.rsi/forcewallspawn.png | Bin 0 -> 2595 bytes .../Structures/Magic/forcewall.rsi/meta.json | 29 ++ 52 files changed, 1120 insertions(+), 1 deletion(-) create mode 100644 Content.Server/Explosion/Components/ActiveTriggerOnTimedCollideComponent.cs create mode 100644 Content.Server/Explosion/Components/TriggerOnActivateComponent.cs create mode 100644 Content.Server/Explosion/Components/TriggerOnTimedCollideComponent.cs create mode 100644 Content.Server/Explosion/EntitySystems/TriggerSystem.TimedCollide.cs create mode 100644 Content.Server/Magic/Components/SpellbookComponent.cs create mode 100644 Content.Server/Magic/Events/InstantSpawnSpellEvent.cs create mode 100644 Content.Server/Magic/Events/KnockSpellEvent.cs create mode 100644 Content.Server/Magic/Events/TeleportSpellEvent.cs create mode 100644 Content.Server/Magic/Events/WorldSpawnSpellEvent.cs create mode 100644 Content.Server/Magic/MagicSystem.cs create mode 100644 Content.Server/Spawners/Components/TimedDespawnComponent.cs create mode 100644 Content.Server/Spawners/EntitySystems/TimedDespawnSystem.cs create mode 100644 Content.Shared/Physics/PreventCollideComponent.cs create mode 100644 Content.Shared/Physics/SharedPreventCollideSystem.cs create mode 100644 Resources/Audio/Magic/blink.ogg create mode 100644 Resources/Audio/Magic/forcewall.ogg create mode 100644 Resources/Audio/Magic/knock.ogg create mode 100644 Resources/Audio/Magic/licenses.txt create mode 100644 Resources/Locale/en-US/magic/spells-actions.ftl create mode 100644 Resources/Prototypes/Entities/Objects/Magic/books.yml create mode 100644 Resources/Prototypes/Magic/Fixtures/runes.yml create mode 100644 Resources/Prototypes/Magic/forcewall_spells.yml create mode 100644 Resources/Prototypes/Magic/knock_spell.yml create mode 100644 Resources/Prototypes/Magic/rune_spells.yml create mode 100644 Resources/Prototypes/Magic/spawn_spells.yml create mode 100644 Resources/Prototypes/Magic/teleport_spells.yml create mode 100644 Resources/Textures/Objects/Magic/magicactions.rsi/blink.png create mode 100644 Resources/Textures/Objects/Magic/magicactions.rsi/knock.png create mode 100644 Resources/Textures/Objects/Magic/magicactions.rsi/meta.json create mode 100644 Resources/Textures/Objects/Magic/magicactions.rsi/shield.png create mode 100644 Resources/Textures/Objects/Magic/magicactions.rsi/spell_default.png create mode 100644 Resources/Textures/Objects/Magic/spellbooks.rsi/bookfireball.png create mode 100644 Resources/Textures/Objects/Magic/spellbooks.rsi/bookforcewall.png create mode 100644 Resources/Textures/Objects/Magic/spellbooks.rsi/bookknock.png create mode 100644 Resources/Textures/Objects/Magic/spellbooks.rsi/meta.json create mode 100644 Resources/Textures/Objects/Magic/spellbooks.rsi/spellbook.png create mode 100644 Resources/Textures/Structures/Magic/Cult/rune.rsi/cult1.png create mode 100644 Resources/Textures/Structures/Magic/Cult/rune.rsi/cult2.png create mode 100644 Resources/Textures/Structures/Magic/Cult/rune.rsi/cult3.png create mode 100644 Resources/Textures/Structures/Magic/Cult/rune.rsi/cult4.png create mode 100644 Resources/Textures/Structures/Magic/Cult/rune.rsi/cult5.png create mode 100644 Resources/Textures/Structures/Magic/Cult/rune.rsi/cult6.png create mode 100644 Resources/Textures/Structures/Magic/Cult/rune.rsi/cult7.png create mode 100644 Resources/Textures/Structures/Magic/Cult/rune.rsi/meta.json create mode 100644 Resources/Textures/Structures/Magic/Cult/trap.rsi/meta.json create mode 100644 Resources/Textures/Structures/Magic/Cult/trap.rsi/trap.png create mode 100644 Resources/Textures/Structures/Magic/forcewall.rsi/forcewall.png create mode 100644 Resources/Textures/Structures/Magic/forcewall.rsi/forcewallspawn.png create mode 100644 Resources/Textures/Structures/Magic/forcewall.rsi/meta.json diff --git a/Content.Server/Explosion/Components/ActiveTriggerOnTimedCollideComponent.cs b/Content.Server/Explosion/Components/ActiveTriggerOnTimedCollideComponent.cs new file mode 100644 index 0000000000..51530d1b22 --- /dev/null +++ b/Content.Server/Explosion/Components/ActiveTriggerOnTimedCollideComponent.cs @@ -0,0 +1,4 @@ +namespace Content.Server.Explosion.Components; + +[RegisterComponent] +public sealed class ActiveTriggerOnTimedCollideComponent : Component { } diff --git a/Content.Server/Explosion/Components/TriggerOnActivateComponent.cs b/Content.Server/Explosion/Components/TriggerOnActivateComponent.cs new file mode 100644 index 0000000000..549ab62f8f --- /dev/null +++ b/Content.Server/Explosion/Components/TriggerOnActivateComponent.cs @@ -0,0 +1,7 @@ +namespace Content.Server.Explosion.Components; + +/// +/// Triggers on click. +/// +[RegisterComponent] +public sealed class TriggerOnActivateComponent : Component { } diff --git a/Content.Server/Explosion/Components/TriggerOnTimedCollideComponent.cs b/Content.Server/Explosion/Components/TriggerOnTimedCollideComponent.cs new file mode 100644 index 0000000000..892ce33e49 --- /dev/null +++ b/Content.Server/Explosion/Components/TriggerOnTimedCollideComponent.cs @@ -0,0 +1,18 @@ +namespace Content.Server.Explosion.Components; + +/// +/// Triggers when the entity is overlapped for the specified duration. +/// +[RegisterComponent] +public sealed class TriggerOnTimedCollideComponent : Component +{ + [ViewVariables(VVAccess.ReadWrite)] + [DataField("threshold")] + public float Threshold; + + /// + /// A collection of entities that are colliding with this, and their own unique accumulator. + /// + [ViewVariables] + public readonly Dictionary Colliding = new(); +} diff --git a/Content.Server/Explosion/EntitySystems/TriggerSystem.TimedCollide.cs b/Content.Server/Explosion/EntitySystems/TriggerSystem.TimedCollide.cs new file mode 100644 index 0000000000..efa39946ee --- /dev/null +++ b/Content.Server/Explosion/EntitySystems/TriggerSystem.TimedCollide.cs @@ -0,0 +1,55 @@ +using System.Linq; +using Content.Server.Explosion.Components; +using Content.Server.Explosion.EntitySystems; +using Robust.Shared.Physics.Dynamics; + +namespace Content.Server.Explosion.EntitySystems; + +public sealed partial class TriggerSystem +{ + private void InitializeTimedCollide() + { + SubscribeLocalEvent(OnTimerCollide); + SubscribeLocalEvent(OnTimerEndCollide); + SubscribeLocalEvent(OnComponentRemove); + } + + private void OnTimerCollide(EntityUid uid, TriggerOnTimedCollideComponent component, StartCollideEvent args) + { + //Ensures the entity trigger will have an active component + EnsureComp(uid); + var otherUID = args.OtherFixture.Body.Owner; + component.Colliding.Add(otherUID, 0); + } + + private void OnTimerEndCollide(EntityUid uid, TriggerOnTimedCollideComponent component, EndCollideEvent args) + { + var otherUID = args.OtherFixture.Body.Owner; + component.Colliding.Remove(otherUID); + + if (component.Colliding.Count == 0 && HasComp(uid)) + RemComp(uid); + } + + private void OnComponentRemove(EntityUid uid, TriggerOnTimedCollideComponent component, ComponentRemove args) + { + if (HasComp(uid)) + RemComp(uid); + } + + private void UpdateTimedCollide(float frameTime) + { + foreach (var (activeTrigger, triggerOnTimedCollide) in EntityQuery()) + { + foreach (var (collidingEntity, collidingTimer) in triggerOnTimedCollide.Colliding) + { + triggerOnTimedCollide.Colliding[collidingEntity] += frameTime; + if (collidingTimer > triggerOnTimedCollide.Threshold) + { + RaiseLocalEvent(activeTrigger.Owner, new TriggerEvent(activeTrigger.Owner, collidingEntity)); + triggerOnTimedCollide.Colliding[collidingEntity] -= triggerOnTimedCollide.Threshold; + } + } + } + } +} diff --git a/Content.Server/Explosion/EntitySystems/TriggerSystem.cs b/Content.Server/Explosion/EntitySystems/TriggerSystem.cs index dafc127ac7..0d04cf2bb5 100644 --- a/Content.Server/Explosion/EntitySystems/TriggerSystem.cs +++ b/Content.Server/Explosion/EntitySystems/TriggerSystem.cs @@ -2,6 +2,8 @@ using Content.Server.Administration.Logs; using Content.Server.Explosion.Components; using Content.Server.Flash; using Content.Server.Flash.Components; +using Content.Server.Sticky.Events; +using Content.Shared.Actions; using JetBrains.Annotations; using Robust.Shared.Audio; using Robust.Shared.Physics; @@ -10,6 +12,7 @@ using Robust.Shared.Player; using Content.Shared.Sound; using Content.Shared.Trigger; using Content.Shared.Database; +using Content.Shared.Interaction; namespace Content.Server.Explosion.EntitySystems { @@ -44,8 +47,10 @@ namespace Content.Server.Explosion.EntitySystems InitializeProximity(); InitializeOnUse(); InitializeSignal(); + InitializeTimedCollide(); SubscribeLocalEvent(OnTriggerCollide); + SubscribeLocalEvent(OnActivate); SubscribeLocalEvent(HandleDeleteTrigger); SubscribeLocalEvent(HandleExplodeTrigger); @@ -76,6 +81,10 @@ namespace Content.Server.Explosion.EntitySystems Trigger(component.Owner); } + private void OnActivate(EntityUid uid, TriggerOnActivateComponent component, ActivateInWorldEvent args) + { + Trigger(component.Owner, args.User); + } public void Trigger(EntityUid trigger, EntityUid? user = null) { @@ -124,6 +133,7 @@ namespace Content.Server.Explosion.EntitySystems UpdateProximity(frameTime); UpdateTimer(frameTime); + UpdateTimedCollide(frameTime); } private void UpdateTimer(float frameTime) diff --git a/Content.Server/Magic/Components/SpellbookComponent.cs b/Content.Server/Magic/Components/SpellbookComponent.cs new file mode 100644 index 0000000000..34a9cd2bba --- /dev/null +++ b/Content.Server/Magic/Components/SpellbookComponent.cs @@ -0,0 +1,36 @@ +using System.Threading; +using Content.Shared.Actions.ActionTypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary; + +namespace Content.Server.Magic; + +/// +/// Spellbooks for having an entity learn spells as long as they've read the book and it's in their hand. +/// +[RegisterComponent] +public sealed class SpellbookComponent : Component +{ + /// + /// List of spells that this book has. This is a combination of the WorldSpells, EntitySpells, and InstantSpells. + /// + [ViewVariables] + public readonly List Spells = new(); + + /// + /// The three fields below is just used for initialization. + /// + [DataField("worldSpells", customTypeSerializer: typeof(PrototypeIdDictionarySerializer))] + public readonly Dictionary WorldSpells = new(); + + [DataField("entitySpells", customTypeSerializer: typeof(PrototypeIdDictionarySerializer))] + public readonly Dictionary EntitySpells = new(); + + [DataField("instantSpells", customTypeSerializer: typeof(PrototypeIdDictionarySerializer))] + public readonly Dictionary InstantSpells = new(); + + [ViewVariables] + [DataField("learnTime")] + public float LearnTime = .75f; + + public CancellationTokenSource? CancelToken; +} diff --git a/Content.Server/Magic/Events/InstantSpawnSpellEvent.cs b/Content.Server/Magic/Events/InstantSpawnSpellEvent.cs new file mode 100644 index 0000000000..5b81b29c6f --- /dev/null +++ b/Content.Server/Magic/Events/InstantSpawnSpellEvent.cs @@ -0,0 +1,42 @@ +using Content.Shared.Actions; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Server.Magic.Events; + +public sealed class InstantSpawnSpellEvent : InstantActionEvent +{ + /// + /// What entity should be spawned. + /// + [DataField("prototype", required: true, customTypeSerializer: typeof(PrototypeIdSerializer))] + public string Prototype = default!; + + [ViewVariables, DataField("preventCollide")] + public bool PreventCollideWithCaster = true; + + /// + /// Gets the targeted spawn positons; may lead to multiple entities being spawned. + /// + [DataField("posData")] public MagicSpawnData Pos = new TargetCasterPos(); +} + +[ImplicitDataDefinitionForInheritors] +public abstract class MagicSpawnData +{ + +} + +/// +/// Spawns 1 at the caster's feet. +/// +public sealed class TargetCasterPos : MagicSpawnData {} + +/// +/// Targets the 3 tiles in front of the caster. +/// +public sealed class TargetInFront : MagicSpawnData +{ + [DataField("width")] + public int Width = 3; +} diff --git a/Content.Server/Magic/Events/KnockSpellEvent.cs b/Content.Server/Magic/Events/KnockSpellEvent.cs new file mode 100644 index 0000000000..cc7d3fb9ed --- /dev/null +++ b/Content.Server/Magic/Events/KnockSpellEvent.cs @@ -0,0 +1,24 @@ +using Content.Shared.Actions; +using Content.Shared.Sound; + +namespace Content.Server.Magic.Events; + +public sealed class KnockSpellEvent : InstantActionEvent +{ + /// + /// The range this spell opens doors in + /// 4f is the default + /// + [DataField("range")] + public float Range = 4f; + + [DataField("knockSound")] + public SoundSpecifier KnockSound = new SoundPathSpecifier("/Audio/Magic/knock.ogg"); + + /// + /// Volume control for the spell. + /// -6f is default because the base soundfile is really loud + /// + [DataField("knockVolume")] + public float KnockVolume = -6f; +} diff --git a/Content.Server/Magic/Events/TeleportSpellEvent.cs b/Content.Server/Magic/Events/TeleportSpellEvent.cs new file mode 100644 index 0000000000..a0dc573377 --- /dev/null +++ b/Content.Server/Magic/Events/TeleportSpellEvent.cs @@ -0,0 +1,10 @@ +using Content.Shared.Actions; +using Content.Shared.Sound; + +namespace Content.Server.Magic.Events; + +public sealed class TeleportSpellEvent : WorldTargetActionEvent +{ + [DataField("blinkSound")] + public SoundSpecifier BlinkSound = new SoundPathSpecifier("/Audio/Magic/blink.ogg"); +} diff --git a/Content.Server/Magic/Events/WorldSpawnSpellEvent.cs b/Content.Server/Magic/Events/WorldSpawnSpellEvent.cs new file mode 100644 index 0000000000..533d9bfcdb --- /dev/null +++ b/Content.Server/Magic/Events/WorldSpawnSpellEvent.cs @@ -0,0 +1,29 @@ +using Content.Shared.Actions; +using Content.Shared.Storage; + +namespace Content.Server.Magic.Events; + +public sealed class WorldSpawnSpellEvent : WorldTargetActionEvent +{ + // TODO:This class needs combining with InstantSpawnSpellEvent + + /// + /// The list of prototypes this spell will spawn + /// + [DataField("prototypes")] + public List Contents = new(); + + // TODO: This offset is liable for deprecation. + /// + /// The offset the prototypes will spawn in on relative to the one prior. + /// Set to 0,0 to have them spawn on the same tile. + /// + [DataField("offset")] + public Vector2 Offset; + + /// + /// Lifetime to set for the entities to self delete + /// + [DataField("lifetime")] public float? Lifetime; +} + diff --git a/Content.Server/Magic/MagicSystem.cs b/Content.Server/Magic/MagicSystem.cs new file mode 100644 index 0000000000..53aecb98a5 --- /dev/null +++ b/Content.Server/Magic/MagicSystem.cs @@ -0,0 +1,317 @@ +using System.Threading; +using Content.Server.Coordinates.Helpers; +using Content.Server.Decals; +using Content.Server.DoAfter; +using Content.Server.Doors.Components; +using Content.Server.Magic.Events; +using Content.Server.Spawners.Components; +using Content.Shared.Actions; +using Content.Shared.Actions.ActionTypes; +using Content.Shared.Doors.Components; +using Content.Shared.Doors.Systems; +using Content.Shared.Interaction.Events; +using Content.Shared.Maps; +using Content.Shared.Physics; +using Content.Shared.Storage; +using Robust.Shared.Audio; +using Robust.Shared.Map; +using Robust.Shared.Player; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; + +namespace Content.Server.Magic; + +/// +/// Handles learning and using spells (actions) +/// +public sealed class MagicSystem : EntitySystem +{ + [Dependency] private readonly IMapManager _mapManager = default!; + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly EntityLookupSystem _lookup = default!; + [Dependency] private readonly SharedDoorSystem _doorSystem = default!; + [Dependency] private readonly SharedActionsSystem _actionsSystem = default!; + [Dependency] private readonly DoAfterSystem _doAfter = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnInit); + SubscribeLocalEvent(OnUse); + SubscribeLocalEvent(OnLearnComplete); + SubscribeLocalEvent(OnLearnCancel); + + SubscribeLocalEvent(OnInstantSpawn); + SubscribeLocalEvent(OnTeleportSpell); + SubscribeLocalEvent(OnKnockSpell); + SubscribeLocalEvent(OnWorldSpawn); + + } + + private void OnInit(EntityUid uid, SpellbookComponent component, ComponentInit args) + { + //Negative charges means the spell can be used without it running out. + foreach (var (id, charges) in component.WorldSpells) + { + var spell = new WorldTargetAction(_prototypeManager.Index(id)); + _actionsSystem.SetCharges(spell, charges < 0 ? null : charges); + component.Spells.Add(spell); + } + + foreach (var (id, charges) in component.InstantSpells) + { + var spell = new InstantAction(_prototypeManager.Index(id)); + _actionsSystem.SetCharges(spell, charges < 0 ? null : charges); + component.Spells.Add(spell); + } + + foreach (var (id, charges) in component.EntitySpells) + { + var spell = new EntityTargetAction(_prototypeManager.Index(id)); + _actionsSystem.SetCharges(spell, charges < 0 ? null : charges); + component.Spells.Add(spell); + } + } + + private void OnUse(EntityUid uid, SpellbookComponent component, UseInHandEvent args) + { + if (args.Handled) + return; + + AttemptLearn(uid, component, args); + + args.Handled = true; + } + + private void AttemptLearn(EntityUid uid, SpellbookComponent component, UseInHandEvent args) + { + if (component.CancelToken != null) return; + + component.CancelToken = new CancellationTokenSource(); + + var doAfterEventArgs = new DoAfterEventArgs(args.User, component.LearnTime, component.CancelToken.Token, uid) + { + BreakOnTargetMove = true, + BreakOnUserMove = true, + BreakOnDamage = true, + BreakOnStun = true, + NeedHand = true, //What, are you going to read with your eyes only?? + TargetFinishedEvent = new LearnDoAfterComplete(args.User), + TargetCancelledEvent = new LearnDoAfterCancel(), + }; + + _doAfter.DoAfter(doAfterEventArgs); + } + + private void OnLearnComplete(EntityUid uid, SpellbookComponent component, LearnDoAfterComplete ev) + { + component.CancelToken = null; + _actionsSystem.AddActions(ev.User, component.Spells, uid); + } + + private void OnLearnCancel(EntityUid uid, SpellbookComponent component, LearnDoAfterCancel args) + { + component.CancelToken = null; + } + + #region Spells + + /// + /// Handles the instant action (i.e. on the caster) attempting to spawn an entity. + /// + private void OnInstantSpawn(InstantSpawnSpellEvent args) + { + if (args.Handled) + return; + + var transform = Transform(args.Performer); + + foreach (var position in GetSpawnPositions(transform, args.Pos)) + { + var ent = Spawn(args.Prototype, position.SnapToGrid(EntityManager, _mapManager)); + + if (args.PreventCollideWithCaster) + { + var comp = EnsureComp(ent); + comp.Uid = args.Performer; + } + } + + args.Handled = true; + } + + private List GetSpawnPositions(TransformComponent casterXform, MagicSpawnData data) + { + switch (data) + { + case TargetCasterPos: + return new List(1) {casterXform.Coordinates}; + case TargetInFront: + { + // This is shit but you get the idea. + var directionPos = casterXform.Coordinates.Offset(casterXform.LocalRotation.ToWorldVec().Normalized); + + if (!_mapManager.TryGetGrid(casterXform.GridID, out var mapGrid)) + return new List(); + + if (!directionPos.TryGetTileRef(out var tileReference, EntityManager, _mapManager)) + return new List(); + + var tileIndex = tileReference.Value.GridIndices; + var coords = mapGrid.GridTileToLocal(tileIndex); + EntityCoordinates coordsPlus; + EntityCoordinates coordsMinus; + + var dir = casterXform.LocalRotation.GetCardinalDir(); + switch (dir) + { + case Direction.North: + case Direction.South: + { + coordsPlus = mapGrid.GridTileToLocal(tileIndex + (1, 0)); + coordsMinus = mapGrid.GridTileToLocal(tileIndex + (-1, 0)); + return new List(3) + { + coords, + coordsPlus, + coordsMinus, + }; + } + case Direction.East: + case Direction.West: + { + coordsPlus = mapGrid.GridTileToLocal(tileIndex + (0, 1)); + coordsMinus = mapGrid.GridTileToLocal(tileIndex + (0, -1)); + return new List(3) + { + coords, + coordsPlus, + coordsMinus, + }; + } + } + + return new List(); + } + default: + throw new ArgumentOutOfRangeException(); + } + } + + /// + /// Teleports the user to the clicked location + /// + /// + private void OnTeleportSpell(TeleportSpellEvent args) + { + if (args.Handled) + return; + + var transform = Transform(args.Performer); + + if (transform.MapID != args.Target.MapId) return; + + transform.WorldPosition = args.Target.Position; + transform.AttachToGridOrMap(); + SoundSystem.Play(Filter.Pvs(args.Target), args.BlinkSound.GetSound()); + args.Handled = true; + } + + /// + /// Opens all doors within range + /// + /// + private void OnKnockSpell(KnockSpellEvent args) + { + if (args.Handled) + return; + + //Get the position of the player + var transform = Transform(args.Performer); + var coords = transform.Coordinates; + + SoundSystem.Play(Filter.Pvs(coords), args.KnockSound.GetSound(), AudioParams.Default.WithVolume(args.KnockVolume)); + + //Look for doors and don't open them if they're already open. + foreach (var entity in _lookup.GetEntitiesInRange(coords, args.Range)) + { + if (TryComp(entity, out var airlock)) + airlock.BoltsDown = false; + + if (TryComp(entity, out var doorComp) && doorComp.State is not DoorState.Open) + _doorSystem.StartOpening(doorComp.Owner); + } + + args.Handled = true; + } + + /// + /// Spawns entity prototypes from a list within range of click. + /// + /// + /// It will offset mobs after the first mob based on the OffsetVector2 property supplied. + /// + /// The Spawn Spell Event args. + private void OnWorldSpawn(WorldSpawnSpellEvent args) + { + if (args.Handled) + return; + + var targetMapCoords = args.Target; + + SpawnSpellHelper(args.Contents, targetMapCoords, args.Lifetime, args.Offset); + + args.Handled = true; + } + + /// + /// Loops through a supplied list of entity prototypes and spawns them + /// + /// + /// If an offset of 0, 0 is supplied then the entities will all spawn on the same tile. + /// Any other offset will spawn entities starting from the source Map Coordinates and will increment the supplied + /// offset + /// + /// The list of Entities to spawn in + /// Map Coordinates where the entities will spawn + /// Check to see if the entities should self delete + /// A Vector2 offset that the entities will spawn in + private void SpawnSpellHelper(List entityEntries, MapCoordinates mapCoords, float? lifetime, Vector2 offsetVector2) + { + var getProtos = EntitySpawnCollection.GetSpawns(entityEntries, _random); + + var offsetCoords = mapCoords; + foreach (var proto in getProtos) + { + // TODO: Share this code with instant because they're both doing similar things for positioning. + var entity = Spawn(proto, offsetCoords); + offsetCoords = offsetCoords.Offset(offsetVector2); + + if (lifetime != null) + { + var comp = EnsureComp(entity); + comp.Lifetime = lifetime.Value; + } + } + } + + #endregion + + #region DoAfterClasses + + private sealed class LearnDoAfterComplete : EntityEventArgs + { + public readonly EntityUid User; + + public LearnDoAfterComplete(EntityUid uid) + { + User = uid; + } + } + + private sealed class LearnDoAfterCancel : EntityEventArgs { } + + #endregion +} diff --git a/Content.Server/Spawners/Components/TimedDespawnComponent.cs b/Content.Server/Spawners/Components/TimedDespawnComponent.cs new file mode 100644 index 0000000000..b5f6e9568c --- /dev/null +++ b/Content.Server/Spawners/Components/TimedDespawnComponent.cs @@ -0,0 +1,15 @@ +namespace Content.Server.Spawners.Components; + +/// +/// Put this component on something you would like to despawn after a certain amount of time +/// +[RegisterComponent] +public sealed class TimedDespawnComponent : Component +{ + /// + /// How long the entity will exist before despawning + /// + [ViewVariables] + [DataField("lifetime")] + public float Lifetime = 5f; +} diff --git a/Content.Server/Spawners/EntitySystems/TimedDespawnSystem.cs b/Content.Server/Spawners/EntitySystems/TimedDespawnSystem.cs new file mode 100644 index 0000000000..172d57b436 --- /dev/null +++ b/Content.Server/Spawners/EntitySystems/TimedDespawnSystem.cs @@ -0,0 +1,19 @@ +using Content.Server.Spawners.Components; + +namespace Content.Server.Spawners.EntitySystems; + +public sealed class TimedDespawnSystem : EntitySystem +{ + public override void Update(float frameTime) + { + base.Update(frameTime); + + foreach (var entity in EntityQuery()) + { + entity.Lifetime -= frameTime; + + if (entity.Lifetime <= 0) + EntityManager.QueueDeleteEntity(entity.Owner); + } + } +} diff --git a/Content.Shared/Physics/PreventCollideComponent.cs b/Content.Shared/Physics/PreventCollideComponent.cs new file mode 100644 index 0000000000..6f11929caa --- /dev/null +++ b/Content.Shared/Physics/PreventCollideComponent.cs @@ -0,0 +1,24 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Serialization; + +namespace Content.Shared.Physics; + +/// +/// Use this to allow a specific UID to prevent collides +/// +[RegisterComponent, NetworkedComponent] +public sealed class PreventCollideComponent : Component +{ + public EntityUid Uid; +} + +[Serializable, NetSerializable] +public sealed class PreventCollideComponentState : ComponentState +{ + public EntityUid Uid; + + public PreventCollideComponentState(PreventCollideComponent component) + { + Uid = component.Uid; + } +} diff --git a/Content.Shared/Physics/SharedPreventCollideSystem.cs b/Content.Shared/Physics/SharedPreventCollideSystem.cs new file mode 100644 index 0000000000..eb1491a997 --- /dev/null +++ b/Content.Shared/Physics/SharedPreventCollideSystem.cs @@ -0,0 +1,38 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Physics.Dynamics; + +namespace Content.Shared.Physics; + +public sealed class SharedPreventCollideSystem : EntitySystem +{ + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnGetState); + SubscribeLocalEvent(OnHandleState); + SubscribeLocalEvent(OnPreventCollide); + } + + private void OnGetState(EntityUid uid, PreventCollideComponent component, ref ComponentGetState args) + { + args.State = new PreventCollideComponentState(component); + } + + private void OnHandleState(EntityUid uid, PreventCollideComponent component, ref ComponentHandleState args) + { + if (args.Current is not PreventCollideComponentState state) + return; + + component.Uid = state.Uid; + } + + private void OnPreventCollide(EntityUid uid, PreventCollideComponent component, PreventCollideEvent args) + { + var otherUid = args.BodyB.Owner; + + if (component.Uid == otherUid) + args.Cancel(); + } + +} diff --git a/Content.Shared/Sound/SoundSpecifier.cs b/Content.Shared/Sound/SoundSpecifier.cs index adea9d2f57..1c89180532 100644 --- a/Content.Shared/Sound/SoundSpecifier.cs +++ b/Content.Shared/Sound/SoundSpecifier.cs @@ -3,13 +3,14 @@ using JetBrains.Annotations; using Robust.Shared.Audio; using Robust.Shared.Prototypes; using Robust.Shared.Random; +using Robust.Shared.Serialization; using Robust.Shared.Serialization.TypeSerializers.Implementations; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; using Robust.Shared.Utility; namespace Content.Shared.Sound { - [ImplicitDataDefinitionForInheritors] + [ImplicitDataDefinitionForInheritors, Serializable, NetSerializable] public abstract class SoundSpecifier { [ViewVariables(VVAccess.ReadWrite), DataField("params")] @@ -19,6 +20,7 @@ namespace Content.Shared.Sound public abstract string GetSound(IRobustRandom? rand = null, IPrototypeManager? proto = null); } + [Serializable, NetSerializable] public sealed class SoundPathSpecifier : SoundSpecifier { public const string Node = "path"; @@ -47,6 +49,7 @@ namespace Content.Shared.Sound } } + [Serializable, NetSerializable] public sealed class SoundCollectionSpecifier : SoundSpecifier { public const string Node = "collection"; diff --git a/Resources/Audio/Magic/blink.ogg b/Resources/Audio/Magic/blink.ogg new file mode 100644 index 0000000000000000000000000000000000000000..58b7cc8562c63d7d481d8bb41a6dd02e5b73b845 GIT binary patch literal 13201 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 literal 0 HcmV?d00001 diff --git a/Resources/Audio/Magic/licenses.txt b/Resources/Audio/Magic/licenses.txt new file mode 100644 index 0000000000..d6cf718f20 --- /dev/null +++ b/Resources/Audio/Magic/licenses.txt @@ -0,0 +1,5 @@ +https://github.com/Citadel-Station-13/Citadel-Station-13/blob/master/sound/magic/ForceWall.ogg +https://github.com/Citadel-Station-13/Citadel-Station-13/blob/master/sound/magic/blink.ogg +https://github.com/Citadel-Station-13/Citadel-Station-13/blob/master/sound/magic/Knock.ogg + +copyright: CC BY-SA 3.0 \ No newline at end of file diff --git a/Resources/Locale/en-US/magic/spells-actions.ftl b/Resources/Locale/en-US/magic/spells-actions.ftl new file mode 100644 index 0000000000..2c956b9664 --- /dev/null +++ b/Resources/Locale/en-US/magic/spells-actions.ftl @@ -0,0 +1,17 @@ +action-name-spell-rune-flash = Flash Rune +action-description-spell-rune-flash = Summons a rune that flashes if used. + +action-name-spell-forcewall = Forcewall +action-description-spell-forcewall = Creates a magical barrier. +action-speech-spell-forcewall = TARCOL MINTI ZHERI + +action-name-spell-knock = Knock +action-description-spell-knock = This spell opens nearby doors. +action-speech-spell-knock = AULIE OXIN FIERA + +action-name-spell-blink = Blink +action-description-spell-blink = Teleport to the clicked location. + +action-name-spell-summon-magicarp = Summon Magicarp +action-description-spell-summon-magicarp = This spell summons three Magi-Carp to your aid! May or may not turn on user. +action-speech-spell-summon-magicarp = AIE KHUSE EU diff --git a/Resources/Prototypes/Entities/Objects/Magic/books.yml b/Resources/Prototypes/Entities/Objects/Magic/books.yml new file mode 100644 index 0000000000..2a939f0942 --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/Magic/books.yml @@ -0,0 +1,65 @@ +- type: entity + id: BaseSpellbook + name: spellbook + parent: BaseItem + abstract: true + components: + - type: Sprite + netsync: false + sprite: Objects/Misc/books.rsi + layers: + - state: book_demonomicon + - type: Spellbook + +- type: entity + id: SpawnSpellbook + name: spawn spellbook + parent: BaseSpellbook + components: + - type: Spellbook + instantSpells: + FlashRune: -1 + worldSpells: + SpawnMagicarpSpell: -1 + +- type: entity + id: ForceWallSpellbook + name: force wall spellbook + parent: BaseSpellbook + components: + - type: Sprite + netsync: false + sprite: Objects/Magic/spellbooks.rsi + layers: + - state: bookforcewall + - type: Spellbook + instantSpells: + ForceWall: -1 + +- type: entity + id: BlinkBook + name: blink spellbook + parent: BaseSpellbook + components: + - type: Sprite + netsync: false + sprite: Objects/Magic/spellbooks.rsi + layers: + - state: spellbook + - type: Spellbook + worldSpells: + Blink: -1 + +- type: entity + id: KnockSpellbook + name: knock spellbook + parent: BaseSpellbook + components: + - type: Sprite + netsync: false + sprite: Objects/Magic/spellbooks.rsi + layers: + - state: bookknock + - type: Spellbook + instantSpells: + Knock: -1 diff --git a/Resources/Prototypes/Entities/Structures/Walls/walls.yml b/Resources/Prototypes/Entities/Structures/Walls/walls.yml index 5c5fa19a2b..efb0286889 100644 --- a/Resources/Prototypes/Entities/Structures/Walls/walls.yml +++ b/Resources/Prototypes/Entities/Structures/Walls/walls.yml @@ -714,3 +714,31 @@ layer: - GlassLayer - type: Airtight + +- type: entity + id: WallForce + name: Force Wall + components: + - type: TimedDespawn + lifetime: 20 + - type: Tag + tags: + - Wall + - type: Physics + bodyType: Static + - type: Fixtures + fixtures: + - shape: + !type:PhysShapeAabb + bounds: "-0.5,-0.5,0.5,0.5" + mask: + - FullTileMask + layer: + - WallLayer + - type: Airtight + - type: Sprite + sprite: Structures/Magic/forcewall.rsi + state: forcewall + - type: Icon + sprite: Structures/Magic/forcewall.rsi + state: forcewall diff --git a/Resources/Prototypes/Magic/Fixtures/runes.yml b/Resources/Prototypes/Magic/Fixtures/runes.yml new file mode 100644 index 0000000000..b4aaa7753e --- /dev/null +++ b/Resources/Prototypes/Magic/Fixtures/runes.yml @@ -0,0 +1,141 @@ +- type: entity + id: BaseRune + name: "rune" + abstract: true + placement: + mode: SnapgridCenter + components: + - type: Clickable + - type: Sprite + sprite: Structures/Magic/Cult/rune.rsi + netsync: false + layers: + - state: cult2 + color: '#FF00FF' + +- type: entity + parent: BaseRune + id: CollideRune + name: "collision rune" + abstract: true + components: + - type: Fixtures + fixtures: + - shape: + !type:PhysShapeAabb + bounds: "-0.4,-0.4,0.4,0.4" + hard: false + id: rune + mask: + - ItemMask + layer: + - SlipLayer + - type: Physics + +- type: entity + parent: CollideRune + id: ActivateRune + name: "activation rune" + abstract: true + components: + - type: TriggerOnActivate + +- type: entity + parent: CollideRune + id: CollideTimerRune + name: "collision timed rune" + abstract: true + components: + - type: TriggerOnTimedCollide + threshold: 5 + +- type: entity + parent: CollideRune + id: ExplosionRune + name: "explosion rune" + components: + - type: TriggerOnCollide + fixtureID: rune + - type: ExplodeOnTrigger + - type: Explosive + explosionType: Cryo + totalIntensity: 20.0 + intensitySlope: 5 + maxIntensity: 4 + - type: Sprite + sprite: Structures/Magic/Cult/trap.rsi + layers: + - state: trap + color: '#FF770055' + +- type: entity + parent: CollideRune + id: StunRune + name: "stun rune" + components: + - type: TriggerOnCollide + fixtureID: rune + - type: DeleteOnTrigger + - type: StunOnCollide + stunAmount: 5 + knockdownAmount: 3 + - type: Sprite + sprite: Structures/Magic/Cult/trap.rsi + layers: + - state: trap + color: '#FFFF0055' + +- type: entity + parent: CollideRune + id: IgniteRune + name: "ignite rune" + components: + - type: TriggerOnCollide + fixtureID: rune + - type: DeleteOnTrigger + - type: IgniteOnCollide + fireStacks: 10 + - type: Sprite + sprite: Structures/Magic/Cult/trap.rsi + layers: + - state: trap + color: '#FF000055' + +- type: entity + parent: CollideTimerRune + id: ExplosionTimedRune + name: "explosion timed rune" + components: + - type: ExplodeOnTrigger + - type: Explosive + explosionType: Cryo + totalIntensity: 20.0 + intensitySlope: 5 + maxIntensity: 4 + +- type: entity + parent: ActivateRune + id: ExplosionActivateRune + name: "explosion activated rune" + components: + - type: ExplodeOnTrigger + - type: Explosive + explosionType: Cryo + totalIntensity: 20.0 + intensitySlope: 5 + maxIntensity: 4 + +- type: entity + parent: ActivateRune + id: FlashRune + name: "flash rune" + components: + - type: FlashOnTrigger + - type: DeleteOnTrigger + +- type: entity + parent: CollideTimerRune + id: FlashRuneTimer + name: "flash timed rune" + components: + - type: FlashOnTrigger diff --git a/Resources/Prototypes/Magic/forcewall_spells.yml b/Resources/Prototypes/Magic/forcewall_spells.yml new file mode 100644 index 0000000000..ab5c038ba9 --- /dev/null +++ b/Resources/Prototypes/Magic/forcewall_spells.yml @@ -0,0 +1,15 @@ +- type: instantAction + id: ForceWall + name: action-name-spell-forcewall + description: action-description-spell-forcewall + useDelay: 10 + speech: action-speech-spell-forcewall + itemIconStyle: BigAction + sound: !type:SoundPathSpecifier + path: /Audio/Magic/forcewall.ogg + icon: + sprite: Objects/Magic/magicactions.rsi + state: shield + serverEvent: !type:InstantSpawnSpellEvent + prototype: WallForce + posData: !type:TargetInFront diff --git a/Resources/Prototypes/Magic/knock_spell.yml b/Resources/Prototypes/Magic/knock_spell.yml new file mode 100644 index 0000000000..3cfade9290 --- /dev/null +++ b/Resources/Prototypes/Magic/knock_spell.yml @@ -0,0 +1,11 @@ +- type: instantAction + id: Knock + name: action-name-spell-knock + description: action-description-spell-knock + useDelay: 10 + speech: action-speech-spell-knock + itemIconStyle: BigAction + icon: + sprite: Objects/Magic/magicactions.rsi + state: knock + serverEvent: !type:KnockSpellEvent diff --git a/Resources/Prototypes/Magic/rune_spells.yml b/Resources/Prototypes/Magic/rune_spells.yml new file mode 100644 index 0000000000..35d74c7007 --- /dev/null +++ b/Resources/Prototypes/Magic/rune_spells.yml @@ -0,0 +1,11 @@ +- type: instantAction + id: FlashRune + name: action-name-spell-rune-flash + description: action-description-spell-rune-flash + useDelay: 10 + itemIconStyle: BigAction + icon: + sprite: Objects/Magic/magicactions.rsi + state: spell_default + serverEvent: !type:InstantSpawnSpellEvent + prototype: FlashRune diff --git a/Resources/Prototypes/Magic/spawn_spells.yml b/Resources/Prototypes/Magic/spawn_spells.yml new file mode 100644 index 0000000000..98aa3639a6 --- /dev/null +++ b/Resources/Prototypes/Magic/spawn_spells.yml @@ -0,0 +1,16 @@ +- type: worldTargetAction + id: SpawnMagicarpSpell + name: action-name-spell-summon-magicarp + description: action-description-spell-summon-magicarp + useDelay: 10 + range: 4 + speech: action-speech-spell-summon-magicarp + itemIconStyle: BigAction + icon: + sprite: Objects/Magic/magicactions.rsi + state: spell_default + serverEvent: !type:WorldSpawnSpellEvent + prototypes: + - id: MobCarpMagic + amount: 3 + offsetVector2: 0, 1 diff --git a/Resources/Prototypes/Magic/teleport_spells.yml b/Resources/Prototypes/Magic/teleport_spells.yml new file mode 100644 index 0000000000..230ae024b7 --- /dev/null +++ b/Resources/Prototypes/Magic/teleport_spells.yml @@ -0,0 +1,14 @@ +- type: worldTargetAction + id: Blink + name: action-name-spell-blink + description: action-description-spell-blink + useDelay: 10 + range: 16 # default examine-range. + # ^ should probably add better validation that the clicked location is on the users screen somewhere, + itemIconStyle: BigAction + checkCanAccess: false + repeat: true + icon: + sprite: Objects/Magic/magicactions.rsi + state: blink + serverEvent: !type:TeleportSpellEvent diff --git a/Resources/Textures/Objects/Magic/magicactions.rsi/blink.png b/Resources/Textures/Objects/Magic/magicactions.rsi/blink.png new file mode 100644 index 0000000000000000000000000000000000000000..1e5f6fdd4ca9176f82a6a95fa8dbedc6782ed469 GIT binary patch literal 547 zcmV+;0^I$HP)&o*NTuKp2x4I^*jd~8 z3nKUlrpiayrBV@W5|JcLRP0RNns-b#d)b@IfdulJ+u2?6-p;()yDXW1#zH`50nZP& zzZ_SO&I%mw+bAm80T7>gl7l2c4bgj#@04j{&Stvk6tBtj)Xl3(B7 zn5&b^_=)*Ovuwiev&!X>w&h9aZV=$h`#C_oyIW01NhXAE+h5Re@pO{lsD zIz+m_W}@;&iT(s0^k{=|F<2cM)_hmAfrv&%Eq&8w3A Ue(aN;4|E=br>mdKI;Vst0AN8<0ssI2 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Magic/magicactions.rsi/meta.json b/Resources/Textures/Objects/Magic/magicactions.rsi/meta.json new file mode 100644 index 0000000000..e8acf68246 --- /dev/null +++ b/Resources/Textures/Objects/Magic/magicactions.rsi/meta.json @@ -0,0 +1,23 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "https://github.com/Citadel-Station-13/Citadel-Station-13/commit/78db6bd5c2b2b3d1f5cd8fd75be3a39d5d929943", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "spell_default" + }, + { + "name": "shield" + }, + { + "name": "knock" + }, + { + "name": "blink" + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Objects/Magic/magicactions.rsi/shield.png b/Resources/Textures/Objects/Magic/magicactions.rsi/shield.png new file mode 100644 index 0000000000000000000000000000000000000000..8d1562b489730862c9a838a27c465ea42d3ea5d6 GIT binary patch literal 398 zcmV;90df9`P)K-hS{U_)WOhTbe;Bd}%NN7>jp45*N z$M<4~0JrX9RRBzreZBAB005@h%4ddqcUk9yUblH z!a)=Ox@t7lDw4;fJW4ePfNDO7F_Vnh#%ne95G9)s6D4D>0z>?bMl1u!R-Y1h#+|s1 z@f!rG0sxri<#$02VnS#ws4?|`Xijerw1T)5i~t7@n^r*^SOr>o&xE_H%aq~MmHeT+}xmP8SK9Dm<@67qmH#6s4!}Q1aCosMQ zN*8GpV`4WK3QRyZh@H=pu|;1WMKyQxcO(GEg_Su9PaAEUO!5INUb-(RJKBxqM8cK; z9C|^j1)5skpja%awRpK)pqF}s5^G82k2uf8yyNqpHDIK6)Yy2sQffd}w{d==Ot0Uu zo&xyZ4UPoh7+VZc@%B>frdFv_Gg6>v>rG=cm9GwL2_Row0|*ESn~_;XL&$m;>MH~1sast{6u&aJ65fBc14oJw|qrl`r zwR?uuWz4)ti@+1yR{2|f!k2MRCMnG zzKnEEIkX_o0UdazV0Ckk9&XOtR_CoozTx1C?%e;sBLG`x_gVy)ME~6VI_B#4YC%r| z$Yr#ZCuB!TuK8>)qJ9@60Gne3B48ylDva-6GhO@u%|~)+ TC*K=w00000NkvXXu0mjfPgo00 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Magic/spellbooks.rsi/bookfireball.png b/Resources/Textures/Objects/Magic/spellbooks.rsi/bookfireball.png new file mode 100644 index 0000000000000000000000000000000000000000..ed18010a728992f4539425de5df522f572bb96cb GIT binary patch literal 652 zcmV;70(1R|P)Yr6%<4e@y`*&19%Vd z3WDeXDhPruyn*7Ti!KB~bRib;&qA@NOf_u?)0mmOH?x@cZA#K6zxTdOrpdflMBoww z5V*tu1THb)zaJb;PkirH#;i_$d{HkTr?~m421M|k-4zUdzMwK$?jBg0ZGR4oOlgl@ zTiixox!|W7px|50Cp0z>VWQQ`15n5XKhqp=K3>Xv!i9%7P>YkFc@k`0H?{kh%Y!(1 ze*Zn$Oa)x(#gEH|pX*;hB|o<@0@TnkLFwc57CvRd&t*V6=|u9}ijO!785@ucz;*Jv z5tm0s2E+qUa+!RG_m@1?NH8)W3P6eaN|?kzITEbq00r+`s$x!U)co8ARD5FtBKX(o zV<(7{eRl>>^NkI-s=cse+vy)A zSr2rlu=DvWNd*c9(=j))53%)FiBXEfU2wY+S0+$$oz$FGCa7lka7P#~WNPmFz z2e8%Wee-iyhjrrW574o7``G#edKD$9YxY^$6h%_2!bmdtD2OxgNynyG9=9uupnKKh zK@_XQ;FNCEc`1w}ho0*if!F>3>iWEIzVru}9w7Yz(jOrG0n#5J{Q;2v0Oyka04Bcl m2c&%|{Q&_;3_#!t-hdyeSrmMJI}Nk|0000A7D0p{dIGiwHo~5d?&#IkmiN$By@c|L;qm!&x_rowYIZoNc-;i%%Krv zLjYkuJe7vEB9K&EzcPN-C02~D=&g{tm7y|b>vibyEQ!)VcAOCRo6c2zn4cVLr z-{z9l^Watj4AcrHt z^T(6AeiXu4eL$M$Q!DCTSlQJ=I03*C#u&s_#sGNs(j2$8QLw8IAakx-e=BZF0QdEQ zND^{n3?MRGWV&tzK;QJ=?*nnH05SlMf)Zo)WB?3-`y5$)0O=u<5X=vX$A(S zbWaz@kcv5PXPxyr>>$#be?Xq4-ogBl{0p}le)C#}yE_8zaK!!+dc@5UB)}s6Xj`{V zjgWcXtS&u~Ka7Fg8p7pS(K-iw|6NmoS)So z$S-blYmbdO-`d68n;Ki{mKi6!(fl3w(ek$9?HyN+E51m&*neGYDyO^sbjI!BTi+!= zeqNPZ-MM7r%JXIiI;!Iye=n6_Tcmd5+HuJP^DiwZ+PE4ho@0KWf5kOj=lj#`nR8w* zW{J_cRk?ei(Zd&;c`a`CZ=0`ptBvvM`6s6iY_s!HIImLtV@juQ?KZ|qw_}~;RUJ;9 zOkwzL|1J6V%$!F-_E#B-&DGBT-SPcmruKJc)i1%k8T0Qw|0O7WHW}z%yK@Xdd^`$I z4DTIL z@4K%b{jy-LIJ|l)ufYZ$k8jVCRg9VRz63JqiLK4CQ@A<1f8rUA9T(g=3)KHi&vE#B z=3IHAa=?nK~_iwzoSU*@k-QnB9tEbr{jHC@#n9D0q6f9WUFI2EGL-jLb zbJb@&`)|t`^CI2s!TPtVQzb#l6rL)`Pxz+z320M@yoAH4!2AQ| Zt4g;>*qvB)0hkUMJYD@<);T3K0RV#^GT;CJ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Magic/spellbooks.rsi/meta.json b/Resources/Textures/Objects/Magic/spellbooks.rsi/meta.json new file mode 100644 index 0000000000..f9f1703f24 --- /dev/null +++ b/Resources/Textures/Objects/Magic/spellbooks.rsi/meta.json @@ -0,0 +1,47 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "https://github.com/Citadel-Station-13/Citadel-Station-13/commit/f3e328af032f0ba0234b866c24ccb0003e1a4993", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "bookfireball", + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1 + ] + ] + }, + { + "name": "bookforcewall", + "delays": [ + [ + 0.1, + 0.1 + ] + ] + }, + { + "name": "bookknock", + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ] + ] + }, + { + "name": "spellbook" + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Objects/Magic/spellbooks.rsi/spellbook.png b/Resources/Textures/Objects/Magic/spellbooks.rsi/spellbook.png new file mode 100644 index 0000000000000000000000000000000000000000..d24f198f949f09bd26e513d9a8df051437a5045c GIT binary patch literal 743 zcmV?P)-Ep z4)8je6vhI$9gFGonaSVB-rg1s-z|VFM+W@r3}Uf+xOwLT0Sq1A(F*v3LA-r=7fL9E zU^t9sclOn4r(a|+S(rb`Pq6@v^r$A=RcVEIVMi_ARg=U+uY6={YT4dh|VUF$?W3F z)#msBf%y<5pBMTNao)}$lt2I)+a4YEW((l)GI2q$6yMmWV0BgLgJ`zfaB8*yIt?a> zeeEP}1wqE|ogfUofzAM|jElcoPvBuM^TU7j2gT9y3Vltz`LCt+ic|M z41CJvglOcV?qg4}6P6h*0a*0Y>NV6VEF90w;PcmK_Nfpf9KtV$c}D||YX8Uof+@fx Z?Khte9agC)|40A;002ovPDHLkV1kOAT(|%L literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Magic/Cult/rune.rsi/cult1.png b/Resources/Textures/Structures/Magic/Cult/rune.rsi/cult1.png new file mode 100644 index 0000000000000000000000000000000000000000..a0bd42ac96bcf9b582937eddf6d8d273677714bd GIT binary patch literal 648 zcmV;30(bq1P)p6kCR?PX(3yH`lTH}u-4k;)KXRE5Z z>k1OhIctNd+fzXA8Fq)^+Gx{FY^l#{MYm@kz*@+k2;`voi>?8x920uO7EdMddkxE#rc&ihL(fT_{xIUI097az-5v zohmAa2*ev2^rb>$oE2TwbFXYeMt}-c)sraYU2FslIbPeunVHjW!o}mOnUVc!_6IN| z`3BX!5$&@-q4r$24&@2p+G%T`Yrh!qWkPwr9~hi_o+&>B#+|(41=OK7iOQ4ioHgRx z_E%;)jpC~K+=l5Cr=c6$j@Bs!j6wxQPb(unr0zVMw zNcbA{9#g@tq1_JrMBp6>hTjpWJodG|-1#suiE6OWtEw2Y)D`zX%}65N(pZ*1RNXx& i!oPo4HKqzN{^UX7XV1;pHQ zZsVtMMJy1CzJ$)@m?`XmnBk;}JW*a_1)|35C!l)w+-t4uCJ=Lqe3VZwKxazttPf8M zK{P4wMFioLCgHq-pj|P@)XgdHN`dlDK$>@EJomnX9GF;`>68@SRX1xR0TOc_giDhG zZ!XC>DWxPp(j^0A_yj;|3#lk0BPnvP3+lV1PO3C`AJ}Ec>60^oNCnCK)>8$??J7GO zV;^|u$d%}fJzwL4&et@mBux=A5{@$!nv=nLa=jQ#W6A!70Z~WvbbNOl%NFZNV+xY? zBLhifFtuiP?j5uQM{_ftPQyKcAtM4J=gwBoMhbLTgxaMRjLAMjl1;vq+V=5xz>|L1?Q#gsKE=(SjaAkfqc67>Y1LlOU8 z$s7a?a4X7Cx+lo781zd@a^3*wfnX$Fj1-=NEWQA?e=Q#|A!Cn@&{1#4te2tpV@dkjw<5%>m z?heR>`k;TOPX{ppFu0@&taaDVbjUykVpOz;QC9zocG?MCRt5(#GAG{I-hAwEQXTu$ zk)Nt$F9w)B9eZ%DtHWK7tSM_UCtI>G86d4PU~pwpop}cndZgYNoea=W27c6BboS-6 zx-&AcAuP-APOfe|8g|#Q*PW#xATc}K_;wW}?vGJzhBIBqnX})nGma8@1K`N3I%e1Jm3@_{EWsIK0?XDzl$Gyw zO`D#AsIQKa8j93*rI8=?2zy3A_&mJhD|)Zo0S>Ubh@=y~-WX621tJSqPKb-2n5;iI z54@=6e?386$vn$4ySVs1;y;-KXg2i_#M%D@=K;=yA+m?B#YeJvgZZ%O<>|7PO$Tr? z@RRjqfrABx$=8~kb|-*3{7WW4Wj_IQAhKXxcQZ>e$dN1^N-GfDXCGwKlLJ$!s^A|0 zG7w&SA21~Z%>ktgo&su( X(6CjazL4Md00000NkvXXu0mjfmPQ{k literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Magic/Cult/rune.rsi/cult4.png b/Resources/Textures/Structures/Magic/Cult/rune.rsi/cult4.png new file mode 100644 index 0000000000000000000000000000000000000000..27d2c2ea7d387ec24f1bcfc4cd020b1ebc8a50f0 GIT binary patch literal 621 zcmV-z0+RiSP)~`Gb{QyZei>7i0!*3umekz%G2*%k)Ro{I-uwBHpXg+VKG5}gsnoS! z&Z81CDkrR+Kz);W08M?|Pdf_0ao^|Ou($=$)D}OIJ)PsY)_x$N+}-C|#I;PZ6;p+2 zn|1x%$Jw^I{cLCa9?3cqD##kA66x&6xrtZ;KMPVUtnon8!f-Ra8+VVmwp^HT_kCCiST zj@t)gUDuuG`~BXoeLkP_`SExxSGHRM04t~hWJA}ozavr-h|L%a&_5$T$(k+JEXz`U z!&XHiB>*_UVQk;`O@S1Ecb;PpgjrXSI1zC0g5dN#h&dT0gaZ|cVVe%%cqv|aoP=YuzQ?b>$3D-8D-xpv*UbQBa%ZwLN0_Q`974cGys%8(^i<%T9!p(| zBYQ~FxJo`(%vE%Ir*`Ze&kKqJWG5tsSI;bwUj(#ZXpg_jWUrdt@B$YD za;H+PCqWZ0el_{3E1G++eI+A%C`4+UPUhKP)pzfpO12{UA`m@!l?$j}MtIgF^9zXr zGoQ)sZTxf}@RFI8XAEQ`YuA1{T#@nKFjesDlU6~`U?1KwRS~Trcs~hrB>ea=+_>k8 zl24l3`BK`EaBy!*nG%psN_c%OuSjHaySF+NxC2iKIEgF-SDyQt3cMtsB;pw&7}H;# mvlAkx;{Sh6b>sTQzvsWmBHWqPmwk``00001RCt`Vmr;(xAPhv4RettV?a|Xy^{?5w>aZ`)n6OgUQUw9y z8EkCmG7ZSOuABOo%cZM(yWLv%&$>!V(ZTfdf$AVSJwFHcsGJr@qGDW0u5$fCCRB)Deijorfg!h9j{f zkioSuzGKG%jXpy_@Jw7@iE&3_839);X_$vm#A2Rg)RzrMVmSkMVW?7(MCc)cXA-** z^uP(KaJYjied;J=(v{xJ1KfQTM;YNxX;`slW-uKIPOk)Z^MEG5pT9fY*#nn12$;vX zp%{xfdh?Km_i4QH5i|=AuXLT>Liam&XLsg#=Y`5n;HaJ68$EbHO4Es;xRhR?9f2~_ zULMFUayw)^M~OKbu3|O<3Wf7PK12>!VNm)x8zM*&hY*Z-fOWxzq33~ok2C^j_xvZt zrXdSYF9ah1RTy*MW`QK9&@?Dj3P!8bzsmv^j9fmeow;!3ahHN35v>lrdywoH=6m8y z+=bSw8MY3%C)HoXf#>_75r{ikHzKc4?qak$hJG$M45@iZ&G||8aHpLi5l{w}QGN4q zLfw2xEpMgf1wAHQ>8u{9oM*w|rlL(}Mr2gk0wiCSS|B z9828JErE)}R7e;knfx?61GfY+iRvum^vpV(ufR(JBoTcPkuic&94XnVaJv7FwQ&8% azvn**RE?FV1FRST0000$UvL_9X#;4Qha{c`f^|h)fC8W{ef+A0v;L|Gqn4 zwq_(+0)Tgh-D_rZxAUY$lcHns8KEQa~HRc_rIF=_8hY)yy$5IWeWN(%A zBOj8i^W>v|y~n%EevB88jX4jzzQ$`0#Ozp&DM$9900uIFI&i#pV&YYe*9Q`|VX~}0 z9YZENaDX#p{4N02%t$y{KLj#S@FI!97}+y930uu4Q9|p6dOn7y%s06t*%|DPCtf=r zyl)V224}oFPzcVHtaHVFS`vA{kcL+h2 z%^G(hN;R%R;6jya?Br^LohNyrFmAw9&7@Nmj`c}_Y+06FXgcHRVXe!m+Py8-S>mN4 zS@mXRxvMLk1FT!Sg+4~a-q-7lDC?cfU1A>;pyMJzLYDE4gjMmq011PqdSDF#bti9n zfF?*PfkDfdGTU=I0fus8$tT&!_-@Q48Zh^}>X|m%N@x`_h6b3O04s$Od0n&5-VXvD z39i%GE7*jx>^e6f+kqbl%t!z@yXCUBqeR}W9r%gBEF5{}{oaF27MXlYcHk|6B#}qT z&DoxF%_H{yUo(@aewXQd^9bpl>^c?y|L4>jw_p5w{sZwe@{n^pmU93A002ovPDHLk FV1kdaGtB@1 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Magic/Cult/rune.rsi/meta.json b/Resources/Textures/Structures/Magic/Cult/rune.rsi/meta.json new file mode 100644 index 0000000000..182c0b5afc --- /dev/null +++ b/Resources/Textures/Structures/Magic/Cult/rune.rsi/meta.json @@ -0,0 +1,32 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "https://github.com/Citadel-Station-13/Citadel-Station-13/commit/f7c09077d2fb8a11fdc11e5e780f8e337f60ef85", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "cult1" + }, + { + "name": "cult2" + }, + { + "name": "cult3" + }, + { + "name": "cult4" + }, + { + "name": "cult5" + }, + { + "name": "cult6" + }, + { + "name": "cult7" + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Structures/Magic/Cult/trap.rsi/meta.json b/Resources/Textures/Structures/Magic/Cult/trap.rsi/meta.json new file mode 100644 index 0000000000..fb18bcc7bc --- /dev/null +++ b/Resources/Textures/Structures/Magic/Cult/trap.rsi/meta.json @@ -0,0 +1,14 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "https://github.com/Citadel-Station-13/Citadel-Station-13/commit/95db5084abc411e77b5d994b473f4456ac72139a", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "trap" + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Structures/Magic/Cult/trap.rsi/trap.png b/Resources/Textures/Structures/Magic/Cult/trap.rsi/trap.png new file mode 100644 index 0000000000000000000000000000000000000000..a522ea67faa39ab3482acd473fb460b5f402e7d5 GIT binary patch literal 640 zcmV-`0)PF9P)1RCt_~meGyFFbqR;fPXVs7U+;&AcJLq9&`YUSDJEj0*WS% zEK#&1YitX-uIqK4=XM;&w(t9o)}PPkE9pNTk4cAXNm>A9pqv(n`lr(Z)a@ad+N<>r zNCZ$DBhC)l@L>F25rdHd zDSA$@rkw$;rSoUH|mpe1TavmV91d#x(a^hd} zfJdDYOc#thPoTVH9mw$JkevGjbeECT8@%e`5wNaHR=1o#`%K`rTs{CWl2ziY%8-(V zRA+N=sPHbPjcib^OF*lsSo;K6?|%$*O~P}7vMNKrJ<~9%3v8%Wrkko1)I!}@S9Su+ z*6X0y;D(e*QwPHJ7*V3SbIvJj8cJ6noJJqp^qi(+*%tNFRIFPn-B@(yXZ;P7)9!&x zWys-y+3tfTsZLDzSl^9u9{`wO1VMuyU3!;ef$OSl0^mSA5?@>Cr1QQFfYMFCNw;gm aEBOU-xsI|c%_(320000u%R literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Magic/forcewall.rsi/forcewall.png b/Resources/Textures/Structures/Magic/forcewall.rsi/forcewall.png new file mode 100644 index 0000000000000000000000000000000000000000..fc5b2a686305024ba26d152978fa43b5769af8f9 GIT binary patch literal 661 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 FV1fkn|2+Tz literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Magic/forcewall.rsi/meta.json b/Resources/Textures/Structures/Magic/forcewall.rsi/meta.json new file mode 100644 index 0000000000..56a718f9e4 --- /dev/null +++ b/Resources/Textures/Structures/Magic/forcewall.rsi/meta.json @@ -0,0 +1,29 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "https://github.com/Citadel-Station-13/Citadel-Station-13/commit/475a7d2499f6c29f31488799902b7cf0f7f495b6", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "forcewallspawn", + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.3, + 0.1 + ] + ] + }, + { + "name": "forcewall" + } + ] +} \ No newline at end of file