-using Content.Shared.Random;
+using Content.Shared.EntityTable.EntitySelectors;
using Robust.Shared.Audio;
using Robust.Shared.GameStates;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
-namespace Content.Shared.RatKing;
+namespace Content.Shared.RatKing.Components;
/// <summary>
/// This is used for entities that can be
/// rummaged through by the rat king to get loot.
/// </summary>
-[RegisterComponent, NetworkedComponent, Access(typeof(SharedRatKingSystem))]
+[RegisterComponent, NetworkedComponent]
[AutoGenerateComponentState]
-public sealed partial class RatKingRummageableComponent : Component
+public sealed partial class RummageableComponent : Component
{
/// <summary>
/// Whether or not this entity has been rummaged through already.
public float RummageDuration = 3f;
/// <summary>
- /// A weighted random entity prototype containing the different loot that rummaging can provide.
+ /// The entity table to select loot from.
/// </summary>
- [DataField("rummageLoot", customTypeSerializer: typeof(PrototypeIdSerializer<WeightedRandomEntityPrototype>)), ViewVariables(VVAccess.ReadWrite)]
- [AutoNetworkedField]
- public string RummageLoot = "RatKingLoot";
+ [DataField(required: true)]
+ public EntityTableSelector Table = default!;
/// <summary>
/// Sound played on rummage completion.
--- /dev/null
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.RatKing.Components;
+
+/// <summary>
+/// This is used for entities that can rummage through entities
+/// with the <see cref="RummageableComponent"/>
+/// </summary>
+///
+[RegisterComponent, NetworkedComponent]
+public sealed partial class RummagerComponent : Component;
using Content.Shared.Actions;
-using Content.Shared.Actions.Components;
-using Content.Shared.DoAfter;
-using Content.Shared.Random;
-using Content.Shared.Random.Helpers;
-using Content.Shared.Verbs;
-using Robust.Shared.Audio;
-using Robust.Shared.Audio.Systems;
-using Robust.Shared.Network;
+using Content.Shared.Actions.Components;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
-using Robust.Shared.Serialization;
namespace Content.Shared.RatKing;
public abstract class SharedRatKingSystem : EntitySystem
{
- [Dependency] private readonly INetManager _net = default!;
[Dependency] protected readonly IPrototypeManager PrototypeManager = default!;
[Dependency] protected readonly IRobustRandom Random = default!;
[Dependency] private readonly SharedActionsSystem _action = default!;
- [Dependency] private readonly SharedAudioSystem _audio = default!;
- [Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
/// <inheritdoc/>
public override void Initialize()
SubscribeLocalEvent<RatKingComponent, ComponentStartup>(OnStartup);
SubscribeLocalEvent<RatKingComponent, ComponentShutdown>(OnShutdown);
SubscribeLocalEvent<RatKingComponent, RatKingOrderActionEvent>(OnOrderAction);
-
SubscribeLocalEvent<RatKingServantComponent, ComponentShutdown>(OnServantShutdown);
-
- SubscribeLocalEvent<RatKingRummageableComponent, GetVerbsEvent<AlternativeVerb>>(OnGetVerb);
- SubscribeLocalEvent<RatKingRummageableComponent, RatKingRummageDoAfterEvent>(OnDoAfterComplete);
}
private void OnStartup(EntityUid uid, RatKingComponent component, ComponentStartup args)
_action.StartUseDelay(component.ActionOrderLooseEntity);
}
- private void OnGetVerb(EntityUid uid, RatKingRummageableComponent component, GetVerbsEvent<AlternativeVerb> args)
- {
- if (!HasComp<RatKingComponent>(args.User) || component.Looted)
- return;
-
- args.Verbs.Add(new AlternativeVerb
- {
- Text = Loc.GetString("rat-king-rummage-text"),
- Priority = 0,
- Act = () =>
- {
- _doAfter.TryStartDoAfter(new DoAfterArgs(EntityManager, args.User, component.RummageDuration,
- new RatKingRummageDoAfterEvent(), uid, uid)
- {
- BlockDuplicate = true,
- BreakOnDamage = true,
- BreakOnMove = true,
- DistanceThreshold = 2f
- });
- }
- });
- }
-
- private void OnDoAfterComplete(EntityUid uid, RatKingRummageableComponent component, RatKingRummageDoAfterEvent args)
- {
- if (args.Cancelled || component.Looted)
- return;
-
- component.Looted = true;
- Dirty(uid, component);
- _audio.PlayPredicted(component.Sound, uid, args.User);
-
- var spawn = PrototypeManager.Index<WeightedRandomEntityPrototype>(component.RummageLoot).Pick(Random);
- if (_net.IsServer)
- Spawn(spawn, Transform(uid).Coordinates);
- }
-
public void UpdateAllServants(EntityUid uid, RatKingComponent component)
{
foreach (var servant in component.Servants)
}
}
-
-[Serializable, NetSerializable]
-public sealed partial class RatKingRummageDoAfterEvent : SimpleDoAfterEvent
-{
-
-}
--- /dev/null
+using Content.Shared.DoAfter;
+using Content.Shared.EntityTable;
+using Content.Shared.RatKing.Components;
+using Content.Shared.Verbs;
+using Robust.Shared.Audio.Systems;
+using Robust.Shared.Network;
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.RatKing.Systems;
+
+public sealed class RummagerSystem : EntitySystem
+{
+ [Dependency] private readonly EntityTableSystem _entityTable = default!;
+ [Dependency] private readonly SharedAudioSystem _audio = default!;
+ [Dependency] private readonly INetManager _net = default!;
+ [Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
+
+ /// <inheritdoc/>
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent<RummageableComponent, GetVerbsEvent<AlternativeVerb>>(OnGetVerb);
+ SubscribeLocalEvent<RummageableComponent, RummageDoAfterEvent>(OnDoAfterComplete);
+ }
+
+ private void OnGetVerb(Entity<RummageableComponent> ent, ref GetVerbsEvent<AlternativeVerb> args)
+ {
+ if (!HasComp<RummagerComponent>(args.User) || ent.Comp.Looted)
+ return;
+
+ var user = args.User;
+
+ args.Verbs.Add(new AlternativeVerb
+ {
+ Text = Loc.GetString("rat-king-rummage-text"),
+ Priority = 0,
+ Act = () =>
+ {
+ _doAfter.TryStartDoAfter(new DoAfterArgs(EntityManager,
+ user,
+ ent.Comp.RummageDuration,
+ new RummageDoAfterEvent(),
+ ent,
+ ent)
+ {
+ BlockDuplicate = true,
+ BreakOnDamage = true,
+ BreakOnMove = true,
+ DistanceThreshold = 2f
+ });
+ }
+ });
+ }
+
+ private void OnDoAfterComplete(Entity<RummageableComponent> ent, ref RummageDoAfterEvent args)
+ {
+ if (args.Cancelled || ent.Comp.Looted)
+ return;
+
+ ent.Comp.Looted = true;
+ Dirty(ent, ent.Comp);
+ _audio.PlayPredicted(ent.Comp.Sound, ent, args.User);
+
+ if (_net.IsClient)
+ return;
+
+ var spawns = _entityTable.GetSpawns(ent.Comp.Table);
+ var coordinates = Transform(ent).Coordinates;
+
+ foreach (var spawn in spawns)
+ {
+ Spawn(spawn, coordinates);
+ }
+ }
+}
+
+/// <summary>
+/// DoAfter event for rummaging through a container with RummageableComponent.
+/// </summary>
+[Serializable, NetSerializable]
+public sealed partial class RummageDoAfterEvent : SimpleDoAfterEvent;
- CannotSuicide
- FootstepSound
- type: NoSlip
+ - type: Rummager
- type: RatKing
hungerPerArmyUse: 25
hungerPerDomainUse: 50
sprite: Mobs/Effects/onfire.rsi
normalState: Mouse_burning
-- type: weightedRandomEntity
+- type: entityTable
id: RatKingLoot
- weights:
- RandomSpawner100: 66 #garbage
- FoodCheese: 28 #food
- IngotGold1: 5 #loot
+ table: !type:GroupSelector
+ children:
+ - id: RandomSpawner100
+ weight: 66
+ - id: FoodCheese
+ weight: 28
+ - id: IngotGold1
+ weight: 5
- type: entity
parent: BaseAction
interfaces:
enum.DisposalUnitUiKey.Key:
type: DisposalUnitBoundUserInterface
- - type: RatKingRummageable
+ - type: Rummageable
+ table: !type:NestedSelector
+ tableId: RatKingLoot
- type: SolutionContainerManager
solutions:
drainBuffer:
interfaces:
enum.DisposalUnitUiKey.Key:
type: DisposalUnitBoundUserInterface
- - type: RatKingRummageable
+ - type: Rummageable
+ table: !type:NestedSelector
+ tableId: RatKingLoot
- type: RequireProjectileTarget
- type: entity