From: Nemanja <98561806+EmoGarbage404@users.noreply.github.com>
Date: Fri, 22 Sep 2023 20:01:05 +0000 (-0400)
Subject: Rat King Milsim + Buffs (#20190)
X-Git-Url: https://git.smokeofanarchy.ru/gitweb.cgi?a=commitdiff_plain;h=f16ff3a2d943845853cee0238216135b704857a5;p=space-station-14.git
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
---
diff --git a/Content.Client/RatKing/RatKingSystem.cs b/Content.Client/RatKing/RatKingSystem.cs
new file mode 100644
index 0000000000..25cc9fdf55
--- /dev/null
+++ b/Content.Client/RatKing/RatKingSystem.cs
@@ -0,0 +1,9 @@
+using Content.Shared.RatKing;
+
+namespace Content.Client.RatKing;
+
+///
+public sealed class RatKingSystem : SharedRatKingSystem
+{
+
+}
diff --git a/Content.Server/NPC/HTN/Preconditions/HasOrdersPrecondition.cs b/Content.Server/NPC/HTN/Preconditions/HasOrdersPrecondition.cs
new file mode 100644
index 0000000000..d2976c98a6
--- /dev/null
+++ b/Content.Server/NPC/HTN/Preconditions/HasOrdersPrecondition.cs
@@ -0,0 +1,13 @@
+namespace Content.Server.NPC.HTN.Preconditions;
+
+public sealed partial class HasOrdersPrecondition : HTNPrecondition
+{
+ [Dependency] private readonly IEntityManager _entManager = default!;
+
+ [DataField("orders", required: true)] public Enum Orders = default!;
+
+ public override bool IsMet(NPCBlackboard blackboard)
+ {
+ return Equals(blackboard.GetValueOrDefault(NPCBlackboard.CurrentOrders, _entManager), Orders);
+ }
+}
diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/Melee/MeleeOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/Melee/MeleeOperator.cs
index c40b037d98..32be027ec4 100644
--- a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/Melee/MeleeOperator.cs
+++ b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/Melee/MeleeOperator.cs
@@ -68,6 +68,20 @@ public sealed partial class MeleeOperator : HTNOperator, IHtnConditionalShutdown
blackboard.Remove(TargetKey);
}
+ public override void TaskShutdown(NPCBlackboard blackboard, HTNOperatorStatus status)
+ {
+ base.TaskShutdown(blackboard, status);
+
+ ConditionalShutdown(blackboard);
+ }
+
+ public override void PlanShutdown(NPCBlackboard blackboard)
+ {
+ base.PlanShutdown(blackboard);
+
+ ConditionalShutdown(blackboard);
+ }
+
public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime)
{
base.Update(blackboard, frameTime);
diff --git a/Content.Server/NPC/NPCBlackboard.cs b/Content.Server/NPC/NPCBlackboard.cs
index 294d9d8027..322ff0f85b 100644
--- a/Content.Server/NPC/NPCBlackboard.cs
+++ b/Content.Server/NPC/NPCBlackboard.cs
@@ -320,6 +320,16 @@ public sealed partial class NPCBlackboard : IEnumerable
+ /// A configurable "order" enum that can be given to an NPC from an external source.
+ ///
+ public const string CurrentOrders = "CurrentOrders";
+
+ ///
+ /// A configurable target that's ordered by external sources.
+ ///
+ public const string CurrentOrderedTarget = "CurrentOrderedTarget";
+
public IEnumerator> GetEnumerator()
{
return _blackboard.GetEnumerator();
diff --git a/Content.Server/NPC/Queries/Considerations/OrderedTargetCon.cs b/Content.Server/NPC/Queries/Considerations/OrderedTargetCon.cs
new file mode 100644
index 0000000000..be56d953c3
--- /dev/null
+++ b/Content.Server/NPC/Queries/Considerations/OrderedTargetCon.cs
@@ -0,0 +1,6 @@
+namespace Content.Server.NPC.Queries.Considerations;
+
+public sealed partial class OrderedTargetCon : UtilityConsideration
+{
+
+}
diff --git a/Content.Server/NPC/Systems/NPCUtilitySystem.cs b/Content.Server/NPC/Systems/NPCUtilitySystem.cs
index d9aec892ce..d764ab2c2e 100644
--- a/Content.Server/NPC/Systems/NPCUtilitySystem.cs
+++ b/Content.Server/NPC/Systems/NPCUtilitySystem.cs
@@ -191,6 +191,16 @@ public sealed class NPCUtilitySystem : EntitySystem
return 1f;
}
+ case OrderedTargetCon:
+ {
+ if (!blackboard.TryGetValue(NPCBlackboard.CurrentOrderedTarget, out var orderedTarget, EntityManager))
+ return 0f;
+
+ if (targetUid != orderedTarget)
+ return 0f;
+
+ return 1f;
+ }
case TargetAccessibleCon:
{
if (_container.TryGetContainingContainer(targetUid, out var container))
diff --git a/Content.Server/Pointing/EntitySystems/PointingSystem.cs b/Content.Server/Pointing/EntitySystems/PointingSystem.cs
index dc610ef409..8756134310 100644
--- a/Content.Server/Pointing/EntitySystems/PointingSystem.cs
+++ b/Content.Server/Pointing/EntitySystems/PointingSystem.cs
@@ -204,6 +204,11 @@ namespace Content.Server.Pointing.EntitySystems
viewerPointedAtMessage = Loc.GetString("pointing-system-point-at-you-other", ("otherName", playerName));
+ var ev = new AfterPointedAtEvent(pointed);
+ RaiseLocalEvent(player, ref ev);
+ var gotev = new AfterGotPointedAtEvent(player);
+ RaiseLocalEvent(pointed, ref gotev);
+
_adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(player):user} pointed at {ToPrettyString(pointed):target} {Transform(pointed).Coordinates}");
}
else
diff --git a/Content.Server/RatKing/RatKingComponent.cs b/Content.Server/RatKing/RatKingComponent.cs
deleted file mode 100644
index 22e9de4135..0000000000
--- a/Content.Server/RatKing/RatKingComponent.cs
+++ /dev/null
@@ -1,50 +0,0 @@
-using Robust.Shared.Prototypes;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
-
-namespace Content.Server.RatKing
-{
- [RegisterComponent]
- public sealed partial class RatKingComponent : Component
- {
- [DataField("actionRaiseArmy", customTypeSerializer: typeof(PrototypeIdSerializer))]
- public string ActionRaiseArmy = "ActionRatKingRaiseArmy";
-
- ///
- /// The action for the Raise Army ability
- ///
- [DataField("actionRaiseArmyEntity")] public EntityUid? ActionRaiseArmyEntity;
-
- ///
- /// The amount of hunger one use of Raise Army consumes
- ///
- [ViewVariables(VVAccess.ReadWrite), DataField("hungerPerArmyUse", required: true)]
- public float HungerPerArmyUse = 25f;
-
- ///
- /// The entity prototype of the mob that Raise Army summons
- ///
- [ViewVariables(VVAccess.ReadWrite), DataField("armyMobSpawnId", customTypeSerializer: typeof(PrototypeIdSerializer))]
- public string ArmyMobSpawnId = "MobRatServant";
-
- [DataField("actionDomain", customTypeSerializer: typeof(PrototypeIdSerializer))]
- public string ActionDomain = "ActionRatKingDomain";
-
- ///
- /// The action for the Domain ability
- ///
- [DataField("actionDomainEntity")]
- public EntityUid? ActionDomainEntity;
-
- ///
- /// The amount of hunger one use of Domain consumes
- ///
- [ViewVariables(VVAccess.ReadWrite), DataField("hungerPerDomainUse", required: true)]
- public float HungerPerDomainUse = 50f;
-
- ///
- /// How many moles of Miasma are released after one us of Domain
- ///
- [DataField("molesMiasmaPerDomain")]
- public float MolesMiasmaPerDomain = 100f;
- }
-}
diff --git a/Content.Server/RatKing/RatKingSystem.cs b/Content.Server/RatKing/RatKingSystem.cs
index cd3cbbb691..3cf6d48751 100644
--- a/Content.Server/RatKing/RatKingSystem.cs
+++ b/Content.Server/RatKing/RatKingSystem.cs
@@ -1,19 +1,30 @@
-using Content.Server.Actions;
+using System.Numerics;
using Content.Server.Atmos.EntitySystems;
+using Content.Server.Chat.Systems;
+using Content.Server.NPC;
+using Content.Server.NPC.HTN;
+using Content.Server.NPC.Systems;
using Content.Server.Popups;
using Content.Shared.Atmos;
+using Content.Shared.Dataset;
using Content.Shared.Nutrition.Components;
using Content.Shared.Nutrition.EntitySystems;
+using Content.Shared.Pointing;
using Content.Shared.RatKing;
using Robust.Server.GameObjects;
+using Robust.Shared.Map;
+using Robust.Shared.Random;
namespace Content.Server.RatKing
{
- public sealed class RatKingSystem : EntitySystem
+ ///
+ public sealed class RatKingSystem : SharedRatKingSystem
{
- [Dependency] private readonly ActionsSystem _action = default!;
[Dependency] private readonly AtmosphereSystem _atmos = default!;
+ [Dependency] private readonly ChatSystem _chat = default!;
+ [Dependency] private readonly HTNSystem _htn = default!;
[Dependency] private readonly HungerSystem _hunger = default!;
+ [Dependency] private readonly NPCSystem _npc = default!;
[Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly TransformSystem _xform = default!;
@@ -21,16 +32,9 @@ namespace Content.Server.RatKing
{
base.Initialize();
- SubscribeLocalEvent(OnMapInit);
-
SubscribeLocalEvent(OnRaiseArmy);
SubscribeLocalEvent(OnDomain);
- }
-
- private void OnMapInit(EntityUid uid, RatKingComponent component, MapInitEvent args)
- {
- _action.AddAction(uid, ref component.ActionRaiseArmyEntity, component.ActionRaiseArmy);
- _action.AddAction(uid, ref component.ActionDomainEntity, component.ActionDomain);
+ SubscribeLocalEvent(OnPointedAt);
}
///
@@ -52,7 +56,14 @@ namespace Content.Server.RatKing
}
args.Handled = true;
_hunger.ModifyHunger(uid, -component.HungerPerArmyUse, hunger);
- Spawn(component.ArmyMobSpawnId, Transform(uid).Coordinates); //spawn the little mouse boi
+ var servant = Spawn(component.ArmyMobSpawnId, Transform(uid).Coordinates);
+ var comp = EnsureComp(servant);
+ comp.King = uid;
+ Dirty(servant, comp);
+
+ component.Servants.Add(servant);
+ _npc.SetBlackboard(servant, NPCBlackboard.FollowTarget, new EntityCoordinates(uid, Vector2.Zero));
+ UpdateServantNpc(servant, component.CurrentOrder);
}
///
@@ -83,5 +94,42 @@ namespace Content.Server.RatKing
var tileMix = _atmos.GetTileMixture(transform.GridUid, transform.MapUid, indices, true);
tileMix?.AdjustMoles(Gas.Miasma, component.MolesMiasmaPerDomain);
}
+
+ private void OnPointedAt(EntityUid uid, RatKingComponent component, ref AfterPointedAtEvent args)
+ {
+ if (component.CurrentOrder != RatKingOrderType.CheeseEm)
+ return;
+
+ foreach (var servant in component.Servants)
+ {
+ _npc.SetBlackboard(servant, NPCBlackboard.CurrentOrderedTarget, args.Pointed);
+ }
+ }
+
+ public override void UpdateServantNpc(EntityUid uid, RatKingOrderType orderType)
+ {
+ base.UpdateServantNpc(uid, orderType);
+
+ if (!TryComp(uid, out var htn))
+ return;
+
+ if (htn.Plan != null)
+ _htn.ShutdownPlan(htn);
+
+ _npc.SetBlackboard(uid, NPCBlackboard.CurrentOrders, orderType);
+ _htn.Replan(htn);
+ }
+
+ public override void DoCommandCallout(EntityUid uid, RatKingComponent component)
+ {
+ base.DoCommandCallout(uid, component);
+
+ if (!component.OrderCallouts.TryGetValue(component.CurrentOrder, out var datasetId) ||
+ !PrototypeManager.TryIndex(datasetId, out var datasetPrototype))
+ return;
+
+ var msg = Random.Pick(datasetPrototype.Values);
+ _chat.TrySendInGameICMessage(uid, msg, InGameICChatType.Speak, true);
+ }
}
}
diff --git a/Content.Shared/Actions/SharedActionsSystem.cs b/Content.Shared/Actions/SharedActionsSystem.cs
index 3d476dd48c..dc0afc8af7 100644
--- a/Content.Shared/Actions/SharedActionsSystem.cs
+++ b/Content.Shared/Actions/SharedActionsSystem.cs
@@ -204,6 +204,19 @@ public abstract class SharedActionsSystem : EntitySystem
Dirty(actionId.Value, action);
}
+ public void StartUseDelay(EntityUid? actionId)
+ {
+ if (actionId == null)
+ return;
+
+ var action = GetActionData(actionId);
+ if (action == null || action.UseDelay == null)
+ return;
+
+ action.Cooldown = (GameTiming.CurTime, GameTiming.CurTime + action.UseDelay.Value);
+ Dirty(actionId.Value, action);
+ }
+
#region ComponentStateManagement
public virtual void Dirty(EntityUid? actionId)
{
diff --git a/Content.Shared/Pointing/PointingEvents.cs b/Content.Shared/Pointing/PointingEvents.cs
index 90c31bcfec..878bd35c7e 100644
--- a/Content.Shared/Pointing/PointingEvents.cs
+++ b/Content.Shared/Pointing/PointingEvents.cs
@@ -17,3 +17,17 @@ public sealed class PointingAttemptEvent : EntityEventArgs
Target = target;
}
}
+
+///
+/// Raised on the entity who is pointing after they point at something.
+///
+///
+[ByRefEvent]
+public readonly record struct AfterPointedAtEvent(EntityUid Pointed);
+
+///
+/// Raised on an entity after they are pointed at by another entity.
+///
+///
+[ByRefEvent]
+public readonly record struct AfterGotPointedAtEvent(EntityUid Pointer);
diff --git a/Content.Shared/RatKing/RatKingActions.cs b/Content.Shared/RatKing/RatKingActions.cs
index 551b27a7a4..e2031e972b 100644
--- a/Content.Shared/RatKing/RatKingActions.cs
+++ b/Content.Shared/RatKing/RatKingActions.cs
@@ -11,3 +11,12 @@ public sealed partial class RatKingDomainActionEvent : InstantActionEvent
{
}
+
+public sealed partial class RatKingOrderActionEvent : InstantActionEvent
+{
+ ///
+ /// The type of order being given
+ ///
+ [DataField("type")]
+ public RatKingOrderType Type;
+}
diff --git a/Content.Shared/RatKing/RatKingComponent.cs b/Content.Shared/RatKing/RatKingComponent.cs
new file mode 100644
index 0000000000..43c2858de8
--- /dev/null
+++ b/Content.Shared/RatKing/RatKingComponent.cs
@@ -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))]
+ public string ActionRaiseArmy = "ActionRatKingRaiseArmy";
+
+ ///
+ /// The action for the Raise Army ability
+ ///
+ [DataField("actionRaiseArmyEntity")]
+ public EntityUid? ActionRaiseArmyEntity;
+
+ ///
+ /// The amount of hunger one use of Raise Army consumes
+ ///
+ [ViewVariables(VVAccess.ReadWrite), DataField("hungerPerArmyUse", required: true)]
+ public float HungerPerArmyUse = 25f;
+
+ ///
+ /// The entity prototype of the mob that Raise Army summons
+ ///
+ [ViewVariables(VVAccess.ReadWrite), DataField("armyMobSpawnId", customTypeSerializer: typeof(PrototypeIdSerializer))]
+ public string ArmyMobSpawnId = "MobRatServant";
+
+ [DataField("actionDomain", customTypeSerializer: typeof(PrototypeIdSerializer))]
+ public string ActionDomain = "ActionRatKingDomain";
+
+ ///
+ /// The action for the Domain ability
+ ///
+ [DataField("actionDomainEntity")]
+ public EntityUid? ActionDomainEntity;
+
+ ///
+ /// The amount of hunger one use of Domain consumes
+ ///
+ [DataField("hungerPerDomainUse", required: true), ViewVariables(VVAccess.ReadWrite)]
+ public float HungerPerDomainUse = 50f;
+
+ ///
+ /// How many moles of Miasma are released after one us of Domain
+ ///
+ [DataField("molesMiasmaPerDomain"), ViewVariables(VVAccess.ReadWrite)]
+ public float MolesMiasmaPerDomain = 100f;
+
+ ///
+ /// The current order that the Rat King assigned.
+ ///
+ [DataField("currentOrders"), ViewVariables(VVAccess.ReadWrite)]
+ [AutoNetworkedField]
+ public RatKingOrderType CurrentOrder = RatKingOrderType.Loose;
+
+ ///
+ /// The servants that the rat king is currently controlling
+ ///
+ [DataField("servants")]
+ public HashSet Servants = new();
+
+ [DataField("actionOrderStay", customTypeSerializer: typeof(PrototypeIdSerializer))]
+ public string ActionOrderStay = "ActionRatKingOrderStay";
+
+ [DataField("actionOrderStayEntity")]
+ public EntityUid? ActionOrderStayEntity;
+
+ [DataField("actionOrderFollow", customTypeSerializer: typeof(PrototypeIdSerializer))]
+ public string ActionOrderFollow = "ActionRatKingOrderFollow";
+
+ [DataField("actionOrderFollowEntity")]
+ public EntityUid? ActionOrderFollowEntity;
+
+ [DataField("actionOrderCheeseEm", customTypeSerializer: typeof(PrototypeIdSerializer))]
+ public string ActionOrderCheeseEm = "ActionRatKingOrderCheeseEm";
+
+ [DataField("actionOrderCheeseEmEntity")]
+ public EntityUid? ActionOrderCheeseEmEntity;
+
+ [DataField("actionOrderLoose", customTypeSerializer: typeof(PrototypeIdSerializer))]
+ public string ActionOrderLoose = "ActionRatKingOrderLoose";
+
+ [DataField("actionOrderLooseEntity")]
+ public EntityUid? ActionOrderLooseEntity;
+
+ ///
+ /// A dictionary with an order type to the corresponding callout dataset.
+ ///
+ [DataField("orderCallouts")]
+ public Dictionary OrderCallouts = new()
+ {
+ { RatKingOrderType.Stay, "RatKingCommandStay" },
+ { RatKingOrderType.Follow, "RatKingCommandFollow" },
+ { RatKingOrderType.CheeseEm, "RatKingCommandCheeseEm" },
+ { RatKingOrderType.Loose, "RatKingCommandLoose" }
+ };
+}
+
+[Serializable, NetSerializable]
+public enum RatKingOrderType : byte
+{
+ Stay,
+ Follow,
+ CheeseEm,
+ Loose
+}
diff --git a/Content.Shared/RatKing/RatKingRummageableComponent.cs b/Content.Shared/RatKing/RatKingRummageableComponent.cs
new file mode 100644
index 0000000000..f3a389ef76
--- /dev/null
+++ b/Content.Shared/RatKing/RatKingRummageableComponent.cs
@@ -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;
+
+///
+/// This is used for entities that can be
+/// rummaged through by the rat king to get loot.
+///
+[RegisterComponent, NetworkedComponent, Access(typeof(SharedRatKingSystem))]
+[AutoGenerateComponentState]
+public sealed partial class RatKingRummageableComponent : Component
+{
+ ///
+ /// Whether or not this entity has been rummaged through already.
+ ///
+ [DataField("looted"), ViewVariables(VVAccess.ReadWrite)]
+ [AutoNetworkedField]
+ public bool Looted;
+
+ ///
+ /// How long it takes to rummage through a rummageable container.
+ ///
+ [DataField("rummageDuration"), ViewVariables(VVAccess.ReadWrite)]
+ [AutoNetworkedField]
+ public float RummageDuration = 3f;
+
+ ///
+ /// A weighted random entity prototype containing the different loot that rummaging can provide.
+ ///
+ [DataField("rummageLoot", customTypeSerializer: typeof(PrototypeIdSerializer)), ViewVariables(VVAccess.ReadWrite)]
+ [AutoNetworkedField]
+ public string RummageLoot = "RatKingLoot";
+
+ ///
+ /// Sound played on rummage completion.
+ ///
+ [DataField("sound")]
+ public SoundSpecifier? Sound = new SoundCollectionSpecifier("storageRustle");
+}
diff --git a/Content.Shared/RatKing/RatKingServantComponent.cs b/Content.Shared/RatKing/RatKingServantComponent.cs
new file mode 100644
index 0000000000..f6e8d0110e
--- /dev/null
+++ b/Content.Shared/RatKing/RatKingServantComponent.cs
@@ -0,0 +1,15 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.RatKing;
+
+[RegisterComponent, NetworkedComponent, Access(typeof(SharedRatKingSystem))]
+[AutoGenerateComponentState]
+public sealed partial class RatKingServantComponent : Component
+{
+ ///
+ /// The king this rat belongs to.
+ ///
+ [DataField("king")]
+ [AutoNetworkedField]
+ public EntityUid? King;
+}
diff --git a/Content.Shared/RatKing/SharedRatKingSystem.cs b/Content.Shared/RatKing/SharedRatKingSystem.cs
new file mode 100644
index 0000000000..2d39815387
--- /dev/null
+++ b/Content.Shared/RatKing/SharedRatKingSystem.cs
@@ -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!;
+
+ ///
+ public override void Initialize()
+ {
+ SubscribeLocalEvent(OnStartup);
+ SubscribeLocalEvent(OnShutdown);
+ SubscribeLocalEvent(OnOrderAction);
+
+ SubscribeLocalEvent(OnServantShutdown);
+
+ SubscribeLocalEvent>(OnGetVerb);
+ SubscribeLocalEvent(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 args)
+ {
+ if (!HasComp(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(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
+{
+
+}
diff --git a/Resources/Locale/en-US/animals/rat-king/rat-king.ftl b/Resources/Locale/en-US/animals/rat-king/rat-king.ftl
index 1c587f4328..f6235a2708 100644
--- a/Resources/Locale/en-US/animals/rat-king/rat-king.ftl
+++ b/Resources/Locale/en-US/animals/rat-king/rat-king.ftl
@@ -1,3 +1,5 @@
rat-king-domain-popup = A cloud of miasma is released into the air!
rat-king-too-hungry = You are too hungry to use this ability!
+
+rat-king-rummage-text = Rummage
diff --git a/Resources/Prototypes/Datasets/rat_king_commands.yml b/Resources/Prototypes/Datasets/rat_king_commands.yml
new file mode 100644
index 0000000000..c53d1e135b
--- /dev/null
+++ b/Resources/Prototypes/Datasets/rat_king_commands.yml
@@ -0,0 +1,26 @@
+- type: dataset
+ id: RatKingCommandStay
+ values:
+ - "Sit!"
+ - "Stay!"
+ - "Stop!"
+
+- type: dataset
+ id: RatKingCommandFollow
+ values:
+ - "Heel!"
+ - "Follow!"
+
+- type: dataset
+ id: RatKingCommandCheeseEm
+ values:
+ - "Attack!"
+ - "Sic!"
+ - "Kill!"
+ - "Cheese 'Em!"
+
+- type: dataset
+ id: RatKingCommandLoose
+ values:
+ - "Free!"
+ - "Loose!"
diff --git a/Resources/Prototypes/Entities/Markers/Spawners/Random/trash.yml b/Resources/Prototypes/Entities/Markers/Spawners/Random/trash.yml
index 60a7098328..4806755a11 100644
--- a/Resources/Prototypes/Entities/Markers/Spawners/Random/trash.yml
+++ b/Resources/Prototypes/Entities/Markers/Spawners/Random/trash.yml
@@ -2,6 +2,7 @@
name: Trash Spawner
id: RandomSpawner
parent: MarkerBase
+ suffix: 50
components:
- type: Sprite
layers:
@@ -35,3 +36,13 @@
offset: 0.2
placement:
mode: AlignTileAny
+
+- type: entity
+ parent: RandomSpawner
+ id: RandomSpawner100
+ suffix: 100
+ placement:
+ mode: AlignTileAny
+ components:
+ - type: RandomSpawner
+ chance: 1
diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml b/Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml
index 9472954cbb..a421a42abc 100644
--- a/Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml
+++ b/Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml
@@ -21,7 +21,7 @@
factions:
- SimpleHostile
- type: Sprite
- drawdepth: Mobs
+ drawdepth: SmallMobs
sprite: Mobs/Animals/regalrat.rsi
layers:
- map: ["enum.DamageStateVisualLayers.Base"]
@@ -78,6 +78,8 @@
states:
Alive:
Base: regalrat
+ Critical:
+ Base: critical
Dead:
Base: dead
- type: GhostRole
@@ -89,7 +91,6 @@
- type: Tag
tags:
- CannotSuicide
- - DoorBumpOpener
- FootstepSound
- type: NoSlip
- type: RatKing
@@ -118,7 +119,6 @@
suffix: Buff
components:
- type: Sprite
- drawdepth: Mobs
sprite: Mobs/Animals/buffrat.rsi
scale: 1.2, 1.2
layers:
@@ -139,17 +139,6 @@
damage:
types:
Blunt: 66 #oof ouch owie my bones
- - type: Fixtures
- fixtures:
- fix1:
- shape:
- !type:PhysShapeCircle
- radius: 0.35
- density: 400
- mask:
- - MobMask
- layer:
- - MobLayer
- type: SlowOnDamage
speedModifierThresholds:
200: 0.7
@@ -163,6 +152,7 @@
id: MobRatServant
parent: SimpleMobBase
description: He's da mini rat. He don't make da roolz.
+ noSpawn: true #Must be configured to a King or the AI breaks.
components:
- type: CombatMode
- type: MovementSpeedModifier
@@ -172,7 +162,14 @@
- type: MobMover
- type: HTN
rootTask:
- task: SimpleHostileCompound
+ task: RatServantCompound
+ blackboard:
+ IdleRange: !type:Single
+ 3.5
+ FollowCloseRange: !type:Single
+ 2.0
+ FollowRange: !type:Single
+ 3.0
- type: Reactive
groups:
Flammable: [Touch]
@@ -254,16 +251,9 @@
Female: Mouse
Unsexed: Mouse
wilhelmProbability: 0.001
- - type: GhostRole
- makeSentient: true
- name: ghost-role-information-rat-servant-name
- description: ghost-role-information-rat-servant-description
- rules: ghost-role-information-rat-servant-rules
- - type: GhostTakeoverAvailable
- type: Tag
tags:
- CannotSuicide
- - DoorBumpOpener
- FootstepSound
- type: NoSlip
- type: MobPrice
@@ -276,6 +266,13 @@
guides:
- MinorAntagonists
+- type: weightedRandomEntity
+ id: RatKingLoot
+ weights:
+ RandomSpawner100: 66 #garbage
+ FoodCheese: 28 #food
+ IngotGold1: 5 #loot
+
- type: entity
id: ActionRatKingRaiseArmy
name: Raise Army
@@ -283,10 +280,11 @@
noSpawn: true
components:
- type: InstantAction
- icon: Interface/Actions/ratKingArmy.png
- itemIconStyle: NoItem
- event: !type:RatKingRaiseArmyActionEvent
useDelay: 4
+ icon:
+ sprite: Interface/Actions/actions_rat_king.rsi
+ state: ratKingArmy
+ event: !type:RatKingRaiseArmyActionEvent
- type: entity
id: ActionRatKingDomain
@@ -295,7 +293,84 @@
noSpawn: true
components:
- type: InstantAction
- useDelay: 10
- icon: Interface/Actions/ratKingDomain.png
- itemIconStyle: NoItem
+ useDelay: 6
+ icon:
+ sprite: Interface/Actions/actions_rat_king.rsi
+ state: ratKingDomain
event: !type:RatKingDomainActionEvent
+
+- type: entity
+ id: ActionRatKingOrderStay
+ name: Stay
+ description: Command your army to stand in place.
+ noSpawn: true
+ components:
+ - type: InstantAction
+ useDelay: 1
+ icon:
+ sprite: Interface/Actions/actions_rat_king.rsi
+ state: stayOff
+ iconOn:
+ sprite: Interface/Actions/actions_rat_king.rsi
+ state: stay
+ event:
+ !type:RatKingOrderActionEvent
+ type: Stay
+ priority: 5
+
+- type: entity
+ id: ActionRatKingOrderFollow
+ name: Follow
+ description: Command your army to follow you around.
+ noSpawn: true
+ components:
+ - type: InstantAction
+ useDelay: 1
+ icon:
+ sprite: Interface/Actions/actions_rat_king.rsi
+ state: followOff
+ iconOn:
+ sprite: Interface/Actions/actions_rat_king.rsi
+ state: follow
+ event:
+ !type:RatKingOrderActionEvent
+ type: Follow
+ priority: 6
+
+- type: entity
+ id: ActionRatKingOrderCheeseEm
+ name: Cheese 'Em
+ description: Command your army to attack whoever you point at.
+ noSpawn: true
+ components:
+ - type: InstantAction
+ useDelay: 1
+ icon:
+ sprite: Interface/Actions/actions_rat_king.rsi
+ state: attackOff
+ iconOn:
+ sprite: Interface/Actions/actions_rat_king.rsi
+ state: attack
+ event:
+ !type:RatKingOrderActionEvent
+ type: CheeseEm
+ priority: 7
+
+- type: entity
+ id: ActionRatKingOrderLoose
+ name: Loose
+ description: Command your army to act at their own will.
+ noSpawn: true
+ components:
+ - type: InstantAction
+ useDelay: 1
+ icon:
+ sprite: Interface/Actions/actions_rat_king.rsi
+ state: looseOff
+ iconOn:
+ sprite: Interface/Actions/actions_rat_king.rsi
+ state: loose
+ event:
+ !type:RatKingOrderActionEvent
+ type: Loose
+ priority: 8
diff --git a/Resources/Prototypes/Entities/Objects/Specific/rehydrateable.yml b/Resources/Prototypes/Entities/Objects/Specific/rehydrateable.yml
index 6521fdf61c..8a2e4a29ce 100644
--- a/Resources/Prototypes/Entities/Objects/Specific/rehydrateable.yml
+++ b/Resources/Prototypes/Entities/Objects/Specific/rehydrateable.yml
@@ -132,7 +132,6 @@
solution: cube
- type: Rehydratable
possibleSpawns:
- - MobRatServant
- MobCarpHolo
- MobXenoRavager
- MobAngryBee
diff --git a/Resources/Prototypes/Entities/Structures/Piping/Disposal/units.yml b/Resources/Prototypes/Entities/Structures/Piping/Disposal/units.yml
index c8792bc3ba..40fb09f7ef 100644
--- a/Resources/Prototypes/Entities/Structures/Piping/Disposal/units.yml
+++ b/Resources/Prototypes/Entities/Structures/Piping/Disposal/units.yml
@@ -86,6 +86,7 @@
interfaces:
- key: enum.DisposalUnitUiKey.Key
type: DisposalUnitBoundUserInterface
+ - type: RatKingRummageable
- type: entity
id: MailingUnit
diff --git a/Resources/Prototypes/GameRules/events.yml b/Resources/Prototypes/GameRules/events.yml
index a8f5d50684..23732b9762 100644
--- a/Resources/Prototypes/GameRules/events.yml
+++ b/Resources/Prototypes/GameRules/events.yml
@@ -176,13 +176,11 @@
- type: VentCrittersRule
entries:
- id: MobMouse
- prob: 0.015
+ prob: 0.02
- id: MobMouse1
- prob: 0.015
+ prob: 0.02
- id: MobMouse2
- prob: 0.015
- - id: MobRatServant
- prob: 0.015
+ prob: 0.02
specialEntries:
- id: SpawnPointGhostRatKing
prob: 0.005
diff --git a/Resources/Prototypes/NPCs/Combat/melee.yml b/Resources/Prototypes/NPCs/Combat/melee.yml
index e35dc82050..282e794ee7 100644
--- a/Resources/Prototypes/NPCs/Combat/melee.yml
+++ b/Resources/Prototypes/NPCs/Combat/melee.yml
@@ -25,6 +25,28 @@
- !type:HTNCompoundTask
task: MeleeAttackTargetCompound
+- type: htnCompound
+ id: RatServantCombatCompound
+ branches:
+ - preconditions:
+ - !type:ActiveHandComponentPrecondition
+ components:
+ - type: MeleeWeapon
+ damage:
+ types:
+ Brute: 0
+ invert: true
+ tasks:
+ - !type:HTNCompoundTask
+ task: PickupMeleeCompound
+
+ - tasks:
+ - !type:HTNPrimitiveTask
+ operator: !type:UtilityOperator
+ proto: OrderedTargets
+ - !type:HTNCompoundTask
+ task: MeleeAttackOrderedTargetCompound
+
- type: htnCompound
id: PickupMeleeCompound
branches:
@@ -79,3 +101,36 @@
id: MeleeService
proto: NearbyMeleeTargets
key: Target
+
+- type: htnCompound
+ id: MeleeAttackOrderedTargetCompound
+ preconditions:
+ - !type:KeyExistsPrecondition
+ key: Target
+ branches:
+ - tasks:
+ - !type:HTNPrimitiveTask
+ operator: !type:MoveToOperator
+ shutdownState: PlanFinished
+ pathfindInPlanning: true
+ removeKeyOnFinish: false
+ targetKey: TargetCoordinates
+ pathfindKey: TargetPathfind
+ rangeKey: MeleeRange
+ - !type:HTNPrimitiveTask
+ operator: !type:JukeOperator
+ jukeType: Away
+ - !type:HTNPrimitiveTask
+ operator: !type:MeleeOperator
+ targetKey: Target
+ preconditions:
+ - !type:KeyExistsPrecondition
+ key: Target
+ - !type:TargetInRangePrecondition
+ targetKey: Target
+ rangeKey: MeleeRange
+ services:
+ - !type:UtilityService
+ id: MeleeService
+ proto: OrderedTargets
+ key: Target
diff --git a/Resources/Prototypes/NPCs/mob.yml b/Resources/Prototypes/NPCs/mob.yml
index 61ab47c5b2..bba5a76ad8 100644
--- a/Resources/Prototypes/NPCs/mob.yml
+++ b/Resources/Prototypes/NPCs/mob.yml
@@ -9,6 +9,16 @@
- !type:HTNCompoundTask
task: IdleCompound
+- type: htnCompound
+ id: RatServantTargetAttackCompound
+ branches:
+ - tasks:
+ - !type:HTNCompoundTask
+ task: RatServantCombatCompound
+ - tasks:
+ - !type:HTNCompoundTask
+ task: IdleCompound
+
- type: htnCompound
id: MouseCompound
branches:
diff --git a/Resources/Prototypes/NPCs/regalrat.yml b/Resources/Prototypes/NPCs/regalrat.yml
new file mode 100644
index 0000000000..8685a51236
--- /dev/null
+++ b/Resources/Prototypes/NPCs/regalrat.yml
@@ -0,0 +1,28 @@
+- type: htnCompound
+ id: RatServantCompound
+ branches:
+ - preconditions:
+ - !type:HasOrdersPrecondition
+ orders: enum.RatKingOrderType.Stay
+ tasks:
+ - !type:HTNCompoundTask
+ task: IdleCompound
+ - preconditions:
+ - !type:HasOrdersPrecondition
+ orders: enum.RatKingOrderType.Follow
+ tasks:
+ - !type:HTNCompoundTask
+ task: FollowCompound
+ - preconditions:
+ - !type:HasOrdersPrecondition
+ orders: enum.RatKingOrderType.CheeseEm
+ tasks:
+ - !type:HTNCompoundTask
+ task: RatServantTargetAttackCompound
+ - preconditions:
+ - !type:HasOrdersPrecondition
+ orders: enum.RatKingOrderType.Loose
+ tasks:
+ - !type:HTNCompoundTask
+ task: SimpleHostileCompound
+
diff --git a/Resources/Prototypes/NPCs/utility_queries.yml b/Resources/Prototypes/NPCs/utility_queries.yml
index b6e037fdd0..d62e1a7e8c 100644
--- a/Resources/Prototypes/NPCs/utility_queries.yml
+++ b/Resources/Prototypes/NPCs/utility_queries.yml
@@ -99,6 +99,27 @@
- !type:TargetInLOSOrCurrentCon
curve: !type:BoolCurve
+- type: utilityQuery
+ id: OrderedTargets
+ query:
+ - !type:NearbyHostilesQuery
+ considerations:
+ - !type:TargetIsAliveCon
+ curve: !type:BoolCurve
+ - !type:TargetDistanceCon
+ curve: !type:PresetCurve
+ preset: TargetDistance
+ - !type:TargetHealthCon
+ curve: !type:PresetCurve
+ preset: TargetHealth
+ - !type:TargetAccessibleCon
+ curve: !type:BoolCurve
+ - !type:TargetInLOSOrCurrentCon
+ curve: !type:BoolCurve
+ # they gotta be what we ordered
+ - !type:OrderedTargetCon
+ curve: !type:BoolCurve
+
- type: utilityQuery
id: NearbyMeleeWeapons
query:
diff --git a/Resources/Prototypes/Reagents/gases.yml b/Resources/Prototypes/Reagents/gases.yml
index f3f298a721..9fa06f632c 100644
--- a/Resources/Prototypes/Reagents/gases.yml
+++ b/Resources/Prototypes/Reagents/gases.yml
@@ -234,10 +234,9 @@
scaleByQuantity: true
ignoreResistances: true
damage:
- types:
- Blunt: -4
- Slash: -3
- Piercing: -3
+ Groups:
+ Brute: -5
+ Burn: -5
- type: reagent
id: NitrousOxide
diff --git a/Resources/Textures/Interface/Actions/actions_rat_king.rsi/attack.png b/Resources/Textures/Interface/Actions/actions_rat_king.rsi/attack.png
new file mode 100644
index 0000000000..35f663c66e
Binary files /dev/null and b/Resources/Textures/Interface/Actions/actions_rat_king.rsi/attack.png differ
diff --git a/Resources/Textures/Interface/Actions/actions_rat_king.rsi/attackOff.png b/Resources/Textures/Interface/Actions/actions_rat_king.rsi/attackOff.png
new file mode 100644
index 0000000000..7a190584e5
Binary files /dev/null and b/Resources/Textures/Interface/Actions/actions_rat_king.rsi/attackOff.png differ
diff --git a/Resources/Textures/Interface/Actions/actions_rat_king.rsi/follow.png b/Resources/Textures/Interface/Actions/actions_rat_king.rsi/follow.png
new file mode 100644
index 0000000000..dd669304ac
Binary files /dev/null and b/Resources/Textures/Interface/Actions/actions_rat_king.rsi/follow.png differ
diff --git a/Resources/Textures/Interface/Actions/actions_rat_king.rsi/followOff.png b/Resources/Textures/Interface/Actions/actions_rat_king.rsi/followOff.png
new file mode 100644
index 0000000000..a0491c5a0e
Binary files /dev/null and b/Resources/Textures/Interface/Actions/actions_rat_king.rsi/followOff.png differ
diff --git a/Resources/Textures/Interface/Actions/actions_rat_king.rsi/loose.png b/Resources/Textures/Interface/Actions/actions_rat_king.rsi/loose.png
new file mode 100644
index 0000000000..bfbc45daed
Binary files /dev/null and b/Resources/Textures/Interface/Actions/actions_rat_king.rsi/loose.png differ
diff --git a/Resources/Textures/Interface/Actions/actions_rat_king.rsi/looseOff.png b/Resources/Textures/Interface/Actions/actions_rat_king.rsi/looseOff.png
new file mode 100644
index 0000000000..60db395e54
Binary files /dev/null and b/Resources/Textures/Interface/Actions/actions_rat_king.rsi/looseOff.png differ
diff --git a/Resources/Textures/Interface/Actions/actions_rat_king.rsi/meta.json b/Resources/Textures/Interface/Actions/actions_rat_king.rsi/meta.json
new file mode 100644
index 0000000000..c9b6bfe9da
--- /dev/null
+++ b/Resources/Textures/Interface/Actions/actions_rat_king.rsi/meta.json
@@ -0,0 +1,41 @@
+{
+ "version": 1,
+ "license": "CC0-1.0",
+ "copyright": "Created by EmoGarbage404 (github). ratKingArmy and ratKingDomain taken from https://github.com/tgstation/tgstation/commit/3d049e69fe71a0be2133005e65ea469135d648c8",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "attack"
+ },
+ {
+ "name": "attackOff"
+ },
+ {
+ "name": "follow"
+ },
+ {
+ "name": "followOff"
+ },
+ {
+ "name": "loose"
+ },
+ {
+ "name": "looseOff"
+ },
+ {
+ "name": "stay"
+ },
+ {
+ "name": "stayOff"
+ },
+ {
+ "name": "ratKingArmy"
+ },
+ {
+ "name": "ratKingDomain"
+ }
+ ]
+}
diff --git a/Resources/Textures/Interface/Actions/ratKingArmy.png b/Resources/Textures/Interface/Actions/actions_rat_king.rsi/ratKingArmy.png
similarity index 100%
rename from Resources/Textures/Interface/Actions/ratKingArmy.png
rename to Resources/Textures/Interface/Actions/actions_rat_king.rsi/ratKingArmy.png
diff --git a/Resources/Textures/Interface/Actions/ratKingDomain.png b/Resources/Textures/Interface/Actions/actions_rat_king.rsi/ratKingDomain.png
similarity index 100%
rename from Resources/Textures/Interface/Actions/ratKingDomain.png
rename to Resources/Textures/Interface/Actions/actions_rat_king.rsi/ratKingDomain.png
diff --git a/Resources/Textures/Interface/Actions/actions_rat_king.rsi/stay.png b/Resources/Textures/Interface/Actions/actions_rat_king.rsi/stay.png
new file mode 100644
index 0000000000..b92a7f3acc
Binary files /dev/null and b/Resources/Textures/Interface/Actions/actions_rat_king.rsi/stay.png differ
diff --git a/Resources/Textures/Interface/Actions/actions_rat_king.rsi/stayOff.png b/Resources/Textures/Interface/Actions/actions_rat_king.rsi/stayOff.png
new file mode 100644
index 0000000000..aa739f71d7
Binary files /dev/null and b/Resources/Textures/Interface/Actions/actions_rat_king.rsi/stayOff.png differ
diff --git a/Resources/Textures/Interface/Actions/meta.json b/Resources/Textures/Interface/Actions/meta.json
index cbe06c11c5..6a6cb73219 100644
--- a/Resources/Textures/Interface/Actions/meta.json
+++ b/Resources/Textures/Interface/Actions/meta.json
@@ -28,12 +28,6 @@
{
"name": "carp_summon"
},
- {
- "name": "ratKingArmy"
- },
- {
- "name": "ratKingDomain"
- },
{
"name": "zombie-turn"
},
diff --git a/Resources/Textures/Mobs/Animals/regalrat.rsi/critical.png b/Resources/Textures/Mobs/Animals/regalrat.rsi/critical.png
new file mode 100644
index 0000000000..e24c9f54d5
Binary files /dev/null and b/Resources/Textures/Mobs/Animals/regalrat.rsi/critical.png differ
diff --git a/Resources/Textures/Mobs/Animals/regalrat.rsi/meta.json b/Resources/Textures/Mobs/Animals/regalrat.rsi/meta.json
index 260803a448..5c80471313 100644
--- a/Resources/Textures/Mobs/Animals/regalrat.rsi/meta.json
+++ b/Resources/Textures/Mobs/Animals/regalrat.rsi/meta.json
@@ -7,6 +7,9 @@
"license": "CC-BY-SA-3.0",
"copyright": "Taken from https://github.com/tgstation/tgstation/commit/53d1f1477d22a11a99c6c6924977cd431075761b Changed by Alekshhh",
"states": [
+ {
+ "name": "critical"
+ },
{
"name": "dead"
},