Wizard Summon Guns/Magic (#32692)

* mostly done but there's a bug with spawning

* RandomGlobalSpawnSpellEvent now actually works

* Summon Guns/Magic is working

* Added sound, cap gun, and auto pick up

* Added all requested changes/fixes from reviews

* Halving cooldowns
This commit is contained in:
ActiveMammmoth
2024-11-17 11:46:31 -05:00
committed by GitHub
parent c7f83523ef
commit 22987fc77f
10 changed files with 326 additions and 22 deletions

View File

@@ -0,0 +1,23 @@
using Content.Shared.Actions;
using Content.Shared.Storage;
using Robust.Shared.Audio;
namespace Content.Shared.Magic.Events;
public sealed partial class RandomGlobalSpawnSpellEvent : InstantActionEvent, ISpeakSpell
{
/// <summary>
/// The list of prototypes this spell can spawn, will select one randomly
/// </summary>
[DataField]
public List<EntitySpawnEntry> Spawns = new();
/// <summary>
/// Sound that will play globally when cast
/// </summary>
[DataField]
public SoundSpecifier Sound = new SoundPathSpecifier("/Audio/Magic/staff_animation.ogg");
[DataField]
public string? Speech { get; private set; }
}

View File

@@ -1,4 +1,4 @@
using System.Numerics;
using System.Numerics;
using Content.Shared.Actions;
using Content.Shared.Body.Components;
using Content.Shared.Body.Systems;
@@ -7,12 +7,17 @@ using Content.Shared.Doors.Components;
using Content.Shared.Doors.Systems;
using Content.Shared.Hands.Components;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Humanoid;
using Content.Shared.Interaction;
using Content.Shared.Inventory;
using Content.Shared.Lock;
using Content.Shared.Magic.Components;
using Content.Shared.Magic.Events;
using Content.Shared.Maps;
using Content.Shared.Mind;
using Content.Shared.Mind.Components;
using Content.Shared.Mobs.Components;
using Content.Shared.Mobs.Systems;
using Content.Shared.Physics;
using Content.Shared.Popups;
using Content.Shared.Speech.Muting;
@@ -20,6 +25,7 @@ using Content.Shared.Storage;
using Content.Shared.Tag;
using Content.Shared.Weapons.Ranged.Components;
using Content.Shared.Weapons.Ranged.Systems;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Network;
@@ -53,6 +59,9 @@ public abstract class SharedMagicSystem : EntitySystem
[Dependency] private readonly LockSystem _lock = default!;
[Dependency] private readonly SharedHandsSystem _hands = default!;
[Dependency] private readonly TagSystem _tag = default!;
[Dependency] private readonly MobStateSystem _mobState = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedMindSystem _mind = default!;
public override void Initialize()
{
@@ -67,6 +76,7 @@ public abstract class SharedMagicSystem : EntitySystem
SubscribeLocalEvent<SmiteSpellEvent>(OnSmiteSpell);
SubscribeLocalEvent<KnockSpellEvent>(OnKnockSpell);
SubscribeLocalEvent<ChargeSpellEvent>(OnChargeSpell);
SubscribeLocalEvent<RandomGlobalSpawnSpellEvent>(OnRandomGlobalSpawnSpell);
// Spell wishlist
// A wishlish of spells that I'd like to implement or planning on implementing in a future PR
@@ -501,6 +511,37 @@ public abstract class SharedMagicSystem : EntitySystem
_gunSystem.UpdateBasicEntityAmmoCount(wand.Value, basicAmmoComp.Count.Value + ev.Charge, basicAmmoComp);
}
// End Charge Spells
#endregion
#region Global Spells
private void OnRandomGlobalSpawnSpell(RandomGlobalSpawnSpellEvent ev)
{
if (!_net.IsServer || ev.Handled || !PassesSpellPrerequisites(ev.Action, ev.Performer) || ev.Spawns is not { } spawns)
return;
ev.Handled = true;
Speak(ev);
var allHumans = _mind.GetAliveHumans();
foreach (var human in allHumans)
{
if (!human.Comp.OwnedEntity.HasValue)
continue;
var ent = human.Comp.OwnedEntity.Value;
var mapCoords = _transform.GetMapCoordinates(ent);
foreach (var spawn in EntitySpawnCollection.GetSpawns(spawns, _random))
{
var spawned = Spawn(spawn, mapCoords);
_hands.PickupOrDrop(ent, spawned);
}
}
_audio.PlayGlobal(ev.Sound, ev.Performer);
}
#endregion
// End Spells
#endregion

View File

@@ -532,22 +532,19 @@ public abstract class SharedMindSystem : EntitySystem
/// <summary>
/// Returns a list of every living humanoid player's minds, except for a single one which is exluded.
/// </summary>
public List<EntityUid> GetAliveHumansExcept(EntityUid exclude)
public HashSet<Entity<MindComponent>> GetAliveHumans(EntityUid? exclude = null)
{
var mindQuery = EntityQuery<MindComponent>();
var allHumans = new List<EntityUid>();
var allHumans = new HashSet<Entity<MindComponent>>();
// HumanoidAppearanceComponent is used to prevent mice, pAIs, etc from being chosen
var query = EntityQueryEnumerator<MindContainerComponent, MobStateComponent, HumanoidAppearanceComponent>();
while (query.MoveNext(out var uid, out var mc, out var mobState, out _))
var query = EntityQueryEnumerator<MobStateComponent, HumanoidAppearanceComponent>();
while (query.MoveNext(out var uid, out var mobState, out _))
{
// the player needs to have a mind and not be the excluded one
if (mc.Mind == null || mc.Mind == exclude)
// the player needs to have a mind and not be the excluded one +
// the player has to be alive
if (!TryGetMind(uid, out var mind, out var mindComp) || mind == exclude || !_mobState.IsAlive(uid, mobState))
continue;
// the player has to be alive
if (_mobState.IsAlive(uid, mobState))
allHumans.Add(mc.Mind.Value);
allHumans.Add(new Entity<MindComponent>(mind, mindComp));
}
return allHumans;

View File

@@ -39,7 +39,8 @@ public partial class ListingData : IEquatable<ListingData>
other.Categories,
other.OriginalCost,
other.RestockTime,
other.DiscountDownTo
other.DiscountDownTo,
other.DisableRefund
)
{
@@ -63,7 +64,8 @@ public partial class ListingData : IEquatable<ListingData>
HashSet<ProtoId<StoreCategoryPrototype>> categories,
IReadOnlyDictionary<ProtoId<CurrencyPrototype>, FixedPoint2> originalCost,
TimeSpan restockTime,
Dictionary<ProtoId<CurrencyPrototype>, FixedPoint2> dataDiscountDownTo
Dictionary<ProtoId<CurrencyPrototype>, FixedPoint2> dataDiscountDownTo,
bool disableRefund
)
{
Name = name;
@@ -84,6 +86,7 @@ public partial class ListingData : IEquatable<ListingData>
OriginalCost = originalCost;
RestockTime = restockTime;
DiscountDownTo = new Dictionary<ProtoId<CurrencyPrototype>, FixedPoint2>(dataDiscountDownTo);
DisableRefund = disableRefund;
}
[ViewVariables]
@@ -194,6 +197,12 @@ public partial class ListingData : IEquatable<ListingData>
[DataField]
public Dictionary<ProtoId<CurrencyPrototype>, FixedPoint2> DiscountDownTo = new();
/// <summary>
/// Whether or not to disable refunding for the store when the listing is purchased from it.
/// </summary>
[DataField]
public bool DisableRefund = false;
public bool Equals(ListingData? listing)
{
if (listing == null)
@@ -287,7 +296,8 @@ public sealed partial class ListingDataWithCostModifiers : ListingData
listingData.Categories,
listingData.OriginalCost,
listingData.RestockTime,
listingData.DiscountDownTo
listingData.DiscountDownTo,
listingData.DisableRefund
)
{
}