Priority Deliveries (#36968)

This commit is contained in:
ScarKy0
2025-04-27 11:13:52 +02:00
committed by GitHub
parent 497f43ec65
commit 2a5cf10aa6
9 changed files with 230 additions and 13 deletions

View File

@@ -0,0 +1,19 @@
using Content.Shared.EntityTable.EntitySelectors;
using Robust.Shared.GameStates;
namespace Content.Shared.ComponentTable;
/// <summary>
/// Applies components from entities selected from the table on init.
/// </summary>
[RegisterComponent, NetworkedComponent]
[Access(typeof(SharedComponentTableSystem))]
public sealed partial class ComponentTableComponent : Component
{
/// <summary>
/// The table from which to grab entities.
/// ALL components of the grabbed entities will be added to the holder of this component.
/// </summary>
[DataField(required: true)]
public EntityTableSelector Table = default!;
}

View File

@@ -0,0 +1,33 @@
using Content.Shared.EntityTable;
using Robust.Shared.Prototypes;
namespace Content.Shared.ComponentTable;
/// <summary>
/// Applies an entity prototype to an entity on map init. Taken from entities inside an EntityTableSelector.
/// </summary>
public sealed class SharedComponentTableSystem : EntitySystem
{
[Dependency] private readonly EntityTableSystem _entTable = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<ComponentTableComponent, MapInitEvent>(OnTableInit);
}
private void OnTableInit(Entity<ComponentTableComponent> ent, ref MapInitEvent args)
{
var spawns = _entTable.GetSpawns(ent.Comp.Table);
foreach (var entity in spawns)
{
if (_proto.TryIndex(entity, out var entProto))
{
EntityManager.AddComponents(ent, entProto.Components);
}
}
}
}

View File

@@ -1,4 +1,9 @@
using Content.Shared.Examine;
using Content.Shared.GameTicking;
using Content.Shared.NameModifier.EntitySystems;
using Robust.Shared.Random;
using Robust.Shared.Serialization;
using Robust.Shared.Timing;
namespace Content.Shared.Delivery;
@@ -8,6 +13,9 @@ namespace Content.Shared.Delivery;
public sealed partial class DeliveryModifierSystem : EntitySystem
{
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly NameModifierSystem _nameModifier = default!;
[Dependency] private readonly SharedDeliverySystem _delivery = default!;
public override void Initialize()
{
@@ -15,8 +23,13 @@ public sealed partial class DeliveryModifierSystem : EntitySystem
SubscribeLocalEvent<DeliveryRandomMultiplierComponent, MapInitEvent>(OnRandomMultiplierMapInit);
SubscribeLocalEvent<DeliveryRandomMultiplierComponent, GetDeliveryMultiplierEvent>(OnGetRandomMultiplier);
SubscribeLocalEvent<DeliveryPriorityComponent, MapInitEvent>(OnPriorityMapInit);
SubscribeLocalEvent<DeliveryPriorityComponent, ExaminedEvent>(OnPriorityExamine);
SubscribeLocalEvent<DeliveryPriorityComponent, GetDeliveryMultiplierEvent>(OnGetPriorityMultiplier);
}
#region Random
private void OnRandomMultiplierMapInit(Entity<DeliveryRandomMultiplierComponent> ent, ref MapInitEvent args)
{
ent.Comp.CurrentMultiplierOffset = _random.NextFloat(ent.Comp.MinMultiplierOffset, ent.Comp.MaxMultiplierOffset);
@@ -27,4 +40,70 @@ public sealed partial class DeliveryModifierSystem : EntitySystem
{
args.AdditiveMultiplier += ent.Comp.CurrentMultiplierOffset;
}
#endregion
#region Priority
private void OnPriorityMapInit(Entity<DeliveryPriorityComponent> ent, ref MapInitEvent args)
{
ent.Comp.DeliverUntilTime = _timing.CurTime + ent.Comp.DeliveryTime;
_delivery.UpdatePriorityVisuals(ent);
Dirty(ent);
}
private void OnPriorityExamine(Entity<DeliveryPriorityComponent> ent, ref ExaminedEvent args)
{
var trueName = _nameModifier.GetBaseName(ent.Owner);
var timeLeft = ent.Comp.DeliverUntilTime - _timing.CurTime;
if (_timing.CurTime < ent.Comp.DeliverUntilTime)
args.PushMarkup(Loc.GetString("delivery-priority-examine", ("type", trueName), ("time", timeLeft.ToString("mm\\:ss"))));
else
args.PushMarkup(Loc.GetString("delivery-priority-expired-examine", ("type", trueName)));
}
private void OnGetPriorityMultiplier(Entity<DeliveryPriorityComponent> ent, ref GetDeliveryMultiplierEvent args)
{
if (_timing.CurTime < ent.Comp.DeliverUntilTime)
args.AdditiveMultiplier += ent.Comp.InTimeMultiplierOffset;
else
args.AdditiveMultiplier += ent.Comp.ExpiredMultiplierOffset;
}
#endregion
#region Update Loops
public override void Update(float frameTime)
{
base.Update(frameTime);
UpdatePriorty(frameTime);
}
private void UpdatePriorty(float frameTime)
{
var priorityQuery = EntityQueryEnumerator<DeliveryPriorityComponent>();
var curTime = _timing.CurTime;
while (priorityQuery.MoveNext(out var uid, out var priorityData))
{
if (priorityData.Expired)
continue;
if (priorityData.DeliverUntilTime < curTime)
{
priorityData.Expired = true;
_delivery.UpdatePriorityVisuals((uid, priorityData));
Dirty(uid, priorityData);
var ev = new DeliveryPriorityExpiredEvent();
RaiseLocalEvent(uid, ev);
}
}
}
#endregion
}
/// <summary>
/// Gets raised on a priority delivery when it's timer expires.
/// </summary>
[Serializable, NetSerializable]
public readonly record struct DeliveryPriorityExpiredEvent;

View File

@@ -0,0 +1,43 @@
using Robust.Shared.GameStates;
namespace Content.Shared.Delivery;
/// <summary>
/// Component given to deliveries.
/// Applies a duration before which the delivery must be delivered.
/// If successful, adds a small multiplier, otherwise removes a small multiplier.
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
[Access(typeof(DeliveryModifierSystem))]
public sealed partial class DeliveryPriorityComponent : Component
{
/// <summary>
/// The highest the random multiplier can go.
/// </summary>
[DataField]
public float InTimeMultiplierOffset = 0.2f;
/// <summary>
/// The lowest the random multiplier can go.
/// </summary>
[DataField]
public float ExpiredMultiplierOffset = -0.1f;
/// <summary>
/// Whether this priority delivery has already ran out of time or not.
/// </summary>
[DataField, AutoNetworkedField]
public bool Expired;
/// <summary>
/// How much time you get from spawn until the delivery expires.
/// </summary>
[DataField, AutoNetworkedField]
public TimeSpan DeliveryTime = TimeSpan.FromMinutes(5);
/// <summary>
/// The time by which this has to be delivered.
/// </summary>
[DataField, AutoNetworkedField]
public TimeSpan DeliverUntilTime;
}

View File

@@ -9,11 +9,18 @@ public enum DeliveryVisuals : byte
IsTrash,
IsBroken,
IsFragile,
IsPriority,
IsPriorityInactive,
PriorityState,
JobIcon,
}
[Serializable, NetSerializable]
public enum DeliveryPriorityState : byte
{
Off,
Active,
Inactive,
}
[Serializable, NetSerializable]
public enum DeliverySpawnerVisuals : byte
{

View File

@@ -69,7 +69,7 @@ public abstract class SharedDeliverySystem : EntitySystem
var multiplier = GetDeliveryMultiplier(ent);
var totalSpesos = Math.Round(ent.Comp.BaseSpesoReward * multiplier);
args.PushMarkup(Loc.GetString("delivery-earnings-examine", ("spesos", totalSpesos)));
args.PushMarkup(Loc.GetString("delivery-earnings-examine", ("spesos", totalSpesos)), -1);
}
}
@@ -238,7 +238,18 @@ public abstract class SharedDeliverySystem : EntitySystem
// If we're trying to unlock, always remove the priority tape
if (!isLocked)
_appearance.SetData(uid, DeliveryVisuals.IsPriority, false);
_appearance.SetData(uid, DeliveryVisuals.PriorityState, DeliveryPriorityState.Off);
}
public void UpdatePriorityVisuals(Entity<DeliveryPriorityComponent> ent)
{
if (!TryComp<DeliveryComponent>(ent, out var delivery))
return;
if (delivery.IsLocked && !delivery.IsOpened)
{
_appearance.SetData(ent, DeliveryVisuals.PriorityState, ent.Comp.Expired ? DeliveryPriorityState.Inactive : DeliveryPriorityState.Active);
}
}
protected void UpdateDeliverySpawnerVisuals(EntityUid uid, int contents)
@@ -257,7 +268,10 @@ public abstract class SharedDeliverySystem : EntitySystem
var ev = new GetDeliveryMultiplierEvent();
RaiseLocalEvent(ent, ref ev);
return ev.AdditiveMultiplier * ev.MultiplicativeMultiplier;
// Ensure the multiplier can never go below 0.
var totalMultiplier = Math.Max(ev.AdditiveMultiplier * ev.MultiplicativeMultiplier, 0);
return totalMultiplier;
}
protected virtual void GrantSpesoReward(Entity<DeliveryComponent?> ent) { }

