add bluespace shelter capsules (#2566)

* move mining_voucher.yml into Salvage folder

* add ShelterCapsuleComponent and system

* add shelter capsules

* add capsules to vendor and voucher

* :trollface:

* add admin logging and delete lava

* mv wire

* changes for namespace refactor

* remove dupe voucher

* add smoke when deploying

---------

Co-authored-by: deltanedas <@deltanedas:kde.org>
This commit is contained in:
deltanedas
2025-03-08 23:22:02 +00:00
committed by tommy
parent 653bc57aef
commit 41d0338fcc
10 changed files with 2328 additions and 3 deletions

View File

@@ -0,0 +1,39 @@
using Content.Shared._DV.Salvage.Systems;
using Content.Shared.Procedural;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
namespace Content.Shared._DV.Salvage.Components;
/// <summary>
/// Spawns a dungeon room after a delay when used and deletes itself.
/// </summary>
[RegisterComponent, NetworkedComponent, Access(typeof(SharedShelterCapsuleSystem))]
[AutoGenerateComponentPause]
public sealed partial class ShelterCapsuleComponent : Component
{
/// <summary>
/// The room to spawn.
/// </summary>
[DataField(required: true)]
public ProtoId<DungeonRoomPrototype> Room;
/// <summary>
/// How long to wait between using and spawning the room.
/// </summary>
[DataField]
public TimeSpan Delay = TimeSpan.FromSeconds(5);
/// <summary>
/// When to next spawn the room, also used to ignore activating multiple times.
/// </summary>
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoPausedField]
public TimeSpan? NextSpawn;
/// <summary>
/// The user of the capsule, used for logging.
/// </summary>
[DataField]
public EntityUid? User;
}

View File

@@ -0,0 +1,66 @@
using Content.Shared._DV.Salvage.Components;
using Content.Shared.Interaction.Events;
using Content.Shared.Popups;
using Robust.Shared.Timing;
namespace Content.Shared._DV.Salvage.Systems;
/// <summary>
/// Handles interaction for shelter capsules.
/// Room spawning is done serverside.
/// </summary>
public abstract class SharedShelterCapsuleSystem : EntitySystem
{
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<ShelterCapsuleComponent, UseInHandEvent>(OnUse);
}
public override void Update(float frameTime)
{
base.Update(frameTime);
var now = _timing.CurTime;
var query = EntityQueryEnumerator<ShelterCapsuleComponent>();
while (query.MoveNext(out var uid, out var comp))
{
if (comp.NextSpawn is not {} nextSpawn || now < nextSpawn)
continue;
comp.User = null;
comp.NextSpawn = null;
if (TrySpawnRoom((uid, comp)) is {} id)
{
var msg = Loc.GetString(id, ("capsule", uid));
_popup.PopupEntity(msg, uid, PopupType.LargeCaution);
}
}
}
/// <summary>
/// Spawn the room, returning a locale string for an error. It gets "capsule" passed.
/// </summary>
protected virtual LocId? TrySpawnRoom(Entity<ShelterCapsuleComponent> ent)
{
return null;
}
private void OnUse(Entity<ShelterCapsuleComponent> ent, ref UseInHandEvent args)
{
if (args.Handled || ent.Comp.NextSpawn != null)
return;
args.Handled = true;
var msg = Loc.GetString("shelter-capsule-warning", ("capsule", ent));
_popup.PopupPredicted(msg, ent, args.User, PopupType.LargeCaution);
ent.Comp.User = args.User;
ent.Comp.NextSpawn = _timing.CurTime + ent.Comp.Delay;
}
}