Ver Fonte

TDM update 2 (#190)

* k/d tracker

* suit, helmet weights, spear range, respawn timers

* fixing waterskins, some strings

* fixes point capturing for criticals

* faster rotting

* barricade directionals, craftable recipes

* yaml fix

* map tweaks

* added flags ported from civ13

* capture timer, map tweaks

* goob's wideswing tweaks, stamina damage

* 📝 Add docstrings to `tdm` (#191)

Docstrings generation was requested by @taislin.

* https://github.com/Civ13/Civ14/pull/190#issuecomment-2864561046

The following files were modified:

* `Content.Server/GameTicking/Rules/CaptureAreaSystem.cs`
* `Content.Shared/Damage/Events/TakeStaminaDamageEvent.cs`
* `Content.Shared/Damage/Systems/StaminaSystem.cs`
* `Content.Shared/Ensnaring/SharedEnsnareableSystem.cs`
* `Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs`
* `Content.Shared/_Shitcode/Weapons/DodgeWideswing/DodgeWideswingSystem.cs`

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* crenelated walls should not be climbable, stamina crit message

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Taislin há 7 meses atrás
pai
commit
7553df7be1
33 ficheiros alterados com 2078 adições e 151 exclusões
  1. 22 1
      Content.Server/GameTicking/Rules/CaptureAreaSystem.cs
  2. 10 0
      Content.Server/GameTicking/Rules/Components/CaptureAreaComponent.cs
  3. 16 0
      Content.Server/_Stalker/Stamina/StaminaActiveSystem.cs
  4. 9 0
      Content.Shared/CombatMode/DisarmedEvent.cs
  5. 14 0
      Content.Shared/Damage/Components/StaminaComponent.cs
  6. 13 1
      Content.Shared/Damage/Components/StaminaDamageOnHitComponent.cs
  7. 1 1
      Content.Shared/Damage/Events/StaminaDamageOnHitAttemptEvent.cs
  8. 54 0
      Content.Shared/Damage/Events/TakeStaminaDamageEvent.cs
  9. 235 61
      Content.Shared/Damage/Systems/StaminaSystem.cs
  10. 18 9
      Content.Shared/Ensnaring/SharedEnsnareableSystem.cs
  11. 10 1
      Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs
  12. 34 9
      Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs
  13. 15 1
      Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs
  14. 35 0
      Content.Shared/_Shitcode/Stunnable/OvertimeStaminaDamageComponent.cs
  15. 22 0
      Content.Shared/_Shitcode/Stunnable/StamcritResistComponent.cs
  16. 36 0
      Content.Shared/_Shitcode/Weapons/DodgeWideswing/DodgeWideswingComponent.cs
  17. 50 0
      Content.Shared/_Shitcode/Weapons/DodgeWideswing/DodgeWideswingSystem.cs
  18. 1 0
      Content.Shared/_Stalker/Stamina/StaminaActiveComponent.cs
  19. 2 0
      Resources/Locale/en-US/chat/emotes.ftl
  20. 1 0
      Resources/Locale/en-US/damage/stamina.ftl
  21. 2 2
      Resources/Maps/civ/tdm/camp.yml
  22. 1 1
      Resources/Prototypes/Civ14/Entities/Markers/capturable_areas.yml
  23. 10 0
      Resources/Prototypes/Civ14/Entities/Objects/Storage/filled_crates.yml
  24. 13 7
      Resources/Prototypes/Civ14/Entities/Objects/Weapons/swords.yml
  25. 1 0
      Resources/Prototypes/Civ14/Entities/Objects/handheld_flags.yml
  26. 1 0
      Resources/Prototypes/Civ14/Entities/Structures/Walls/barricades.yml
  27. 280 0
      Resources/Prototypes/Civ14/Entities/Structures/flags.yml
  28. 1091 0
      Resources/Prototypes/Civ14/Entities/Structures/wall_flags.yml
  29. 2 0
      Resources/Prototypes/Entities/Mobs/NPCs/animals.yml
  30. 3 0
      Resources/Prototypes/Entities/Mobs/Species/base.yml
  31. 4 0
      Resources/Prototypes/Roles/Jobs/Civ14/TDM/english.yml
  32. 4 0
      Resources/Prototypes/Roles/Jobs/Civ14/TDM/french.yml
  33. 68 57
      Resources/Prototypes/Voice/speech_emotes.yml

+ 22 - 1
Content.Server/GameTicking/Rules/CaptureAreaSystem.cs

@@ -1,4 +1,3 @@
-
 using Content.Server.GameTicking.Rules.Components;
 using Content.Shared.NPC.Components;
 using Content.Shared.Physics;
@@ -33,6 +32,12 @@ public override void Update(float frameTime)
             ProcessArea(uid, area, frameTime);
         }
     }
