predict morgue and crematorium (#39293)
This commit is contained in:
5
Content.Client/Morgue/CrematoriumSystem.cs
Normal file
5
Content.Client/Morgue/CrematoriumSystem.cs
Normal file
@@ -0,0 +1,5 @@
|
||||
using Content.Shared.Morgue;
|
||||
|
||||
namespace Content.Client.Morgue;
|
||||
|
||||
public sealed class CrematoriumSystem : SharedCrematoriumSystem;
|
||||
5
Content.Client/Morgue/MorgueSystem.cs
Normal file
5
Content.Client/Morgue/MorgueSystem.cs
Normal file
@@ -0,0 +1,5 @@
|
||||
using Content.Shared.Morgue;
|
||||
|
||||
namespace Content.Client.Morgue;
|
||||
|
||||
public sealed class MorgueSystem : SharedMorgueSystem;
|
||||
@@ -1,10 +0,0 @@
|
||||
using Content.Shared.Storage.Components;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Client.Storage.Components;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class EntityStorageComponent : SharedEntityStorageComponent
|
||||
{
|
||||
|
||||
}
|
||||
@@ -31,7 +31,7 @@ public sealed class EntityStorageSystem : SharedEntityStorageSystem
|
||||
SubscribeLocalEvent<EntityStorageComponent, ComponentHandleState>(OnHandleState);
|
||||
}
|
||||
|
||||
public override bool ResolveStorage(EntityUid uid, [NotNullWhen(true)] ref SharedEntityStorageComponent? component)
|
||||
public override bool ResolveStorage(EntityUid uid, [NotNullWhen(true)] ref EntityStorageComponent? component)
|
||||
{
|
||||
if (component != null)
|
||||
return true;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Content.Server.Storage.Components;
|
||||
using Content.Shared.Storage.Components;
|
||||
using Content.Server.Storage.EntitySystems;
|
||||
using Content.Shared.Administration;
|
||||
using Robust.Shared.Console;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Content.Server.Storage.Components;
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.Storage.Components;
|
||||
using Robust.Shared.Console;
|
||||
|
||||
namespace Content.Server.Administration.Commands;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Content.Server.Storage.Components;
|
||||
using Content.Shared.Storage.Components;
|
||||
using Content.Server.Storage.EntitySystems;
|
||||
using Content.Shared.Administration;
|
||||
using Robust.Shared.Console;
|
||||
|
||||
@@ -14,7 +14,6 @@ using Content.Server.Pointing.Components;
|
||||
using Content.Server.Polymorph.Systems;
|
||||
using Content.Server.Popups;
|
||||
using Content.Server.Speech.Components;
|
||||
using Content.Server.Storage.Components;
|
||||
using Content.Server.Storage.EntitySystems;
|
||||
using Content.Server.Tabletop;
|
||||
using Content.Server.Tabletop.Components;
|
||||
@@ -40,6 +39,7 @@ using Content.Shared.Movement.Systems;
|
||||
using Content.Shared.Nutrition.Components;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Slippery;
|
||||
using Content.Shared.Storage.Components;
|
||||
using Content.Shared.Stunnable;
|
||||
using Content.Shared.Tabletop.Components;
|
||||
using Content.Shared.Tools.Systems;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using Content.Server.Storage.Components;
|
||||
using Content.Shared.Construction;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Storage.Components;
|
||||
using Content.Shared.Tools.Systems;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
namespace Content.Server.Morgue.Components;
|
||||
|
||||
/// <summary>
|
||||
/// used to track actively cooking crematoriums
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class ActiveCrematoriumComponent : Component
|
||||
{
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float Accumulator = 0;
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
using Robust.Shared.Audio;
|
||||
|
||||
namespace Content.Server.Morgue.Components;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class CrematoriumComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The time it takes to cook in second
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public int CookTime = 5;
|
||||
|
||||
[DataField("cremateStartSound")]
|
||||
public SoundSpecifier CremateStartSound = new SoundPathSpecifier("/Audio/Items/Lighters/lighter1.ogg");
|
||||
|
||||
[DataField("crematingSound")]
|
||||
public SoundSpecifier CrematingSound = new SoundPathSpecifier("/Audio/Effects/burning.ogg");
|
||||
|
||||
[DataField("cremateFinishSound")]
|
||||
public SoundSpecifier CremateFinishSound = new SoundPathSpecifier("/Audio/Machines/ding.ogg");
|
||||
}
|
||||
@@ -1,195 +1,58 @@
|
||||
using Content.Server.Ghost;
|
||||
using Content.Server.Morgue.Components;
|
||||
using Content.Server.Storage.Components;
|
||||
using Content.Server.Storage.EntitySystems;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Morgue;
|
||||
using Content.Shared.Morgue.Components;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Standing;
|
||||
using Content.Shared.Storage;
|
||||
using Content.Shared.Storage.Components;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Server.Morgue;
|
||||
|
||||
public sealed class CrematoriumSystem : EntitySystem
|
||||
public sealed class CrematoriumSystem : SharedCrematoriumSystem
|
||||
{
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
[Dependency] private readonly GhostSystem _ghostSystem = default!;
|
||||
[Dependency] private readonly EntityStorageSystem _entityStorage = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
[Dependency] private readonly StandingStateSystem _standing = default!;
|
||||
[Dependency] private readonly SharedMindSystem _minds = default!;
|
||||
[Dependency] private readonly SharedContainerSystem _containers = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<CrematoriumComponent, ExaminedEvent>(OnExamine);
|
||||
SubscribeLocalEvent<CrematoriumComponent, GetVerbsEvent<AlternativeVerb>>(AddCremateVerb);
|
||||
SubscribeLocalEvent<CrematoriumComponent, SuicideByEnvironmentEvent>(OnSuicideByEnvironment);
|
||||
SubscribeLocalEvent<ActiveCrematoriumComponent, StorageOpenAttemptEvent>(OnAttemptOpen);
|
||||
}
|
||||
|
||||
private void OnExamine(EntityUid uid, CrematoriumComponent component, ExaminedEvent args)
|
||||
{
|
||||
if (!TryComp<AppearanceComponent>(uid, out var appearance))
|
||||
return;
|
||||
|
||||
using (args.PushGroup(nameof(CrematoriumComponent)))
|
||||
{
|
||||
if (_appearance.TryGetData<bool>(uid, CrematoriumVisuals.Burning, out var isBurning, appearance) &&
|
||||
isBurning)
|
||||
{
|
||||
args.PushMarkup(Loc.GetString("crematorium-entity-storage-component-on-examine-details-is-burning",
|
||||
("owner", uid)));
|
||||
}
|
||||
|
||||
if (_appearance.TryGetData<bool>(uid, StorageVisuals.HasContents, out var hasContents, appearance) &&
|
||||
hasContents)
|
||||
{
|
||||
args.PushMarkup(Loc.GetString("crematorium-entity-storage-component-on-examine-details-has-contents"));
|
||||
}
|
||||
else
|
||||
{
|
||||
args.PushMarkup(Loc.GetString("crematorium-entity-storage-component-on-examine-details-empty"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAttemptOpen(EntityUid uid, ActiveCrematoriumComponent component, ref StorageOpenAttemptEvent args)
|
||||
{
|
||||
args.Cancelled = true;
|
||||
}
|
||||
|
||||
private void AddCremateVerb(EntityUid uid, CrematoriumComponent component, GetVerbsEvent<AlternativeVerb> args)
|
||||
{
|
||||
if (!TryComp<EntityStorageComponent>(uid, out var storage))
|
||||
return;
|
||||
|
||||
if (!args.CanAccess || !args.CanInteract || args.Hands == null || storage.Open)
|
||||
return;
|
||||
|
||||
if (HasComp<ActiveCrematoriumComponent>(uid))
|
||||
return;
|
||||
|
||||
AlternativeVerb verb = new()
|
||||
{
|
||||
Text = Loc.GetString("cremate-verb-get-data-text"),
|
||||
// TODO VERB ICON add flame/burn symbol?
|
||||
Act = () => TryCremate(uid, component, storage),
|
||||
Impact = LogImpact.High // could be a body? or evidence? I dunno.
|
||||
};
|
||||
args.Verbs.Add(verb);
|
||||
}
|
||||
|
||||
public bool Cremate(EntityUid uid, CrematoriumComponent? component = null, EntityStorageComponent? storage = null)
|
||||
{
|
||||
if (!Resolve(uid, ref component, ref storage))
|
||||
return false;
|
||||
|
||||
if (HasComp<ActiveCrematoriumComponent>(uid))
|
||||
return false;
|
||||
|
||||
_audio.PlayPvs(component.CremateStartSound, uid);
|
||||
_appearance.SetData(uid, CrematoriumVisuals.Burning, true);
|
||||
|
||||
_audio.PlayPvs(component.CrematingSound, uid);
|
||||
|
||||
AddComp<ActiveCrematoriumComponent>(uid);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryCremate(EntityUid uid, CrematoriumComponent? component = null, EntityStorageComponent? storage = null)
|
||||
{
|
||||
if (!Resolve(uid, ref component, ref storage))
|
||||
return false;
|
||||
|
||||
if (storage.Open || storage.Contents.ContainedEntities.Count < 1)
|
||||
return false;
|
||||
|
||||
return Cremate(uid, component, storage);
|
||||
}
|
||||
|
||||
private void FinishCooking(EntityUid uid, CrematoriumComponent component, EntityStorageComponent? storage = null)
|
||||
{
|
||||
if (!Resolve(uid, ref storage))
|
||||
return;
|
||||
|
||||
_appearance.SetData(uid, CrematoriumVisuals.Burning, false);
|
||||
RemComp<ActiveCrematoriumComponent>(uid);
|
||||
|
||||
if (storage.Contents.ContainedEntities.Count > 0)
|
||||
{
|
||||
for (var i = storage.Contents.ContainedEntities.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var item = storage.Contents.ContainedEntities[i];
|
||||
_containers.Remove(item, storage.Contents);
|
||||
Del(item);
|
||||
}
|
||||
var ash = Spawn("Ash", Transform(uid).Coordinates);
|
||||
_containers.Insert(ash, storage.Contents);
|
||||
}
|
||||
|
||||
_entityStorage.OpenStorage(uid, storage);
|
||||
_audio.PlayPvs(component.CremateFinishSound, uid);
|
||||
}
|
||||
|
||||
private void OnSuicideByEnvironment(EntityUid uid, CrematoriumComponent component, SuicideByEnvironmentEvent args)
|
||||
private void OnSuicideByEnvironment(Entity<CrematoriumComponent> ent, ref SuicideByEnvironmentEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
var victim = args.Victim;
|
||||
if (TryComp(victim, out ActorComponent? actor) && _minds.TryGetMind(victim, out var mindId, out var mind))
|
||||
if (HasComp<ActorComponent>(victim) && Mind.TryGetMind(victim, out var mindId, out var mind))
|
||||
{
|
||||
_ghostSystem.OnGhostAttempt(mindId, false, mind: mind);
|
||||
|
||||
if (mind.OwnedEntity is { Valid: true } entity)
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("crematorium-entity-storage-component-suicide-message"), entity);
|
||||
Popup.PopupEntity(Loc.GetString("crematorium-entity-storage-component-suicide-message"), entity);
|
||||
}
|
||||
}
|
||||
|
||||
_popup.PopupEntity(Loc.GetString("crematorium-entity-storage-component-suicide-message-others",
|
||||
Popup.PopupEntity(Loc.GetString("crematorium-entity-storage-component-suicide-message-others",
|
||||
("victim", Identity.Entity(victim, EntityManager))),
|
||||
victim, Filter.PvsExcept(victim), true, PopupType.LargeCaution);
|
||||
victim,
|
||||
Filter.PvsExcept(victim),
|
||||
true,
|
||||
PopupType.LargeCaution);
|
||||
|
||||
if (_entityStorage.CanInsert(victim, uid))
|
||||
if (EntityStorage.CanInsert(victim, ent.Owner))
|
||||
{
|
||||
_entityStorage.CloseStorage(uid);
|
||||
_standing.Down(victim, false);
|
||||
_entityStorage.Insert(victim, uid);
|
||||
EntityStorage.CloseStorage(ent.Owner);
|
||||
Standing.Down(victim, false);
|
||||
EntityStorage.Insert(victim, ent.Owner);
|
||||
}
|
||||
else
|
||||
{
|
||||
EntityStorage.CloseStorage(ent.Owner);
|
||||
Del(victim);
|
||||
}
|
||||
_entityStorage.CloseStorage(uid);
|
||||
Cremate(uid, component);
|
||||
Cremate(ent.AsNullable());
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
var query = EntityQueryEnumerator<ActiveCrematoriumComponent, CrematoriumComponent>();
|
||||
while (query.MoveNext(out var uid, out var act, out var crem))
|
||||
{
|
||||
act.Accumulator += frameTime;
|
||||
|
||||
if (act.Accumulator >= crem.CookTime)
|
||||
FinishCooking(uid, crem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,75 +1,27 @@
|
||||
using Content.Server.Storage.Components;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Morgue;
|
||||
using Content.Shared.Morgue.Components;
|
||||
using Content.Shared.Storage.Components;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server.Morgue;
|
||||
|
||||
public sealed class MorgueSystem : EntitySystem
|
||||
public sealed class MorgueSystem : SharedMorgueSystem
|
||||
{
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<MorgueComponent, ExaminedEvent>(OnExamine);
|
||||
SubscribeLocalEvent<MorgueComponent, MapInitEvent>(OnMapInit);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the examination text for looking at a morgue.
|
||||
/// </summary>
|
||||
private void OnExamine(Entity<MorgueComponent> ent, ref ExaminedEvent args)
|
||||
private void OnMapInit(Entity<MorgueComponent> ent, ref MapInitEvent args)
|
||||
{
|
||||
if (!args.IsInDetailsRange)
|
||||
return;
|
||||
|
||||
_appearance.TryGetData<MorgueContents>(ent.Owner, MorgueVisuals.Contents, out var contents);
|
||||
|
||||
var text = contents switch
|
||||
{
|
||||
MorgueContents.HasSoul => "morgue-entity-storage-component-on-examine-details-body-has-soul",
|
||||
MorgueContents.HasContents => "morgue-entity-storage-component-on-examine-details-has-contents",
|
||||
MorgueContents.HasMob => "morgue-entity-storage-component-on-examine-details-body-has-no-soul",
|
||||
_ => "morgue-entity-storage-component-on-examine-details-empty"
|
||||
};
|
||||
|
||||
args.PushMarkup(Loc.GetString(text));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates data periodically in case something died/got deleted in the morgue.
|
||||
/// </summary>
|
||||
private void CheckContents(EntityUid uid, MorgueComponent? morgue = null, EntityStorageComponent? storage = null, AppearanceComponent? app = null)
|
||||
{
|
||||
if (!Resolve(uid, ref morgue, ref storage, ref app))
|
||||
return;
|
||||
|
||||
if (storage.Contents.ContainedEntities.Count == 0)
|
||||
{
|
||||
_appearance.SetData(uid, MorgueVisuals.Contents, MorgueContents.Empty);
|
||||
return;
|
||||
}
|
||||
|
||||
var hasMob = false;
|
||||
|
||||
foreach (var ent in storage.Contents.ContainedEntities)
|
||||
{
|
||||
if (!hasMob && HasComp<MobStateComponent>(ent))
|
||||
hasMob = true;
|
||||
|
||||
if (HasComp<ActorComponent>(ent))
|
||||
{
|
||||
_appearance.SetData(uid, MorgueVisuals.Contents, MorgueContents.HasSoul, app);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_appearance.SetData(uid, MorgueVisuals.Contents, hasMob ? MorgueContents.HasMob : MorgueContents.HasContents, app);
|
||||
ent.Comp.NextBeep = _timing.CurTime + ent.Comp.NextBeep;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -79,17 +31,16 @@ public sealed class MorgueSystem : EntitySystem
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
var curTime = _timing.CurTime;
|
||||
var query = EntityQueryEnumerator<MorgueComponent, EntityStorageComponent, AppearanceComponent>();
|
||||
while (query.MoveNext(out var uid, out var comp, out var storage, out var appearance))
|
||||
{
|
||||
comp.AccumulatedFrameTime += frameTime;
|
||||
|
||||
CheckContents(uid, comp, storage);
|
||||
|
||||
if (comp.AccumulatedFrameTime < comp.BeepTime)
|
||||
if (curTime < comp.NextBeep)
|
||||
continue;
|
||||
|
||||
comp.AccumulatedFrameTime -= comp.BeepTime;
|
||||
comp.NextBeep += comp.BeepTime;
|
||||
|
||||
CheckContents(uid, comp, storage);
|
||||
|
||||
if (comp.DoSoulBeep && _appearance.TryGetData<MorgueContents>(uid, MorgueVisuals.Contents, out var contents, appearance) && contents == MorgueContents.HasSoul)
|
||||
{
|
||||
|
||||
@@ -7,7 +7,6 @@ using Content.Server.NPC.Queries.Curves;
|
||||
using Content.Server.NPC.Queries.Queries;
|
||||
using Content.Server.Nutrition.Components;
|
||||
using Content.Server.Nutrition.EntitySystems;
|
||||
using Content.Server.Storage.Components;
|
||||
using Content.Server.Temperature.Components;
|
||||
using Content.Shared.Chemistry.EntitySystems;
|
||||
using Content.Shared.Damage;
|
||||
@@ -20,6 +19,7 @@ using Content.Shared.Mobs.Systems;
|
||||
using Content.Shared.NPC.Systems;
|
||||
using Content.Shared.Nutrition.Components;
|
||||
using Content.Shared.Nutrition.EntitySystems;
|
||||
using Content.Shared.Storage.Components;
|
||||
using Content.Shared.Stunnable;
|
||||
using Content.Shared.Tools.Systems;
|
||||
using Content.Shared.Turrets;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
using Content.Server.Popups;
|
||||
using Content.Server.Storage.Components;
|
||||
using Content.Server.Storage.EntitySystems;
|
||||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.Lock;
|
||||
using Content.Shared.Movement.Events;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Resist;
|
||||
using Content.Shared.Storage.Components;
|
||||
using Content.Shared.Tools.Components;
|
||||
using Content.Shared.Tools.Systems;
|
||||
using Content.Shared.ActionBlocker;
|
||||
|
||||
@@ -3,7 +3,7 @@ using Content.Shared.Damage;
|
||||
using Content.Shared.Revenant;
|
||||
using Robust.Shared.Random;
|
||||
using Content.Shared.Tag;
|
||||
using Content.Server.Storage.Components;
|
||||
using Content.Shared.Storage.Components;
|
||||
using Content.Server.Light.Components;
|
||||
using Content.Server.Ghost;
|
||||
using Robust.Shared.Physics;
|
||||
|
||||
@@ -4,6 +4,7 @@ using Content.Server.Storage.Components;
|
||||
using Content.Server.Storage.EntitySystems;
|
||||
using Content.Shared.Access.Components;
|
||||
using Content.Shared.Station.Components;
|
||||
using Content.Shared.Storage.Components;
|
||||
using Content.Shared.GameTicking.Components;
|
||||
|
||||
namespace Content.Server.StationEvents.Events;
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
using Content.Server.GameTicking.Rules.Components;
|
||||
using Content.Server.StationEvents.Components;
|
||||
using Content.Server.Storage.Components;
|
||||
using Content.Server.Storage.EntitySystems;
|
||||
using Content.Shared.GameTicking.Components;
|
||||
using Content.Shared.Storage.Components;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
using Content.Server.Atmos;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Storage.Components;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Server.Storage.Components;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class EntityStorageComponent : SharedEntityStorageComponent, IGasMixtureHolder
|
||||
{
|
||||
/// <summary>
|
||||
/// Gas currently contained in this entity storage.
|
||||
/// None while open. Grabs gas from the atmosphere when closed, and exposes any entities inside to it.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("air")]
|
||||
public GasMixture Air { get; set; } = new (200);
|
||||
}
|
||||
@@ -68,7 +68,7 @@ public sealed class EntityStorageSystem : SharedEntityStorageSystem
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnComponentInit(EntityUid uid, SharedEntityStorageComponent component, ComponentInit args)
|
||||
protected override void OnComponentInit(EntityUid uid, EntityStorageComponent component, ComponentInit args)
|
||||
{
|
||||
base.OnComponentInit(uid, component, args);
|
||||
|
||||
@@ -76,7 +76,7 @@ public sealed class EntityStorageSystem : SharedEntityStorageSystem
|
||||
_construction.AddContainer(uid, ContainerName, construction);
|
||||
}
|
||||
|
||||
public override bool ResolveStorage(EntityUid uid, [NotNullWhen(true)] ref SharedEntityStorageComponent? component)
|
||||
public override bool ResolveStorage(EntityUid uid, [NotNullWhen(true)] ref EntityStorageComponent? component)
|
||||
{
|
||||
if (component != null)
|
||||
return true;
|
||||
@@ -107,7 +107,7 @@ public sealed class EntityStorageSystem : SharedEntityStorageSystem
|
||||
args.Contents.AddRange(ent.Comp.Contents.ContainedEntities);
|
||||
}
|
||||
|
||||
protected override void TakeGas(EntityUid uid, SharedEntityStorageComponent component)
|
||||
protected override void TakeGas(EntityUid uid, EntityStorageComponent component)
|
||||
{
|
||||
if (!component.Airtight)
|
||||
return;
|
||||
@@ -121,7 +121,7 @@ public sealed class EntityStorageSystem : SharedEntityStorageSystem
|
||||
}
|
||||
}
|
||||
|
||||
public override void ReleaseGas(EntityUid uid, SharedEntityStorageComponent component)
|
||||
public override void ReleaseGas(EntityUid uid, EntityStorageComponent component)
|
||||
{
|
||||
var serverComp = (EntityStorageComponent) component;
|
||||
|
||||
|
||||
@@ -2,10 +2,10 @@ using Content.Server.Body.Systems;
|
||||
using Content.Server.Popups;
|
||||
using Content.Server.Power.EntitySystems;
|
||||
using Content.Server.Stack;
|
||||
using Content.Server.Storage.Components;
|
||||
using Content.Shared.Body.Components;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Power;
|
||||
using Content.Shared.Storage.Components;
|
||||
using Content.Shared.Verbs;
|
||||
using Content.Shared.Whitelist;
|
||||
using Content.Shared.Xenoarchaeology.Equipment;
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Morgue.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Used to track actively cooking crematoriums.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class ActiveCrematoriumComponent : Component;
|
||||
42
Content.Shared/Morgue/Components/CrematoriumComponent.cs
Normal file
42
Content.Shared/Morgue/Components/CrematoriumComponent.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||
|
||||
namespace Content.Shared.Morgue.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Allows an entity storage to dispose bodies by turning them into ash.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
[AutoGenerateComponentState, AutoGenerateComponentPause]
|
||||
public sealed partial class CrematoriumComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The entity to spawn when something was burned.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public EntProtoId LeftOverProtoId = "Ash";
|
||||
|
||||
/// <summary>
|
||||
/// The time it takes to cremate something.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public TimeSpan CookTime = TimeSpan.FromSeconds(5);
|
||||
|
||||
/// <summary>
|
||||
/// The timestamp at which cremating is finished.
|
||||
/// </summary>
|
||||
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
|
||||
[AutoNetworkedField, AutoPausedField]
|
||||
public TimeSpan ActiveUntil = TimeSpan.Zero;
|
||||
|
||||
[DataField]
|
||||
public SoundSpecifier CremateStartSound = new SoundPathSpecifier("/Audio/Items/Lighters/lighter1.ogg");
|
||||
|
||||
[DataField]
|
||||
public SoundSpecifier CrematingSound = new SoundPathSpecifier("/Audio/Effects/burning.ogg");
|
||||
|
||||
[DataField]
|
||||
public SoundSpecifier CremateFinishSound = new SoundPathSpecifier("/Audio/Machines/ding.ogg");
|
||||
}
|
||||
@@ -1,6 +1,10 @@
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Morgue.Components;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class EntityStorageLayingDownOverrideComponent : Component
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// Makes an entity storage only accept entities that are laying down.
|
||||
/// This is true for mobs that are crit, dead or crawling.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class EntityStorageLayingDownOverrideComponent : Component;
|
||||
|
||||
@@ -1,26 +1,38 @@
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||
|
||||
namespace Content.Shared.Morgue.Components;
|
||||
|
||||
/// <summary>
|
||||
/// When added to an entity storage this component will keep track of the mind status of the player inside.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
[AutoGenerateComponentState, AutoGenerateComponentPause]
|
||||
public sealed partial class MorgueComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether or not the morgue beeps if a living player is inside.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
[DataField, AutoNetworkedField]
|
||||
public bool DoSoulBeep = true;
|
||||
|
||||
[DataField]
|
||||
public float AccumulatedFrameTime = 0f;
|
||||
/// <summary>
|
||||
/// The timestamp for the next beep.
|
||||
/// </summary>
|
||||
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
|
||||
[AutoPausedField]
|
||||
public TimeSpan NextBeep = TimeSpan.Zero;
|
||||
|
||||
/// <summary>
|
||||
/// The amount of time between each beep.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float BeepTime = 10f;
|
||||
public TimeSpan BeepTime = TimeSpan.FromSeconds(10);
|
||||
|
||||
/// <summary>
|
||||
/// The beep sound to play.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public SoundSpecifier OccupantHasSoulAlarmSound = new SoundPathSpecifier("/Audio/Weapons/Guns/EmptyAlarm/smg_empty_alarm.ogg");
|
||||
}
|
||||
|
||||
170
Content.Shared/Morgue/SharedCrematoriumSystem.cs
Normal file
170
Content.Shared/Morgue/SharedCrematoriumSystem.cs
Normal file
@@ -0,0 +1,170 @@
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Morgue.Components;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Standing;
|
||||
using Content.Shared.Storage;
|
||||
using Content.Shared.Storage.Components;
|
||||
using Content.Shared.Storage.EntitySystems;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Shared.Morgue;
|
||||
|
||||
public abstract class SharedCrematoriumSystem : EntitySystem
|
||||
{
|
||||
[Dependency] protected readonly SharedEntityStorageSystem EntityStorage = default!;
|
||||
[Dependency] protected readonly SharedPopupSystem Popup = default!;
|
||||
[Dependency] protected readonly StandingStateSystem Standing = default!;
|
||||
[Dependency] protected readonly SharedMindSystem Mind = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly INetManager _net = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
[Dependency] private readonly SharedContainerSystem _container = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<CrematoriumComponent, ExaminedEvent>(OnExamine);
|
||||
SubscribeLocalEvent<CrematoriumComponent, GetVerbsEvent<AlternativeVerb>>(AddCremateVerb);
|
||||
SubscribeLocalEvent<ActiveCrematoriumComponent, StorageOpenAttemptEvent>(OnAttemptOpen);
|
||||
}
|
||||
|
||||
private void OnExamine(Entity<CrematoriumComponent> ent, ref ExaminedEvent args)
|
||||
{
|
||||
if (!TryComp<AppearanceComponent>(ent, out var appearance))
|
||||
return;
|
||||
|
||||
using (args.PushGroup(nameof(CrematoriumComponent)))
|
||||
{
|
||||
if (_appearance.TryGetData<bool>(ent.Owner, CrematoriumVisuals.Burning, out var isBurning, appearance) &&
|
||||
isBurning)
|
||||
{
|
||||
args.PushMarkup(Loc.GetString("crematorium-entity-storage-component-on-examine-details-is-burning",
|
||||
("owner", ent.Owner)));
|
||||
}
|
||||
|
||||
if (_appearance.TryGetData<bool>(ent.Owner, StorageVisuals.HasContents, out var hasContents, appearance) &&
|
||||
hasContents)
|
||||
{
|
||||
args.PushMarkup(Loc.GetString("crematorium-entity-storage-component-on-examine-details-has-contents"));
|
||||
}
|
||||
else
|
||||
{
|
||||
args.PushMarkup(Loc.GetString("crematorium-entity-storage-component-on-examine-details-empty"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAttemptOpen(Entity<ActiveCrematoriumComponent> ent, ref StorageOpenAttemptEvent args)
|
||||
{
|
||||
args.Cancelled = true;
|
||||
}
|
||||
|
||||
private void AddCremateVerb(EntityUid uid, CrematoriumComponent component, GetVerbsEvent<AlternativeVerb> args)
|
||||
{
|
||||
if (!TryComp<EntityStorageComponent>(uid, out var storage))
|
||||
return;
|
||||
|
||||
if (!args.CanAccess || !args.CanInteract || args.Hands == null || storage.Open)
|
||||
return;
|
||||
|
||||
if (HasComp<ActiveCrematoriumComponent>(uid))
|
||||
return;
|
||||
|
||||
AlternativeVerb verb = new()
|
||||
{
|
||||
Text = Loc.GetString("cremate-verb-get-data-text"),
|
||||
// TODO VERB ICON add flame/burn symbol?
|
||||
Act = () => TryCremate((uid, component, storage), args.User),
|
||||
Impact = LogImpact.High // could be a body? or evidence? I dunno.
|
||||
};
|
||||
args.Verbs.Add(verb);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start the cremation.
|
||||
/// </summary>
|
||||
public bool Cremate(Entity<CrematoriumComponent?> ent, EntityUid? user = null)
|
||||
{
|
||||
if (!Resolve(ent, ref ent.Comp))
|
||||
return false;
|
||||
|
||||
if (HasComp<ActiveCrematoriumComponent>(ent))
|
||||
return false;
|
||||
|
||||
_audio.PlayPredicted(ent.Comp.CremateStartSound, ent.Owner, user);
|
||||
_audio.PlayPredicted(ent.Comp.CrematingSound, ent.Owner, user);
|
||||
_appearance.SetData(ent.Owner, CrematoriumVisuals.Burning, true);
|
||||
|
||||
AddComp<ActiveCrematoriumComponent>(ent);
|
||||
ent.Comp.ActiveUntil = _timing.CurTime + ent.Comp.CookTime;
|
||||
Dirty(ent);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to start to start the cremation.
|
||||
/// Only works when the crematorium is closed and there are entities inside.
|
||||
/// </summary>
|
||||
public bool TryCremate(Entity<CrematoriumComponent?, EntityStorageComponent?> ent, EntityUid? user = null)
|
||||
{
|
||||
if (!Resolve(ent, ref ent.Comp1, ref ent.Comp2))
|
||||
return false;
|
||||
|
||||
if (ent.Comp2.Open || ent.Comp2.Contents.ContainedEntities.Count < 1)
|
||||
return false;
|
||||
|
||||
return Cremate((ent.Owner, ent.Comp1), user);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finish the cremation process.
|
||||
/// This will delete the entities inside and spawn ash.
|
||||
/// </summary>
|
||||
private void FinishCooking(Entity<CrematoriumComponent?, EntityStorageComponent?> ent)
|
||||
{
|
||||
if (!Resolve(ent, ref ent.Comp1, ref ent.Comp2))
|
||||
return;
|
||||
|
||||
_appearance.SetData(ent.Owner, CrematoriumVisuals.Burning, false);
|
||||
RemComp<ActiveCrematoriumComponent>(ent);
|
||||
|
||||
if (ent.Comp2.Contents.ContainedEntities.Count > 0)
|
||||
{
|
||||
for (var i = ent.Comp2.Contents.ContainedEntities.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var item = ent.Comp2.Contents.ContainedEntities[i];
|
||||
_container.Remove(item, ent.Comp2.Contents);
|
||||
PredictedDel(item);
|
||||
}
|
||||
PredictedTrySpawnInContainer(ent.Comp1.LeftOverProtoId, ent.Owner, ent.Comp2.Contents.ID, out _);
|
||||
}
|
||||
|
||||
EntityStorage.OpenStorage(ent.Owner, ent.Comp2);
|
||||
|
||||
if (_net.IsServer) // can't predict without the user
|
||||
_audio.PlayPvs(ent.Comp1.CremateFinishSound, ent.Owner);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
var curTime = _timing.CurTime;
|
||||
var query = EntityQueryEnumerator<ActiveCrematoriumComponent, CrematoriumComponent>();
|
||||
while (query.MoveNext(out var uid, out _, out var crematorium))
|
||||
{
|
||||
if (curTime < crematorium.ActiveUntil)
|
||||
continue;
|
||||
|
||||
FinishCooking((uid, crematorium, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
83
Content.Shared/Morgue/SharedMorgueSystem.cs
Normal file
83
Content.Shared/Morgue/SharedMorgueSystem.cs
Normal file
@@ -0,0 +1,83 @@
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Storage.Components;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Morgue.Components;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Shared.Morgue;
|
||||
|
||||
public abstract class SharedMorgueSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<MorgueComponent, ExaminedEvent>(OnExamine);
|
||||
SubscribeLocalEvent<MorgueComponent, StorageAfterCloseEvent>(OnClosed);
|
||||
SubscribeLocalEvent<MorgueComponent, StorageAfterOpenEvent>(OnOpened);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the examination text for looking at a morgue.
|
||||
/// </summary>
|
||||
private void OnExamine(Entity<MorgueComponent> ent, ref ExaminedEvent args)
|
||||
{
|
||||
if (!args.IsInDetailsRange)
|
||||
return;
|
||||
|
||||
_appearance.TryGetData<MorgueContents>(ent.Owner, MorgueVisuals.Contents, out var contents);
|
||||
|
||||
var text = contents switch
|
||||
{
|
||||
MorgueContents.HasSoul => "morgue-entity-storage-component-on-examine-details-body-has-soul",
|
||||
MorgueContents.HasContents => "morgue-entity-storage-component-on-examine-details-has-contents",
|
||||
MorgueContents.HasMob => "morgue-entity-storage-component-on-examine-details-body-has-no-soul",
|
||||
_ => "morgue-entity-storage-component-on-examine-details-empty"
|
||||
};
|
||||
|
||||
args.PushMarkup(Loc.GetString(text));
|
||||
}
|
||||
|
||||
private void OnClosed(Entity<MorgueComponent> ent, ref StorageAfterCloseEvent args)
|
||||
{
|
||||
CheckContents(ent.Owner, ent.Comp);
|
||||
}
|
||||
|
||||
private void OnOpened(Entity<MorgueComponent> ent, ref StorageAfterOpenEvent args)
|
||||
{
|
||||
CheckContents(ent.Owner, ent.Comp);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates data in case something died/got deleted in the morgue.
|
||||
/// </summary>
|
||||
public void CheckContents(EntityUid uid, MorgueComponent? morgue = null, EntityStorageComponent? storage = null, AppearanceComponent? app = null)
|
||||
{
|
||||
if (!Resolve(uid, ref morgue, ref storage, ref app))
|
||||
return;
|
||||
|
||||
if (storage.Contents.ContainedEntities.Count == 0)
|
||||
{
|
||||
_appearance.SetData(uid, MorgueVisuals.Contents, MorgueContents.Empty, app);
|
||||
return;
|
||||
}
|
||||
|
||||
var hasMob = false;
|
||||
|
||||
foreach (var ent in storage.Contents.ContainedEntities)
|
||||
{
|
||||
if (!hasMob && HasComp<MobStateComponent>(ent))
|
||||
hasMob = true;
|
||||
|
||||
if (HasComp<ActorComponent>(ent))
|
||||
{
|
||||
_appearance.SetData(uid, MorgueVisuals.Contents, MorgueContents.HasSoul, app);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_appearance.SetData(uid, MorgueVisuals.Contents, hasMob ? MorgueContents.HasMob : MorgueContents.HasContents, app);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Numerics;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Physics;
|
||||
using Content.Shared.Whitelist;
|
||||
using Robust.Shared.Audio;
|
||||
@@ -8,8 +9,8 @@ using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Storage.Components;
|
||||
|
||||
[NetworkedComponent]
|
||||
public abstract partial class SharedEntityStorageComponent : Component
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class EntityStorageComponent : Component, IGasMixtureHolder
|
||||
{
|
||||
public readonly float MaxSize = 1.0f; // maximum width or height of an entity allowed inside the storage.
|
||||
|
||||
@@ -33,13 +34,13 @@ public abstract partial class SharedEntityStorageComponent : Component
|
||||
/// <summary>
|
||||
/// The total amount of items that can fit in one entitystorage
|
||||
/// </summary>
|
||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField]
|
||||
public int Capacity = 30;
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not the entity still has collision when open
|
||||
/// </summary>
|
||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField]
|
||||
public bool IsCollidableWhenOpen;
|
||||
|
||||
/// <summary>
|
||||
@@ -47,45 +48,45 @@ public abstract partial class SharedEntityStorageComponent : Component
|
||||
/// If false, it prevents the storage from opening when the entity inside of it moves.
|
||||
/// This is for objects that you want the player to move while inside, like large cardboard boxes, without opening the storage.
|
||||
/// </summary>
|
||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField]
|
||||
public bool OpenOnMove = true;
|
||||
|
||||
//The offset for where items are emptied/vacuumed for the EntityStorage.
|
||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField]
|
||||
public Vector2 EnteringOffset = new(0, 0);
|
||||
|
||||
//The collision groups checked, so that items are depositied or grabbed from inside walls.
|
||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField]
|
||||
public CollisionGroup EnteringOffsetCollisionFlags = CollisionGroup.Impassable | CollisionGroup.MidImpassable;
|
||||
|
||||
/// <summary>
|
||||
/// How close you have to be to the "entering" spot to be able to enter
|
||||
/// </summary>
|
||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField]
|
||||
public float EnteringRange = 0.18f;
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not to show the contents when the storage is closed
|
||||
/// </summary>
|
||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField]
|
||||
public bool ShowContents;
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not light is occluded by the storage
|
||||
/// </summary>
|
||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField]
|
||||
public bool OccludesLight = true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not all the contents stored should be deleted with the entitystorage
|
||||
/// </summary>
|
||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField]
|
||||
public bool DeleteContentsOnDestruction;
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not the container is sealed and traps air inside of it
|
||||
/// </summary>
|
||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField]
|
||||
public bool Airtight = true;
|
||||
|
||||
/// <summary>
|
||||
@@ -118,6 +119,13 @@ public abstract partial class SharedEntityStorageComponent : Component
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public Container Contents = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Gas currently contained in this entity storage.
|
||||
/// None while open. Grabs gas from the atmosphere when closed, and exposes any entities inside to it.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public GasMixture Air { get; set; } = new(200);
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
@@ -48,12 +48,12 @@ public abstract class SharedEntityStorageSystem : EntitySystem
|
||||
|
||||
public const string ContainerName = "entity_storage";
|
||||
|
||||
protected void OnEntityUnpausedEvent(EntityUid uid, SharedEntityStorageComponent component, EntityUnpausedEvent args)
|
||||
protected void OnEntityUnpausedEvent(EntityUid uid, EntityStorageComponent component, EntityUnpausedEvent args)
|
||||
{
|
||||
component.NextInternalOpenAttempt += args.PausedTime;
|
||||
}
|
||||
|
||||
protected void OnGetState(EntityUid uid, SharedEntityStorageComponent component, ref ComponentGetState args)
|
||||
protected void OnGetState(EntityUid uid, EntityStorageComponent component, ref ComponentGetState args)
|
||||
{
|
||||
args.State = new EntityStorageComponentState(component.Open,
|
||||
component.Capacity,
|
||||
@@ -63,7 +63,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem
|
||||
component.NextInternalOpenAttempt);
|
||||
}
|
||||
|
||||
protected void OnHandleState(EntityUid uid, SharedEntityStorageComponent component, ref ComponentHandleState args)
|
||||
protected void OnHandleState(EntityUid uid, EntityStorageComponent component, ref ComponentHandleState args)
|
||||
{
|
||||
if (args.Current is not EntityStorageComponentState state)
|
||||
return;
|
||||
@@ -75,19 +75,19 @@ public abstract class SharedEntityStorageSystem : EntitySystem
|
||||
component.NextInternalOpenAttempt = state.NextInternalOpenAttempt;
|
||||
}
|
||||
|
||||
protected virtual void OnComponentInit(EntityUid uid, SharedEntityStorageComponent component, ComponentInit args)
|
||||
protected virtual void OnComponentInit(EntityUid uid, EntityStorageComponent component, ComponentInit args)
|
||||
{
|
||||
component.Contents = _container.EnsureContainer<Container>(uid, ContainerName);
|
||||
component.Contents.ShowContents = component.ShowContents;
|
||||
component.Contents.OccludesLight = component.OccludesLight;
|
||||
}
|
||||
|
||||
protected virtual void OnComponentStartup(EntityUid uid, SharedEntityStorageComponent component, ComponentStartup args)
|
||||
protected virtual void OnComponentStartup(EntityUid uid, EntityStorageComponent component, ComponentStartup args)
|
||||
{
|
||||
_appearance.SetData(uid, StorageVisuals.Open, component.Open);
|
||||
}
|
||||
|
||||
protected void OnInteract(EntityUid uid, SharedEntityStorageComponent component, ActivateInWorldEvent args)
|
||||
protected void OnInteract(EntityUid uid, EntityStorageComponent component, ActivateInWorldEvent args)
|
||||
{
|
||||
if (args.Handled || !args.Complex)
|
||||
return;
|
||||
@@ -96,9 +96,9 @@ public abstract class SharedEntityStorageSystem : EntitySystem
|
||||
ToggleOpen(args.User, uid, component);
|
||||
}
|
||||
|
||||
public abstract bool ResolveStorage(EntityUid uid, [NotNullWhen(true)] ref SharedEntityStorageComponent? component);
|
||||
public abstract bool ResolveStorage(EntityUid uid, [NotNullWhen(true)] ref EntityStorageComponent? component);
|
||||
|
||||
protected void OnLockToggleAttempt(EntityUid uid, SharedEntityStorageComponent target, ref LockToggleAttemptEvent args)
|
||||
protected void OnLockToggleAttempt(EntityUid uid, EntityStorageComponent target, ref LockToggleAttemptEvent args)
|
||||
{
|
||||
// Cannot (un)lock open lockers.
|
||||
if (target.Open)
|
||||
@@ -109,7 +109,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem
|
||||
args.Cancelled = true;
|
||||
}
|
||||
|
||||
protected void OnDestruction(EntityUid uid, SharedEntityStorageComponent component, DestructionEventArgs args)
|
||||
protected void OnDestruction(EntityUid uid, EntityStorageComponent component, DestructionEventArgs args)
|
||||
{
|
||||
component.Open = true;
|
||||
Dirty(uid, component);
|
||||
@@ -125,7 +125,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem
|
||||
}
|
||||
}
|
||||
|
||||
protected void OnRelayMovement(EntityUid uid, SharedEntityStorageComponent component, ref ContainerRelayMovementEntityEvent args)
|
||||
protected void OnRelayMovement(EntityUid uid, EntityStorageComponent component, ref ContainerRelayMovementEntityEvent args)
|
||||
{
|
||||
if (!HasComp<HandsComponent>(args.Entity))
|
||||
return;
|
||||
@@ -136,21 +136,21 @@ public abstract class SharedEntityStorageSystem : EntitySystem
|
||||
if (_timing.CurTime < component.NextInternalOpenAttempt)
|
||||
return;
|
||||
|
||||
component.NextInternalOpenAttempt = _timing.CurTime + SharedEntityStorageComponent.InternalOpenAttemptDelay;
|
||||
component.NextInternalOpenAttempt = _timing.CurTime + EntityStorageComponent.InternalOpenAttemptDelay;
|
||||
Dirty(uid, component);
|
||||
|
||||
if (component.OpenOnMove)
|
||||
TryOpenStorage(args.Entity, uid);
|
||||
}
|
||||
|
||||
protected void OnFoldAttempt(EntityUid uid, SharedEntityStorageComponent component, ref FoldAttemptEvent args)
|
||||
protected void OnFoldAttempt(EntityUid uid, EntityStorageComponent component, ref FoldAttemptEvent args)
|
||||
{
|
||||
if (args.Cancelled)
|
||||
return;
|
||||
args.Cancelled = component.Open || component.Contents.ContainedEntities.Count != 0;
|
||||
}
|
||||
|
||||
protected void AddToggleOpenVerb(EntityUid uid, SharedEntityStorageComponent component, GetVerbsEvent<InteractionVerb> args)
|
||||
protected void AddToggleOpenVerb(EntityUid uid, EntityStorageComponent component, GetVerbsEvent<InteractionVerb> args)
|
||||
{
|
||||
if (!args.CanAccess || !args.CanInteract)
|
||||
return;
|
||||
@@ -175,7 +175,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem
|
||||
}
|
||||
|
||||
|
||||
public void ToggleOpen(EntityUid user, EntityUid target, SharedEntityStorageComponent? component = null)
|
||||
public void ToggleOpen(EntityUid user, EntityUid target, EntityStorageComponent? component = null)
|
||||
{
|
||||
if (!ResolveStorage(target, ref component))
|
||||
return;
|
||||
@@ -190,7 +190,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem
|
||||
}
|
||||
}
|
||||
|
||||
public void EmptyContents(EntityUid uid, SharedEntityStorageComponent? component = null)
|
||||
public void EmptyContents(EntityUid uid, EntityStorageComponent? component = null)
|
||||
{
|
||||
if (!ResolveStorage(uid, ref component))
|
||||
return;
|
||||
@@ -203,7 +203,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem
|
||||
}
|
||||
}
|
||||
|
||||
public void OpenStorage(EntityUid uid, SharedEntityStorageComponent? component = null)
|
||||
public void OpenStorage(EntityUid uid, EntityStorageComponent? component = null)
|
||||
{
|
||||
if (!ResolveStorage(uid, ref component))
|
||||
return;
|
||||
@@ -224,7 +224,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem
|
||||
RaiseLocalEvent(uid, ref afterev);
|
||||
}
|
||||
|
||||
public void CloseStorage(EntityUid uid, SharedEntityStorageComponent? component = null)
|
||||
public void CloseStorage(EntityUid uid, EntityStorageComponent? component = null)
|
||||
{
|
||||
if (!ResolveStorage(uid, ref component))
|
||||
return;
|
||||
@@ -275,7 +275,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem
|
||||
RaiseLocalEvent(uid, ref afterev);
|
||||
}
|
||||
|
||||
public bool Insert(EntityUid toInsert, EntityUid container, SharedEntityStorageComponent? component = null)
|
||||
public bool Insert(EntityUid toInsert, EntityUid container, EntityStorageComponent? component = null)
|
||||
{
|
||||
if (!ResolveStorage(container, ref component))
|
||||
return false;
|
||||
@@ -295,7 +295,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Remove(EntityUid toRemove, EntityUid container, SharedEntityStorageComponent? component = null, TransformComponent? xform = null)
|
||||
public bool Remove(EntityUid toRemove, EntityUid container, EntityStorageComponent? component = null, TransformComponent? xform = null)
|
||||
{
|
||||
if (!Resolve(container, ref xform, false))
|
||||
return false;
|
||||
@@ -322,7 +322,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool CanInsert(EntityUid toInsert, EntityUid container, SharedEntityStorageComponent? component = null)
|
||||
public bool CanInsert(EntityUid toInsert, EntityUid container, EntityStorageComponent? component = null)
|
||||
{
|
||||
if (!ResolveStorage(container, ref component))
|
||||
return false;
|
||||
@@ -379,7 +379,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool IsOpen(EntityUid target, SharedEntityStorageComponent? component = null)
|
||||
public bool IsOpen(EntityUid target, EntityStorageComponent? component = null)
|
||||
{
|
||||
if (!ResolveStorage(target, ref component))
|
||||
return false;
|
||||
@@ -387,7 +387,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem
|
||||
return component.Open;
|
||||
}
|
||||
|
||||
public bool CanOpen(EntityUid user, EntityUid target, bool silent = false, SharedEntityStorageComponent? component = null)
|
||||
public bool CanOpen(EntityUid user, EntityUid target, bool silent = false, EntityStorageComponent? component = null)
|
||||
{
|
||||
if (!ResolveStorage(target, ref component))
|
||||
return false;
|
||||
@@ -429,7 +429,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem
|
||||
return !ev.Cancelled;
|
||||
}
|
||||
|
||||
public bool AddToContents(EntityUid toAdd, EntityUid container, SharedEntityStorageComponent? component = null)
|
||||
public bool AddToContents(EntityUid toAdd, EntityUid container, EntityStorageComponent? component = null)
|
||||
{
|
||||
if (!ResolveStorage(container, ref component))
|
||||
return false;
|
||||
@@ -440,7 +440,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem
|
||||
return Insert(toAdd, container, component);
|
||||
}
|
||||
|
||||
private void ModifyComponents(EntityUid uid, SharedEntityStorageComponent? component = null)
|
||||
private void ModifyComponents(EntityUid uid, EntityStorageComponent? component = null)
|
||||
{
|
||||
if (!ResolveStorage(uid, ref component))
|
||||
return;
|
||||
@@ -472,12 +472,12 @@ public abstract class SharedEntityStorageSystem : EntitySystem
|
||||
_appearance.SetData(uid, StorageVisuals.HasContents, component.Contents.ContainedEntities.Count > 0);
|
||||
}
|
||||
|
||||
protected virtual void TakeGas(EntityUid uid, SharedEntityStorageComponent component)
|
||||
protected virtual void TakeGas(EntityUid uid, EntityStorageComponent component)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public virtual void ReleaseGas(EntityUid uid, SharedEntityStorageComponent component)
|
||||
public virtual void ReleaseGas(EntityUid uid, EntityStorageComponent component)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user