Vending Machine Abuse (#8863)
* piece of shit i'll abuse your vending ass * placeholder * Update types.yml * threshold
This commit is contained in:
@@ -0,0 +1,47 @@
|
|||||||
|
using Content.Server.VendingMachines;
|
||||||
|
using Content.Shared.Throwing;
|
||||||
|
using Robust.Shared.Random;
|
||||||
|
|
||||||
|
namespace Content.Server.Destructible.Thresholds.Behaviors
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Throws out a specific amount of random items from a vendor
|
||||||
|
/// </summary>
|
||||||
|
[Serializable]
|
||||||
|
[DataDefinition]
|
||||||
|
public sealed class EjectVendorItems : IThresholdBehavior
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The percent amount of the total inventory that will be ejected.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("percent", required: true)]
|
||||||
|
public float Percent = 0.25f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum amount of vendor items it can eject
|
||||||
|
/// useful for high-inventory vendors
|
||||||
|
/// </summary>
|
||||||
|
[DataField("max")]
|
||||||
|
public int Max = 3;
|
||||||
|
|
||||||
|
public void Execute(EntityUid owner, DestructibleSystem system)
|
||||||
|
{
|
||||||
|
if (!system.EntityManager.TryGetComponent<VendingMachineComponent>(owner, out var vendingcomp) ||
|
||||||
|
!system.EntityManager.TryGetComponent<TransformComponent>(owner, out var xform))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var throwingsys = system.EntityManager.EntitySysManager.GetEntitySystem<ThrowingSystem>();
|
||||||
|
var totalItems = vendingcomp.AllInventory.Count;
|
||||||
|
|
||||||
|
var toEject = Math.Min(totalItems * Percent, Max);
|
||||||
|
for (var i = 0; i < toEject; i++)
|
||||||
|
{
|
||||||
|
var entity = system.EntityManager.SpawnEntity(system.Random.PickAndTake(vendingcomp.AllInventory).ID, xform.Coordinates);
|
||||||
|
|
||||||
|
float range = vendingcomp.NonLimitedEjectRange;
|
||||||
|
Vector2 direction = new Vector2(system.Random.NextFloat(-range, range), system.Random.NextFloat(-range, range));
|
||||||
|
throwingsys.TryThrow(entity, direction, vendingcomp.NonLimitedEjectForce);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using Content.Server.UserInterface;
|
using Content.Server.UserInterface;
|
||||||
|
using Content.Shared.Actions.ActionTypes;
|
||||||
using Content.Shared.Sound;
|
using Content.Shared.Sound;
|
||||||
using Content.Shared.VendingMachines;
|
using Content.Shared.VendingMachines;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
@@ -26,6 +27,16 @@ namespace Content.Server.VendingMachines
|
|||||||
[DataField("speedLimiter")]
|
[DataField("speedLimiter")]
|
||||||
public bool CanShoot = false;
|
public bool CanShoot = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The chance that a vending machine will randomly dispense an item on hit.
|
||||||
|
/// Chance is 0 if null.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("dispenseOnHitChance")]
|
||||||
|
public float? DispenseOnHitChance;
|
||||||
|
|
||||||
|
[DataField("dispenseOnHitThreshold")]
|
||||||
|
public float? DispenseOnHitThreshold;
|
||||||
|
|
||||||
[DataField("soundVend")]
|
[DataField("soundVend")]
|
||||||
// Grabbed from: https://github.com/discordia-space/CEV-Eris/blob/f702afa271136d093ddeb415423240a2ceb212f0/sound/machines/vending_drop.ogg
|
// Grabbed from: https://github.com/discordia-space/CEV-Eris/blob/f702afa271136d093ddeb415423240a2ceb212f0/sound/machines/vending_drop.ogg
|
||||||
public SoundSpecifier SoundVend = new SoundPathSpecifier("/Audio/Machines/machine_vend.ogg");
|
public SoundSpecifier SoundVend = new SoundPathSpecifier("/Audio/Machines/machine_vend.ogg");
|
||||||
@@ -34,6 +45,9 @@ namespace Content.Server.VendingMachines
|
|||||||
// Yoinked from: https://github.com/discordia-space/CEV-Eris/blob/35bbad6764b14e15c03a816e3e89aa1751660ba9/sound/machines/Custom_deny.ogg
|
// Yoinked from: https://github.com/discordia-space/CEV-Eris/blob/35bbad6764b14e15c03a816e3e89aa1751660ba9/sound/machines/Custom_deny.ogg
|
||||||
public SoundSpecifier SoundDeny = new SoundPathSpecifier("/Audio/Machines/custom_deny.ogg");
|
public SoundSpecifier SoundDeny = new SoundPathSpecifier("/Audio/Machines/custom_deny.ogg");
|
||||||
|
|
||||||
|
[DataField("action", customTypeSerializer: typeof(PrototypeIdSerializer<InstantActionPrototype>))]
|
||||||
|
public string? Action = "VendingThrow";
|
||||||
|
|
||||||
[ViewVariables] public BoundUserInterface? UserInterface => Owner.GetUIOrNull(VendingMachineUiKey.Key);
|
[ViewVariables] public BoundUserInterface? UserInterface => Owner.GetUIOrNull(VendingMachineUiKey.Key);
|
||||||
|
|
||||||
public float NonLimitedEjectForce = 7.5f;
|
public float NonLimitedEjectForce = 7.5f;
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ using Content.Server.Power.Components;
|
|||||||
using Content.Server.Power.EntitySystems;
|
using Content.Server.Power.EntitySystems;
|
||||||
using Content.Shared.Access.Components;
|
using Content.Shared.Access.Components;
|
||||||
using Content.Shared.Access.Systems;
|
using Content.Shared.Access.Systems;
|
||||||
|
using Content.Shared.Actions;
|
||||||
|
using Content.Shared.Actions.ActionTypes;
|
||||||
|
using Content.Shared.Damage;
|
||||||
using Content.Shared.Destructible;
|
using Content.Shared.Destructible;
|
||||||
using Content.Shared.Emag.Systems;
|
using Content.Shared.Emag.Systems;
|
||||||
using Content.Shared.Throwing;
|
using Content.Shared.Throwing;
|
||||||
@@ -24,6 +27,7 @@ namespace Content.Server.VendingMachines
|
|||||||
[Dependency] private readonly AccessReaderSystem _accessReader = default!;
|
[Dependency] private readonly AccessReaderSystem _accessReader = default!;
|
||||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||||
[Dependency] private readonly ThrowingSystem _throwingSystem = default!;
|
[Dependency] private readonly ThrowingSystem _throwingSystem = default!;
|
||||||
|
[Dependency] private readonly SharedActionsSystem _action = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -34,6 +38,9 @@ namespace Content.Server.VendingMachines
|
|||||||
SubscribeLocalEvent<VendingMachineComponent, VendingMachineEjectMessage>(OnInventoryEjectMessage);
|
SubscribeLocalEvent<VendingMachineComponent, VendingMachineEjectMessage>(OnInventoryEjectMessage);
|
||||||
SubscribeLocalEvent<VendingMachineComponent, BreakageEventArgs>(OnBreak);
|
SubscribeLocalEvent<VendingMachineComponent, BreakageEventArgs>(OnBreak);
|
||||||
SubscribeLocalEvent<VendingMachineComponent, GotEmaggedEvent>(OnEmagged);
|
SubscribeLocalEvent<VendingMachineComponent, GotEmaggedEvent>(OnEmagged);
|
||||||
|
SubscribeLocalEvent<VendingMachineComponent, DamageChangedEvent>(OnDamage);
|
||||||
|
|
||||||
|
SubscribeLocalEvent<VendingMachineComponent, VendingMachineSelfDispenseEvent>(OnSelfDispense);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnComponentInit(EntityUid uid, VendingMachineComponent component, ComponentInit args)
|
private void OnComponentInit(EntityUid uid, VendingMachineComponent component, ComponentInit args)
|
||||||
@@ -45,6 +52,12 @@ namespace Content.Server.VendingMachines
|
|||||||
TryUpdateVisualState(uid, null, component);
|
TryUpdateVisualState(uid, null, component);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (component.Action != null)
|
||||||
|
{
|
||||||
|
var action = new InstantAction(_prototypeManager.Index<InstantActionPrototype>(component.Action));
|
||||||
|
_action.AddAction(uid, action, uid);
|
||||||
|
}
|
||||||
|
|
||||||
InitializeFromPrototype(uid, component);
|
InitializeFromPrototype(uid, component);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,6 +105,24 @@ namespace Content.Server.VendingMachines
|
|||||||
args.Handled = true;
|
args.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnDamage(EntityUid uid, VendingMachineComponent component, DamageChangedEvent args)
|
||||||
|
{
|
||||||
|
if (component.DispenseOnHitChance == null || args.DamageDelta == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (args.DamageDelta.Total >= component.DispenseOnHitThreshold && _random.Prob(component.DispenseOnHitChance.Value))
|
||||||
|
EjectRandom(uid, true, component);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnSelfDispense(EntityUid uid, VendingMachineComponent component, VendingMachineSelfDispenseEvent args)
|
||||||
|
{
|
||||||
|
if (args.Handled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
args.Handled = true;
|
||||||
|
EjectRandom(uid, true, component);
|
||||||
|
}
|
||||||
|
|
||||||
public void InitializeFromPrototype(EntityUid uid, VendingMachineComponent? vendComponent = null)
|
public void InitializeFromPrototype(EntityUid uid, VendingMachineComponent? vendComponent = null)
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref vendComponent))
|
if (!Resolve(uid, ref vendComponent))
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using Content.Shared.Actions;
|
||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
@@ -121,4 +122,6 @@ namespace Content.Shared.VendingMachines
|
|||||||
{
|
{
|
||||||
StatusKey,
|
StatusKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public sealed class VendingMachineSelfDispenseEvent : InstantActionEvent { };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,3 +3,8 @@
|
|||||||
vending-machine-component-try-eject-invalid-item = Invalid item
|
vending-machine-component-try-eject-invalid-item = Invalid item
|
||||||
vending-machine-component-try-eject-out-of-stock = Out of stock
|
vending-machine-component-try-eject-out-of-stock = Out of stock
|
||||||
vending-machine-component-try-eject-access-denied = Access denied
|
vending-machine-component-try-eject-access-denied = Access denied
|
||||||
|
|
||||||
|
## VendingMachineSelfDespense Action
|
||||||
|
|
||||||
|
vending-machine-action-name = Dispense Item
|
||||||
|
vending-machine-action-description = Randomly dispense an item from your stock.
|
||||||
@@ -48,3 +48,10 @@
|
|||||||
userPopup: action-popup-combat
|
userPopup: action-popup-combat
|
||||||
popupToggleSuffix: -disabling
|
popupToggleSuffix: -disabling
|
||||||
event: !type:ToggleCombatActionEvent
|
event: !type:ToggleCombatActionEvent
|
||||||
|
|
||||||
|
- type: instantAction
|
||||||
|
id: VendingThrow
|
||||||
|
name: vending-machine-action-name
|
||||||
|
description: vending-machine-action-description
|
||||||
|
useDelay: 30
|
||||||
|
event: !type:VendingMachineSelfDispenseEvent
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
behaviors:
|
behaviors:
|
||||||
- !type:DoActsBehavior
|
- !type:DoActsBehavior
|
||||||
acts: ["Breakage"]
|
acts: ["Breakage"]
|
||||||
|
- !type:EjectVendorItems
|
||||||
- type: ActivatableUI
|
- type: ActivatableUI
|
||||||
key: enum.VendingMachineUiKey.Key
|
key: enum.VendingMachineUiKey.Key
|
||||||
- type: ActivatableUIRequiresPower
|
- type: ActivatableUIRequiresPower
|
||||||
@@ -64,6 +65,7 @@
|
|||||||
- type: ApcPowerReceiver
|
- type: ApcPowerReceiver
|
||||||
powerLoad: 200
|
powerLoad: 200
|
||||||
priority: Low
|
priority: Low
|
||||||
|
- type: Actions
|
||||||
- type: SentienceTarget
|
- type: SentienceTarget
|
||||||
flavorKind: mechanical
|
flavorKind: mechanical
|
||||||
|
|
||||||
@@ -166,6 +168,8 @@
|
|||||||
components:
|
components:
|
||||||
- type: VendingMachine
|
- type: VendingMachine
|
||||||
pack: CigaretteMachineInventory
|
pack: CigaretteMachineInventory
|
||||||
|
dispenseOnHitChance: 0.25
|
||||||
|
dispenseOnHitThreshold: 2
|
||||||
- type: Advertise
|
- type: Advertise
|
||||||
pack: CigaretteMachineAds
|
pack: CigaretteMachineAds
|
||||||
- type: Speech
|
- type: Speech
|
||||||
@@ -232,6 +236,8 @@
|
|||||||
components:
|
components:
|
||||||
- type: VendingMachine
|
- type: VendingMachine
|
||||||
pack: HotDrinksMachineInventory
|
pack: HotDrinksMachineInventory
|
||||||
|
dispenseOnHitChance: 0.25
|
||||||
|
dispenseOnHitThreshold: 2
|
||||||
- type: Advertise
|
- type: Advertise
|
||||||
pack: HotDrinksMachineAds
|
pack: HotDrinksMachineAds
|
||||||
- type: Speech
|
- type: Speech
|
||||||
@@ -270,6 +276,8 @@
|
|||||||
components:
|
components:
|
||||||
- type: VendingMachine
|
- type: VendingMachine
|
||||||
pack: RobustSoftdrinksInventory
|
pack: RobustSoftdrinksInventory
|
||||||
|
dispenseOnHitChance: 0.25
|
||||||
|
dispenseOnHitThreshold: 2
|
||||||
- type: Advertise
|
- type: Advertise
|
||||||
pack: RobustSoftdrinksAds
|
pack: RobustSoftdrinksAds
|
||||||
- type: Speech
|
- type: Speech
|
||||||
@@ -338,6 +346,8 @@
|
|||||||
components:
|
components:
|
||||||
- type: VendingMachine
|
- type: VendingMachine
|
||||||
pack: DiscountDansInventory
|
pack: DiscountDansInventory
|
||||||
|
dispenseOnHitChance: 0.25
|
||||||
|
dispenseOnHitThreshold: 2
|
||||||
- type: Advertise
|
- type: Advertise
|
||||||
pack: DiscountDansAds
|
pack: DiscountDansAds
|
||||||
- type: Speech
|
- type: Speech
|
||||||
@@ -574,6 +584,8 @@
|
|||||||
components:
|
components:
|
||||||
- type: VendingMachine
|
- type: VendingMachine
|
||||||
pack: GetmoreChocolateCorpInventory
|
pack: GetmoreChocolateCorpInventory
|
||||||
|
dispenseOnHitChance: 0.25
|
||||||
|
dispenseOnHitThreshold: 2
|
||||||
- type: Advertise
|
- type: Advertise
|
||||||
pack: GetmoreChocolateCorpAds
|
pack: GetmoreChocolateCorpAds
|
||||||
- type: Speech
|
- type: Speech
|
||||||
@@ -608,6 +620,8 @@
|
|||||||
components:
|
components:
|
||||||
- type: VendingMachine
|
- type: VendingMachine
|
||||||
pack: BodaInventory
|
pack: BodaInventory
|
||||||
|
dispenseOnHitChance: 0.25
|
||||||
|
dispenseOnHitThreshold: 2
|
||||||
- type: Advertise
|
- type: Advertise
|
||||||
pack: BodaAds
|
pack: BodaAds
|
||||||
- type: Speech
|
- type: Speech
|
||||||
@@ -815,6 +829,8 @@
|
|||||||
components:
|
components:
|
||||||
- type: VendingMachine
|
- type: VendingMachine
|
||||||
pack: ChangInventory
|
pack: ChangInventory
|
||||||
|
dispenseOnHitChance: 0.25
|
||||||
|
dispenseOnHitThreshold: 2
|
||||||
- type: Advertise
|
- type: Advertise
|
||||||
pack: ChangAds
|
pack: ChangAds
|
||||||
- type: Speech
|
- type: Speech
|
||||||
|
|||||||
Reference in New Issue
Block a user