Rat King Milsim + Buffs (#20190)
* rat king update * rummaging * buuuuunnnnncccchhh of shit * the last of it * make rat servants not ghost roles * pissma buff and cooldown
This commit is contained in:
@@ -11,3 +11,12 @@ public sealed partial class RatKingDomainActionEvent : InstantActionEvent
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public sealed partial class RatKingOrderActionEvent : InstantActionEvent
|
||||
{
|
||||
/// <summary>
|
||||
/// The type of order being given
|
||||
/// </summary>
|
||||
[DataField("type")]
|
||||
public RatKingOrderType Type;
|
||||
}
|
||||
|
||||
111
Content.Shared/RatKing/RatKingComponent.cs
Normal file
111
Content.Shared/RatKing/RatKingComponent.cs
Normal file
@@ -0,0 +1,111 @@
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
|
||||
namespace Content.Shared.RatKing;
|
||||
|
||||
[RegisterComponent, NetworkedComponent, Access(typeof(SharedRatKingSystem))]
|
||||
[AutoGenerateComponentState]
|
||||
public sealed partial class RatKingComponent : Component
|
||||
{
|
||||
[DataField("actionRaiseArmy", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
|
||||
public string ActionRaiseArmy = "ActionRatKingRaiseArmy";
|
||||
|
||||
/// <summary>
|
||||
/// The action for the Raise Army ability
|
||||
/// </summary>
|
||||
[DataField("actionRaiseArmyEntity")]
|
||||
public EntityUid? ActionRaiseArmyEntity;
|
||||
|
||||
/// <summary>
|
||||
/// The amount of hunger one use of Raise Army consumes
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("hungerPerArmyUse", required: true)]
|
||||
public float HungerPerArmyUse = 25f;
|
||||
|
||||
/// <summary>
|
||||
/// The entity prototype of the mob that Raise Army summons
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("armyMobSpawnId", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
|
||||
public string ArmyMobSpawnId = "MobRatServant";
|
||||
|
||||
[DataField("actionDomain", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
|
||||
public string ActionDomain = "ActionRatKingDomain";
|
||||
|
||||
/// <summary>
|
||||
/// The action for the Domain ability
|
||||
/// </summary>
|
||||
[DataField("actionDomainEntity")]
|
||||
public EntityUid? ActionDomainEntity;
|
||||
|
||||
/// <summary>
|
||||
/// The amount of hunger one use of Domain consumes
|
||||
/// </summary>
|
||||
[DataField("hungerPerDomainUse", required: true), ViewVariables(VVAccess.ReadWrite)]
|
||||
public float HungerPerDomainUse = 50f;
|
||||
|
||||
/// <summary>
|
||||
/// How many moles of Miasma are released after one us of Domain
|
||||
/// </summary>
|
||||
[DataField("molesMiasmaPerDomain"), ViewVariables(VVAccess.ReadWrite)]
|
||||
public float MolesMiasmaPerDomain = 100f;
|
||||
|
||||
/// <summary>
|
||||
/// The current order that the Rat King assigned.
|
||||
/// </summary>
|
||||
[DataField("currentOrders"), ViewVariables(VVAccess.ReadWrite)]
|
||||
[AutoNetworkedField]
|
||||
public RatKingOrderType CurrentOrder = RatKingOrderType.Loose;
|
||||
|
||||
/// <summary>
|
||||
/// The servants that the rat king is currently controlling
|
||||
/// </summary>
|
||||
[DataField("servants")]
|
||||
public HashSet<EntityUid> Servants = new();
|
||||
|
||||
[DataField("actionOrderStay", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
|
||||
public string ActionOrderStay = "ActionRatKingOrderStay";
|
||||
|
||||
[DataField("actionOrderStayEntity")]
|
||||
public EntityUid? ActionOrderStayEntity;
|
||||
|
||||
[DataField("actionOrderFollow", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
|
||||
public string ActionOrderFollow = "ActionRatKingOrderFollow";
|
||||
|
||||
[DataField("actionOrderFollowEntity")]
|
||||
public EntityUid? ActionOrderFollowEntity;
|
||||
|
||||
[DataField("actionOrderCheeseEm", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
|
||||
public string ActionOrderCheeseEm = "ActionRatKingOrderCheeseEm";
|
||||
|
||||
[DataField("actionOrderCheeseEmEntity")]
|
||||
public EntityUid? ActionOrderCheeseEmEntity;
|
||||
|
||||
[DataField("actionOrderLoose", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
|
||||
public string ActionOrderLoose = "ActionRatKingOrderLoose";
|
||||
|
||||
[DataField("actionOrderLooseEntity")]
|
||||
public EntityUid? ActionOrderLooseEntity;
|
||||
|
||||
/// <summary>
|
||||
/// A dictionary with an order type to the corresponding callout dataset.
|
||||
/// </summary>
|
||||
[DataField("orderCallouts")]
|
||||
public Dictionary<RatKingOrderType, string> OrderCallouts = new()
|
||||
{
|
||||
{ RatKingOrderType.Stay, "RatKingCommandStay" },
|
||||
{ RatKingOrderType.Follow, "RatKingCommandFollow" },
|
||||
{ RatKingOrderType.CheeseEm, "RatKingCommandCheeseEm" },
|
||||
{ RatKingOrderType.Loose, "RatKingCommandLoose" }
|
||||
};
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum RatKingOrderType : byte
|
||||
{
|
||||
Stay,
|
||||
Follow,
|
||||
CheeseEm,
|
||||
Loose
|
||||
}
|
||||
42
Content.Shared/RatKing/RatKingRummageableComponent.cs
Normal file
42
Content.Shared/RatKing/RatKingRummageableComponent.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using Content.Shared.Random;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
|
||||
namespace Content.Shared.RatKing;
|
||||
|
||||
/// <summary>
|
||||
/// This is used for entities that can be
|
||||
/// rummaged through by the rat king to get loot.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, Access(typeof(SharedRatKingSystem))]
|
||||
[AutoGenerateComponentState]
|
||||
public sealed partial class RatKingRummageableComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether or not this entity has been rummaged through already.
|
||||
/// </summary>
|
||||
[DataField("looted"), ViewVariables(VVAccess.ReadWrite)]
|
||||
[AutoNetworkedField]
|
||||
public bool Looted;
|
||||
|
||||
/// <summary>
|
||||
/// How long it takes to rummage through a rummageable container.
|
||||
/// </summary>
|
||||
[DataField("rummageDuration"), ViewVariables(VVAccess.ReadWrite)]
|
||||
[AutoNetworkedField]
|
||||
public float RummageDuration = 3f;
|
||||
|
||||
/// <summary>
|
||||
/// A weighted random entity prototype containing the different loot that rummaging can provide.
|
||||
/// </summary>
|
||||
[DataField("rummageLoot", customTypeSerializer: typeof(PrototypeIdSerializer<WeightedRandomEntityPrototype>)), ViewVariables(VVAccess.ReadWrite)]
|
||||
[AutoNetworkedField]
|
||||
public string RummageLoot = "RatKingLoot";
|
||||
|
||||
/// <summary>
|
||||
/// Sound played on rummage completion.
|
||||
/// </summary>
|
||||
[DataField("sound")]
|
||||
public SoundSpecifier? Sound = new SoundCollectionSpecifier("storageRustle");
|
||||
}
|
||||
15
Content.Shared/RatKing/RatKingServantComponent.cs
Normal file
15
Content.Shared/RatKing/RatKingServantComponent.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.RatKing;
|
||||
|
||||
[RegisterComponent, NetworkedComponent, Access(typeof(SharedRatKingSystem))]
|
||||
[AutoGenerateComponentState]
|
||||
public sealed partial class RatKingServantComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The king this rat belongs to.
|
||||
/// </summary>
|
||||
[DataField("king")]
|
||||
[AutoNetworkedField]
|
||||
public EntityUid? King;
|
||||
}
|
||||
163
Content.Shared/RatKing/SharedRatKingSystem.cs
Normal file
163
Content.Shared/RatKing/SharedRatKingSystem.cs
Normal file
@@ -0,0 +1,163 @@
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.Random;
|
||||
using Content.Shared.Random.Helpers;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Shared.Network;
|
||||
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)
|
||||
{
|
||||
if (!TryComp(uid, out ActionsComponent? comp))
|
||||
return;
|
||||
|
||||
_action.AddAction(uid, ref component.ActionRaiseArmyEntity, component.ActionRaiseArmy, holderComp: comp);
|
||||
_action.AddAction(uid, ref component.ActionDomainEntity, component.ActionDomain, holderComp: comp);
|
||||
_action.AddAction(uid, ref component.ActionOrderStayEntity, component.ActionOrderStay, holderComp: comp);
|
||||
_action.AddAction(uid, ref component.ActionOrderFollowEntity, component.ActionOrderFollow, holderComp: comp);
|
||||
_action.AddAction(uid, ref component.ActionOrderCheeseEmEntity, component.ActionOrderCheeseEm, holderComp: comp);
|
||||
_action.AddAction(uid, ref component.ActionOrderLooseEntity, component.ActionOrderLoose, holderComp: comp);
|
||||
|
||||
UpdateActions(uid, component);
|
||||
}
|
||||
|
||||
private void OnShutdown(EntityUid uid, RatKingComponent component, ComponentShutdown args)
|
||||
{
|
||||
foreach (var servant in component.Servants)
|
||||
{
|
||||
if (TryComp(servant, out RatKingServantComponent? servantComp))
|
||||
servantComp.King = null;
|
||||
}
|
||||
|
||||
if (!TryComp(uid, out ActionsComponent? comp))
|
||||
return;
|
||||
|
||||
_action.RemoveAction(uid, component.ActionRaiseArmyEntity, comp);
|
||||
_action.RemoveAction(uid, component.ActionDomainEntity, comp);
|
||||
_action.RemoveAction(uid, component.ActionOrderStayEntity, comp);
|
||||
_action.RemoveAction(uid, component.ActionOrderFollowEntity, comp);
|
||||
_action.RemoveAction(uid, component.ActionOrderCheeseEmEntity, comp);
|
||||
_action.RemoveAction(uid, component.ActionOrderLooseEntity, comp);
|
||||
}
|
||||
|
||||
private void OnOrderAction(EntityUid uid, RatKingComponent component, RatKingOrderActionEvent args)
|
||||
{
|
||||
if (component.CurrentOrder == args.Type)
|
||||
return;
|
||||
args.Handled = true;
|
||||
|
||||
component.CurrentOrder = args.Type;
|
||||
Dirty(uid, component);
|
||||
|
||||
DoCommandCallout(uid, component);
|
||||
UpdateActions(uid, component);
|
||||
UpdateAllServants(uid, component);
|
||||
}
|
||||
|
||||
private void OnServantShutdown(EntityUid uid, RatKingServantComponent component, ComponentShutdown args)
|
||||
{
|
||||
if (TryComp(component.King, out RatKingComponent? ratKingComponent))
|
||||
ratKingComponent.Servants.Remove(uid);
|
||||
}
|
||||
|
||||
private void UpdateActions(EntityUid uid, RatKingComponent? component = null)
|
||||
{
|
||||
if (!Resolve(uid, ref component))
|
||||
return;
|
||||
|
||||
_action.SetToggled(component.ActionOrderStayEntity, component.CurrentOrder == RatKingOrderType.Stay);
|
||||
_action.SetToggled(component.ActionOrderFollowEntity, component.CurrentOrder == RatKingOrderType.Follow);
|
||||
_action.SetToggled(component.ActionOrderCheeseEmEntity, component.CurrentOrder == RatKingOrderType.CheeseEm);
|
||||
_action.SetToggled(component.ActionOrderLooseEntity, component.CurrentOrder == RatKingOrderType.Loose);
|
||||
_action.StartUseDelay(component.ActionOrderStayEntity);
|
||||
_action.StartUseDelay(component.ActionOrderFollowEntity);
|
||||
_action.StartUseDelay(component.ActionOrderCheeseEmEntity);
|
||||
_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,
|
||||
BreakOnUserMove = true
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void OnDoAfterComplete(EntityUid uid, RatKingRummageableComponent component, RatKingRummageDoAfterEvent args)
|
||||
{
|
||||
if (args.Cancelled || component.Looted)
|
||||
return;
|
||||
|
||||
component.Looted = true;
|
||||
Dirty(uid, component);
|
||||
_audio.PlayPvs(component.Sound, uid);
|
||||
|
||||
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)
|
||||
{
|
||||
UpdateServantNpc(servant, component.CurrentOrder);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void UpdateServantNpc(EntityUid uid, RatKingOrderType orderType)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public virtual void DoCommandCallout(EntityUid uid, RatKingComponent component)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class RatKingRummageDoAfterEvent : SimpleDoAfterEvent
|
||||
{
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user