View File

@@ -141,7 +141,8 @@ public abstract class SharedItemSystem : EntitySystem
{
// show at end of message generally
args.PushMarkup(Loc.GetString("item-component-on-examine-size",
("size", GetItemSizeLocale(component.Size))), priority: -1);
("size", GetItemSizeLocale(component.Size))),
priority: -2);
}
public ItemSizePrototype GetSizePrototype(ProtoId<ItemSizePrototype> id)

View File

@@ -20,3 +20,8 @@ delivery-teleporter-amount-examine =
}
delivery-teleporter-empty = The {$entity} is empty.
delivery-teleporter-empty-verb = Take mail
# modifiers
delivery-priority-examine = This is a [color=orange]priority {$type}[/color]. You have [color=orange]{$time}[/color] left to deliver it to get a bonus.
delivery-priority-expired-examine = This is a [color=orange]priority {$type}[/color]. It seems you ran out of time.

View File

@@ -14,14 +14,11 @@
enum.DeliveryVisualLayers.Lock:
True: { visible: true }
False: { visible: false }
enum.DeliveryVisuals.IsPriority:
enum.DeliveryVisuals.PriorityState:
enum.DeliveryVisualLayers.PriorityTape:
True: { visible: true }
False: { visible: false }
enum.DeliveryVisuals.IsPriorityInactive:
enum.DeliveryVisualLayers.PriorityTape:
True: { shader: shaded, state: priority_inactive }
False: { shader: unshaded, state: priority }
Off: { visible: false }
Active: { visible: true, shader: unshaded, state: priority }
Inactive: { visible: true, shader: shaded, state: priority_inactive }
enum.DeliveryVisuals.IsBroken:
enum.DeliveryVisualLayers.Breakage:
True: { visible: true }
@@ -45,6 +42,9 @@
- type: SimpleToolUsage
doAfter: 4
usageVerb: delivery-slice-verb
- type: ComponentTable
table: !type:NestedSelector
tableId: DeliveryModifierTable
- type: entity
parent: BaseDelivery
@@ -128,3 +128,19 @@
containers:
delivery: !type:NestedSelector
tableId: LetterDeliveryRewards
# Modifier Tables
- type: entityTable
id: DeliveryModifierTable
table: !type:AllSelector
children:
- id: DeliveryModifierPriority
prob: 0.25
- type: entity
id: DeliveryModifierPriority
description: Components to add when a delivery is rolled as priority.
categories: [ HideSpawnMenu ]
components:
- type: DeliveryPriority