+    /// <summary>
+    /// Processes a capture area, determining faction control based on the presence of alive faction members, updating control status, managing capture timers, and dispatching global announcements for control changes, timed warnings, and victory.
+    /// </summary>
+    /// <param name="uid">The entity identifier of the capture area.</param>
+    /// <param name="area">The capture area component to process.</param>
+    /// <param name="frameTime">The elapsed time since the last update, in seconds.</param>
     private void ProcessArea(EntityUid uid, CaptureAreaComponent area, float frameTime)
     {
         var areaXform = _transform.GetMapCoordinates(uid);
@@ -88,6 +93,8 @@ private void ProcessArea(EntityUid uid, CaptureAreaComponent area, float frameTi
             // Controller changed (or became contested/empty)
             area.Controller = currentController;
             area.CaptureTimer = 0f; // Reset timer on change
+            area.CaptureTimerAnnouncement1 = false;
+            area.CaptureTimerAnnouncement2 = false;
             if (currentController == "")
             {
                 _chat.DispatchGlobalAnnouncement($"{area.PreviousController} has lost control of {area.Name}!", "Objective", false, null, Color.Red);
@@ -102,6 +109,18 @@ private void ProcessArea(EntityUid uid, CaptureAreaComponent area, float frameTi
             // Controller remains the same, increment timer
             area.CaptureTimer += frameTime;
 
+            //announce when theres 2 and 1 minutes left.
+            var timeleft = area.CaptureDuration - area.CaptureTimer;
+            if (timeleft <= 120 && area.CaptureTimerAnnouncement2 == false)
+            {
+                _chat.DispatchGlobalAnnouncement($"Two minutes until {currentController} captures {area.Name}!", "Round", false, null, Color.Blue);
+                area.CaptureTimerAnnouncement2 = true;
+            }
+            else if (timeleft < 60 && area.CaptureTimerAnnouncement1 == false)
+            {
+                _chat.DispatchGlobalAnnouncement($"One minute until {currentController} captures {area.Name}!", "Round", false, null, Color.Blue);
+                area.CaptureTimerAnnouncement1 = true;
+            }
             //Check for capture completion
             if (area.CaptureTimer >= area.CaptureDuration)
             {
@@ -117,6 +136,8 @@ private void ProcessArea(EntityUid uid, CaptureAreaComponent area, float frameTi
         {
             // Area is empty or contested, and wasn't previously controlled by a single faction
             area.CaptureTimer = 0f; // Ensure timer is reset/stays reset
+            area.CaptureTimerAnnouncement1 = false;
+            area.CaptureTimerAnnouncement2 = false;
         }
         area.PreviousController = currentController;
     }

+ 10 - 0
Content.Server/GameTicking/Rules/Components/CaptureAreaComponent.cs

@@ -29,6 +29,16 @@ public sealed partial class CaptureAreaComponent : Component
     [DataField("captureTimer")]
     public float CaptureTimer { get; set; } = 0f;
     /// <summary>
+    /// Has 1 minute left been announced?
+    /// </summary>
+    [DataField("captureTimerAnnouncement1")]
+    public bool CaptureTimerAnnouncement1 { get; set; } = false;
+    /// <summary>
+    /// Has 2 minute left been announced?
+    /// </summary>
+    [DataField("captureTimerAnnouncement2")]
+    public bool CaptureTimerAnnouncement2 { get; set; } = false;
+    /// <summary>
     /// Is the area currently occupied?
     /// </summary>
     [DataField("occupied")]

+ 16 - 0
Content.Server/_Stalker/Stamina/StaminaActiveSystem.cs

@@ -4,6 +4,9 @@
 using Content.Shared.Movement.Components;
 using Content.Shared.Movement.Systems;
 using Robust.Shared.Physics.Components;
+using Content.Server.Chat.Systems;
+using Robust.Shared.Random;
+using Robust.Shared.Timing;
 
 namespace Content.Server._Stalker.Stamina;
 
@@ -11,6 +14,10 @@ public sealed class StaminaActiveSystem : EntitySystem
 {
     [Dependency] private readonly StaminaSystem _stamina = default!;
     [Dependency] private readonly MovementSpeedModifierSystem _speed = default!;
+    [Dependency] private readonly ChatSystem _chat = default!;
+    [Dependency] private readonly IRobustRandom _random = default!;
+
+    [Dependency] private readonly IGameTiming _gameTiming = default!;
     private ISawmill _sawmill = default!;
 
     public override void Initialize()
@@ -25,6 +32,15 @@ public override void Update(float frameTime)
         var query = EntityQueryEnumerator<StaminaComponent, MovementSpeedModifierComponent, StaminaActiveComponent, InputMoverComponent>();
         while (query.MoveNext(out var uid, out var stamina, out var modifier, out var active, out var input))
         {
+            var curTime = _gameTiming.CurTime;
+            if (stamina.StaminaDamage > stamina.SlowdownThreshold)
+            {
+                if ((curTime - stamina.LastMessageTime).TotalSeconds >= 6)
+                {
+                    _chat.TryEmoteWithChat(uid, "BreathGasp");
+                    stamina.LastMessageTime = curTime; // Update last message time
+                }
+            }
             // If our entity is slowed, we can't apply new speed/speed modifiers
             // Because CurrentSprintSpeed will change
             if (!active.Slowed)

+ 9 - 0
Content.Shared/CombatMode/DisarmedEvent.cs

@@ -27,5 +27,14 @@ public sealed class DisarmedEvent : HandledEntityEventArgs
         ///     Whether the entity was successfully stunned from a shove.
         /// </summary>
         public bool IsStunned { get; set; }
+        /// <summary>
+        ///     Potential stamina damage if this disarm results in a shove.
+        /// </summary>
+        public float StaminaDamage { get; init; }
+
+        /// <summary>
+        ///     Whether the entity was successfully stunned from a shove.
+        /// </summary>
+        public bool WasDisarmed { get; set; }
     }
 }

+ 14 - 0
Content.Shared/Damage/Components/StaminaComponent.cs

@@ -45,6 +45,14 @@ public sealed partial class StaminaComponent : Component
 
     [DataField, AutoNetworkedField]
     public float CritThresholdModifier = 1f; // stalker-changes
+
+    /// <summary>
+    /// A dictionary of active stamina drains, with the key being the source of the drain,
+    /// DrainRate how much it changes per tick, and ModifiesSpeed if it should slow down the user.
+    /// </summary>
+    [DataField, AutoNetworkedField]
+    public Dictionary<EntityUid, (float DrainRate, bool ModifiesSpeed)> ActiveDrains = new();
+
     /// <summary>
     /// How long will this mob be stunned for?
     /// </summary>
@@ -67,4 +75,10 @@ public sealed partial class StaminaComponent : Component
     [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField]
     public float SlowdownThreshold = 50f; // CritThreshold / 2
     // stalker-changes-end
+
+    /// <summary>
+    /// When the last "gasp" message was sent
+    /// </summary>
+    [DataField("lastMessageTime"), AutoNetworkedField, ViewVariables(VVAccess.ReadWrite)]
+    public TimeSpan LastMessageTime { get; set; } = TimeSpan.Zero;
 }

+ 13 - 1
Content.Shared/Damage/Components/StaminaDamageOnHitComponent.cs

@@ -6,7 +6,19 @@ namespace Content.Shared.Damage.Components;
 public sealed partial class StaminaDamageOnHitComponent : Component
 {
     [ViewVariables(VVAccess.ReadWrite), DataField("damage")]
-    public float Damage = 30f;
+    public float Damage = 20f; // goob edit
+
+    // goob edit
+    [DataField]
+    public float Overtime = 0f;
+
+    // goob edit
+    [DataField]
+    public float LightAttackDamageMultiplier = 1f;
+
+    // goob edit
+    [DataField]
+    public float LightAttackOvertimeDamageMultiplier = 1f;
 
     [DataField("sound")]
     public SoundSpecifier? Sound;

+ 1 - 1
Content.Shared/Damage/Events/StaminaDamageOnHitAttemptEvent.cs

@@ -4,4 +4,4 @@ namespace Content.Shared.Damage.Events;
 /// Attempting to apply stamina damage on entity.
 /// </summary>
 [ByRefEvent]
-public record struct StaminaDamageOnHitAttemptEvent(bool Cancelled);
+public record struct StaminaDamageOnHitAttemptEvent(bool LightAttack, bool Cancelled);

+ 54 - 0
Content.Shared/Damage/Events/TakeStaminaDamageEvent.cs

@@ -0,0 +1,54 @@
+// SPDX-FileCopyrightText: 2022 Rane <60792108+Elijahrane@users.noreply.github.com>
+// SPDX-FileCopyrightText: 2023 metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
+// SPDX-FileCopyrightText: 2024 Piras314 <p1r4s@proton.me>
+// SPDX-FileCopyrightText: 2024 username <113782077+whateverusername0@users.noreply.github.com>
+// SPDX-FileCopyrightText: 2024 whateverusername0 <whateveremail>
+// SPDX-FileCopyrightText: 2025 Aiden <28298836+Aidenkrz@users.noreply.github.com>
+// SPDX-FileCopyrightText: 2025 Aiden <aiden@djkraz.com>
+// SPDX-FileCopyrightText: 2025 Aviu00 <93730715+Aviu00@users.noreply.github.com>
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+
+using System.Numerics;
+using Content.Shared.Damage.Components;
+using Content.Shared.Inventory;
+
+namespace Content.Shared.Damage.Events;
+
+/// <summary>
+/// The entity is going to be hit,
+/// give opportunities to change the damage or other stuff.
+/// </summary>
+// goobstation - stun resistance. try not to modify this event allat much
+public sealed class TakeStaminaDamageEvent : HandledEntityEventArgs, IInventoryRelayEvent
+{
+    public SlotFlags TargetSlots { get; } = SlotFlags.WITHOUT_POCKET;
+
+    public Entity<StaminaComponent>? Target;
+
+    /// <summary>
+    /// The multiplier. Generally, try to use *= or /= instead of overwriting.
+    /// </summary>
+    public float Multiplier = 1;
+
+    /// <summary>
+    /// The flat modifier. Generally, try to use += or -= instead of overwriting.
+    /// </summary>
+    public float FlatModifier = 0;
+
+    /// <summary>
+    /// Initialises a new event for handling stamina damage about to be applied to a specific entity.
+    /// </summary>
+    /// <param name="target">The entity with a stamina component that will receive damage.</param>
+    public TakeStaminaDamageEvent(Entity<StaminaComponent> target)
+    {
+        Target = target;
+    }
+}
+
+public sealed class StaminaDamageMeleeHitEvent(List<(EntityUid Entity, StaminaComponent Component)> hitEntities, Vector2? direction) : EntityEventArgs
+{
+    public List<(EntityUid Entity, StaminaComponent Component)> HitEntities = hitEntities;
+
+    public Vector2? Direction = direction;
+}

+ 235 - 61
Content.Shared/Damage/Systems/StaminaSystem.cs

@@ -6,11 +6,12 @@
 using Content.Shared.Damage.Events;
 using Content.Shared.Database;
 using Content.Shared.Effects;
-using Content.Shared.IdentityManagement;
-using Content.Shared.Popups;
+using Content.Shared.Jittering;
 using Content.Shared.Projectiles;
 using Content.Shared.Rejuvenate;
 using Content.Shared.Rounding;
+using Content.Shared.Speech.EntitySystems;
+using Content.Shared.StatusEffect;
 using Content.Shared.Stunnable;
 using Content.Shared.Throwing;
 using Content.Shared.Weapons.Melee.Events;
@@ -19,8 +20,9 @@
 using Robust.Shared.Audio.Systems;
 using Robust.Shared.Network;
 using Robust.Shared.Player;
-using Robust.Shared.Random;
+using Robust.Shared.Random; // Goob - Shove
 using Robust.Shared.Timing;
+using Content.Shared.Common.Stunnable;
 
 namespace Content.Shared.Damage.Systems;
 
@@ -34,12 +36,22 @@ public sealed partial class StaminaSystem : EntitySystem
     [Dependency] private readonly SharedColorFlashEffectSystem _color = default!;
     [Dependency] private readonly SharedStunSystem _stunSystem = default!;
     [Dependency] private readonly SharedAudioSystem _audio = default!;
+    [Dependency] private readonly StatusEffectsSystem _statusEffect = default!; // goob edit
+    [Dependency] private readonly SharedStutteringSystem _stutter = default!; // goob edit
+    [Dependency] private readonly SharedJitteringSystem _jitter = default!; // goob edit
+    [Dependency] private readonly IRobustRandom _random = default!; // Goob - Shove
+    [Dependency] private readonly ILogManager _logManager = default!;
+
+    private ISawmill _sawmill = default!;
 
     /// <summary>
     /// How much of a buffer is there between the stun duration and when stuns can be re-applied.
     /// </summary>
     private static readonly TimeSpan StamCritBufferTime = TimeSpan.FromSeconds(3f);
 
+    /// <summary>
+    /// Initializes the StaminaSystem, setting up event subscriptions for stamina-related components and configuring logging.
+    /// </summary>
     public override void Initialize()
     {
         base.Initialize();
@@ -58,12 +70,18 @@ public override void Initialize()
         SubscribeLocalEvent<StaminaDamageOnCollideComponent, ThrowDoHitEvent>(OnThrowHit);
 
         SubscribeLocalEvent<StaminaDamageOnHitComponent, MeleeHitEvent>(OnMeleeHit);
+
+        _sawmill = _logManager.GetSawmill("stamina");
     }
 
+    /// <summary>
+    /// Handles stamina state changes after state synchronisation, entering stamina critical state if necessary or updating active stamina components.
+    /// </summary>
     private void OnStamHandleState(EntityUid uid, StaminaComponent component, ref AfterAutoHandleStateEvent args)
     {
+        // goob edit - stunmeta
         if (component.Critical)
-            EnterStamCrit(uid, component);
+            EnterStamCrit(uid, component, duration: 3f);
         else
         {
             if (component.StaminaDamage > 0f)
@@ -111,23 +129,29 @@ private void OnRejuvenate(EntityUid uid, StaminaComponent component, RejuvenateE
         Dirty(uid, component);
     }
 
+    /// <summary>
+    /// Applies immediate stamina damage with resistances to an entity when disarmed, unless already handled or in a critical state.
+    /// </summary>
     private void OnDisarmed(EntityUid uid, StaminaComponent component, DisarmedEvent args)
     {
+        // No random stamina damage
         if (args.Handled)
             return;
 
         if (component.Critical)
             return;
 
-        var damage = args.PushProbability * component.CritThreshold;
-        TakeStaminaDamage(uid, damage, component, source: args.Source);
+        TakeStaminaDamage(uid, args.StaminaDamage, component, source: args.Source, applyResistances: true, immediate: true);
 
         args.PopupPrefix = "disarm-action-shove-";
         args.IsStunned = component.Critical;
-
-        args.Handled = true;
+        // Shoving shouldnt handle it
     }
 
+    /// <summary>
+    /// Handles stamina damage application when an entity with a <see cref="StaminaDamageOnHitComponent"/> lands a melee hit,
+    /// splitting immediate and overtime stamina damage among all valid hit entities and applying relevant multipliers and modifiers.
+    /// </summary>
     private void OnMeleeHit(EntityUid uid, StaminaDamageOnHitComponent component, MeleeHitEvent args)
     {
         if (!args.IsHit ||
@@ -137,7 +161,7 @@ private void OnMeleeHit(EntityUid uid, StaminaDamageOnHitComponent component, Me
             return;
         }
 
-        var ev = new StaminaDamageOnHitAttemptEvent();
+        var ev = new StaminaDamageOnHitAttemptEvent(args.Direction == null, false); // Goob edit
         RaiseLocalEvent(uid, ref ev);
         if (ev.Cancelled)
             return;
@@ -154,21 +178,34 @@ private void OnMeleeHit(EntityUid uid, StaminaDamageOnHitComponent component, Me
             toHit.Add((ent, stam));
         }
 
-        var hitEvent = new StaminaMeleeHitEvent(toHit);
-        RaiseLocalEvent(uid, hitEvent);
+        // Goobstation
+        RaiseLocalEvent(uid, new StaminaDamageMeleeHitEvent(toHit, args.Direction));
 
-        if (hitEvent.Handled)
-            return;
+        // goobstation
+        foreach (var (ent, comp) in toHit)
+        {
+            var hitEvent = new TakeStaminaDamageEvent((ent, comp));
+            // raise event for each entity hit
+            RaiseLocalEvent(ent, hitEvent);
 
-        var damage = component.Damage;
+            if (hitEvent.Handled)
+                return;
 
-        damage *= hitEvent.Multiplier;
+            var damageImmediate = component.Damage;
+            var damageOvertime = component.Overtime;
+            damageImmediate *= hitEvent.Multiplier;
+            damageImmediate += hitEvent.FlatModifier;
+            damageOvertime *= hitEvent.Multiplier;
+            damageOvertime += hitEvent.FlatModifier;
 
-        damage += hitEvent.FlatModifier;
+            if (args.Direction == null)
+            {
+                damageImmediate *= component.LightAttackDamageMultiplier;
+                damageOvertime *= component.LightAttackOvertimeDamageMultiplier;
+            }
 
-        foreach (var (ent, comp) in toHit)
-        {
-            TakeStaminaDamage(ent, damage / toHit.Count, comp, source: args.User, with: args.Weapon, sound: component.Sound);
+            TakeStaminaDamage(ent, damageImmediate / toHit.Count, comp, source: args.User, with: args.Weapon, sound: component.Sound, immediate: true);
+            TakeOvertimeStaminaDamage(ent, damageOvertime);
         }
     }
 
@@ -177,24 +214,36 @@ private void OnProjectileHit(EntityUid uid, StaminaDamageOnCollideComponent comp
         OnCollide(uid, component, args.Target);
     }
 
+    /// <summary>
+    /// Applies immediate stamina damage with resistances to an entity when a projectile embeds into it.
+    /// </summary>
     private void OnProjectileEmbed(EntityUid uid, StaminaDamageOnEmbedComponent component, ref EmbedEvent args)
     {
         if (!TryComp<StaminaComponent>(args.Embedded, out var stamina))
             return;
 
-        TakeStaminaDamage(args.Embedded, component.Damage, stamina, source: uid);
+        TakeStaminaDamage(args.Embedded, component.Damage, stamina, source: uid, applyResistances: true, immediate: true);
     }
 
+    /// <summary>
+    /// Applies stamina damage to a target entity when struck by a thrown object.
+    /// </summary>
     private void OnThrowHit(EntityUid uid, StaminaDamageOnCollideComponent component, ThrowDoHitEvent args)
     {
         OnCollide(uid, component, args.Target);
     }
 
+    /// <summary>
+    /// Applies stamina damage to a target entity upon collision if it has a stamina component, allowing for event-based modification or cancellation.
+    /// </summary>
+    /// <param name="uid">The entity causing the collision.</param>
+    /// <param name="component">The stamina damage on collide component.</param>
+    /// <param name="target">The entity being collided with.</param>
     private void OnCollide(EntityUid uid, StaminaDamageOnCollideComponent component, EntityUid target)
     {
         // you can't inflict stamina damage on things with no stamina component
         // this prevents stun batons from using up charges when throwing it at lockers or lights
-        if (!HasComp<StaminaComponent>(target))
+        if (!TryComp<StaminaComponent>(target, out var stamComp))
             return;
 
         var ev = new StaminaDamageOnHitAttemptEvent();
@@ -202,9 +251,28 @@ private void OnCollide(EntityUid uid, StaminaDamageOnCollideComponent component,
         if (ev.Cancelled)
             return;
 
-        TakeStaminaDamage(target, component.Damage, source: uid, sound: component.Sound);
+        // goobstation
+        var hitEvent = new TakeStaminaDamageEvent((target, stamComp));
+        RaiseLocalEvent(target, hitEvent);
+
+        if (hitEvent.Handled)
+            return;
+
+        var damage = component.Damage;
+        var overtime = component.Damage;
+
+        damage *= hitEvent.Multiplier;
+        damage += hitEvent.FlatModifier;
+        overtime *= hitEvent.Multiplier;
+        overtime += hitEvent.FlatModifier;
+
+        TakeStaminaDamage(target, damage, source: uid, sound: component.Sound, immediate: true);
+        TakeOvertimeStaminaDamage(target, overtime); // Goobstation
     }
 
+    /// <summary>
+    /// Updates the stamina alert level for an entity based on its current stamina damage relative to the critical threshold.
+    /// </summary>
     private void SetStaminaAlert(EntityUid uid, StaminaComponent? component = null)
     {
         if (!Resolve(uid, ref component, false) || component.Deleted)
@@ -216,7 +284,15 @@ private void SetStaminaAlert(EntityUid uid, StaminaComponent? component = null)
 
     /// <summary>
     /// Tries to take stamina damage without raising the entity over the crit threshold.
+    /// <summary>
+    /// Attempts to apply stamina damage to an entity, returning whether the entity remains below the critical threshold.
     /// </summary>
+    /// <param name="uid">The entity to apply stamina damage to.</param>
+    /// <param name="value">The amount of stamina damage to attempt to apply.</param>
+    /// <param name="component">Optional stamina component; resolved if not provided.</param>
+    /// <param name="source">Optional source of the stamina damage.</param>
+    /// <param name="with">Optional weapon or item used to inflict the damage.</param>
+    /// <returns>True if the stamina damage was applied and the entity is not in a critical state; false if the entity would exceed or is already at the critical threshold.</returns>
     public bool TryTakeStamina(EntityUid uid, float value, StaminaComponent? component = null, EntityUid? source = null, EntityUid? with = null)
     {
         // Something that has no Stamina component automatically passes stamina checks
@@ -228,15 +304,51 @@ public bool TryTakeStamina(EntityUid uid, float value, StaminaComponent? compone
         if (oldStam + value > component.CritThreshold || component.Critical)
             return false;
 
-        TakeStaminaDamage(uid, value, component, source, with, visual: false);
+        TakeStaminaDamage(uid, value, component, source, with, visual: false, immediate: true);
         return true;
     }
 
+    /// <summary>
+    /// Adds stamina damage over time to the specified entity, accumulating the value in its overtime stamina component.
+    /// </summary>
+    /// <param name="uid">The entity to receive overtime stamina damage.</param>
+    /// <param name="value">The amount of stamina damage to add.</param>
+    public void TakeOvertimeStaminaDamage(EntityUid uid, float value)
+    {
+        // do this only on server side because otherwise shit happens
+        if (value == 0)
+            return;
+
+        var hasComp = TryComp<OvertimeStaminaDamageComponent>(uid, out var overtime);
+
+        if (!hasComp)
+            overtime = EnsureComp<OvertimeStaminaDamageComponent>(uid);
+
+        overtime!.Amount = hasComp ? overtime.Amount + value : value;
+        overtime!.Damage = hasComp ? overtime.Damage + value : value;
+    }
+
+    /// <summary>
+    /// Applies stamina damage to an entity, optionally factoring in resistances, triggering visual and audio effects, and logging the event.
+    /// </summary>
+    /// <param name="uid">The entity receiving stamina damage.</param>
+    /// <param name="value">The amount of stamina damage to apply.</param>
+    /// <param name="component">Optional stamina component; resolved if not provided.</param>
+    /// <param name="source">Optional source entity responsible for the damage.</param>
+    /// <param name="with">Optional entity used to inflict the damage.</param>
+    /// <param name="visual">Whether to trigger visual effects for the damage.</param>
+    /// <param name="sound">Optional sound to play when damage is applied.</param>
+    /// <param name="immediate">If true, applies a hard stun when entering stamina crit.</param>
+    /// <param name="applyResistances">If true, applies resistance modifiers before applying damage.</param>
+    /// <param name="shouldLog">Whether to log the stamina damage event.</param>
+    /// <remarks>
+    /// If the entity is already in stamina crit or the event is cancelled, no damage is applied. Exceeding the slowdown threshold applies jitter, stutter, and slowdown effects. Entering stamina crit may apply a hard stun depending on the <paramref name="immediate"/> flag.
+    /// </remarks>
     public void TakeStaminaDamage(EntityUid uid, float value, StaminaComponent? component = null,
-        EntityUid? source = null, EntityUid? with = null, bool visual = true, SoundSpecifier? sound = null,
-        bool shouldLog = true) // stalker-changes
+        EntityUid? source = null, EntityUid? with = null, bool visual = true, SoundSpecifier? sound = null, bool immediate = false, bool applyResistances = false, bool shouldLog = true)
     {
-        if (!Resolve(uid, ref component, false))
+        if (!Resolve(uid, ref component, false)
+        || value == 0) // no damage???
             return;
 
         var ev = new BeforeStaminaDamageEvent(value);
@@ -248,6 +360,18 @@ public bool TryTakeStamina(EntityUid uid, float value, StaminaComponent? compone
         if (component.Critical)
             return;
 
+        if (applyResistances)
+        {
+            var hitEvent = new TakeStaminaDamageEvent((uid, component));
+            RaiseLocalEvent(uid, hitEvent);
+
+            if (hitEvent.Handled)
+                return;
+
+            value *= hitEvent.Multiplier;
+            value += hitEvent.FlatModifier;
+        }
+
         var oldDamage = component.StaminaDamage;
         component.StaminaDamage = MathF.Max(0f, component.StaminaDamage + value);
 
@@ -262,29 +386,22 @@ public bool TryTakeStamina(EntityUid uid, float value, StaminaComponent? compone
 
         var slowdownThreshold = component.SlowdownThreshold; // stalker-changes
 
-        // If we go above n% then apply slowdown
-        if (oldDamage < slowdownThreshold &&
-            component.StaminaDamage > slowdownThreshold)
+        // If we go above n% then apply effects
+        if (component.StaminaDamage > slowdownThreshold)
         {
-            _stunSystem.TrySlowdown(uid, TimeSpan.FromSeconds(3), true, 0.8f, 0.8f);
+            // goob edit - stunmeta
+            _jitter.DoJitter(uid, TimeSpan.FromSeconds(2f), true);
+            _stutter.DoStutter(uid, TimeSpan.FromSeconds(10f), true);
+            _stunSystem.TrySlowdown(uid, TimeSpan.FromSeconds(8), true, 0.7f, 0.7f);
+
         }
 
         SetStaminaAlert(uid, component);
 
-        if (!component.Critical)
-        {
-            if (component.StaminaDamage >= component.CritThreshold)
-            {
-                EnterStamCrit(uid, component);
-            }
-        }
-        else
-        {
-            if (component.StaminaDamage < component.CritThreshold)
-            {
-                ExitStamCrit(uid, component);
-            }
-        }
+        if (!component.Critical && component.StaminaDamage >= component.CritThreshold && value > 0) // goob edit
+            EnterStamCrit(uid, component, immediate, duration: 3f);
+        else if (component.StaminaDamage < component.CritThreshold)
+            ExitStamCrit(uid, component);
 
         EnsureComp<ActiveStaminaComponent>(uid);
         Dirty(uid, component);
@@ -311,27 +428,61 @@ public bool TryTakeStamina(EntityUid uid, float value, StaminaComponent? compone
         }
     }
 
+    /// <summary>
+    /// Enables or disables a stamina drain effect on an entity from a specified source, with an optional speed modification.
+    /// </summary>
+    /// <param name="target">The entity to apply or remove the stamina drain from.</param>
+    /// <param name="drainRate">The rate at which stamina is drained per second.</param>
+    /// <param name="enabled">Whether to enable or disable the stamina drain.</param>
+    /// <param name="modifiesSpeed">Whether the drain should also affect the entity's movement speed.</param>
+    /// <param name="source">The source entity responsible for the drain; if null, the target is used as the source.</param>
+    public void ToggleStaminaDrain(EntityUid target, float drainRate, bool enabled, bool modifiesSpeed, EntityUid? source = null)
+    {
+        if (!TryComp<StaminaComponent>(target, out var stamina))
+            return;
+
+        // If theres no source, we assume its the target that caused the drain.
+        var actualSource = source ?? target;
+
+        if (enabled)
+        {
+            stamina.ActiveDrains[actualSource] = (drainRate, modifiesSpeed);
+            EnsureComp<ActiveStaminaComponent>(target);
+        }
+        else
+            stamina.ActiveDrains.Remove(actualSource);
+
+        Dirty(target, stamina);
+    }
+
+    /// <summary>
+    /// Processes stamina updates for all entities with active stamina components, applying stamina drains, handling recovery, and managing entry and exit from stamina critical states.
+    /// </summary>
     public override void Update(float frameTime)
     {
         base.Update(frameTime);
-
         if (!_timing.IsFirstTimePredicted)
             return;
 
         var stamQuery = GetEntityQuery<StaminaComponent>();
         var query = EntityQueryEnumerator<ActiveStaminaComponent>();
         var curTime = _timing.CurTime;
-
         while (query.MoveNext(out var uid, out _))
         {
             // Just in case we have active but not stamina we'll check and account for it.
             if (!stamQuery.TryGetComponent(uid, out var comp) ||
-                comp.StaminaDamage <= 0f && !comp.Critical)
+                comp.StaminaDamage <= 0f && !comp.Critical && comp.ActiveDrains.Count == 0)
             {
                 RemComp<ActiveStaminaComponent>(uid);
                 continue;
             }
-
+            if (comp.ActiveDrains.Count > 0)
+                foreach (var (source, (drainRate, modifiesSpeed)) in comp.ActiveDrains)
+                    TakeStaminaDamage(uid,
+                    drainRate * frameTime,
+                    comp,
+                    source: source,
+                    visual: false);
             // Shouldn't need to consider paused time as we're only iterating non-paused stamina components.
             var nextUpdate = comp.NextUpdate;
 
@@ -346,35 +497,58 @@ public override void Update(float frameTime)
             }
 
             comp.NextUpdate += TimeSpan.FromSeconds(1f);
-            TakeStaminaDamage(uid, -comp.Decay, comp);
+            // If theres no active drains, recover stamina.
+            if (comp.ActiveDrains.Count == 0)
+                TakeStaminaDamage(uid, -comp.Decay, comp);
+
             Dirty(uid, comp);
         }
     }
 
-    private void EnterStamCrit(EntityUid uid, StaminaComponent? component = null)
+    /// <summary>
+    /// Puts an entity into stamina critical state, optionally applying a hard stun (paralysis) for a specified duration.
+    /// </summary>
+    /// <param name="uid">The entity to enter stamina crit.</param>
+    /// <param name="component">The stamina component, if already resolved.</param>
+    /// <param name="hardStun">If true, applies a full paralysis; otherwise, does not apply a hard stun.</param>
+    /// <param name="duration">Duration of the stun effect in seconds if hard stun is applied.</param>
+    private void EnterStamCrit(EntityUid uid, StaminaComponent? component = null, bool hardStun = false, float duration = 6f)
     {
-        if (!Resolve(uid, ref component) ||
-            component.Critical)
+        if (!Resolve(uid, ref component) || component.Critical)
         {
             return;
         }
+        _sawmill.Info("entering stamcrit");
+        if (!hardStun)
+        {
+            _sawmill.Info("no hardcrit");
+            //var parsedDuration = TimeSpan.FromSeconds(duration);
+            //if (!_statusEffect.HasStatusEffect(uid, "KnockedDown"))
+            //    _stunSystem.TryKnockdown(uid, parsedDuration, true);
+            //return;
+        }
+        else
+        {        // you got batonned hard.
+            component.Critical = true;
+            _stunSystem.TryParalyze(uid, component.StunTime, true);
+        }
 
-        // To make the difference between a stun and a stamcrit clear
-        // TODO: Mask?
-
-        component.Critical = true;
-        component.StaminaDamage = component.CritThreshold;
 
-        _stunSystem.TryParalyze(uid, component.StunTime, true);
+        component.NextUpdate = _timing.CurTime + component.StunTime + StamCritBufferTime; // Goobstation
 
-        // Give them buffer before being able to be re-stunned
-        component.NextUpdate = _timing.CurTime + component.StunTime + StamCritBufferTime;
         EnsureComp<ActiveStaminaComponent>(uid);
         Dirty(uid, component);
+
         _adminLogger.Add(LogType.Stamina, LogImpact.Medium, $"{ToPrettyString(uid):user} entered stamina crit");
     }
 
-    private void ExitStamCrit(EntityUid uid, StaminaComponent? component = null)
+    // goob edit - made it public.
+    // in any case it requires a stamina component that can be freely modified.
+    // so it doesn't really matter if it's public or private. besides, very convenient.
+    /// <summary>
+    /// Exits stamina critical state for the specified entity, resetting stamina damage and related effects.
+    /// </summary>
+    public void ExitStamCrit(EntityUid uid, StaminaComponent? component = null)
     {
         if (!Resolve(uid, ref component) ||
             !component.Critical)

+ 18 - 9
Content.Shared/Ensnaring/SharedEnsnareableSystem.cs

@@ -27,17 +27,20 @@ public sealed partial class EnsnareableDoAfterEvent : SimpleDoAfterEvent
 
 public abstract class SharedEnsnareableSystem : EntitySystem
 {
-    [Dependency] private   readonly AlertsSystem _alerts = default!;
-    [Dependency] private   readonly MovementSpeedModifierSystem _speedModifier = default!;
+    [Dependency] private readonly AlertsSystem _alerts = default!;
+    [Dependency] private readonly MovementSpeedModifierSystem _speedModifier = default!;
     [Dependency] protected readonly SharedAppearanceSystem Appearance = default!;
-    [Dependency] private   readonly SharedAudioSystem _audio = default!;
-    [Dependency] private   readonly SharedBodySystem _body = default!;
+    [Dependency] private readonly SharedAudioSystem _audio = default!;
+    [Dependency] private readonly SharedBodySystem _body = default!;
     [Dependency] protected readonly SharedContainerSystem Container = default!;
-    [Dependency] private   readonly SharedDoAfterSystem _doAfter = default!;
-    [Dependency] private   readonly SharedHandsSystem _hands = default!;
+    [Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
+    [Dependency] private readonly SharedHandsSystem _hands = default!;
     [Dependency] protected readonly SharedPopupSystem Popup = default!;
-    [Dependency] private   readonly StaminaSystem _stamina = default!;
+    [Dependency] private readonly StaminaSystem _stamina = default!;
 
+    /// <summary>
+    /// Subscribes to local events related to ensnaring and ensnareable components to initialise the system's event handling.
+    /// </summary>
     public override void Initialize()
     {
         base.Initialize();
@@ -249,7 +252,13 @@ private void OnThrowHit(EntityUid uid, EnsnaringComponent component, ThrowDoHitE
     /// </summary>
     /// <param name="target">The entity that will be ensnared</param>
     /// <paramref name="ensnare"> The entity that is used to ensnare</param>
-    /// <param name="component">The ensnaring component</param>
+    /// <summary>
+    /// Attempts to ensnare a target entity using the specified ensnaring entity.
+    /// </summary>
+    /// <param name="target">The entity to be ensnared.</param>
+    /// <param name="ensnare">The ensnaring entity to apply.</param>
+    /// <param name="component">The ensnaring component.</param>
+    /// <returns>True if the target was successfully ensnared; otherwise, false.</returns>
     public bool TryEnsnare(EntityUid target, EntityUid ensnare, EnsnaringComponent component)
     {
         //Don't do anything if they don't have the ensnareable component.
@@ -267,7 +276,7 @@ public bool TryEnsnare(EntityUid target, EntityUid ensnare, EnsnaringComponent c
         // Apply stamina damage to target
         if (TryComp<StaminaComponent>(target, out var stamina))
         {
-            _stamina.TakeStaminaDamage(target, component.StaminaDamage, with: ensnare, component: stamina);
+            _stamina.TakeStaminaDamage(target, component.StaminaDamage, with: ensnare, component: stamina, immediate: true);
         }
 
         component.Ensnared = target;

+ 10 - 1
Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs

@@ -97,6 +97,13 @@ public sealed partial class MeleeWeaponComponent : Component
     [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField]
     public float Range = 1.5f;
 
+    // goob edit - stunmeta
+    /// <summary>
+    ///     Applies stamina damage on each successful wideswing hit to the attacker.
+    /// </summary>
+    [DataField, AutoNetworkedField]
+    public float HeavyStaminaCost = 5f;
+
     /// <summary>
     /// Total width of the angle for wide attacks.
     /// </summary>
@@ -169,7 +176,9 @@ public sealed partial class MeleeWeaponComponent : Component
     public float HeavyPartDamageMultiplier = 0.5f;
 
     // Shitmed Change End
-
+    // Goobstation
+    [DataField, AutoNetworkedField]
+    public bool CanWideSwing = true;
 }
 
 /// <summary>

+ 34 - 9
Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs

@@ -28,7 +28,7 @@
 using Robust.Shared.Prototypes;
 using Robust.Shared.Timing;
 using ItemToggleMeleeWeaponComponent = Content.Shared.Item.ItemToggle.Components.ItemToggleMeleeWeaponComponent;
-
+using Content.Shared.Damage.Components;
 namespace Content.Shared.Weapons.Melee;
 
 public abstract class SharedMeleeWeaponSystem : EntitySystem
@@ -191,7 +191,8 @@ private void OnHeavyAttack(HeavyAttackEvent msg, EntitySessionEventArgs args)
             return;
 
         if (!TryGetWeapon(user, out var weaponUid, out var weapon) ||
-            weaponUid != GetEntity(msg.Weapon))
+            weaponUid != GetEntity(msg.Weapon) ||
+            !weapon.CanWideSwing) // Goobstation Change
         {
             return;
         }
@@ -416,13 +417,14 @@ private bool AttemptAttack(EntityUid user, EntityUid weaponUid, MeleeWeaponCompo
             switch (attack)
             {
                 case LightAttackEvent light:
-                    DoLightAttack(user, light, weaponUid, weapon, session);
+                    if (!DoLightAttack(user, light, weaponUid, weapon, session))
+                        return false;
                     animation = weapon.Animation;
                     break;
                 case DisarmAttackEvent disarm:
+                    // DoDisarm already returns bool and is checked
                     if (!DoDisarm(user, disarm, weaponUid, weapon, session))
                         return false;
-
                     animation = weapon.Animation;
                     break;
                 case HeavyAttackEvent heavy:
@@ -447,13 +449,20 @@ private bool AttemptAttack(EntityUid user, EntityUid weaponUid, MeleeWeaponCompo
 
     protected abstract bool InRange(EntityUid user, EntityUid target, float range, ICommonSession? session);
 
-    protected virtual void DoLightAttack(EntityUid user, LightAttackEvent ev, EntityUid meleeUid, MeleeWeaponComponent component, ICommonSession? session)
+    protected virtual bool DoLightAttack(EntityUid user, LightAttackEvent ev, EntityUid meleeUid, MeleeWeaponComponent component, ICommonSession? session)
     {
         // If I do not come back later to fix Light Attacks being Heavy Attacks you can throw me in the spider pit -Errant
         var damage = GetDamage(meleeUid, user, component) * GetHeavyDamageModifier(meleeUid, user, component);
         var target = GetEntity(ev.Target);
         var resistanceBypass = GetResistanceBypass(meleeUid, user, component);
 
+        //do a stamina check before attacking
+        if (TryComp<StaminaComponent>(user, out var stam))
+        {
+            if (stam.StaminaDamage > stam.SlowdownThreshold)
+            { return false; }
+        }
+
         // For consistency with wide attacks stuff needs damageable.
         if (Deleted(target) ||
             !HasComp<DamageableComponent>(target) ||
@@ -480,7 +489,7 @@ protected virtual void DoLightAttack(EntityUid user, LightAttackEvent ev, Entity
             var missEvent = new MeleeHitEvent(new List<EntityUid>(), user, meleeUid, damage, null);
             RaiseLocalEvent(meleeUid, missEvent);
             _meleeSound.PlaySwingSound(user, meleeUid, component);
-            return;
+            return true;
         }
 
         // Sawmill.Debug($"Melee damage is {damage.Total} out of {component.Damage.Total}");
@@ -490,7 +499,7 @@ protected virtual void DoLightAttack(EntityUid user, LightAttackEvent ev, Entity
         RaiseLocalEvent(meleeUid, hitEvent);
 
         if (hitEvent.Handled)
-            return;
+            return true;
 
         var targets = new List<EntityUid>(1)
         {
@@ -513,13 +522,16 @@ protected virtual void DoLightAttack(EntityUid user, LightAttackEvent ev, Entity
         var modifiedDamage = DamageSpecifier.ApplyModifierSets(damage + hitEvent.BonusDamage + attackedEvent.BonusDamage, hitEvent.ModifiersList);
         var damageResult = Damageable.TryChangeDamage(target, modifiedDamage, origin: user, ignoreResistances: resistanceBypass);
 
+        //drain stamina from the attacker as well
+        //hardcoded at 10 for now, TODO: Make it take into account the weapons weight?
+        _stamina.TakeStaminaDamage(user, 10f, visual: false, source: user, with: meleeUid == user ? null : meleeUid, immediate: false);
 
         if (damageResult is { Empty: false })
         {
             // If the target has stamina and is taking blunt damage, they should also take stamina damage based on their blunt to stamina factor
             if (damageResult.DamageDict.TryGetValue("Blunt", out var bluntDamage))
             {
-                _stamina.TakeStaminaDamage(target.Value, (bluntDamage * component.BluntStaminaDamageFactor).Float(), visual: false, source: user, with: meleeUid == user ? null : meleeUid);
+                _stamina.TakeStaminaDamage(target.Value, (bluntDamage * component.BluntStaminaDamageFactor).Float(), visual: false, source: user, with: meleeUid == user ? null : meleeUid, immediate: false);
             }
 
             if (meleeUid == user)
@@ -543,6 +555,8 @@ protected virtual void DoLightAttack(EntityUid user, LightAttackEvent ev, Entity
         {
             DoDamageEffect(targets, user, targetXform);
         }
+
+        return true;
     }
 
     protected abstract void DoDamageEffect(List<EntityUid> targets, EntityUid? user, TransformComponent targetXform);
@@ -558,6 +572,13 @@ private bool DoHeavyAttack(EntityUid user, HeavyAttackEvent ev, EntityUid meleeU
         if (targetMap.MapId != userXform.MapID)
             return false;
 
+        //do a stamina check before attacking
+        if (TryComp<StaminaComponent>(user, out var stam))
+        {
+            if (stam.StaminaDamage > stam.SlowdownThreshold)
+            { return false; }
+        }
+
         var userPos = TransformSystem.GetWorldPosition(userXform);
         var direction = targetMap.Position - userPos;
         var distance = Math.Min(component.Range, direction.Length());
@@ -565,6 +586,10 @@ private bool DoHeavyAttack(EntityUid user, HeavyAttackEvent ev, EntityUid meleeU
         var damage = GetDamage(meleeUid, user, component);
         var entities = GetEntityList(ev.Entities);
 
+        //drain stamina from the attacker as well
+        //hardcoded at 20 for now, TODO: Make it take into account the weapons weight?
+        _stamina.TakeStaminaDamage(user, 20f, visual: false, source: user, with: meleeUid == user ? null : meleeUid, immediate: false);
+
         if (entities.Count == 0)
         {
             if (meleeUid == user)
@@ -674,7 +699,7 @@ private bool DoHeavyAttack(EntityUid user, HeavyAttackEvent ev, EntityUid meleeU
                 // If the target has stamina and is taking blunt damage, they should also take stamina damage based on their blunt to stamina factor
                 if (damageResult.DamageDict.TryGetValue("Blunt", out var bluntDamage))
                 {
-                    _stamina.TakeStaminaDamage(entity, (bluntDamage * component.BluntStaminaDamageFactor).Float(), visual: false, source: user, with: meleeUid == user ? null : meleeUid);
+                    _stamina.TakeStaminaDamage(entity, (bluntDamage * component.BluntStaminaDamageFactor).Float(), visual: false, source: user, with: meleeUid == user ? null : meleeUid, immediate: false);
                 }
 
                 appliedDamage += damageResult;

+ 15 - 1
Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs

@@ -384,6 +384,20 @@ public void AttemptShoot(EntityUid gunUid, GunComponent gun)
         Shoot(gunUid, gun, new List<(EntityUid? Entity, IShootable Shootable)>(1) { (ammo, shootable) }, fromCoordinates, toCoordinates, out userImpulse, user, throwItems);
     }
 
+    /// <summary>
+    /// Fires one or more projectiles or hitscan shots from a gun using the provided ammo, handling recoil, effects, and impact logic.
+    /// </summary>
+    /// <param name="gunUid">The entity UID of the gun firing.</param>
+    /// <param name="gun">The gun component associated with the firing gun.</param>
+    /// <param name="ammo">A list of ammo entities and their shootable components to be fired.</param>
+    /// <param name="fromCoordinates">The origin coordinates of the shot.</param>
+    /// <param name="toCoordinates">The target coordinates of the shot.</param>
+    /// <param name="userImpulse">Set to true if the user should receive recoil impulse; false if not.</param>
+    /// <param name="user">The entity UID of the user firing the gun, if any.</param>
+    /// <param name="throwItems">If true, items are thrown instead of shot as projectiles.</param>
+    /// <param name="predictedProjectiles">Optional list of predicted projectile indices for client-side prediction.</param>
+    /// <param name="userSession">Optional session of the user for prediction purposes.</param>
+    /// <returns>A list of entity UIDs representing the fired projectiles, or null if none were fired.</returns>
     public List<EntityUid>? Shoot(
         EntityUid gunUid,
         GunComponent gun,
@@ -581,7 +595,7 @@ void MarkPredicted(EntityUid projectile, int index)
                     {
                         var hitEntity = lastHit.Value;
                         if (hitscan.StaminaDamage > 0f)
-                            _stamina.TakeStaminaDamage(hitEntity, hitscan.StaminaDamage, source: user);
+                            _stamina.TakeStaminaDamage(hitEntity, hitscan.StaminaDamage, source: user, immediate: true);
 
                         var dmg = hitscan.Damage;
 

+ 35 - 0
Content.Shared/_Shitcode/Stunnable/OvertimeStaminaDamageComponent.cs

@@ -0,0 +1,35 @@
+// SPDX-FileCopyrightText: 2024 username <113782077+whateverusername0@users.noreply.github.com>
+// SPDX-FileCopyrightText: 2024 whateverusername0 <whateveremail>
+// SPDX-FileCopyrightText: 2025 Aiden <28298836+Aidenkrz@users.noreply.github.com>
+// SPDX-FileCopyrightText: 2025 Misandry <mary@thughunt.ing>
+// SPDX-FileCopyrightText: 2025 gus <august.eymann@gmail.com>
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+
+using Robust.Shared.GameObjects;
+using Robust.Shared.GameStates;
+using Robust.Shared.Serialization.Manager.Attributes;
+using Robust.Shared.ViewVariables;
+
+namespace Content.Shared.Common.Stunnable;
+
+[RegisterComponent, NetworkedComponent]
+public sealed partial class OvertimeStaminaDamageComponent : Component
+{
+    [DataField] public float Delay = 1f;
+    [ViewVariables(VVAccess.ReadWrite)] public float Timer = 1f;
+
+    /// <summary>
+    ///     Total amount of stamina damage a person is about to get
+    /// </summary>
+    [DataField] public float Amount = 10f;
+
+    [ViewVariables(VVAccess.ReadWrite)] public float Damage = 10f;
+
+
+    /// <summary>
+    ///     Divisor. How much damage should we add overtime.
+    /// </summary>
+    /// <remarks> For example, if the divisor is 5, out entity will get the entire overtime stam damage only after 5 seconds. </remarks>
+    [DataField] public float Delta = 5f;
+}

+ 22 - 0
Content.Shared/_Shitcode/Stunnable/StamcritResistComponent.cs

@@ -0,0 +1,22 @@
+// SPDX-FileCopyrightText: 2024 username <113782077+whateverusername0@users.noreply.github.com>
+// SPDX-FileCopyrightText: 2024 whateverusername0 <whateveremail>
+// SPDX-FileCopyrightText: 2025 Aiden <28298836+Aidenkrz@users.noreply.github.com>
+// SPDX-FileCopyrightText: 2025 Misandry <mary@thughunt.ing>
+// SPDX-FileCopyrightText: 2025 gus <august.eymann@gmail.com>
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+
+using Robust.Shared.GameObjects;
+using Robust.Shared.GameStates;
+using Robust.Shared.Serialization.Manager.Attributes;
+
+namespace Content.Goobstation.Common.Stunnable;
+
+[RegisterComponent, NetworkedComponent]
+public sealed partial class StamcritResistComponent : Component
+{
+    /// <summary>
+    ///     If stamina damage reaches (damage * multiplier), then the entity will enter stamina crit.
+    /// </summary>
+    [DataField] public float Multiplier = 2f;
+}

+ 36 - 0
Content.Shared/_Shitcode/Weapons/DodgeWideswing/DodgeWideswingComponent.cs

@@ -0,0 +1,36 @@
+// SPDX-FileCopyrightText: 2025 Aiden <28298836+Aidenkrz@users.noreply.github.com>
+// SPDX-FileCopyrightText: 2025 Ilya246 <57039557+Ilya246@users.noreply.github.com>
+// SPDX-FileCopyrightText: 2025 Misandry <mary@thughunt.ing>
+// SPDX-FileCopyrightText: 2025 gus <august.eymann@gmail.com>
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+
+using Robust.Shared.GameStates;
+using Robust.Shared.Localization;
+
+namespace Content.Shared.Goobstation.Weapons.DodgeWideswing;
+
+/// <summary>
+/// Makes this entity have a chance to dodge a wideswing attack, converting the incoming damage into stamina damage.
+/// </summary>
+[RegisterComponent]
+public sealed partial class DodgeWideswingComponent : Component
+{
+    [DataField]
+    public float Chance = 1f;
+
+    /// <summary>
+    /// How much stamina damage to apply per damage from source.
+    /// </summary>
+    [DataField]
+    public float StaminaRatio = 1f;
+
+    /// <summary>
+    /// Whether to still evade if knocked down.
+    /// </summary>
+    [DataField]
+    public bool WhenKnockedDown = false;
+
+    [DataField]
+    public LocId? PopupId = "wideswing-dodge-generic";
+}

+ 50 - 0
Content.Shared/_Shitcode/Weapons/DodgeWideswing/DodgeWideswingSystem.cs

@@ -0,0 +1,50 @@
+// SPDX-FileCopyrightText: 2025 Aiden <28298836+Aidenkrz@users.noreply.github.com>
+// SPDX-FileCopyrightText: 2025 Ilya246 <57039557+Ilya246@users.noreply.github.com>
+// SPDX-FileCopyrightText: 2025 Misandry <mary@thughunt.ing>
+// SPDX-FileCopyrightText: 2025 gus <august.eymann@gmail.com>
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+
+using Content.Shared.Damage;
+using Content.Shared.Damage.Systems;
+using Content.Shared.Popups;
+using Content.Shared.Stunnable;
+using Robust.Shared.Random;
+
+namespace Content.Shared.Goobstation.Weapons.DodgeWideswing;
+
+public sealed class DodgeWideswingSystem : EntitySystem
+{
+    [Dependency] private readonly SharedPopupSystem _popup = default!;
+    [Dependency] private readonly IRobustRandom _random = default!;
+    [Dependency] private readonly StaminaSystem _stamina = default!;
+
+    /// <summary>
+    /// Subscribes to damage change events for entities with the <see cref="DodgeWideswingComponent"/>.
+    /// </summary>
+    public override void Initialize()
+    {
+        base.Initialize();
+
+        SubscribeLocalEvent<DodgeWideswingComponent, BeforeDamageChangedEvent>(OnDamageChanged);
+    }
+
+    /// <summary>
+    /// Handles incoming heavy attack damage for entities with a DodgeWideswingComponent, potentially converting the damage into stamina loss and cancelling the original damage based on configured chance and conditions.
+    /// </summary>
+    /// <param name="uid">The entity receiving the damage.</param>
+    /// <param name="component">The DodgeWideswingComponent associated with the entity.</param>
+    /// <param name="args">The event data for the incoming damage, passed by reference.</param>
+    private void OnDamageChanged(EntityUid uid, DodgeWideswingComponent component, ref BeforeDamageChangedEvent args)
+    {
+        if (args.HeavyAttack && (!HasComp<KnockedDownComponent>(uid) || component.WhenKnockedDown) && _random.Prob(component.Chance))
+        {
+            _stamina.TakeStaminaDamage(uid, args.Damage.GetTotal().Float() * component.StaminaRatio, source: args.Origin, immediate: false);
+
+            if (component.PopupId != null)
+                _popup.PopupPredicted(Loc.GetString(component.PopupId, ("target", uid)), uid, args.Origin);
+
+            args.Cancelled = true;
+        }
+    }
+}

+ 1 - 0
Content.Shared/_Stalker/Stamina/StaminaActiveComponent.cs

@@ -37,4 +37,5 @@ public sealed partial class StaminaActiveComponent : Component
     /// Nothing will happen if you'll set it manually.
     /// </summary>
     public bool Slowed = false;
+
 }

+ 2 - 0
Resources/Locale/en-US/chat/emotes.ftl

@@ -15,6 +15,7 @@ chat-emote-name-clap-single = Single Clap
 chat-emote-name-snap = Snap
 chat-emote-name-salute = Salute
 chat-emote-name-gasp = Gasp
+chat-emote-name-gasp-stamina = Out-of-Breath Gasp
 chat-emote-name-deathgasp = Deathgasp
 chat-emote-name-buzz = Buzz
 chat-emote-name-weh = Weh
@@ -50,6 +51,7 @@ chat-emote-msg-clap-single = claps {POSS-ADJ($entity)} hands together.
 chat-emote-msg-snap = snaps {POSS-ADJ($entity)} fingers.
 chat-emote-msg-salute = salutes.
 chat-emote-msg-gasp = gasps.
+chat-emote-msg-gasp-stamina = gasps, out of breath.
 chat-emote-msg-deathgasp = seizes up and falls limp, {POSS-ADJ($entity)} eyes dead and lifeless...
 chat-emote-msg-deathgasp-monkey = lets out a faint chimper as {SUBJECT($entity)} collapses and stops moving...
 chat-emote-msg-buzz = buzzes!

+ 1 - 0
Resources/Locale/en-US/damage/stamina.ftl

@@ -1,2 +1,3 @@
 melee-stamina = Not enough stamina
 slow-on-damage-modifier-examine = Slowness from injuries is reduced by [color=yellow]{$mod}%[/color]
+wideswing-dodge-generic = {THE($target)} swiftly evades the broad swing!

Diff do ficheiro suprimidas por serem muito extensas
+ 2 - 2
Resources/Maps/civ/tdm/camp.yml


+ 1 - 1
Resources/Prototypes/Civ14/Entities/Markers/capturable_areas.yml

@@ -22,7 +22,7 @@
       state: capture_green
     - type: CaptureArea
       name: "the Castle"
-      captureDuration: 300 # 5 min
+      captureDuration: 240 # 4 min
       captureRadius: 6
       capturableFactions:
         - England

+ 10 - 0
Resources/Prototypes/Civ14/Entities/Objects/Storage/filled_crates.yml

@@ -0,0 +1,10 @@
+- type: entity
+  parent: CrateWood
+  id: CrateWoodArrows
+  name: wood crate
+  suffix: arrows
+  components:
+    - type: StorageFill
+      contents:
+        - id: ArrowIron
+          amount: 12

+ 13 - 7
Resources/Prototypes/Civ14/Entities/Objects/Weapons/swords.yml

@@ -330,13 +330,15 @@
     - type: Sprite
       sprite: Civ14/Weapons/longsword.rsi
     - type: MeleeWeapon
-      damage: 
+      range: 2
+      attackRate: 1.3
+      damage:
         types:
           Slash: 38
       soundHit:
         path: /Audio/Weapons/bladeslice.ogg
     - type: Wieldable
-    - type: IncreaseDamageOnWield 
+    - type: IncreaseDamageOnWield
       damage:
         types:
           Piercing: 5
@@ -355,13 +357,15 @@
     - type: Sprite
       sprite: Civ14/Weapons/zweihander.rsi
     - type: MeleeWeapon
+      range: 2
+      attackRate: 1.3
       damage:
         types:
           Slash: 35
       soundHit:
         path: /Audio/Weapons/bladeslice.ogg
     - type: Wieldable
-    - type: IncreaseDamageOnWield 
+    - type: IncreaseDamageOnWield
       damage:
         types:
           Piercing: 8
@@ -380,13 +384,15 @@
     - type: Sprite
       sprite: Civ14/Weapons/claymore.rsi
     - type: MeleeWeapon
+      range: 2
+      attackRate: 1.3
       damage:
         types:
           Slash: 32
       soundHit:
         path: /Audio/Weapons/bladeslice.ogg
     - type: Wieldable
-    - type: IncreaseDamageOnWield 
+    - type: IncreaseDamageOnWield
       damage:
         types:
           Piercing: 8
@@ -430,15 +436,15 @@
     - type: MeleeWeapon
       damage:
         types:
-          Slash: 36     
+          Slash: 36
       soundHit:
         path: /Audio/Weapons/bladeslice.ogg
     - type: Wieldable
-    - type: IncreaseDamageOnWield 
+    - type: IncreaseDamageOnWield
       damage:
         types:
           Piercing: 2
-          Slash: 15 
+          Slash: 15
     - type: Item
       heldPrefix: null
       sprite: Civ14/Weapons/broadsword.rsi

+ 1 - 0
Resources/Prototypes/Civ14/Entities/Objects/handheld_flags.yml

@@ -0,0 +1 @@
+# placeholder

+ 1 - 0
Resources/Prototypes/Civ14/Entities/Structures/Walls/barricades.yml

@@ -70,6 +70,7 @@
       state: sandbag
       drawdepth: FloorObjects
       noRot: true
+    - type: Climbable
     - type: Physics
     - type: Fixtures
       fixtures:

+ 280 - 0
Resources/Prototypes/Civ14/Entities/Structures/flags.yml

@@ -0,0 +1,280 @@
+- type: entity
+  parent: BaseSign
+  id: BaseFlagPole
+  abstract: true
+  description: "A flag on a pole."
+  components:
+    - type: Sprite
+      drawdepth: WallMountedItems
+      sprite: Civ14/Objects/flags.rsi
+      state: cust_flag
+
+- type: entity
+  id: civ13_flag_pirates
+  name: Pirate flag
+  description: A black and white pirate flags with skull and bones.
+  parent: BaseFlagPole
+  components:
+    - type: Sprite
+      state: pirates
+
+- type: entity
+  id: civ13_flag_black
+  name: Black flag
+  description: A black flag.
+  parent: BaseFlagPole
+  components:
+    - type: Sprite
+      state: black
+
+- type: entity
+  id: civ13_flag_french
+  name: French flag
+  description: The French flag, white with golden fleur-de-lys.
+  parent: BaseFlagPole
+  components:
+    - type: Sprite
+      state: french
+
+- type: entity
+  id: civ13_flag_french_modern
+  name: French flag
+  description: The modern french tricoleur.
+  parent: BaseFlagPole
+  components:
+    - type: Sprite
+      state: french2
+
+- type: entity
+  id: civ13_flag_french_monarchist
+  name: French flag
+  description: The french monarchist flag.
+  parent: BaseFlagPole
+  components:
+    - type: Sprite
+      state: french3
+
+- type: entity
+  id: civ13_flag_spanish
+  name: Spanish Flag
+  description: The Spanish flag, white with a red cross of burgundy.
+  parent: BaseFlagPole
+  components:
+    - type: Sprite
+      state: spanish
+
+- type: entity
+  id: civ13_flag_spanish_modern
+  name: Spanish Flag
+  description: The modern yellow and red spanish flag.
+  parent: BaseFlagPole
+  components:
+    - type: Sprite
+      state: spanish2
+
+- type: entity
+  id: civ13_flag_italian
+  name: Italian Flag
+  description: The modern italian flag.
+  parent: BaseFlagPole
+  components:
+    - type: Sprite
+      state: italian
+
+- type: entity
+  id: civ13_flag_british
+  name: British flag
+  description: The Union Jack.
+  parent: BaseFlagPole
+  components:
+    - type: Sprite
+      state: british
+
+- type: entity
+  id: civ13_flag_portuguese
+  name: Portuguese flag
+  description: A white flag with the Portuguese Coat of Arms in the middle.
+  parent: BaseFlagPole
+  components:
+    - type: Sprite
+      state: portuguese
+
+- type: entity
+  id: civ13_flag_dutch
+  name: Dutch Flag
+  description: The tricolor Dutch flag.
+  parent: BaseFlagPole
+  components:
+    - type: Sprite
+      state: netherlands
+
+- type: entity
+  id: civ13_flag_dutch_old
+  name: Dutch Flag
+  description: The tricolor Dutch flag.
+  parent: BaseFlagPole
+  components:
+    - type: Sprite
+      state: netherlands_old
+
+- type: entity
+  id: civ13_flag_japanese
+  name: Imperial Japanese flag
+  description: The Imperial Japanese flag.
+  parent: BaseFlagPole
+  components:
+    - type: Sprite
+      state: japanese
+
+- type: entity
+  id: civ13_flag_russian
+  name: Russian flag
+  description: The tricolor Russian flag.
+  parent: BaseFlagPole
+  components:
+    - type: Sprite
+      state: russian
+
+- type: entity
+  id: civ13_flag_soviet
+  name: Soviet Union Flag
+  description: The Soviet flag.
+  parent: BaseFlagPole
+  components:
+    - type: Sprite
+      state: soviet
+
+- type: entity
+  id: civ13_flag_us
+  name: USA flag
+  description: The US flag.
+  parent: BaseFlagPole
+  components:
+    - type: Sprite
+      state: us
+
+- type: entity
+  id: civ13_flag_german
+  name: German flag
+  description: The German flag.
+  parent: BaseFlagPole
+  components:
+    - type: Sprite
+      state: german
+
+- type: entity
+  id: civ13_flag_german_modern
+  name: German flag
+  description: The German flag.
+  parent: BaseFlagPole
+  components:
+    - type: Sprite
+      state: german2
+
+- type: entity
+  id: civ13_flag_confed
+  name: Confederate flag
+  description: The Confederate flag
+  parent: BaseFlagPole
+  components:
+    - type: Sprite
+      state: confed
+
+- type: entity
+  id: civ13_flag_reich
+  name: Third Reich Flag
+  description: The Third Reich war flag.
+  parent: BaseFlagPole
+  components:
+    - type: Sprite
+      state: reich
+
+- type: entity
+  id: civ13_flag_chinese
+  name: Republic of China Flag
+  description: The Republic of China flag.
+  parent: BaseFlagPole
+  components:
+    - type: Sprite
+      state: chinese
+
+- type: entity
+  id: civ13_flag_filipino
+  name: Philippines Republic
+  description: The Republic of the Philippines flag.
+  parent: BaseFlagPole
+  components:
+    - type: Sprite
+      state: filipino
+
+- type: entity
+  id: civ13_flag_filipino_war
+  name: Philippines Republic
+  description: The Republic of the Philippines flag. This one flipped for wartime.
+  parent: BaseFlagPole
+  components:
+    - type: Sprite
+      state: filipino_wartime
+
+- type: entity
+  id: civ13_flag_nva
+  name: North Vietnam Flag
+  description: The flag of North Vietnam.
+  parent: BaseFlagPole
+  components:
+    - type: Sprite
+      state: nva
+
+- type: entity
+  id: civ13_flag_vietcong
+  name: Vietcong Flag
+  description: The flag of the National Liberation Front of Vietnam.
+  parent: BaseFlagPole
+  components:
+    - type: Sprite
+      state: vietcong
+
+- type: entity
+  id: civ13_flag_campaign_redmenia
+  name: Redmenia Flag
+  description: The flag of Redmenia.
+  parent: BaseFlagPole
+  components:
+    - type: Sprite
+      state: redmenia
+
+- type: entity
+  id: civ13_flag_campaign_blugoslavia
+  name: Blugoslavia Flag
+  description: The flag of Blugoslavia.
+  parent: BaseFlagPole
+  components:
+    - type: Sprite
+      state: blugoslavia
+
+- type: entity
+  id: civ13_flag_pole
+  name: Flagpole
+  description: Flagless, apply cloth or a flag.
+  parent: BaseFlagPole
+  components:
+    - type: Sprite
+      state: flagpole_blank
+
+- type: entity
+  id: civ13_flag_bearclan
+  name: Bearclan Banner
+  description: A Bearclan banner.
+  parent: BaseFlagPole
+  components:
+    - type: Sprite
+      state: bearclan
+
+- type: entity
+  id: civ13_flag_ravenclan
+  name: Raven Banner
+  description: A Ravenclan banner.
+  parent: BaseFlagPole
+  components:
+    - type: Sprite
+      state: ravenclan

+ 1091 - 0
Resources/Prototypes/Civ14/Entities/Structures/wall_flags.yml

@@ -0,0 +1,1091 @@
+- type: entity
+  parent: BaseFlag
+  id: WallFlagWhite
+  name: white flag
+  description: A wall mounted flag.
+  components:
+    - type: Sprite
+      sprite: Civ14/Objects/decals.rsi
+      state: f_white
+
+- type: entity
+  id: civ13_wallflag_green
+  name: green banner
+  description: A green linen banner.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: green_banner
+
+- type: entity
+  id: civ13_wallflag_red
+  name: red banner
+  description: A red linen banner.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: red_banner
+
+- type: entity
+  id: civ13_wallflag_red2
+  name: red banner
+  description: A red linen banner, with golden trims.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: red_banner2
+
+- type: entity
+  id: civ13_wallflag_blue
+  name: blue banner
+  description: A blue linen banner.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: blue_banner
+
+- type: entity
+  id: civ13_wallflag_reich
+  name: Reich Flag
+  description: A Reich flag for glory.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: reich
+
+- type: entity
+  id: civ13_wallflag_gb_imperial
+  name: Extra-Galactic Empire Flag
+  description: An Imperial Flag for the Extra-Galactic Empire.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_galacticempire
+
+- type: entity
+  id: civ13_wallflag_gb_rebel
+  name: Alliance to Restore the Democracy Flag
+  description: A Rebellious flag for the Alliance.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_rebelalliance
+
+- type: entity
+  id: civ13_wallflag_gb_pysker
+  name: Pysker Order Flag
+  description: A blue and white flag for the ancient order of pyskers.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_pysker
+
+- type: entity
+  id: civ13_wallflag_gb_cis
+  name: Confederacy of Issolationist Star-Systems Flag
+  description: A bright blue and white with a circular emblem.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_cis
+
+- type: entity
+  id: civ13_wallflag_russia
+  name: Russian flag
+  description: A flag of Russsia.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_russia
+
+- type: entity
+  id: civ13_wallflag_brazil_empire
+  name: Empire of Brazil flag
+  description: The flag of the Empire of Brazil.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_brazil_empire
+
+- type: entity
+  id: civ13_wallflag_russia_kornilov
+  name: Kornilov Shock Regiment flag
+  description: A flag of the infamous regiment of the Volunteer Army.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_russia_kornilov
+
+- type: entity
+  id: civ13_wallflag_sov_navy
+  name: Soviet Navy flag
+  description: The flag of the naval service branch of the Soviet Armed Forces.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_sovfleet
+
+- type: entity
+  id: civ13_wallflag_russia_rsfsr
+  name: RSFSR flag
+  description: A flag of the Russian Soviet Federative Socialist Republic.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_rsfsr
+
+- type: entity
+  id: civ13_wallflag_usa
+  name: USA flag
+  description: The star-spangled banner.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_usa
+
+- type: entity
+  id: civ13_wallflag_blue2
+  name: blue banner
+  description: A blue linen banner, with golden trims.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: blue_banner2
+
+- type: entity
+  id: civ13_wallflag_templar1
+  name: templar banner
+  description: A white banner with the red cross of the templars in the middle.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: templar_banner1
+
+- type: entity
+  id: civ13_wallflag_templar2
+  name: templar banner
+  description: A white banner with the red cross of the templars in the middle.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: templar_banner2
+
+- type: entity
+  id: civ13_wallflag_jihad1
+  name: black islamic flag
+  description: A black flag with Allah written in Arabic.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: jihad1
+
+- type: entity
+  id: civ13_wallflag_jihad2
+  name: green islamic flag
+  description: A green flag with Allah written in Arabic.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: jihad2
+
+- type: entity
+  id: civ13_wallflag_jihad3
+  name: red islamic banner
+  description: A red banner with three moons.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: jihad3
+
+- type: entity
+  id: civ13_wallflag_jihad4
+  name: green islamic banner
+  description: A green banner with the shadada.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: jihad4
+
+- type: entity
+  id: civ13_wallflag_taliban
+  name: taliban flag
+  description: A white flag of the Taliban.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_taliban
+
+- type: entity
+  id: civ13_wallflag_isis
+  name: ISIS flag
+  description: A black flag of the ISIS.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_isis
+
+- type: entity
+  id: civ13_wallflag_chechen
+  name: chechen flag
+  description: The Chechen Separatist flag.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_chechen
+
+- type: entity
+  id: civ13_wallflag_ireland
+  name: irish flag
+  description: The Irish Republic flag.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_ireland
+
+- type: entity
+  id: civ13_wallflag_gadsen
+  name: Gadsen flag
+  description: The classic Gadsen flag.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_gadsen
+
+- type: entity
+  id: civ13_wallflag_medical
+  name: Medical flag
+  description: >-
+    A flag with the universally recognized symbol for medicine and humanitarian
+    aid.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: medical_flag
+
+- type: entity
+  id: civ13_wallflag_medical_crescent
+  name: Red crescent flag
+  description: A flag with the crescent emblem for medicine and humanitarian aid.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: medical_flag_crescent
+
+- type: entity
+  id: civ13_wallflag_medical_crystal
+  name: Medical crystal flag
+  description: A flag with the crystal symbol for medicine and humaniarian aid.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: medical_flag_crystal
+
+- type: entity
+  id: civ13_wallflag_japanese
+  name: Imperial Japanese flag
+  description: A flag with the imperial Japanese rising sun.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_japan_empire
+
+- type: entity
+  id: civ13_wallflag_german_modern
+  name: German flag
+  description: A horizontal tricolour flag of the German Republic.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_germany_republic
+
+- type: entity
+  id: civ13_wallflag_chinese
+  name: Republic of China flag
+  description: A flag with the republic of China design.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_china
+
+- type: entity
+  id: civ13_wallflag_chinese_prc
+  name: People's Republic of China flag
+  description: A flag with the PRC design.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_chinacommie
+
+- type: entity
+  id: civ13_wallflag_mongolia
+  name: Mongolian State flag
+  description: A flag of the state of Mongolia.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_mongolia
+
+- type: entity
+  id: civ13_wallflag_mongolia_communist
+  name: Mongolian People's Republic flag
+  description: A flag of the Mongolian People's Republic.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_mongolia_communist
+
+- type: entity
+  id: civ13_wallflag_french
+  name: French flag
+  description: A flag with the tricolour french flag.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_france
+
+- type: entity
+  id: civ13_wallflag_denmark
+  name: Danish flag
+  description: A flag with the red and white dannebrog.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_denmark
+
+- type: entity
+  id: civ13_wallflag_german
+  name: German Empire flag
+  description: A horizontal tricolour flag of the German Empire.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_germany
+
+- type: entity
+  id: civ13_wallflag_german_east
+  name: East German flag
+  description: A horizontal tricolour flag of the German Democratic Republic.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_germany_east
+
+- type: entity
+  id: civ13_wallflag_uk
+  name: United Kingdom flag
+  description: A flag of the United Kingdom.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_uk
+
+- type: entity
+  id: civ13_wallflag_ukraine
+  name: Ukrainian flag
+  description: A flag of Ukraine.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_ukraine
+
+- type: entity
+  id: civ13_wallflag_ukraine_upa
+  name: flag of the UPA
+  description: The flag of the Ukrainian Insurgent Army called UPA.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_ukraine_upa
+
+- type: entity
+  id: civ13_wallflag_ukraine_makhno
+  name: Makhnovsti flag
+  description: >-
+    A flag of the Revolutionary Insurgent Army of Ukraine. Also known as the
+    Black Army or Makhnovsti.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_makhno
+
+- type: entity
+  id: civ13_wallflag_ukraine_azov
+  name: flag of the Azov regiment
+  description: The flag of the infamous Azov regiment of the Ukrainian National Guard.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_ukraine_azov
+
+- type: entity
+  id: civ13_wallflag_ukraine_rightsector
+  name: flag of the Right Sector
+  description: The flag of the Ukrainian far-right paramilitary movement.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_ukraine_rightsector
+
+- type: entity
+  id: civ13_wallflag_ukraine_dnr
+  name: flag of the Donetsk People's Republic
+  description: The flag of the self-proclaimed state of the Donetsk People's Republic
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_ukraine_dnr
+
+- type: entity
+  id: civ13_wallflag_ukraine_lnr
+  name: flag of the Luhansk People's Republic
+  description: The flag of the self-proclaimed state of the Luhansk People's Republic
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_ukraine_lnr
+
+- type: entity
+  id: civ13_wallflag_ukraine_afu
+  name: AFU flag
+  description: The flag of the Armed Forces of Ukraine.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_vsu
+
+- type: entity
+  id: civ13_wallflag_doncossack
+  name: Don Cossack Host flag
+  description: A flag of the Don cossacks.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_doncossack
+
+- type: entity
+  id: civ13_wallflag_terekcossack
+  name: Terek Cossack Host flag
+  description: A flag of the Terek cossacks.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_terekcossack
+
+- type: entity
+  id: civ13_wallflag_poland
+  name: Polish flag
+  description: A flag of Poland.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_poland
+
+- type: entity
+  id: civ13_wallflag_vietnam
+  name: North Vietnam flag
+  description: The North Vietnamese flag.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_vietnam
+
+- type: entity
+  id: civ13_wallflag_vietcong
+  name: Viet Cong flag
+  description: The blue and red flag of the Viet Cong forces.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_vietcong
+
+- type: entity
+  id: civ13_wallflag_usa_union
+  name: Union flag
+  description: The red, white and blue flag flying above ranks of blue-clad troops.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_union
+
+- type: entity
+  id: civ13_wallflag_usa_confed
+  name: Confederate flag
+  description: The flag of the Confederate States.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_confederate
+
+- type: entity
+  id: civ13_wallflag_texas
+  name: Texan flag
+  description: The flag of the state of Texas.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_texas
+
+- type: entity
+  id: civ13_wallflag_hungary_sov
+  name: Hungarian People's Republic flag
+  description: The flag of the Hungarian People's Republic.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_hungary_sov
+
+- type: entity
+  id: civ13_wallflag_sov_vdv
+  name: Soviet VDV flag
+  description: The flag of the Soviet Airborne Forces.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_vdv
+
+- type: entity
+  id: civ13_wallflag_sov_air
+  name: Soviet Air Forces flag
+  description: The flag of the Soviet Air Forces.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_sovair
+
+- type: entity
+  id: civ13_wallflag_sov_border
+  name: Soviet Border Troops flag
+  description: The flag of the Soviet Border Troops.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_sovborder
+
+- type: entity
+  id: civ13_wallflag_nazi
+  name: Third Reich flag
+  description: The red, white and black flag of the Third Reich.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_nazi
+
+- type: entity
+  id: civ13_wallflag_israel
+  name: Israel flag
+  description: The white and blue flag of Israel, with the 6 pointed star in the middle.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_israel
+
+- type: entity
+  id: civ13_wallflag_un
+  name: UN flag
+  description: The flag of the United Nations.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_un
+
+- type: entity
+  id: civ13_wallflag_dutch
+  name: Dutch flag
+  description: The flag of Netherlands.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_netherlands
+
+- type: entity
+  id: civ13_wallflag_dutch_old
+  name: Prince's flag
+  description: The Dutch flag.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_netherlands_old
+
+- type: entity
+  id: civ13_wallflag_chetnik
+  name: Chetnik flag
+  description: A Chetnik flag.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_chetnik
+
+- type: entity
+  id: civ13_wallflag_yugoslavia
+  name: Yugoslavian flag
+  description: The flag of Yugoslavia.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_yugo
+
+- type: entity
+  id: civ13_wallflag_yugoslavia_partisan
+  name: Yugoslavian flag
+  description: The flag of Yugoslavian partisans.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_yugopart
+
+- type: entity
+  id: civ13_wallflag_gns
+  name: GNS flag
+  description: The flag of the Goverment of National Salvation.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_gns
+
+- type: entity
+  id: civ13_wallflag_australia
+  name: Australian flag
+  description: The flag of Australia.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_australia
+
+- type: entity
+  id: civ13_wallflag_canada
+  name: Canadian flag
+  description: The flag of Canada.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_canada
+
+- type: entity
+  id: civ13_wallflag_hezbollah
+  name: Hezbollah flag
+  description: The yellow and green flag of the Shia Hezbollah organization.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_hezbollah
+
+- type: entity
+  id: civ13_wallflag_philippine
+  name: Filipino flag
+  description: The flag of the Philippines.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_fp
+
+- type: entity
+  id: civ13_wallflag_philippine_war
+  name: Filipino flag
+  description: The flag of the Philippines. Flipped for wartime.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_fp_war
+
+- type: entity
+  id: civ13_wallflag_pirate
+  name: Pirate flag
+  description: The black pirate flag, with a skull in the middle.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: pirate
+
+- type: entity
+  id: civ13_wallflag_firstcav
+  name: 1st Cavalry Division flag
+  description: Flag of the United States Army 1st Cavalry Division.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_1stcav
+
+- type: entity
+  id: civ13_wallflag_cuba
+  name: Cuban flag
+  description: The Cuban flag.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_cuba
+
+- type: entity
+  id: civ13_wallflag_colombia
+  name: Colombian flag
+  description: The flag of Colombia.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_colombia
+
+- type: entity
+  id: civ13_wallflag_colombia_farc
+  name: FARC flag
+  description: The flag of the Revolutionary Armed Forces of Columbia.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_colombia_farc
+
+- type: entity
+  id: civ13_wallflag_mexico
+  name: Mexican flag
+  description: The flag of Mexico.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_mexico
+
+- type: entity
+  id: civ13_wallflag_brazil
+  name: Brazilian flag
+  description: The flag of Brazil.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_brazil
+
+- type: entity
+  id: civ13_wallflag_paraguay
+  name: Paraguayan flag
+  description: The flag of Paraguay.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_paraguay
+
+- type: entity
+  id: civ13_wallflag_argentina
+  name: Argentinian flag
+  description: The flag of Argentina.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_argentina
+
+- type: entity
+  id: civ13_wallflag_venezuela
+  name: Venezuelan flag
+  description: The flag of Venezuela.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_venezuela
+
+- type: entity
+  id: civ13_wallflag_peru
+  name: Peruvian flag
+  description: The flag of Peru.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_peru
+
+- type: entity
+  id: civ13_wallflag_bolivia
+  name: Bolivian flag
+  description: The flag of Bolivia.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_bolivia
+
+- type: entity
+  id: civ13_wallflag_chile
+  name: Chilean flag
+  description: The flag of Chile.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_chile
+
+- type: entity
+  id: civ13_wallflag_afghan_dra
+  name: DRA flag
+  description: The Democratic Republic of Afghanistan flag.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_dra
+
+- type: entity
+  id: civ13_wallflag_iran
+  name: Iranian flag
+  description: The Iranian flag.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_iran
+
+- type: entity
+  id: civ13_wallflag_iraq
+  name: Iraqui flag
+  description: The flag of Iraq.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_iraq
+
+- type: entity
+  id: civ13_wallflag_syria
+  name: Syrian Arab Republic flag
+  description: The flag of the Syrian Arab Republic.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_syria
+
+- type: entity
+  id: civ13_wallflag_fsa
+  name: FSA flag
+  description: The flag of the Free Syrian Army.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_syria_fsa
+
+- type: entity
+  id: civ13_wallflag_turkey
+  name: Turkish flag
+  description: The flag of Turkey.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_turkey
+
+- type: entity
+  id: civ13_wallflag_kurdistan
+  name: Kurdish flag
+  description: The flag of Kurdistan.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_kurdistan
+
+- type: entity
+  id: civ13_wallflag_georgia
+  name: Georgian flag
+  description: The flag of Georgia.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_georgia
+
+- type: entity
+  id: civ13_wallflag_india
+  name: Indian flag
+  description: The flag of India.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_india
+
+- type: entity
+  id: civ13_wallflag_pakistan
+  name: Pakistani flag
+  description: The flag of Pakistan.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_pakistan
+
+- type: entity
+  id: civ13_wallflag_italy
+  name: Italian flag
+  description: The Italian flag.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_italy
+
+- type: entity
+  id: civ13_wallflag_finland
+  name: Finnish flag
+  description: The flag of Finland.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_finland
+
+- type: entity
+  id: civ13_wallflag_nigeria
+  name: Nigerian flag
+  description: The flag of Nigeria.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_nigeria
+
+- type: entity
+  id: civ13_wallflag_ethiopia
+  name: Ethiopian flag
+  description: The flag of Ethiopia.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_ethiopia
+
+- type: entity
+  id: civ13_wallflag_armenia
+  name: Armenian flag
+  description: The flag of Armenia.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_armenia
+
+- type: entity
+  id: civ13_wallflag_azerbaijan
+  name: Azerbaijani flag
+  description: The flag of the Republic of Azerbaijan.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_azerbaijan
+
+- type: entity
+  id: civ13_wallflag_bosnia
+  name: Bosnian flag
+  description: The flag of Bosnia.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_bosnia
+
+- type: entity
+  id: civ13_wallflag_kosovo
+  name: Kosovo flag
+  description: The flag of Kosovo.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_kosovo
+
+- type: entity
+  id: civ13_wallflag_albania
+  name: Albanian flag
+  description: The flag of Albania.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_albania
+
+- type: entity
+  id: civ13_wallflag_serbia
+  name: Serbian flag
+  description: The flag of Serbia.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_serbia
+
+- type: entity
+  id: civ13_wallflag_romania
+  name: Romanian flag
+  description: The flag of Romania.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_romania
+
+- type: entity
+  id: civ13_wallflag_romania_socialist
+  name: RSR flag
+  description: The flag of the Socialist Republic of Romania.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_romania_soc
+
+- type: entity
+  id: civ13_wallflag_moldova
+  name: Moldovan flag
+  description: The flag of the Republic of Moldova.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_moldova
+
+- type: entity
+  id: civ13_wallflag_moldova_transnistria
+  name: Transnistrian flag
+  description: The flag of the Pridnestrovian Moldavian Republic.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_transnistria
+
+- type: entity
+  id: civ13_wallflag_czech
+  name: Czechoslovakian flag
+  description: The flag of Czechoslovakia.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_czech
+
+- type: entity
+  id: civ13_wallflag_hungary
+  name: Hungarian flag
+  description: The flag of Hungary.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_hungary
+
+- type: entity
+  id: civ13_wallflag_warpact
+  name: WARPACT flag
+  description: The flag of the Wasrsaw Pact.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_warpact
+
+- type: entity
+  id: civ13_wallflag_warpact_alt
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_warpact2
+
+- type: entity
+  id: civ13_wallflag_nato
+  name: NATO flag
+  description: The flag of North Atlantic Treaty Organization.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_nato
+
+- type: entity
+  id: civ13_wallflag_redmenia
+  name: Redmenian flag
+  description: The flag of the Empire of Redmenia.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_redmenia
+
+- type: entity
+  id: civ13_wallflag_blugoslavia
+  name: Blugoslavian flag
+  description: The flag of the Republic of Blugoslavia.
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_blugoslavia
+
+- type: entity
+  id: civ13_wallflag_arstotzka
+  name: Arstotzkan flag
+  description: Glory to Arstotzka!
+  parent: WallFlagWhite
+  components:
+    - type: Sprite
+      state: flag_arstotzka

+ 2 - 0
Resources/Prototypes/Entities/Mobs/NPCs/animals.yml

@@ -1279,6 +1279,8 @@
       noMovementLayers:
         movement:
           state: mouse-0
+    - type: DodgeWideswing
+      staminaRatio: 1 # mice are small so can probably evade without much stamina drain
     - type: STWeight
       self: 0.75
     - type: Item

+ 3 - 0
Resources/Prototypes/Entities/Mobs/Species/base.yml

@@ -76,6 +76,9 @@
             False: { visible: false }
     - type: StatusIcon
       bounds: -0.5,-0.5,0.5,0.5
+    - type: DodgeWideswing
+      staminaRatio: 10
+      chance: 0.25
     - type: RotationVisuals
       defaultRotation: 90
       horizontalRotation: 90

+ 4 - 0
Resources/Prototypes/Roles/Jobs/Civ14/TDM/english.yml

@@ -236,6 +236,10 @@
       - ArrowIron
       - ArrowIron
       - ArrowIron
+      - ArrowIron
+      - ArrowIron
+      - ArrowIron
+      - ArrowIron
 # Medic
 
 - type: job

+ 4 - 0
Resources/Prototypes/Roles/Jobs/Civ14/TDM/french.yml

@@ -236,6 +236,10 @@
       - ArrowIron
       - ArrowIron
       - ArrowIron
+      - ArrowIron
+      - ArrowIron
+      - ArrowIron
+      - ArrowIron
 # Medic
 
 - type: job

+ 68 - 57
Resources/Prototypes/Voice/speech_emotes.yml

@@ -6,10 +6,10 @@
   icon: Interface/Emotes/scream.png
   whitelist:
     components:
-    - Vocal
+      - Vocal
   blacklist:
     components:
-    - BorgChassis
+      - BorgChassis
   chatMessages: ["chat-emote-msg-scream"]
   chatTriggers:
     - scream
@@ -36,10 +36,10 @@
   icon: Interface/Emotes/laugh.png
   whitelist:
     components:
-    - Vocal
+      - Vocal
   blacklist:
     components:
-    - BorgChassis
+      - BorgChassis
   chatMessages: ["chat-emote-msg-laugh"]
   chatTriggers:
     - laugh
@@ -66,8 +66,8 @@
   whitelist:
     requireAll: true
     components:
-    - Vocal
-    - BorgChassis
+      - Vocal
+      - BorgChassis
   chatMessages: ["chat-emote-msg-honk"]
   chatTriggers:
     - honk
@@ -82,10 +82,10 @@
   icon: Interface/Emotes/sigh.png
   whitelist:
     components:
-    - Vocal
+      - Vocal
   blacklist:
     components:
-    - BorgChassis
+      - BorgChassis
   chatMessages: ["chat-emote-msg-sigh"]
   chatTriggers:
     - sigh
@@ -99,10 +99,10 @@
   icon: Interface/Emotes/whistle.png
   whitelist:
     components:
-    - Vocal
+      - Vocal
   blacklist:
     components:
-    - BorgChassis
+      - BorgChassis
   chatMessages: ["chat-emote-msg-whistle"]
   chatTriggers:
     - whistle
@@ -116,10 +116,10 @@
   icon: Interface/Emotes/cry.png
   whitelist:
     components:
-    - Vocal
+      - Vocal
   blacklist:
     components:
-    - BorgChassis
+      - BorgChassis
   chatMessages: ["chat-emote-msg-crying"]
   chatTriggers:
     - cry
@@ -137,10 +137,10 @@
   icon: Interface/Emotes/squish.png
   whitelist:
     components:
-    - Vocal
+      - Vocal
   blacklist:
     components:
-    - BorgChassis
+      - BorgChassis
   chatMessages: ["chat-emote-msg-squish"]
   chatTriggers:
     - squish
@@ -155,15 +155,15 @@
   icon: Interface/Emotes/chitter.png
   whitelist:
     components:
-    - Vocal
+      - Vocal
   blacklist:
     components:
-    - BorgChassis
+      - BorgChassis
   chatMessages: ["chat-emote-msg-chitter"]
   chatTriggers:
-   - chitter
-   - chitters
-   - chittered
+    - chitter
+    - chitters
+    - chittered
 
 - type: emote
   id: Squeak
@@ -176,12 +176,12 @@
       - Vocal
   blacklist:
     components:
-    - BorgChassis
+      - BorgChassis
   chatMessages: ["chat-emote-msg-squeak"]
   chatTriggers:
-   - squeak
-   - squeaks
-   - squeaked
+    - squeak
+    - squeaks
+    - squeaked
 
 - type: emote
   id: Click
@@ -191,14 +191,14 @@
   icon: Interface/Emotes/click.png
   whitelist:
     components:
-    - Vocal
+      - Vocal
   blacklist:
     components:
-    - BorgChassis
+      - BorgChassis
   chatMessages: ["chat-emote-msg-click"]
   chatTriggers:
-   - click
-   - clicks
+    - click
+    - clicks
 
 # hand emotes
 - type: emote
@@ -208,10 +208,10 @@
   icon: Interface/Emotes/clap.png
   whitelist:
     components:
-    - Hands
+      - Hands
   blacklist:
     components:
-    - BorgChassis
+      - BorgChassis
   chatMessages: ["chat-emote-msg-clap"]
   chatTriggers:
     - claps
@@ -225,11 +225,11 @@
   icon: Interface/Emotes/clap.png #TODO: Needs a sprite that distinguishes it better from clap
   whitelist:
     components:
-    - Hands
+      - Hands
   blacklist:
     components:
-    - BorgChassis
-  chatMessages: [ "chat-emote-msg-clap-single" ]
+      - BorgChassis
+  chatMessages: ["chat-emote-msg-clap-single"]
   chatTriggers:
     - clap
     - claps their hands together
@@ -244,10 +244,10 @@
   icon: Interface/Emotes/snap.png
   whitelist:
     components:
-    - Hands
+      - Hands
   blacklist:
     components:
-    - BorgChassis
+      - BorgChassis
   chatMessages: ["chat-emote-msg-snap"]
   chatTriggers:
     - snap
@@ -271,10 +271,10 @@
   icon: Interface/Emotes/tailslap.png
   whitelist:
     components:
-    - Hands
+      - Hands
   blacklist:
     components:
-    - BorgChassis
+      - BorgChassis
   chatMessages: ["chat-emote-msg-thump"]
   chatTriggers:
     - thump
@@ -295,10 +295,10 @@
   icon: Interface/Emotes/salute.png
   whitelist:
     components:
-    - Hands
+      - Hands
   blacklist:
     components:
-    - BorgChassis
+      - BorgChassis
   chatMessages: ["chat-emote-msg-salute"]
   chatTriggers:
     - salute
@@ -309,12 +309,12 @@
   name: chat-emote-name-gasp
   whitelist:
     components:
-    - Respirator
+      - Respirator
   chatMessages: ["chat-emote-msg-gasp"]
   chatTriggers:
-   - gasp
-   - gasps
-   - gasped
+    - gasp
+    - gasps
+    - gasped
 
 - type: emote
   id: DefaultDeathgasp
@@ -322,10 +322,10 @@
   icon: Interface/Emotes/deathgasp.png
   whitelist:
     components:
-    - MobState
+      - MobState
   chatMessages: ["chat-emote-msg-deathgasp"]
   chatTriggers:
-  - deathgasp
+    - deathgasp
 
 - type: emote
   id: MonkeyDeathgasp
@@ -333,6 +333,17 @@
   icon: Interface/Emotes/deathgasp.png
   chatMessages: ["chat-emote-msg-deathgasp-monkey"]
 
+# for out of breath effects due to low stamina
+- type: emote
+  id: BreathGasp
+  name: chat-emote-name-gasp-stamina
+  whitelist:
+    components:
+      - Respirator
+  chatMessages: ["chat-emote-msg-gasp-stamina"]
+  chatTriggers:
+    - breathgasp
+
 - type: emote
   id: Buzz
   name: chat-emote-name-buzz
@@ -341,8 +352,8 @@
   whitelist:
     requireAll: true
     components:
-    - BorgChassis
-    - Vocal
+      - BorgChassis
+      - Vocal
   chatMessages: ["chat-emote-msg-buzz"]
   chatTriggers:
     - buzzing
@@ -372,11 +383,11 @@
   icon: Interface/Emotes/chirp.png
   whitelist:
     components:
-    - Nymph
-    - Vocal
+      - Nymph
+      - Vocal
   blacklist:
     components:
-    - BorgChassis
+      - BorgChassis
   chatMessages: ["chat-emote-msg-chirp"]
   chatTriggers:
     - chirp
@@ -393,8 +404,8 @@
   whitelist:
     requireAll: true
     components:
-    - BorgChassis
-    - Vocal
+      - BorgChassis
+      - Vocal
   chatMessages: ["chat-emote-msg-beep"]
   chatTriggers:
     - beep
@@ -410,8 +421,8 @@
   whitelist:
     requireAll: true
     components:
-    - BorgChassis
-    - Vocal
+      - BorgChassis
+      - Vocal
   chatMessages: ["chat-emote-msg-chime"]
   chatTriggers:
     - chime
@@ -427,8 +438,8 @@
   whitelist:
     requireAll: true
     components:
-    - BorgChassis
-    - Vocal
+      - BorgChassis
+      - Vocal
   chatMessages: ["chat-emote-msg-buzzestwo"]
   chatTriggers:
     - buzztwice
@@ -450,8 +461,8 @@
   whitelist:
     requireAll: true
     components:
-    - BorgChassis
-    - Vocal
+      - BorgChassis
+      - Vocal
   chatMessages: ["chat-emote-msg-ping"]
   chatTriggers:
     - ping

Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff