Tearable Deliveries V2 (#36815)
* Add new fields to DeliveryComponent for #36636 * Setting the baseSpesoPenalty for currently available deliveries * Small fixes * Basic delivery penalization * Penalty and reward multiplier calculation in place Also fixes an issue in SharedCargoSystem when opening a delivery in dev server due to trying to allocate cargo twice. * Calling penalty no longer happens on opening * Extract multiplier getting * Removing unused include * Changing method description. \n\n Not actually sure what I meant by the first one * Localising default delivery messages * Unused include removal * init or smth * minor tweaks * I KEEP MERGE CONFLICTING MYSELF * comments * no icon * slight increase * slarti changes * forgot * stuffs * yippee * Locn't * doc * partial review * message * review * pain * stuff --------- Co-authored-by: Lmorgan89 <billsmith116@gmail.com>
This commit is contained in:
@@ -8,6 +8,7 @@ using Content.Shared.Interaction.Events;
|
|||||||
using Content.Shared.NameModifier.EntitySystems;
|
using Content.Shared.NameModifier.EntitySystems;
|
||||||
using Content.Shared.Objectives.Components;
|
using Content.Shared.Objectives.Components;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
|
using Content.Shared.Tools.Components;
|
||||||
using Content.Shared.Tag;
|
using Content.Shared.Tag;
|
||||||
using Content.Shared.Verbs;
|
using Content.Shared.Verbs;
|
||||||
using Robust.Shared.Audio.Systems;
|
using Robust.Shared.Audio.Systems;
|
||||||
@@ -41,6 +42,8 @@ public abstract class SharedDeliverySystem : EntitySystem
|
|||||||
SubscribeLocalEvent<DeliveryComponent, ExaminedEvent>(OnDeliveryExamine);
|
SubscribeLocalEvent<DeliveryComponent, ExaminedEvent>(OnDeliveryExamine);
|
||||||
SubscribeLocalEvent<DeliveryComponent, UseInHandEvent>(OnUseInHand);
|
SubscribeLocalEvent<DeliveryComponent, UseInHandEvent>(OnUseInHand);
|
||||||
SubscribeLocalEvent<DeliveryComponent, GetVerbsEvent<AlternativeVerb>>(OnGetDeliveryVerbs);
|
SubscribeLocalEvent<DeliveryComponent, GetVerbsEvent<AlternativeVerb>>(OnGetDeliveryVerbs);
|
||||||
|
SubscribeLocalEvent<DeliveryComponent, AttemptSimpleToolUseEvent>(OnAttemptSimpleToolUse);
|
||||||
|
SubscribeLocalEvent<DeliveryComponent, SimpleToolDoAfterEvent>(OnSimpleToolUse);
|
||||||
|
|
||||||
SubscribeLocalEvent<DeliverySpawnerComponent, ExaminedEvent>(OnSpawnerExamine);
|
SubscribeLocalEvent<DeliverySpawnerComponent, ExaminedEvent>(OnSpawnerExamine);
|
||||||
SubscribeLocalEvent<DeliverySpawnerComponent, GetVerbsEvent<AlternativeVerb>>(OnGetSpawnerVerbs);
|
SubscribeLocalEvent<DeliverySpawnerComponent, GetVerbsEvent<AlternativeVerb>>(OnGetSpawnerVerbs);
|
||||||
@@ -100,6 +103,24 @@ public abstract class SharedDeliverySystem : EntitySystem
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void OnAttemptSimpleToolUse(Entity<DeliveryComponent> ent, ref AttemptSimpleToolUseEvent args)
|
||||||
|
{
|
||||||
|
if (ent.Comp.IsOpened || !ent.Comp.IsLocked)
|
||||||
|
args.Cancelled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnSimpleToolUse(Entity<DeliveryComponent> ent, ref SimpleToolDoAfterEvent args)
|
||||||
|
{
|
||||||
|
if (ent.Comp.IsOpened || args.Cancelled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
HandlePenalty(ent);
|
||||||
|
|
||||||
|
TryUnlockDelivery(ent, args.User, false, true);
|
||||||
|
OpenDelivery(ent, args.User, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
private void OnGetSpawnerVerbs(Entity<DeliverySpawnerComponent> ent, ref GetVerbsEvent<AlternativeVerb> args)
|
private void OnGetSpawnerVerbs(Entity<DeliverySpawnerComponent> ent, ref GetVerbsEvent<AlternativeVerb> args)
|
||||||
{
|
{
|
||||||
if (!args.CanAccess || !args.CanInteract || args.Hands == null)
|
if (!args.CanAccess || !args.CanInteract || args.Hands == null)
|
||||||
@@ -127,14 +148,15 @@ public abstract class SharedDeliverySystem : EntitySystem
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool TryUnlockDelivery(Entity<DeliveryComponent> ent, EntityUid user, bool rewardMoney = true)
|
private bool TryUnlockDelivery(Entity<DeliveryComponent> ent, EntityUid user, bool rewardMoney = true, bool force = false)
|
||||||
{
|
{
|
||||||
// Check fingerprint access if there is a reader on the mail
|
// Check fingerprint access if there is a reader on the mail
|
||||||
if (TryComp<FingerprintReaderComponent>(ent, out var reader) && !_fingerprintReader.IsAllowed((ent, reader), user))
|
if (!force && TryComp<FingerprintReaderComponent>(ent, out var reader) && !_fingerprintReader.IsAllowed((ent, reader), user))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var deliveryName = _nameModifier.GetBaseName(ent.Owner);
|
var deliveryName = _nameModifier.GetBaseName(ent.Owner);
|
||||||
|
|
||||||
|
if (!force)
|
||||||
_audio.PlayPredicted(ent.Comp.UnlockSound, user, user);
|
_audio.PlayPredicted(ent.Comp.UnlockSound, user, user);
|
||||||
|
|
||||||
ent.Comp.IsLocked = false;
|
ent.Comp.IsLocked = false;
|
||||||
@@ -142,18 +164,22 @@ public abstract class SharedDeliverySystem : EntitySystem
|
|||||||
|
|
||||||
DirtyField(ent, ent.Comp, nameof(DeliveryComponent.IsLocked));
|
DirtyField(ent, ent.Comp, nameof(DeliveryComponent.IsLocked));
|
||||||
|
|
||||||
|
RemCompDeferred<SimpleToolUsageComponent>(ent); // we don't want unlocked mail to still be cuttable
|
||||||
|
|
||||||
var ev = new DeliveryUnlockedEvent(user);
|
var ev = new DeliveryUnlockedEvent(user);
|
||||||
RaiseLocalEvent(ent, ref ev);
|
RaiseLocalEvent(ent, ref ev);
|
||||||
|
|
||||||
if (rewardMoney)
|
if (rewardMoney)
|
||||||
GrantSpesoReward(ent.AsNullable());
|
GrantSpesoReward(ent.AsNullable());
|
||||||
|
|
||||||
|
if (!force)
|
||||||
_popup.PopupPredicted(Loc.GetString("delivery-unlocked-self", ("delivery", deliveryName)),
|
_popup.PopupPredicted(Loc.GetString("delivery-unlocked-self", ("delivery", deliveryName)),
|
||||||
Loc.GetString("delivery-unlocked-others", ("delivery", deliveryName), ("recipient", Identity.Name(user, EntityManager)), ("possadj", user)), user, user);
|
Loc.GetString("delivery-unlocked-others", ("delivery", deliveryName), ("recipient", Identity.Name(user, EntityManager)), ("possadj", user)), user, user);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OpenDelivery(Entity<DeliveryComponent> ent, EntityUid user, bool attemptPickup = true)
|
private void OpenDelivery(Entity<DeliveryComponent> ent, EntityUid user, bool attemptPickup = true, bool force = false)
|
||||||
{
|
{
|
||||||
var deliveryName = _nameModifier.GetBaseName(ent.Owner);
|
var deliveryName = _nameModifier.GetBaseName(ent.Owner);
|
||||||
|
|
||||||
@@ -170,10 +196,11 @@ public abstract class SharedDeliverySystem : EntitySystem
|
|||||||
|
|
||||||
_tag.AddTags(ent, TrashTag, RecyclableTag);
|
_tag.AddTags(ent, TrashTag, RecyclableTag);
|
||||||
EnsureComp<SpaceGarbageComponent>(ent);
|
EnsureComp<SpaceGarbageComponent>(ent);
|
||||||
RemComp<StealTargetComponent>(ent); // opened mail should not count for the objective
|
RemCompDeferred<StealTargetComponent>(ent); // opened mail should not count for the objective
|
||||||
|
|
||||||
DirtyField(ent.Owner, ent.Comp, nameof(DeliveryComponent.IsOpened));
|
DirtyField(ent.Owner, ent.Comp, nameof(DeliveryComponent.IsOpened));
|
||||||
|
|
||||||
|
if (!force)
|
||||||
_popup.PopupPredicted(Loc.GetString("delivery-opened-self", ("delivery", deliveryName)),
|
_popup.PopupPredicted(Loc.GetString("delivery-opened-self", ("delivery", deliveryName)),
|
||||||
Loc.GetString("delivery-opened-others", ("delivery", deliveryName), ("recipient", Identity.Name(user, EntityManager)), ("possadj", user)), user, user);
|
Loc.GetString("delivery-opened-others", ("delivery", deliveryName), ("recipient", Identity.Name(user, EntityManager)), ("possadj", user)), user, user);
|
||||||
|
|
||||||
@@ -189,7 +216,7 @@ public abstract class SharedDeliverySystem : EntitySystem
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_container.EmptyContainer(container, true, Transform(ent.Owner).Coordinates);
|
_container.EmptyContainer(container, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ public sealed class FingerprintReaderSystem : EntitySystem
|
|||||||
/// <param name="user">User trying to gain access.</param>
|
/// <param name="user">User trying to gain access.</param>
|
||||||
/// <returns>True if access was granted, otherwise false.</returns>
|
/// <returns>True if access was granted, otherwise false.</returns>
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public bool IsAllowed(Entity<FingerprintReaderComponent?> target, EntityUid user)
|
public bool IsAllowed(Entity<FingerprintReaderComponent?> target, EntityUid user, bool showPopup = true)
|
||||||
{
|
{
|
||||||
if (!Resolve(target, ref target.Comp, false))
|
if (!Resolve(target, ref target.Comp, false))
|
||||||
return true;
|
return true;
|
||||||
@@ -30,7 +30,7 @@ public sealed class FingerprintReaderSystem : EntitySystem
|
|||||||
// Check for gloves first
|
// Check for gloves first
|
||||||
if (!target.Comp.IgnoreGloves && TryGetBlockingGloves(user, out var gloves))
|
if (!target.Comp.IgnoreGloves && TryGetBlockingGloves(user, out var gloves))
|
||||||
{
|
{
|
||||||
if (target.Comp.FailGlovesPopup != null)
|
if (target.Comp.FailGlovesPopup != null && showPopup)
|
||||||
_popup.PopupClient(Loc.GetString(target.Comp.FailGlovesPopup, ("blocker", gloves)), target, user);
|
_popup.PopupClient(Loc.GetString(target.Comp.FailGlovesPopup, ("blocker", gloves)), target, user);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -39,7 +39,7 @@ public sealed class FingerprintReaderSystem : EntitySystem
|
|||||||
if (!TryComp<FingerprintComponent>(user, out var fingerprint) || fingerprint.Fingerprint == null ||
|
if (!TryComp<FingerprintComponent>(user, out var fingerprint) || fingerprint.Fingerprint == null ||
|
||||||
!target.Comp.AllowedFingerprints.Contains(fingerprint.Fingerprint))
|
!target.Comp.AllowedFingerprints.Contains(fingerprint.Fingerprint))
|
||||||
{
|
{
|
||||||
if (target.Comp.FailPopup != null)
|
if (target.Comp.FailPopup != null && showPopup)
|
||||||
_popup.PopupClient(Loc.GetString(target.Comp.FailPopup), target, user);
|
_popup.PopupClient(Loc.GetString(target.Comp.FailPopup), target, user);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
47
Content.Shared/Tools/Components/SimpleToolUsageComponent.cs
Normal file
47
Content.Shared/Tools/Components/SimpleToolUsageComponent.cs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
using Content.Shared.DoAfter;
|
||||||
|
using Content.Shared.Tools.Systems;
|
||||||
|
using Robust.Shared.GameStates;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Shared.Tools.Components;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Component responsible for simple tool interactions.
|
||||||
|
/// Using a tool with the correct quality on an entity with this component will start a doAfter and raise events.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent, NetworkedComponent]
|
||||||
|
[Access(typeof(SimpleToolUsageSystem))]
|
||||||
|
public sealed partial class SimpleToolUsageComponent : Component
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Tool quality required to use a tool on this.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public ProtoId<ToolQualityPrototype> Quality = "Slicing";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The duration using a tool on this entity will take in seconds.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public float DoAfter = 5;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// What verb should display to allow you to use a tool on this entity.
|
||||||
|
/// If null, no verb will be shown.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public LocId? UsageVerb;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The message to show when the verb is disabled.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public LocId BlockedMessage = "simple-tool-usage-blocked-message";
|
||||||
|
}
|
||||||
|
|
||||||
|
[ByRefEvent]
|
||||||
|
public record struct AttemptSimpleToolUseEvent(EntityUid User, bool Cancelled = false);
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed partial class SimpleToolDoAfterEvent : SimpleDoAfterEvent;
|
||||||
79
Content.Shared/Tools/Systems/SimpleToolUsageSystem.cs
Normal file
79
Content.Shared/Tools/Systems/SimpleToolUsageSystem.cs
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
using Content.Shared.DoAfter;
|
||||||
|
using Content.Shared.Interaction;
|
||||||
|
using Content.Shared.Tools.Components;
|
||||||
|
using Content.Shared.Verbs;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
|
namespace Content.Shared.Tools.Systems;
|
||||||
|
|
||||||
|
public sealed partial class SimpleToolUsageSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!;
|
||||||
|
[Dependency] private readonly SharedToolSystem _tools = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<SimpleToolUsageComponent, AfterInteractUsingEvent>(OnAfterInteract);
|
||||||
|
SubscribeLocalEvent<SimpleToolUsageComponent, GetVerbsEvent<InteractionVerb>>(OnGetInteractionVerbs);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnAfterInteract(Entity<SimpleToolUsageComponent> ent, ref AfterInteractUsingEvent args)
|
||||||
|
{
|
||||||
|
if (!args.CanReach || args.Handled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!_tools.HasQuality(args.Used, ent.Comp.Quality))
|
||||||
|
return;
|
||||||
|
|
||||||
|
AttemptToolUsage(ent, args.User, args.Used);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnGetInteractionVerbs(Entity<SimpleToolUsageComponent> ent, ref GetVerbsEvent<InteractionVerb> args)
|
||||||
|
{
|
||||||
|
if (ent.Comp.UsageVerb == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!args.CanAccess || !args.CanInteract)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var disabled = args.Using == null || !_tools.HasQuality(args.Using.Value, ent.Comp.Quality);
|
||||||
|
|
||||||
|
var used = args.Using;
|
||||||
|
var user = args.User;
|
||||||
|
|
||||||
|
InteractionVerb verb = new()
|
||||||
|
{
|
||||||
|
Act = () =>
|
||||||
|
{
|
||||||
|
if (used != null)
|
||||||
|
AttemptToolUsage(ent, user, used.Value);
|
||||||
|
},
|
||||||
|
Disabled = disabled,
|
||||||
|
Message = disabled ? Loc.GetString(ent.Comp.BlockedMessage, ("quality", ent.Comp.Quality)) : null,
|
||||||
|
Text = Loc.GetString(ent.Comp.UsageVerb),
|
||||||
|
};
|
||||||
|
|
||||||
|
args.Verbs.Add(verb);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AttemptToolUsage(Entity<SimpleToolUsageComponent> ent, EntityUid user, EntityUid tool)
|
||||||
|
{
|
||||||
|
var attemptEv = new AttemptSimpleToolUseEvent(user);
|
||||||
|
RaiseLocalEvent(ent, ref attemptEv);
|
||||||
|
|
||||||
|
if (attemptEv.Cancelled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var doAfterArgs = new DoAfterArgs(EntityManager, user, ent.Comp.DoAfter, new SimpleToolDoAfterEvent(), ent, tool)
|
||||||
|
{
|
||||||
|
BreakOnDamage = true,
|
||||||
|
BreakOnDropItem = true,
|
||||||
|
BreakOnMove = true,
|
||||||
|
BreakOnHandChange = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
_doAfterSystem.TryStartDoAfter(doAfterArgs);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ delivery-opened-others = {CAPITALIZE($recipient)} opened the {$delivery}.
|
|||||||
|
|
||||||
delivery-unlock-verb = Unlock
|
delivery-unlock-verb = Unlock
|
||||||
delivery-open-verb = Open
|
delivery-open-verb = Open
|
||||||
|
delivery-slice-verb = Slice open
|
||||||
|
|
||||||
delivery-teleporter-amount-examine =
|
delivery-teleporter-amount-examine =
|
||||||
{ $amount ->
|
{ $amount ->
|
||||||
|
|||||||
1
Resources/Locale/en-US/tools/simple-tool-usage.ftl
Normal file
1
Resources/Locale/en-US/tools/simple-tool-usage.ftl
Normal file
@@ -0,0 +1 @@
|
|||||||
|
simple-tool-usage-blocked-message = You need a tool that can perform {$quality}!
|
||||||
@@ -41,6 +41,9 @@
|
|||||||
delivery: !type:Container
|
delivery: !type:Container
|
||||||
- type: StealTarget
|
- type: StealTarget
|
||||||
stealGroup: Mail
|
stealGroup: Mail
|
||||||
|
- type: SimpleToolUsage
|
||||||
|
doAfter: 4
|
||||||
|
usageVerb: delivery-slice-verb
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: BaseDelivery
|
parent: BaseDelivery
|
||||||
@@ -75,9 +78,11 @@
|
|||||||
size: Huge
|
size: Huge
|
||||||
- type: Delivery
|
- type: Delivery
|
||||||
baseSpesoReward: 1000
|
baseSpesoReward: 1000
|
||||||
baseSpesoPenalty: 500
|
baseSpesoPenalty: 250 # So low due to dept economy splitting all the earnings, but not splitting the penalty.
|
||||||
- type: Speech
|
- type: Speech
|
||||||
speechVerb: Robotic
|
speechVerb: Robotic
|
||||||
|
- type: SimpleToolUsage
|
||||||
|
doAfter: 6
|
||||||
- type: EntityTableContainerFill
|
- type: EntityTableContainerFill
|
||||||
containers:
|
containers:
|
||||||
delivery: !type:NestedSelector
|
delivery: !type:NestedSelector
|
||||||
@@ -115,7 +120,7 @@
|
|||||||
storedRotation: 90
|
storedRotation: 90
|
||||||
- type: Delivery
|
- type: Delivery
|
||||||
baseSpesoReward: 500
|
baseSpesoReward: 500
|
||||||
baseSpesoPenalty: 250
|
baseSpesoPenalty: 125 # So low due to dept economy splitting all the earnings, but not splitting the penalty.
|
||||||
- type: Speech
|
- type: Speech
|
||||||
speechVerb: Robotic
|
speechVerb: Robotic
|
||||||
- type: EntityTableContainerFill
|
- type: EntityTableContainerFill
|
||||||
|
|||||||
Reference in New Issue
Block a user