Priority Deliveries (#36968)
This commit is contained in:
19
Content.Shared/ComponentTable/ComponentTableComponent.cs
Normal file
19
Content.Shared/ComponentTable/ComponentTableComponent.cs
Normal 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!;
|
||||||
|
}
|
||||||
33
Content.Shared/ComponentTable/SharedComponentTableSystem.cs
Normal file
33
Content.Shared/ComponentTable/SharedComponentTableSystem.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,9 @@
|
|||||||
|
using Content.Shared.Examine;
|
||||||
|
using Content.Shared.GameTicking;
|
||||||
|
using Content.Shared.NameModifier.EntitySystems;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
namespace Content.Shared.Delivery;
|
namespace Content.Shared.Delivery;
|
||||||
|
|
||||||
@@ -8,6 +13,9 @@ namespace Content.Shared.Delivery;
|
|||||||
public sealed partial class DeliveryModifierSystem : EntitySystem
|
public sealed partial class DeliveryModifierSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
[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()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -15,8 +23,13 @@ public sealed partial class DeliveryModifierSystem : EntitySystem
|
|||||||
|
|
||||||
SubscribeLocalEvent<DeliveryRandomMultiplierComponent, MapInitEvent>(OnRandomMultiplierMapInit);
|
SubscribeLocalEvent<DeliveryRandomMultiplierComponent, MapInitEvent>(OnRandomMultiplierMapInit);
|
||||||
SubscribeLocalEvent<DeliveryRandomMultiplierComponent, GetDeliveryMultiplierEvent>(OnGetRandomMultiplier);
|
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)
|
private void OnRandomMultiplierMapInit(Entity<DeliveryRandomMultiplierComponent> ent, ref MapInitEvent args)
|
||||||
{
|
{
|
||||||
ent.Comp.CurrentMultiplierOffset = _random.NextFloat(ent.Comp.MinMultiplierOffset, ent.Comp.MaxMultiplierOffset);
|
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;
|
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;
|
||||||
|
|||||||
43
Content.Shared/Delivery/DeliveryPriorityComponent.cs
Normal file
43
Content.Shared/Delivery/DeliveryPriorityComponent.cs
Normal 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;
|
||||||
|
}
|
||||||
@@ -9,11 +9,18 @@ public enum DeliveryVisuals : byte
|
|||||||
IsTrash,
|
IsTrash,
|
||||||
IsBroken,
|
IsBroken,
|
||||||
IsFragile,
|
IsFragile,
|
||||||
IsPriority,
|
PriorityState,
|
||||||
IsPriorityInactive,
|
|
||||||
JobIcon,
|
JobIcon,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public enum DeliveryPriorityState : byte
|
||||||
|
{
|
||||||
|
Off,
|
||||||
|
Active,
|
||||||
|
Inactive,
|
||||||
|
}
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
public enum DeliverySpawnerVisuals : byte
|
public enum DeliverySpawnerVisuals : byte
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ public abstract class SharedDeliverySystem : EntitySystem
|
|||||||
var multiplier = GetDeliveryMultiplier(ent);
|
var multiplier = GetDeliveryMultiplier(ent);
|
||||||
var totalSpesos = Math.Round(ent.Comp.BaseSpesoReward * multiplier);
|
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 we're trying to unlock, always remove the priority tape
|
||||||
if (!isLocked)
|
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)
|
protected void UpdateDeliverySpawnerVisuals(EntityUid uid, int contents)
|
||||||
@@ -257,7 +268,10 @@ public abstract class SharedDeliverySystem : EntitySystem
|
|||||||
var ev = new GetDeliveryMultiplierEvent();
|
var ev = new GetDeliveryMultiplierEvent();
|
||||||
RaiseLocalEvent(ent, ref ev);
|
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) { }
|
protected virtual void GrantSpesoReward(Entity<DeliveryComponent?> ent) { }
|
||||||
|
|||||||
@@ -141,7 +141,8 @@ public abstract class SharedItemSystem : EntitySystem
|
|||||||
{
|
{
|
||||||
// show at end of message generally
|
// show at end of message generally
|
||||||
args.PushMarkup(Loc.GetString("item-component-on-examine-size",
|
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)
|
public ItemSizePrototype GetSizePrototype(ProtoId<ItemSizePrototype> id)
|
||||||
|
|||||||
@@ -20,3 +20,8 @@ delivery-teleporter-amount-examine =
|
|||||||
}
|
}
|
||||||
delivery-teleporter-empty = The {$entity} is empty.
|
delivery-teleporter-empty = The {$entity} is empty.
|
||||||
delivery-teleporter-empty-verb = Take mail
|
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.
|
||||||
|
|||||||
@@ -14,14 +14,11 @@
|
|||||||
enum.DeliveryVisualLayers.Lock:
|
enum.DeliveryVisualLayers.Lock:
|
||||||
True: { visible: true }
|
True: { visible: true }
|
||||||
False: { visible: false }
|
False: { visible: false }
|
||||||
enum.DeliveryVisuals.IsPriority:
|
enum.DeliveryVisuals.PriorityState:
|
||||||
enum.DeliveryVisualLayers.PriorityTape:
|
enum.DeliveryVisualLayers.PriorityTape:
|
||||||
True: { visible: true }
|
Off: { visible: false }
|
||||||
False: { visible: false }
|
Active: { visible: true, shader: unshaded, state: priority }
|
||||||
enum.DeliveryVisuals.IsPriorityInactive:
|
Inactive: { visible: true, shader: shaded, state: priority_inactive }
|
||||||
enum.DeliveryVisualLayers.PriorityTape:
|
|
||||||
True: { shader: shaded, state: priority_inactive }
|
|
||||||
False: { shader: unshaded, state: priority }
|
|
||||||
enum.DeliveryVisuals.IsBroken:
|
enum.DeliveryVisuals.IsBroken:
|
||||||
enum.DeliveryVisualLayers.Breakage:
|
enum.DeliveryVisualLayers.Breakage:
|
||||||
True: { visible: true }
|
True: { visible: true }
|
||||||
@@ -45,6 +42,9 @@
|
|||||||
- type: SimpleToolUsage
|
- type: SimpleToolUsage
|
||||||
doAfter: 4
|
doAfter: 4
|
||||||
usageVerb: delivery-slice-verb
|
usageVerb: delivery-slice-verb
|
||||||
|
- type: ComponentTable
|
||||||
|
table: !type:NestedSelector
|
||||||
|
tableId: DeliveryModifierTable
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: BaseDelivery
|
parent: BaseDelivery
|
||||||
@@ -128,3 +128,19 @@
|
|||||||
containers:
|
containers:
|
||||||
delivery: !type:NestedSelector
|
delivery: !type:NestedSelector
|
||||||
tableId: LetterDeliveryRewards
|
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
|
||||||
|
|||||||
Reference in New Issue
Block a user