Familiars respawn (#7640)
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.MobState.Components;
|
||||
using Content.Shared.MobState;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Verbs;
|
||||
using Content.Shared.Tag;
|
||||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.Actions;
|
||||
using Content.Server.Cooldown;
|
||||
@@ -23,7 +23,6 @@ namespace Content.Server.Bible
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
|
||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||
[Dependency] private readonly TagSystem _tagSystem = default!;
|
||||
[Dependency] private readonly ActionBlockerSystem _blocker = default!;
|
||||
[Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
|
||||
|
||||
@@ -35,6 +34,51 @@ namespace Content.Server.Bible
|
||||
SubscribeLocalEvent<SummonableComponent, GetVerbsEvent<AlternativeVerb>>(AddSummonVerb);
|
||||
SubscribeLocalEvent<SummonableComponent, GetItemActionsEvent>(GetSummonAction);
|
||||
SubscribeLocalEvent<SummonableComponent, SummonActionEvent>(OnSummon);
|
||||
SubscribeLocalEvent<FamiliarComponent, MobStateChangedEvent>(OnFamiliarDeath);
|
||||
}
|
||||
|
||||
private Queue<EntityUid> AddQueue = new();
|
||||
private Queue<EntityUid> RemQueue = new();
|
||||
|
||||
/// <summary>
|
||||
/// This handles familiar respawning.
|
||||
/// </summary>
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
foreach(var entity in AddQueue)
|
||||
{
|
||||
EnsureComp<SummonableRespawningComponent>(entity);
|
||||
}
|
||||
AddQueue.Clear();
|
||||
|
||||
foreach(var entity in RemQueue)
|
||||
{
|
||||
RemComp<SummonableRespawningComponent>(entity);
|
||||
}
|
||||
RemQueue.Clear();
|
||||
|
||||
foreach (var (respawning, summonableComp) in EntityQuery<SummonableRespawningComponent, SummonableComponent>())
|
||||
{
|
||||
summonableComp.Accumulator += frameTime;
|
||||
if (summonableComp.Accumulator < summonableComp.RespawnTime)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
/// Clean up the old body
|
||||
if (summonableComp.Summon != null)
|
||||
{
|
||||
EntityManager.DeleteEntity(summonableComp.Summon.Value);
|
||||
summonableComp.Summon = null;
|
||||
}
|
||||
summonableComp.AlreadySummoned = false;
|
||||
_popupSystem.PopupEntity(Loc.GetString("bible-summon-respawn-ready", ("book", summonableComp.Owner)), summonableComp.Owner, Filter.Pvs(summonableComp.Owner));
|
||||
SoundSystem.Play(Filter.Pvs(summonableComp.Owner), "/Audio/Effects/radpulse9.ogg", summonableComp.Owner, AudioParams.Default.WithVolume(-4f));
|
||||
/// Clean up the accumulator and respawn tracking component
|
||||
summonableComp.Accumulator = 0;
|
||||
RemQueue.Enqueue(respawning.Owner);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAfterInteract(EntityUid uid, BibleComponent component, AfterInteractEvent args)
|
||||
@@ -67,7 +111,8 @@ namespace Content.Server.Bible
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_invSystem.TryGetSlotEntity(args.Target.Value, "head", out var entityUid) && !_tagSystem.HasTag(args.Target.Value, "Familiar"))
|
||||
// This only has a chance to fail if the target is not wearing anything on their head and is not a familiar.
|
||||
if (!_invSystem.TryGetSlotEntity(args.Target.Value, "head", out var entityUid) && !HasComp<FamiliarComponent>(args.Target.Value))
|
||||
{
|
||||
if (_random.Prob(component.FailChance))
|
||||
{
|
||||
@@ -125,6 +170,24 @@ namespace Content.Server.Bible
|
||||
{
|
||||
AttemptSummon(component, args.Performer, Transform(args.Performer));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts up the respawn stuff when
|
||||
/// the chaplain's familiar dies.
|
||||
/// </summary>
|
||||
private void OnFamiliarDeath(EntityUid uid, FamiliarComponent component, MobStateChangedEvent args)
|
||||
{
|
||||
if (!args.Component.IsDead() || component.Source == null)
|
||||
return;
|
||||
|
||||
var source = component.Source;
|
||||
if (source != null && TryComp<SummonableComponent>(source, out var summonable))
|
||||
{
|
||||
AddQueue.Enqueue(summonable.Owner);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void AttemptSummon(SummonableComponent component, EntityUid user, TransformComponent? position)
|
||||
{
|
||||
if (component.AlreadySummoned || component.SpecialItemPrototype == null)
|
||||
@@ -138,7 +201,17 @@ namespace Content.Server.Bible
|
||||
if (!_blocker.CanInteract(user, component.Owner))
|
||||
return;
|
||||
|
||||
EntityManager.SpawnEntity(component.SpecialItemPrototype, position.Coordinates);
|
||||
// Make this familiar the component's summon
|
||||
var familiar = EntityManager.SpawnEntity(component.SpecialItemPrototype, position.Coordinates);
|
||||
component.Summon = familiar;
|
||||
|
||||
/// We only want to add the familiar component to mobs
|
||||
if (HasComp<MobStateComponent>(familiar))
|
||||
{
|
||||
/// Make this Summon the familiar's source
|
||||
var familiarComp = EnsureComp<FamiliarComponent>(familiar);
|
||||
familiarComp.Source = component.Owner;
|
||||
}
|
||||
component.AlreadySummoned = true;
|
||||
_actionsSystem.RemoveAction(user, component.SummonAction);
|
||||
}
|
||||
|
||||
17
Content.Server/Bible/Components/FamiliarComponent.cs
Normal file
17
Content.Server/Bible/Components/FamiliarComponent.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace Content.Server.Bible.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// This component is for the chaplain's familiars, and mostly
|
||||
/// used to track their current state and to give a component to check for
|
||||
/// if any special behavior is needed.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed class FamiliarComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The entity this familiar was summoned from.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public EntityUid? Source = null;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Content.Shared.Actions.ActionTypes;
|
||||
using Content.Server.Bible;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.Bible.Components
|
||||
@@ -22,6 +21,12 @@ namespace Content.Server.Bible.Components
|
||||
[DataField("requriesBibleUser")]
|
||||
public bool RequiresBibleUser = true;
|
||||
|
||||
/// <summary>
|
||||
/// The specific creature this summoned, if the SpecialItemPrototype has a mobstate.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public EntityUid? Summon = null;
|
||||
|
||||
[DataField("summonAction")]
|
||||
public InstantAction SummonAction = new()
|
||||
{
|
||||
@@ -30,5 +35,13 @@ namespace Content.Server.Bible.Components
|
||||
Description = "bible-summon-verb-desc",
|
||||
Event = new SummonActionEvent(),
|
||||
};
|
||||
|
||||
/// Used for respawning
|
||||
[ViewVariables]
|
||||
[DataField("accumulator")]
|
||||
public float Accumulator = 0f;
|
||||
[ViewVariables]
|
||||
[DataField("respawnTime")]
|
||||
public float RespawnTime = 180f;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Content.Server.Bible.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// EntityQuery Tracking Component for Summonables that are counting up a respawn.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed class SummonableRespawningComponent : Component
|
||||
{}
|
||||
}
|
||||
Reference in New Issue
Block a user