diff --git a/Content.Server/Wagging/WaggingSystem.cs b/Content.Server/Wagging/WaggingSystem.cs
new file mode 100644
index 0000000000..5d4163fa65
--- /dev/null
+++ b/Content.Server/Wagging/WaggingSystem.cs
@@ -0,0 +1,110 @@
+using Content.Server.Actions;
+using Content.Server.Chat.Systems;
+using Content.Server.Humanoid;
+using Content.Shared.Humanoid;
+using Content.Shared.Humanoid.Markings;
+using Content.Shared.Mobs;
+using Content.Shared.Toggleable;
+using Content.Shared.Wagging;
+using Robust.Shared.Prototypes;
+
+namespace Content.Server.Wagging;
+
+///
+/// Adds an action to toggle wagging animation for tails markings that supporting this
+///
+public sealed class WaggingSystem : EntitySystem
+{
+ [Dependency] private readonly ActionsSystem _actions = default!;
+ [Dependency] private readonly ChatSystem _chat = default!;
+ [Dependency] private readonly HumanoidAppearanceSystem _humanoidAppearance = default!;
+ [Dependency] private readonly IPrototypeManager _prototype = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnWaggingMapInit);
+ SubscribeLocalEvent(OnWaggingShutdown);
+ SubscribeLocalEvent(OnWaggingToggle);
+ SubscribeLocalEvent(OnMobStateChanged);
+ }
+
+ private void OnWaggingMapInit(EntityUid uid, WaggingComponent component, MapInitEvent args)
+ {
+ _actions.AddAction(uid, ref component.ActionEntity, component.Action, uid);
+ }
+
+ private void OnWaggingShutdown(EntityUid uid, WaggingComponent component, ComponentShutdown args)
+ {
+ _actions.RemoveAction(uid, component.ActionEntity);
+ }
+
+ private void OnWaggingToggle(EntityUid uid, WaggingComponent component, ref ToggleActionEvent args)
+ {
+ if (args.Handled)
+ return;
+
+ TryToggleWagging(uid, wagging: component);
+ }
+
+ private void OnMobStateChanged(EntityUid uid, WaggingComponent component, MobStateChangedEvent args)
+ {
+ if (args.NewMobState != MobState.Dead)
+ return;
+
+ if (component.Wagging)
+ TryToggleWagging(uid, wagging: component);
+ }
+
+ public bool TryToggleWagging(EntityUid uid, WaggingComponent? wagging = null, HumanoidAppearanceComponent? humanoid = null)
+ {
+ if (!Resolve(uid, ref wagging, ref humanoid))
+ return false;
+
+ if (!humanoid.MarkingSet.Markings.TryGetValue(MarkingCategories.Tail, out var markings))
+ return false;
+
+ if (markings.Count == 0)
+ return false;
+
+ wagging.Wagging = !wagging.Wagging;
+
+ for (var idx = 0; idx < markings.Count; idx++) // Animate all possible tails
+ {
+ var currentMarkingId = markings[idx].MarkingId;
+ string newMarkingId;
+
+ if (wagging.Wagging)
+ {
+ newMarkingId = $"{currentMarkingId}{wagging.Suffix}";
+ }
+ else
+ {
+ if (currentMarkingId.EndsWith(wagging.Suffix))
+ {
+ newMarkingId = currentMarkingId[..^wagging.Suffix.Length];
+ }
+ else
+ {
+ newMarkingId = currentMarkingId;
+ Log.Warning($"Unable to revert wagging for {currentMarkingId}");
+ }
+ }
+
+ if (!_prototype.HasIndex(newMarkingId))
+ {
+ Log.Warning($"{ToPrettyString(uid)} tried toggling wagging but {newMarkingId} marking doesn't exist");
+ continue;
+ }
+
+ _humanoidAppearance.SetMarkingId(uid, MarkingCategories.Tail, idx, newMarkingId,
+ humanoid: humanoid);
+ }
+
+ var emoteText = Loc.GetString(wagging.Wagging ? "wagging-emote-start" : "wagging-emote-stop", ("ent", uid));
+ _chat.TrySendInGameICMessage(uid, emoteText, InGameICChatType.Emote, ChatTransmitRange.Normal); // Ok while emotes dont have radial menu
+
+ return true;
+ }
+}
diff --git a/Content.Shared/Actions/SharedActionsSystem.cs b/Content.Shared/Actions/SharedActionsSystem.cs
index 4323a46114..fc7af4a408 100644
--- a/Content.Shared/Actions/SharedActionsSystem.cs
+++ b/Content.Shared/Actions/SharedActionsSystem.cs
@@ -562,7 +562,7 @@ public abstract class SharedActionsSystem : EntitySystem
/// Action entity to add
/// The 's action component of
/// The action entity prototype id to use if is invalid.
- /// The entity that contains/enables this action (e.g., flashlight)..
+ /// The entity that contains/enables this action (e.g., flashlight).
public bool AddAction(EntityUid performer,
[NotNullWhen(true)] ref EntityUid? actionId,
string? actionPrototypeId,
diff --git a/Content.Shared/Wagging/WaggingComponent.cs b/Content.Shared/Wagging/WaggingComponent.cs
new file mode 100644
index 0000000000..76881827dd
--- /dev/null
+++ b/Content.Shared/Wagging/WaggingComponent.cs
@@ -0,0 +1,33 @@
+using Content.Shared.Chat.Prototypes;
+using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
+
+namespace Content.Shared.Wagging;
+
+///
+/// An emoting wag for markings.
+///
+[RegisterComponent, NetworkedComponent]
+public sealed partial class WaggingComponent : Component
+{
+ [DataField]
+ public EntProtoId Action = "ActionToggleWagging";
+
+ [DataField]
+ public EntityUid? ActionEntity;
+
+ [DataField]
+ public ProtoId EmoteId = "WagTail";
+
+ ///
+ /// Suffix to add to get the animated marking.
+ ///
+ public string Suffix = "Animated";
+
+ ///
+ /// Is the entity currently wagging.
+ ///
+ [DataField]
+ public bool Wagging = false;
+}
diff --git a/Resources/Locale/en-US/actions/actions/wagging.ftl b/Resources/Locale/en-US/actions/actions/wagging.ftl
new file mode 100644
index 0000000000..2fbcb676f4
--- /dev/null
+++ b/Resources/Locale/en-US/actions/actions/wagging.ftl
@@ -0,0 +1,5 @@
+action-name-toggle-wagging = Wagging Tail
+action-description-toggle-wagging = Start or stop wagging tail.
+
+wagging-emote-start = starts wagging {POSS-ADJ($ent)} tail.
+wagging-emote-stop = stops wagging {POSS-ADJ($ent)} tail.
\ No newline at end of file
diff --git a/Resources/Prototypes/Actions/types.yml b/Resources/Prototypes/Actions/types.yml
index f301589879..3c7597f14e 100644
--- a/Resources/Prototypes/Actions/types.yml
+++ b/Resources/Prototypes/Actions/types.yml
@@ -315,3 +315,15 @@
event: !type:ToggleEyesActionEvent
useDelay: 1 # so u cant give yourself and observers eyestrain by rapidly spamming the action
+- type: entity
+ id: ActionToggleWagging
+ name: action-name-toggle-wagging
+ description: action-description-toggle-wagging
+ noSpawn: true
+ components:
+ - type: InstantAction
+ icon: { sprite: Mobs/Customization/reptilian_parts.rsi, state: tail_smooth_behind }
+ iconOn: { sprite: Mobs/Customization/reptilian_parts.rsi, state: tail_smooth_behind }
+ itemIconStyle: NoItem
+ useDelay: 1 # emote spam
+ event: !type:ToggleActionEvent
diff --git a/Resources/Prototypes/Entities/Mobs/Customization/Markings/reptilian.yml b/Resources/Prototypes/Entities/Mobs/Customization/Markings/reptilian.yml
index 81827adb8d..7183472596 100644
--- a/Resources/Prototypes/Entities/Mobs/Customization/Markings/reptilian.yml
+++ b/Resources/Prototypes/Entities/Mobs/Customization/Markings/reptilian.yml
@@ -280,7 +280,7 @@
sprites:
- sprite: Mobs/Customization/reptilian_parts.rsi
state: horns_kobold_ears
-
+
- type: marking
id: LizardHornsFloppyKoboldEars
bodyPart: HeadSide
@@ -307,3 +307,40 @@
sprites:
- sprite: Mobs/Customization/reptilian_parts.rsi
state: body_backspikes
+
+# Animated
+- type: marking
+ id: LizardTailSmoothAnimated
+ bodyPart: Tail
+ markingCategory: Tail
+ speciesRestriction: []
+ sprites:
+ - sprite: Mobs/Customization/reptilian_parts.rsi
+ state: tail_smooth_wagging
+
+- type: marking
+ id: LizardTailSpikesAnimated
+ bodyPart: Tail
+ markingCategory: Tail
+ speciesRestriction: []
+ sprites:
+ - sprite: Mobs/Customization/reptilian_parts.rsi
+ state: tail_spikes_wagging
+
+- type: marking
+ id: LizardTailLTigerAnimated
+ bodyPart: Tail
+ markingCategory: Tail
+ speciesRestriction: []
+ sprites:
+ - sprite: Mobs/Customization/reptilian_parts.rsi
+ state: tail_ltiger_wagging
+
+- type: marking
+ id: LizardTailDTigerAnimated
+ bodyPart: Tail
+ markingCategory: Tail
+ speciesRestriction: []
+ sprites:
+ - sprite: Mobs/Customization/reptilian_parts.rsi
+ state: tail_dtiger_wagging
diff --git a/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml b/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml
index ab0e6f2abd..c469cb2084 100644
--- a/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml
+++ b/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml
@@ -60,6 +60,7 @@
heatDamage:
types:
Heat : 1.5 #per second, scales with temperature & other constants
+ - type: Wagging
- type: entity
parent: BaseSpeciesDummy
diff --git a/Resources/Prototypes/Voice/tail_emotes.yml b/Resources/Prototypes/Voice/tail_emotes.yml
new file mode 100644
index 0000000000..610a2ea801
--- /dev/null
+++ b/Resources/Prototypes/Voice/tail_emotes.yml
@@ -0,0 +1,14 @@
+- type: emote
+ id: WagTail
+ chatMessages: [wags tail]
+ chatTriggers:
+ - wag
+ - wag.
+ - wags
+ - wags.
+ - wagging
+ - wagging.
+ - wag tail
+ - wag tail.
+ - wags tail
+ - wags tail.
diff --git a/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/meta.json b/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/meta.json
index 763e212529..1c4c1a2fbc 100644
--- a/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/meta.json
+++ b/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/meta.json
@@ -1,7 +1,7 @@
{
"version": 1,
"license": "CC-BY-SA-3.0",
- "copyright": "https://github.com/Skyrat-SS13/Skyrat-tg/tree/40e3cdbb15b8bc0d5ef2fb46133adf805bda5297, while Argali, Ayrshire, Myrsore and Bighorn are drawn by Ubaser, and Kobold Ears are drawn by Pigeonpeas. Body_underbelly made by Nairod(github) for SS14. Large is drawn by Ubaser.",
+ "copyright": "https://github.com/Skyrat-SS13/Skyrat-tg/tree/40e3cdbb15b8bc0d5ef2fb46133adf805bda5297, while Argali, Ayrshire, Myrsore and Bighorn are drawn by Ubaser, and Kobold Ears are drawn by Pigeonpeas. Body_underbelly made by Nairod(github) for SS14. Large drawn by Ubaser. Wagging tail by SonicDC.",
"size": {
"x": 32,
"y": 32
@@ -67,6 +67,318 @@
"name": "tail_ltiger",
"directions": 4
},
+ {
+ "name": "tail_smooth_wagging",
+ "directions": 4,
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "tail_dtiger_wagging",
+ "directions": 4,
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "tail_ltiger_wagging",
+ "directions": 4,
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "tail_spikes_wagging",
+ "directions": 4,
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
{
"name": "snout_round",
"directions": 4
diff --git a/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/tail_dtiger_wagging.png b/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/tail_dtiger_wagging.png
new file mode 100644
index 0000000000..889b0078dc
Binary files /dev/null and b/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/tail_dtiger_wagging.png differ
diff --git a/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/tail_ltiger_wagging.png b/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/tail_ltiger_wagging.png
new file mode 100644
index 0000000000..87ec63ed3a
Binary files /dev/null and b/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/tail_ltiger_wagging.png differ
diff --git a/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/tail_smooth_wagging.png b/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/tail_smooth_wagging.png
new file mode 100644
index 0000000000..65222703c6
Binary files /dev/null and b/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/tail_smooth_wagging.png differ
diff --git a/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/tail_spikes_wagging.png b/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/tail_spikes_wagging.png
new file mode 100644
index 0000000000..faad0cf6a9
Binary files /dev/null and b/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/tail_spikes_wagging.png differ