瀏覽代碼

QOL patch 1 (#229)

* buffs walls, reverts bug

* fixes setting presets

* job icons, research and mortar tweak

* 📝 Add docstrings to `qol_patch_1` (#230)

Docstrings generation was requested by @taislin.

* https://github.com/Civ13/Civ14/pull/229#issuecomment-2908241025

The following files were modified:

* `Content.Client/Overlays/ShowFactionIconsSystem.cs`
* `Content.Server/GameTicking/GameTicker.GameRule.cs`
* `Content.Server/GameTicking/Rules/RandomWeatherRuleSystem.cs`
* `Content.Shared/Inventory/InventorySystem.Relay.cs`

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

* fix sandals

* squad icons and rank icons

* armor tweaks

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Taislin 6 月之前
父節點
當前提交
14c538a4d1
共有 38 個文件被更改,包括 990 次插入1022 次删除
  1. 20 105
      Content.Client/Overlays/ShowFactionIconsSystem.cs
  2. 6 1
      Content.Server/GameTicking/GameTicker.GameRule.cs
  3. 5 0
      Content.Server/GameTicking/Rules/Components/RandomWeatherRuleComponent.cs
  4. 10 1
      Content.Server/GameTicking/Rules/RandomWeatherRuleSystem.cs
  5. 34 0
      Content.Server/GameTicking/Rules/TeamDeathMatchRuleSystem.cs
  6. 6 0
      Content.Server/Maps/GameMapPrototype.cs
  7. 235 0
      Content.Server/Overlays/ShowFactionIconsSystem.cs
  8. 71 6
      Content.Server/StationRecords/Systems/StationRecordsSystem.cs
  9. 2 2
      Content.Shared/Civ14/CivResearch/CivResearchComponent.cs
  10. 66 0
      Content.Shared/Civ14/CivTDMFactions/CivTDMFactionsComponent.cs
  11. 3 5
      Content.Shared/Inventory/InventorySystem.Relay.cs
  12. 1 1
      Content.Shared/NPC/Systems/NpcFactionSystem.cs
  13. 21 41
      Content.Shared/Overlays/ShowFactionIconsComponent.cs
  14. 131 0
      Content.Shared/Overlays/ShowFactionIconsSystem.cs
  15. 1 1
      Content.Shared/_RMC14/Mortar/MortarComponent.cs
  16. 1 1
      LICENSE.TXT
  17. 3 0
      Resources/Maps/civ/tdm/camp_ww2.yml
  18. 3 0
      Resources/Maps/civ/tdm/hotel.yml
  19. 3 0
      Resources/Maps/civ/tdm/opushka.yml
  20. 62 526
      Resources/Prototypes/Civ14/Entities/Clothing/entities_clothing_accessories.yml
  21. 48 184
      Resources/Prototypes/Civ14/Entities/Clothing/entities_clothing_shoes.yml
  22. 18 18
      Resources/Prototypes/Civ14/Entities/Objects/Explosives/Mortars/mortar_shells.yml
  23. 53 55
      Resources/Prototypes/Civ14/Entities/Objects/Explosives/Mortars/mortars.yml
  24. 6 0
      Resources/Prototypes/Civ14/Entities/Structures/Walls/walls.yml
  25. 0 15
      Resources/Prototypes/Civ14/StatusIcon/faction.yml
  26. 74 18
      Resources/Prototypes/Civ14/StatusIcon/job.yml
  27. 0 3
      Resources/Prototypes/Entities/Structures/Furniture/beds.yml
  28. 4 1
      Resources/Prototypes/Entities/Structures/Walls/walls.yml
  29. 6 6
      Resources/Prototypes/Roles/Jobs/Civ14/TDM/english.yml
  30. 6 6
      Resources/Prototypes/Roles/Jobs/Civ14/TDM/french.yml
  31. 20 8
      Resources/Prototypes/Roles/Jobs/Civ14/TDM/german.yml
  32. 20 8
      Resources/Prototypes/Roles/Jobs/Civ14/TDM/soviet.yml
  33. 15 5
      Resources/Prototypes/Roles/Jobs/Civ14/TDM/sovietCW.yml
  34. 13 5
      Resources/Prototypes/Roles/Jobs/Civ14/TDM/usa.yml
  35. 23 0
      Resources/Textures/Civ14/Objects/medals.rsi/meta.json
  36. 二進制
      Resources/Textures/Civ14/Objects/medals.rsi/nomads_bronze.png
  37. 二進制
      Resources/Textures/Civ14/Objects/medals.rsi/nomads_gold.png
  38. 二進制
      Resources/Textures/Civ14/Objects/medals.rsi/nomads_silver.png

+ 20 - 105
Content.Client/Overlays/ShowFactionIconsSystem.cs

@@ -1,8 +1,4 @@
-using Content.Shared.Access.Components;
-using Content.Shared.Access.Systems;
-using Content.Shared.NPC.Components;
 using Content.Shared.Overlays;
 using Content.Shared.Overlays;
-using System.Linq;
 using Content.Shared.StatusIcon;
 using Content.Shared.StatusIcon;
 using Content.Shared.StatusIcon.Components;
 using Content.Shared.StatusIcon.Components;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Prototypes;
@@ -13,6 +9,7 @@ public sealed class ShowFactionIconsSystem : EquipmentHudSystem<ShowFactionIcons
 {
 {
     [Dependency] private readonly IPrototypeManager _prototype = default!;
     [Dependency] private readonly IPrototypeManager _prototype = default!;
 
 
+
     public override void Initialize()
     public override void Initialize()
     {
     {
         base.Initialize();
         base.Initialize();
@@ -21,114 +18,32 @@ public override void Initialize()
 
 
     }
     }
 
 
+    /// <summary>
+    /// Adds faction and job icons to the status icon list for an entity if their prototypes are found.
+    /// </summary>
+    /// <param name="uid">The entity requesting status icons.</param>
+    /// <param name="component">The component specifying faction and job icon identifiers.</param>
+    /// <param name="ev">The event containing the status icon list to update.</param>
     private void OnGetStatusIconsEvent(EntityUid uid, ShowFactionIconsComponent component, ref GetStatusIconsEvent ev)
     private void OnGetStatusIconsEvent(EntityUid uid, ShowFactionIconsComponent component, ref GetStatusIconsEvent ev)
     {
     {
         if (!IsActive)
         if (!IsActive)
             return;
             return;
 
 
+        // Display regular faction icon
         if (_prototype.TryIndex<FactionIconPrototype>(component.FactionIcon, out var iconPrototype))
         if (_prototype.TryIndex<FactionIconPrototype>(component.FactionIcon, out var iconPrototype))
             ev.StatusIcons.Add(iconPrototype);
             ev.StatusIcons.Add(iconPrototype);
-    }
-}
-
-public sealed class ShowFrenchFactionIconsSystem : EquipmentHudSystem<ShowFrenchFactionIconsComponent>
-{
-    [Dependency] private readonly IPrototypeManager _prototype = default!;
-    public override void Initialize()
-    {
-        base.Initialize();
-
-        SubscribeLocalEvent<ShowFrenchFactionIconsComponent, GetStatusIconsEvent>(OnGetStatusIconsEvent);
-
-    }
-
-    private void OnGetStatusIconsEvent(EntityUid uid, ShowFrenchFactionIconsComponent component, ref GetStatusIconsEvent ev)
-    {
-        if (!IsActive)
-            return;
-
-        if (_prototype.TryIndex<FactionIconPrototype>(component.FactionIcon, out var iconPrototype))
-            ev.StatusIcons.Add(iconPrototype);
-    }
-}
-public sealed class ShowEnglishFactionIconsSystem : EquipmentHudSystem<ShowEnglishFactionIconsComponent>
-{
-    [Dependency] private readonly IPrototypeManager _prototype = default!;
-    public override void Initialize()
-    {
-        base.Initialize();
-
-        SubscribeLocalEvent<ShowEnglishFactionIconsComponent, GetStatusIconsEvent>(OnGetStatusIconsEvent);
-
-    }
-
-    private void OnGetStatusIconsEvent(EntityUid uid, ShowEnglishFactionIconsComponent component, ref GetStatusIconsEvent ev)
-    {
-        if (!IsActive)
-            return;
 
 
-        if (_prototype.TryIndex<FactionIconPrototype>(component.FactionIcon, out var iconPrototype))
-            ev.StatusIcons.Add(iconPrototype);
+        // Display squad-specific icon if assigned by the server
+        if (component.AssignSquad && component.SquadIcon != null)
+        {
+            if (_prototype.TryIndex<JobIconPrototype>(component.SquadIcon, out var squadIconPrototype))
+                ev.StatusIcons.Add(squadIconPrototype);
+        }
+        // Otherwise, display the general job icon if no squad icon is present or if not part of a squad
+        if (component.JobIcon != null && component.JobIcon != "JobIconSoldier" && component.JobIcon != "JobIconRifleman" && component.JobIcon != "JobIconMG")
+        {
+            if (_prototype.TryIndex<JobIconPrototype>(component.JobIcon, out var jobIconPrototype))
+                ev.StatusIcons.Add(jobIconPrototype);
+        }
     }
     }
 }
 }
-public sealed class ShowGermanFactionIconsSystem : EquipmentHudSystem<ShowGermanFactionIconsComponent>
-{
-    [Dependency] private readonly IPrototypeManager _prototype = default!;
-    public override void Initialize()
-    {
-        base.Initialize();
-
-        SubscribeLocalEvent<ShowGermanFactionIconsComponent, GetStatusIconsEvent>(OnGetStatusIconsEvent);
-
-    }
-
-    private void OnGetStatusIconsEvent(EntityUid uid, ShowGermanFactionIconsComponent component, ref GetStatusIconsEvent ev)
-    {
-        if (!IsActive)
-            return;
-
-        if (_prototype.TryIndex<FactionIconPrototype>(component.FactionIcon, out var iconPrototype))
-            ev.StatusIcons.Add(iconPrototype);
-    }
-}
-public sealed class ShowSovietFactionIconsSystem : EquipmentHudSystem<ShowSovietFactionIconsComponent>
-{
-    [Dependency] private readonly IPrototypeManager _prototype = default!;
-    public override void Initialize()
-    {
-        base.Initialize();
-
-        SubscribeLocalEvent<ShowSovietFactionIconsComponent, GetStatusIconsEvent>(OnGetStatusIconsEvent);
-
-    }
-
-    private void OnGetStatusIconsEvent(EntityUid uid, ShowSovietFactionIconsComponent component, ref GetStatusIconsEvent ev)
-    {
-        if (!IsActive)
-            return;
-
-        if (_prototype.TryIndex<FactionIconPrototype>(component.FactionIcon, out var iconPrototype))
-            ev.StatusIcons.Add(iconPrototype);
-    }
-}
-public sealed class ShowUsFactionIconsSystem : EquipmentHudSystem<ShowUsFactionIconsComponent>
-{
-    [Dependency] private readonly IPrototypeManager _prototype = default!;
-    public override void Initialize()
-    {
-        base.Initialize();
-
-        SubscribeLocalEvent<ShowUsFactionIconsComponent, GetStatusIconsEvent>(OnGetStatusIconsEvent);
-
-    }
-
-    private void OnGetStatusIconsEvent(EntityUid uid, ShowUsFactionIconsComponent component, ref GetStatusIconsEvent ev)
-    {
-        if (!IsActive)
-            return;
-
-        if (_prototype.TryIndex<FactionIconPrototype>(component.FactionIcon, out var iconPrototype))
-            ev.StatusIcons.Add(iconPrototype);
-    }
-}
-

+ 6 - 1
Content.Server/GameTicking/GameTicker.GameRule.cs

@@ -313,15 +313,20 @@ public IEnumerable<EntityPrototype> GetAllGameRulePrototypes()
         }
         }
     }
     }
 
 
+    /// <summary>
+    /// Sets the game preset for the selected map if required, or starts any delayed game rules whose start time has elapsed.
+    /// </summary>
     private void UpdateGameRules()
     private void UpdateGameRules()
     {
     {
 
 
         if (_gameMapManager.GetSelectedMap() is { } mapPrototype)
         if (_gameMapManager.GetSelectedMap() is { } mapPrototype)
         {
         {
             var map = mapPrototype;
             var map = mapPrototype;
-            if (map.FixedPreset != "")
+            if (map.FixedPreset != "" && map.FixedPresetInitialised == false)
             {
             {
+                _sawmill.Info("Set game preset to " + map.FixedPreset);
                 SetGamePreset(map.FixedPreset);
                 SetGamePreset(map.FixedPreset);
+                map.FixedPresetInitialised = true;
             }
             }
         }
         }
         else
         else

+ 5 - 0
Content.Server/GameTicking/Rules/Components/RandomWeatherRuleComponent.cs

@@ -23,7 +23,12 @@ public sealed partial class RandomWeatherRuleComponent : Component
     /// <summary>
     /// <summary>
     /// List of pre-set colors, mostly for tdm maps so we can set fixed times of day.
     /// List of pre-set colors, mostly for tdm maps so we can set fixed times of day.
     /// </summary>
     /// </summary>
+    [DataField("weatherInitialised")]
+    public bool WeatherInitialised = false;
 
 
+    /// <summary>
+    /// List of pre-set colors, mostly for tdm maps so we can set fixed times of day.
+    /// </summary>
     [DataField("dayTimes")]
     [DataField("dayTimes")]
     public List<string> DayTimes = [
     public List<string> DayTimes = [
         "Day", //Daylight #D8B059
         "Day", //Daylight #D8B059

+ 10 - 1
Content.Server/GameTicking/Rules/RandomWeatherRuleSystem.cs

@@ -42,7 +42,12 @@ protected override void Started(EntityUid uid, RandomWeatherRuleComponent compon
 
 
     /// <summary>
     /// <summary>
     /// Picks a random weather from the component's AllowedWeathers list and sets it as the CurrentWeather.
     /// Picks a random weather from the component's AllowedWeathers list and sets it as the CurrentWeather.
+    /// <summary>
+    /// Selects and applies a random weather type from the allowed list to all maps, setting the weather for one hour if it has not already been initialised.
     /// </summary>
     /// </summary>
+    /// <remarks>
+    /// If the allowed weather list is empty, no weather is set. If the selected weather is not recognised, the operation is aborted. Weather is only set once per rule activation.
+    /// </remarks>
     public void PickRandomWeather(EntityUid uid, RandomWeatherRuleComponent? component = null)
     public void PickRandomWeather(EntityUid uid, RandomWeatherRuleComponent? component = null)
     {
     {
         if (!Resolve(uid, ref component))
         if (!Resolve(uid, ref component))
@@ -70,7 +75,11 @@ public void PickRandomWeather(EntityUid uid, RandomWeatherRuleComponent? compone
         }
         }
         foreach (var mapId in _mapManager.GetAllMapIds())
         foreach (var mapId in _mapManager.GetAllMapIds())
         {
         {
-            _weather.SetWeather(mapId, weather, endTime);
+            if (component.WeatherInitialised == false)
+            {
+                _weather.SetWeather(mapId, weather, endTime);
+                component.WeatherInitialised = true;
+            }
         }
         }
     }
     }
 
 

+ 34 - 0
Content.Server/GameTicking/Rules/TeamDeathMatchRuleSystem.cs

@@ -17,6 +17,9 @@
 using Robust.Shared.Utility;
 using Robust.Shared.Utility;
 using Content.Shared.NPC.Systems;
 using Content.Shared.NPC.Systems;
 using Robust.Shared.Player;
 using Robust.Shared.Player;
+using Content.Server.Overlays; // Added for FactionIconsSystem
+using Content.Shared.Overlays;
+using Content.Shared.Civ14.CivTDMFactions; // Added for CivTDMFactionsComponent
 
 
 namespace Content.Server.GameTicking.Rules;
 namespace Content.Server.GameTicking.Rules;
 
 
@@ -34,6 +37,7 @@ public sealed class TeamDeathMatchRuleSystem : GameRuleSystem<TeamDeathMatchRule
     [Dependency] private readonly NpcFactionSystem _factionSystem = default!; // Added dependency
     [Dependency] private readonly NpcFactionSystem _factionSystem = default!; // Added dependency
     [Dependency] private readonly TransformSystem _transform = default!;
     [Dependency] private readonly TransformSystem _transform = default!;
     [Dependency] private readonly IEntityManager _entities = default!;
     [Dependency] private readonly IEntityManager _entities = default!;
+    [Dependency] private readonly FactionIconsSystem _factionIconsSystem = default!;
     public override void Initialize()
     public override void Initialize()
     {
     {
         base.Initialize();
         base.Initialize();
@@ -105,27 +109,57 @@ private void OnKillReported(ref KillReportedEvent ev)
             if (!GameTicker.IsGameRuleActive(uid, rule))
             if (!GameTicker.IsGameRuleActive(uid, rule))
                 continue;
                 continue;
 
 
+            bool killedPlayerWasInSquad = false;
+
             // Check if the killed entity is part of either team using FactionSystem
             // Check if the killed entity is part of either team using FactionSystem
             if (HasComp<NpcFactionMemberComponent>(ev.Entity))
             if (HasComp<NpcFactionMemberComponent>(ev.Entity))
             {
             {
                 string killedTeam = "";
                 string killedTeam = "";
+                ShowFactionIconsComponent? factIcons = null; // Resolve component once
+                TryComp<ShowFactionIconsComponent>(ev.Entity, out factIcons);
 
 
                 if (_factionSystem.IsMember(ev.Entity, dm.Team1))
                 if (_factionSystem.IsMember(ev.Entity, dm.Team1))
                 {
                 {
                     dm.Team1Deaths += 1;
                     dm.Team1Deaths += 1;
                     dm.Team2Kills += 1;
                     dm.Team2Kills += 1;
                     killedTeam = dm.Team1;
                     killedTeam = dm.Team1;
+                    if (factIcons != null && factIcons.AssignedSquadNameKey != null)
+                    {
+                        killedPlayerWasInSquad = true;
+                    }
                 }
                 }
                 else if (_factionSystem.IsMember(ev.Entity, dm.Team2))
                 else if (_factionSystem.IsMember(ev.Entity, dm.Team2))
                 {
                 {
                     dm.Team2Deaths += 1;
                     dm.Team2Deaths += 1;
                     dm.Team1Kills += 1;
                     dm.Team1Kills += 1;
                     killedTeam = dm.Team2;
                     killedTeam = dm.Team2;
+                    if (factIcons != null && factIcons.AssignedSquadNameKey != null)
+                    {
+                        killedPlayerWasInSquad = true;
+                    }
+                }
+
+                if (killedPlayerWasInSquad)
+                {
+                    CivTDMFactionsComponent? civTDMComp = null;
+                    // Attempt to find the CivTDMFactionsComponent.
+                    // This query assumes it's a somewhat global component (e.g., on a map or game rule entity).
+                    var civQuery = _entities.EntityQueryEnumerator<CivTDMFactionsComponent>();
+                    if (civQuery.MoveNext(out _, out civTDMComp)) // Use the first one found
+                    {
+                        _factionIconsSystem.RecalculateAllCivFactionSquadCounts(civTDMComp);
+                        Log.Debug($"Player {ToPrettyString(ev.Entity)} died while in squad {factIcons?.AssignedSquadNameKey}. Recalculating CivTDMFaction squad counts.");
+                    }
+                    else
+                    {
+                        Log.Warning($"Player {ToPrettyString(ev.Entity)} died in a squad, but CivTDMFactionsComponent was not found to update counts.");
+                    }
                 }
                 }
 
 
                 // Track individual player stats
                 // Track individual player stats
                 if (ev.Primary is KillPlayerSource playerSource)
                 if (ev.Primary is KillPlayerSource playerSource)
                 {
                 {
+
                     var playerIdStr = playerSource.PlayerId.ToString();
                     var playerIdStr = playerSource.PlayerId.ToString();
 
 
                     if (!dm.KDRatio.ContainsKey(playerIdStr))
                     if (!dm.KDRatio.ContainsKey(playerIdStr))

+ 6 - 0
Content.Server/Maps/GameMapPrototype.cs

@@ -50,6 +50,12 @@ public sealed partial class GameMapPrototype : IPrototype
     [DataField("fixedPreset")]
     [DataField("fixedPreset")]
     public string FixedPreset { get; private set; } = "";
     public string FixedPreset { get; private set; } = "";
 
 
+    /// <summary>
+    /// To prevent looping
+    /// </summary>
+    [DataField("fixedPresetInitialised")]
+    public bool FixedPresetInitialised { get; set; } = false;
+
     [DataField("stations", required: true)]
     [DataField("stations", required: true)]
     private Dictionary<string, StationConfig> _stations = new();
     private Dictionary<string, StationConfig> _stations = new();
 
 

+ 235 - 0
Content.Server/Overlays/ShowFactionIconsSystem.cs

@@ -0,0 +1,235 @@
+using Content.Shared.Overlays;
+using Robust.Shared.Player;
+using Content.Shared.Civ14.CivTDMFactions;
+using Robust.Shared.Random; // Added for IRobustRandom
+using System.Linq;
+using Content.Shared.NPC.Components;         // Added for LINQ
+
+namespace Content.Server.Overlays
+{
+    /// <summary>
+    /// Server-side system for managing faction and squad icon assignments.
+    /// Inherits core logic from SharedFactionIconsSystem.
+    /// </summary>
+    public sealed class FactionIconsSystem : SharedFactionIconsSystem
+    {
+        [Dependency] private readonly IRobustRandom _random = default!;
+        [Dependency] private readonly EntityManager _entityManager = default!;
+
+        public override void Initialize()
+        {
+            base.Initialize();
+        }
+
+        /// <summary>
+        /// Attempts to assign a player entity to a squad within a specific CivFaction,
+        /// balancing members and managing sergeant roles per CivFaction.
+        /// This can be called by other server systems (e.g., role assignment, admin commands).
+        /// </summary>
+        /// <param name="playerUid">The entity UID of the player.</param>
+        /// <param name="playerAssignedCivFactionId">The ID of the CivFaction the player belongs to (e.g., Faction1Id from CivTDMFactionsComponent).</param>
+        /// <param name="wantsToBeSergeant">Whether the player desires a sergeant role.</param>
+        /// <param name="sfiComponent">The player's ShowFactionIconsComponent.</param>
+        /// <returns>True if successfully assigned, false otherwise.</returns>
+        public bool AttemptAssignPlayerToSquad(EntityUid playerUid, string playerAssignedCivFactionId, bool wantsToBeSergeant, ShowFactionIconsComponent? sfiComponent = null)
+        {
+            if (!Resolve(playerUid, ref sfiComponent, logMissing: false))
+            {
+                Log.Warning($"Player {ToPrettyString(playerUid)} does not have ShowFactionIconsComponent. Cannot assign to squad.");
+                return false;
+            }
+            if (TryComp<ShowFactionIconsComponent>(playerUid, out var factMem))
+            {
+                if (factMem.AssignSquad == false)
+                {
+                    return false;
+                }
+            }
+            // Get the CivTDMFactionsComponent
+            CivTDMFactionsComponent? civTDMComp = null;
+            var civQuery = _entityManager.EntityQueryEnumerator<CivTDMFactionsComponent>();
+            if (civQuery.MoveNext(out _, out civTDMComp))
+            {
+                // Ensure Faction IDs are set
+                if (civTDMComp.Faction1Id == null || civTDMComp.Faction2Id == null)
+                {
+                    Log.Error("CivTDMFactionsComponent Faction1Id or Faction2Id is not set. Cannot assign squads.");
+                    return false;
+                }
+            }
+            else
+            {
+                Log.Error("CivTDMFactionsComponent not found. Cannot assign squads.");
+                return false;
+            }
+
+            string? targetSquadNameKey = null; // e.g., "Alpha", "Bravo"
+            bool assignAsSergeantInCall = wantsToBeSergeant;
+            string targetCivFactionIdForAssignment = playerAssignedCivFactionId;
+
+            if (wantsToBeSergeant)
+            {
+                var squadsInTargetCivFaction = GetCivFactionSquads(civTDMComp, targetCivFactionIdForAssignment);
+                targetSquadNameKey = FindBestSquadForRole(squadsInTargetCivFaction, true);
+
+                if (targetSquadNameKey == null) // No suitable squad for sergeant in target CivFaction
+                {
+                    assignAsSergeantInCall = false; // Try to assign as member in their original faction
+                    targetCivFactionIdForAssignment = playerAssignedCivFactionId; // Revert to player's own faction
+                }
+            }
+
+            if (!assignAsSergeantInCall) // Assigning as member (either initially or fallback)
+            {
+                targetCivFactionIdForAssignment = playerAssignedCivFactionId; // Ensure assignment is to player's own faction
+                var squadsInPlayerCivFaction = GetCivFactionSquads(civTDMComp, playerAssignedCivFactionId);
+                targetSquadNameKey = FindBestSquadForRole(squadsInPlayerCivFaction, false);
+            }
+
+            if (targetSquadNameKey == null)
+            {
+                Log.Info($"Could not find a suitable squad for {ToPrettyString(playerUid)} in CivFaction {targetCivFactionIdForAssignment} as {(assignAsSergeantInCall ? "Sergeant" : "Member")}.");
+                return false;
+            }
+
+            // Store old state for count updates
+            var oldSquadIcon = sfiComponent.SquadIcon;
+            var oldBelongsToCivFaction = sfiComponent.BelongsToCivFactionId;
+
+            bool success = base.TryAssignToSquad(playerUid, targetSquadNameKey, assignAsSergeantInCall, sfiComponent);
+
+            if (success)
+            {
+                sfiComponent.BelongsToCivFactionId = targetCivFactionIdForAssignment; // Update player's CivFaction if it changed
+                Dirty(playerUid, sfiComponent);
+                RecalculateAllCivFactionSquadCounts(civTDMComp); // Recalculate counts after assignment
+                Log.Info($"Successfully assigned {ToPrettyString(playerUid)} to squad {targetSquadNameKey} in CivFaction {targetCivFactionIdForAssignment} as {(assignAsSergeantInCall ? "Sergeant" : "Member")}. New icon: {sfiComponent.SquadIcon}");
+            }
+            else
+            {
+                Log.Info($"Failed to assign {ToPrettyString(playerUid)} to squad {targetSquadNameKey} via SharedFactionIconsSystem.");
+                // Revert BelongsToCivFactionId if it was tentatively changed for sergeant assignment
+                if (wantsToBeSergeant && targetCivFactionIdForAssignment != playerAssignedCivFactionId)
+                {
+                    sfiComponent.BelongsToCivFactionId = playerAssignedCivFactionId;
+                }
+            }
+            return success;
+        }
+
+        private Dictionary<string, int> CountSergeantsPerCivFaction(CivTDMFactionsComponent civTDMComp)
+        {
+            var counts = new Dictionary<string, int>();
+            if (civTDMComp.Faction1Id != null) counts[civTDMComp.Faction1Id] = 0;
+            if (civTDMComp.Faction2Id != null) counts[civTDMComp.Faction2Id] = 0;
+
+            var query = _entityManager.EntityQueryEnumerator<ShowFactionIconsComponent>();
+            while (query.MoveNext(out _, out var sfiComp))
+            {
+                if (sfiComp.BelongsToCivFactionId != null &&
+                    sfiComp.AssignSquad && // Must be assigned to a squad
+                    sfiComp.IsSergeantInSquad && // Must be a sergeant
+                    counts.ContainsKey(sfiComp.BelongsToCivFactionId))
+                {
+                    counts[sfiComp.BelongsToCivFactionId]++;
+                }
+            }
+            return counts;
+        }
+
+        private Dictionary<string, SquadData>? GetCivFactionSquads(CivTDMFactionsComponent civTDMComp, string civFactionId)
+        {
+            if (civFactionId == civTDMComp.Faction1Id)
+                return civTDMComp.Faction1Squads;
+            if (civFactionId == civTDMComp.Faction2Id)
+                return civTDMComp.Faction2Squads;
+            return null;
+        }
+
+        private string? FindBestSquadForRole(Dictionary<string, SquadData>? squadsData, bool findForSergeant)
+        {
+            if (squadsData == null)
+                return null;
+
+            string? bestSquad = null;
+            int minMembers = int.MaxValue;
+
+            foreach (var (squadNameKey, squadData) in squadsData.OrderBy(x => _random.Next())) // Randomize tie-breaking
+            {
+                if (!Squads.TryGetValue(squadNameKey, out var squadConfig))
+                    continue; // This squad type isn't defined in SharedFactionIconsSystem
+
+                int currentTotal = squadData.SergeantCount + squadData.MemberCount;
+                if (currentTotal >= squadConfig.MaxSize)
+                    continue; // Squad is full
+
+                if (findForSergeant)
+                {
+                    if (squadData.SergeantCount == 0) // Slot for sergeant is open
+                    {
+                        if (currentTotal < minMembers) // Prefer less populated squads for sergeants too
+                        {
+                            minMembers = currentTotal;
+                            bestSquad = squadNameKey;
+                        }
+                    }
+                }
+                else // Finding for member
+                {
+                    if (currentTotal < minMembers)
+                    {
+                        minMembers = currentTotal;
+                        bestSquad = squadNameKey;
+                    }
+                }
+            }
+            return bestSquad;
+        }
+
+        public void RecalculateAllCivFactionSquadCounts(CivTDMFactionsComponent civTDMComp)
+        {
+            // Reset counts
+            foreach (var squadDataDict in new[] { civTDMComp.Faction1Squads, civTDMComp.Faction2Squads })
+            {
+                foreach (var squadData in squadDataDict.Values)
+                {
+                    squadData.MemberCount = 0;
+                    squadData.SergeantCount = 0;
+                }
+            }
+
+            var memberIconIds = Squads.ToDictionary(kvp => kvp.Value.MemberIconId, kvp => kvp.Key);
+            var sergeantIconIds = Squads.ToDictionary(kvp => kvp.Value.SergeantIconId, kvp => kvp.Key);
+
+            var query = _entityManager.EntityQueryEnumerator<ShowFactionIconsComponent>();
+            while (query.MoveNext(out _, out var sfiComp))
+            {
+                if (sfiComp.SquadIcon == null || sfiComp.BelongsToCivFactionId == null || sfiComp.AssignSquad == false)
+                    continue;
+
+                var targetSquadsDict = GetCivFactionSquads(civTDMComp, sfiComp.BelongsToCivFactionId);
+                if (targetSquadsDict == null)
+                    continue;
+
+                if (memberIconIds.TryGetValue(sfiComp.SquadIcon, out var squadNameKeySgt) && targetSquadsDict.TryGetValue(squadNameKeySgt, out var squadData))
+                {
+                    if (sfiComp.JobIcon == "JobIconISgt")
+                    {
+                        squadData.SergeantCount++;
+                    }
+                    else
+                    {
+                        squadData.MemberCount++;
+                    }
+                }
+
+            }
+            // Mark CivTDMFactionsComponent as dirty. Need to get the MapUid from the TransformComponent.
+            if (_entityManager.TryGetComponent<TransformComponent>(civTDMComp.Owner, out var xform) && xform.MapUid.HasValue)
+            {
+                Dirty(xform.MapUid.Value, civTDMComp);
+            }
+        }
+    }
+}
+

+ 71 - 6
Content.Server/StationRecords/Systems/StationRecordsSystem.cs

@@ -3,6 +3,7 @@
 using Content.Server.Forensics;
 using Content.Server.Forensics;
 using Content.Shared.Access.Components;
 using Content.Shared.Access.Components;
 using Content.Shared.Forensics.Components;
 using Content.Shared.Forensics.Components;
+using Content.Server.Overlays; // Namespace for FactionIconsSystem
 using Content.Shared.GameTicking;
 using Content.Shared.GameTicking;
 using Content.Shared.Inventory;
 using Content.Shared.Inventory;
 using Content.Shared.PDA;
 using Content.Shared.PDA;
@@ -12,6 +13,9 @@
 using Robust.Shared.Enums;
 using Robust.Shared.Enums;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Random;
 using Robust.Shared.Random;
+using Content.Shared.Overlays; // Namespace for ShowFactionIconsComponent
+using Content.Shared.Civ14.CivTDMFactions;
+using Content.Shared.NPC.Components; // Namespace for CivTDMFactionsComponent
 
 
 namespace Content.Server.StationRecords.Systems;
 namespace Content.Server.StationRecords.Systems;
 
 
@@ -41,6 +45,7 @@ public sealed class StationRecordsSystem : SharedStationRecordsSystem
     [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
     [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
     [Dependency] private readonly IdCardSystem _idCard = default!;
     [Dependency] private readonly IdCardSystem _idCard = default!;
     [Dependency] private readonly IRobustRandom _random = default!;
     [Dependency] private readonly IRobustRandom _random = default!;
+    [Dependency] private readonly FactionIconsSystem _factionIcons = default!; // Added dependency
 
 
     public override void Initialize()
     public override void Initialize()
     {
     {
@@ -55,7 +60,67 @@ private void OnPlayerSpawn(PlayerSpawnCompleteEvent args)
         if (!TryComp<StationRecordsComponent>(args.Station, out var stationRecords))
         if (!TryComp<StationRecordsComponent>(args.Station, out var stationRecords))
             return;
             return;
 
 
+        // Create the general record first
         CreateGeneralRecord(args.Station, args.Mob, args.Profile, args.JobId, stationRecords);
         CreateGeneralRecord(args.Station, args.Mob, args.Profile, args.JobId, stationRecords);
+
+        // --- Attempt Squad Assignment ---
+        if (TryComp<ShowFactionIconsComponent>(args.Mob, out var sfiComponent))
+        {
+            // Determine if player wants to be a sergeant (e.g., based on job)
+            bool wantsToBeSergeant = sfiComponent.JobIcon == "JobIconISgt"; // Example: "JobIconISgt" implies sergeant role
+
+            // Determine player's CivFaction (this is crucial and needs proper game logic)
+            // For this example, let's assume a simple alternating assignment or based on JobId.
+            // In a real game, this would come from team selection, game mode logic, etc.
+            string? playerCivFactionId = null;
+
+            // Query for the CivTDMFactionsComponent (assuming one exists on a game rule or map entity)
+            var civQuery = EntityQueryEnumerator<CivTDMFactionsComponent>();
+            CivTDMFactionsComponent? civTDMComp = null;
+            if (civQuery.MoveNext(out _, out civTDMComp))
+            {
+                // Example: Assign to Faction1Id if JobId contains "Faction1", else Faction2Id
+                // This is placeholder logic. Replace with your actual faction assignment logic.
+                if (args.JobId != null) // Ensure JobId is not null
+                {
+                    if (TryComp<NpcFactionMemberComponent>(args.Mob, out var factionComp))
+                    {
+                        foreach (var faction in factionComp.Factions)
+                        {
+                            if (civTDMComp.Faction1Id == null || faction == civTDMComp.Faction1Id)
+                            {
+                                playerCivFactionId = civTDMComp.Faction1Id; // This is already a string, no need for ProtoId conversion here
+                                break;
+                            }
+                            else
+                            {
+                                playerCivFactionId = civTDMComp.Faction2Id;
+                                break;
+                            }
+                        }
+                    }
+                }
+
+                // Fallback or default assignment if not determined by job
+                if (playerCivFactionId == null)
+                {
+                    // Simplistic: assign to Faction1Id by default if not specified or if factionComp.Factions was empty/null.
+                    // Or implement round-robin, or based on current team populations.
+                    playerCivFactionId = civTDMComp.Faction1Id;
+                }
+            }
+
+            if (playerCivFactionId != null)
+            {
+                sfiComponent.BelongsToCivFactionId = playerCivFactionId; // Store it on the component
+                _factionIcons.AttemptAssignPlayerToSquad(args.Mob, playerCivFactionId, wantsToBeSergeant, sfiComponent);
+            }
+            else
+            {
+                Log.Warning($"Could not determine CivFaction for player {ToPrettyString(args.Mob)} with job {args.JobId}. Squad assignment skipped.");
+            }
+        }
+        // --- End Squad Assignment ---
     }
     }
 
 
     private void OnRename(ref EntityRenamedEvent ev)
     private void OnRename(ref EntityRenamedEvent ev)
@@ -65,13 +130,13 @@ private void OnRename(ref EntityRenamedEvent ev)
         // given entity is a card and the card itself is the key the record will be mistakenly renamed to the card's name
         // given entity is a card and the card itself is the key the record will be mistakenly renamed to the card's name
         // if we don't return early.
         // if we don't return early.
         // We also do not include the PDA itself being renamed, as that triggers the same event (e.g. for chameleon PDAs).
         // We also do not include the PDA itself being renamed, as that triggers the same event (e.g. for chameleon PDAs).
-        if (HasComp<IdCardComponent>(ev.Uid) ||  HasComp<PdaComponent>(ev.Uid))
+        if (HasComp<IdCardComponent>(ev.Uid) || HasComp<PdaComponent>(ev.Uid))
             return;
             return;
 
 
         if (_idCard.TryFindIdCard(ev.Uid, out var idCard))
         if (_idCard.TryFindIdCard(ev.Uid, out var idCard))
         {
         {
             if (TryComp(idCard, out StationRecordKeyStorageComponent? keyStorage)
             if (TryComp(idCard, out StationRecordKeyStorageComponent? keyStorage)
-                && keyStorage.Key is {} key)
+                && keyStorage.Key is { } key)
             {
             {
                 if (TryGetRecord<GeneralStationRecord>(key, out var generalRecord))
                 if (TryGetRecord<GeneralStationRecord>(key, out var generalRecord))
                 {
                 {
@@ -146,7 +211,7 @@ private void OnRename(ref EntityRenamedEvent ev)
 
 
         // when adding a record that already exists use the old one
         // when adding a record that already exists use the old one
         // this happens when respawning as the same character
         // this happens when respawning as the same character
-        if (GetRecordByName(station, name, records) is {} id)
+        if (GetRecordByName(station, name, records) is { } id)
         {
         {
             SetIdKey(idUid, new StationRecordKey(id, station));
             SetIdKey(idUid, new StationRecordKey(id, station));
             return;
             return;
@@ -183,11 +248,11 @@ private void OnRename(ref EntityRenamedEvent ev)
     /// </summary>
     /// </summary>
     public void SetIdKey(EntityUid? uid, StationRecordKey key)
     public void SetIdKey(EntityUid? uid, StationRecordKey key)
     {
     {
-        if (uid is not {} idUid)
+        if (uid is not { } idUid)
             return;
             return;
 
 
         var keyStorageEntity = idUid;
         var keyStorageEntity = idUid;
-        if (TryComp<PdaComponent>(idUid, out var pda) && pda.ContainedId is {} id)
+        if (TryComp<PdaComponent>(idUid, out var pda) && pda.ContainedId is { } id)
         {
         {
             keyStorageEntity = id;
             keyStorageEntity = id;
         }
         }
@@ -283,7 +348,7 @@ public bool TryGetRandomRecord<T>(Entity<StationRecordsComponent?> ent, [NotNull
     public string RecordName(StationRecordKey key)
     public string RecordName(StationRecordKey key)
     {
     {
         if (!TryGetRecord<GeneralStationRecord>(key, out var record))
         if (!TryGetRecord<GeneralStationRecord>(key, out var record))
-           return string.Empty;
+            return string.Empty;
 
 
         return record.Name;
         return record.Name;
     }
     }

+ 2 - 2
Content.Shared/Civ14/CivResearch/CivResearchComponent.cs

@@ -26,11 +26,11 @@ public sealed partial class CivResearchComponent : Component
     public float ResearchLevel { get; set; } = 0f;
     public float ResearchLevel { get; set; } = 0f;
     /// <summary>
     /// <summary>
     /// For autoresearch, how much research increases per tick.
     /// For autoresearch, how much research increases per tick.
-    /// This defaults to 100 levels per day.
+    /// This defaults to 100 levels per hour.
     /// </summary>
     /// </summary>
 
 
     [DataField("researchSpeed"), AutoNetworkedField]
     [DataField("researchSpeed"), AutoNetworkedField]
-    public float ResearchSpeed { get; set; } = 0.000057f;
+    public float ResearchSpeed { get; set; } = 0.001368f;
     /// <summary>
     /// <summary>
     /// The maximum research level.
     /// The maximum research level.
     /// Should probably stay below 900 as 9 is used as the research level for disabled and futuristic stuff.
     /// Should probably stay below 900 as 9 is used as the research level for disabled and futuristic stuff.

+ 66 - 0
Content.Shared/Civ14/CivTDMFactions/CivTDMFactionsComponent.cs

@@ -0,0 +1,66 @@
+using System.Collections.Generic;
+using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
+using Robust.Shared.Serialization; // Added this line
+using System; // Added for [Serializable]
+
+namespace Content.Shared.Civ14.CivTDMFactions;
+
+[AutoGenerateComponentState]
+[RegisterComponent]
+[NetworkedComponent]
+public sealed partial class CivTDMFactionsComponent : Component
+{
+    //TODO: Consider making FactionId a prototype for more structured data (color, sprite, etc.)
+    /// <summary>
+    /// The name of faction1
+    /// </summary>
+    [DataField("faction1Id", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>)), AutoNetworkedField]
+    public string? Faction1Id { get; set; }
+
+    /// <summary>
+    /// The name of faction2
+    /// </summary>
+    [DataField("faction2Id", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>)), AutoNetworkedField]
+    public string? Faction2Id { get; set; }
+
+    /// <summary>
+    /// Squads belonging to faction 1. Key is squad name (e.g., "Alpha").
+    /// </summary>
+    [DataField("faction1Squads"), AutoNetworkedField]
+    public Dictionary<string, SquadData> Faction1Squads { get; set; } = new()
+    {
+        { "Alpha", new SquadData() },
+        { "Bravo", new SquadData() },
+        { "Charlie", new SquadData() }
+    };
+
+    /// <summary>
+    /// Squads belonging to faction 2. Key is squad name (e.g., "Alpha").
+    /// </summary>
+    [DataField("faction2Squads"), AutoNetworkedField]
+    public Dictionary<string, SquadData> Faction2Squads { get; set; } = new()
+    {
+        { "Alpha", new SquadData() },
+        { "Bravo", new SquadData() },
+        { "Charlie", new SquadData() }
+    };
+}
+
+/// <summary>
+/// Holds data for a single squad, like member counts.
+/// </summary>
+[DataDefinition, NetSerializable, Serializable]
+public sealed partial class SquadData
+{
+    [DataField("sergeantCount")] // Removed AutoNetworkedField
+    public int SergeantCount { get; set; } = 0;
+
+    [DataField("memberCount")] // Removed AutoNetworkedField
+    public int MemberCount { get; set; } = 0;
+
+    // You could add MaxSize here if it's per-squad rather than global from ShowFactionIconsSystem
+    // [DataField("maxSize")]
+    // public int MaxSize { get; set; } = 3;
+}

+ 3 - 5
Content.Shared/Inventory/InventorySystem.Relay.cs

@@ -25,6 +25,9 @@ namespace Content.Shared.Inventory;
 
 
 public partial class InventorySystem
 public partial class InventorySystem
 {
 {
+    /// <summary>
+    /// Subscribes the inventory component to a range of events, enabling automatic relaying of relevant events to equipped items in specified inventory slots.
+    /// </summary>
     public void InitializeRelay()
     public void InitializeRelay()
     {
     {
         SubscribeLocalEvent<InventoryComponent, DamageModifyEvent>(RelayInventoryEvent);
         SubscribeLocalEvent<InventoryComponent, DamageModifyEvent>(RelayInventoryEvent);
@@ -67,11 +70,6 @@ public void InitializeRelay()
         SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowCriminalRecordIconsComponent>>(RefRelayInventoryEvent);
         SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowCriminalRecordIconsComponent>>(RefRelayInventoryEvent);
 
 
         SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowFactionIconsComponent>>(RefRelayInventoryEvent);
         SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowFactionIconsComponent>>(RefRelayInventoryEvent);
-        SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowFrenchFactionIconsComponent>>(RefRelayInventoryEvent);
-        SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowEnglishFactionIconsComponent>>(RefRelayInventoryEvent);
-        SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowGermanFactionIconsComponent>>(RefRelayInventoryEvent);
-        SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowSovietFactionIconsComponent>>(RefRelayInventoryEvent);
-        SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowUsFactionIconsComponent>>(RefRelayInventoryEvent);
 
 
         SubscribeLocalEvent<InventoryComponent, GetVerbsEvent<EquipmentVerb>>(OnGetEquipmentVerbs);
         SubscribeLocalEvent<InventoryComponent, GetVerbsEvent<EquipmentVerb>>(OnGetEquipmentVerbs);
     }
     }

+ 1 - 1
Content.Shared/NPC/Systems/NpcFactionSystem.cs

@@ -309,7 +309,7 @@ private void RefreshFactions()
     {
     {
         _factions = _proto.EnumeratePrototypes<NpcFactionPrototype>().ToFrozenDictionary(
         _factions = _proto.EnumeratePrototypes<NpcFactionPrototype>().ToFrozenDictionary(
             faction => faction.ID,
             faction => faction.ID,
-            faction =>  new FactionData
+            faction => new FactionData
             {
             {
                 Friendly = faction.Friendly.ToHashSet(),
                 Friendly = faction.Friendly.ToHashSet(),
                 Hostile = faction.Hostile.ToHashSet()
                 Hostile = faction.Hostile.ToHashSet()

+ 21 - 41
Content.Shared/Overlays/ShowFactionIconsComponent.cs

@@ -7,63 +7,43 @@ namespace Content.Shared.Overlays;
 /// <summary>
 /// <summary>
 ///     This component allows you to see faction icons above mobs.
 ///     This component allows you to see faction icons above mobs.
 /// </summary>
 /// </summary>
-[RegisterComponent, NetworkedComponent]
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
 public sealed partial class ShowFactionIconsComponent : Component
 public sealed partial class ShowFactionIconsComponent : Component
 {
 {
 
 
     /// <summary>
     /// <summary>
     /// The faction icon to display
     /// The faction icon to display
     /// </summary>
     /// </summary>
-    [DataField("factionIcon", customTypeSerializer: typeof(PrototypeIdSerializer<FactionIconPrototype>))]
-    public string FactionIcon = "HostileFaction";
-}
-[RegisterComponent, NetworkedComponent]
-public sealed partial class ShowEnglishFactionIconsComponent : Component
-{
-
+    [DataField("factionIcon", customTypeSerializer: typeof(PrototypeIdSerializer<FactionIconPrototype>)), AutoNetworkedField]
+    public string FactionIcon { get; set; } = "HostileFaction";
     /// <summary>
     /// <summary>
-    /// The faction icon to display
+    /// The job icon to display (if any)
     /// </summary>
     /// </summary>
-    [DataField("factionIcon", customTypeSerializer: typeof(PrototypeIdSerializer<FactionIconPrototype>))]
-    public string FactionIcon = "EnglishFaction";
-}
-[RegisterComponent, NetworkedComponent]
-public sealed partial class ShowFrenchFactionIconsComponent : Component
-{
-
+    [DataField("jobIcon", customTypeSerializer: typeof(PrototypeIdSerializer<JobIconPrototype>)), AutoNetworkedField]
+    public string JobIcon { get; set; } = "JobIconSoldier";
     /// <summary>
     /// <summary>
-    /// The faction icon to display
+    /// If this role is part of one of the squads
     /// </summary>
     /// </summary>
-    [DataField("factionIcon", customTypeSerializer: typeof(PrototypeIdSerializer<FactionIconPrototype>))]
-    public string FactionIcon = "FrenchFaction";
-}
-[RegisterComponent, NetworkedComponent]
-public sealed partial class ShowGermanFactionIconsComponent : Component
-{
-
+    [DataField("assignSquad"), AutoNetworkedField]
+    public bool AssignSquad { get; set; } = false;
     /// <summary>
     /// <summary>
-    /// The faction icon to display
+    /// The specific squad icon (e.g., "JobIconSquadAlphaSergeant") assigned by the server.
     /// </summary>
     /// </summary>
-    [DataField("factionIcon", customTypeSerializer: typeof(PrototypeIdSerializer<FactionIconPrototype>))]
-    public string FactionIcon = "GermanFaction";
-}
-[RegisterComponent, NetworkedComponent]
-public sealed partial class ShowSovietFactionIconsComponent : Component
-{
+    [DataField("squadIcon", customTypeSerializer: typeof(PrototypeIdSerializer<JobIconPrototype>)), AutoNetworkedField]
+    public string? SquadIcon { get; set; }
 
 
     /// <summary>
     /// <summary>
-    /// The faction icon to display
+    /// The key/name of the squad the entity is assigned to (e.g., "Alpha").
     /// </summary>
     /// </summary>
-    [DataField("factionIcon", customTypeSerializer: typeof(PrototypeIdSerializer<FactionIconPrototype>))]
-    public string FactionIcon = "SovietFaction";
-}
-[RegisterComponent, NetworkedComponent]
-public sealed partial class ShowUsFactionIconsComponent : Component
-{
+    [DataField("assignedSquadNameKey"), AutoNetworkedField]
+    public string? AssignedSquadNameKey { get; set; }
+
+    [DataField("isSergeantInSquad"), AutoNetworkedField]
+    public bool IsSergeantInSquad { get; set; }
 
 
     /// <summary>
     /// <summary>
-    /// The faction icon to display
+    /// Identifier for the major CivTeamDeathmatch Faction this entity belongs to (e.g., Faction1Id or Faction2Id from CivTDMFactionsComponent).
     /// </summary>
     /// </summary>
-    [DataField("factionIcon", customTypeSerializer: typeof(PrototypeIdSerializer<FactionIconPrototype>))]
-    public string FactionIcon = "UsFaction";
+    [DataField("belongsToCivFactionId"), AutoNetworkedField]
+    public string? BelongsToCivFactionId { get; set; }
 }
 }

+ 131 - 0
Content.Shared/Overlays/ShowFactionIconsSystem.cs

@@ -0,0 +1,131 @@
+using Content.Shared.StatusIcon.Components; // For JobIconPrototype if you use it directly
+using Robust.Shared.Prototypes;
+using System.Linq; // For LINQ queries if needed for checking existing squad members
+
+namespace Content.Shared.Overlays;
+
+public abstract class SharedFactionIconsSystem : EntitySystem
+{
+    [Dependency] protected readonly IPrototypeManager PrototypeManager = default!;
+    [Dependency] private readonly IEntityManager _entityManager = default!;
+
+    // Example: Define your squad configurations. This could be more dynamic.
+    // You'd likely have prototypes for squads themselves eventually.
+    protected static readonly Dictionary<string, SquadConfig> Squads = new()
+    {
+        { "Alpha", new SquadConfig("JobIconSquad1", "JobIconSquad1", 20) },
+        { "Bravo", new SquadConfig("JobIconSquad2", "JobIconSquad2", 20) },
+        { "Charlie", new SquadConfig("JobIconSquad3", "JobIconSquad3", 20) },
+        // Add more squads here: "SquadName", "MemberIconId", "SergeantIconId", MaxSize
+    };
+    protected record SquadConfig(string MemberIconId, string SergeantIconId, int MaxSize);
+
+    /// <summary>
+    /// Call this on the SERVER to attempt to assign an entity to a squad.
+    /// </summary>
+    public virtual bool TryAssignToSquad(EntityUid uid, string squadName, bool assignAsSergeant, ShowFactionIconsComponent? component = null)
+    {
+        if (!Resolve(uid, ref component, logMissing: false))
+            return false; // Only run on server and if component exists
+
+        if (!Squads.TryGetValue(squadName, out var config))
+            return false; // Squad doesn't exist
+
+        // --- Server-Side Logic to check rules based on new explicit fields ---
+        int currentOccupantsInSquad = 0;
+        bool sergeantRoleFilledInSquad = false;
+        EntityUid? existingSergeantUid = null;
+        ShowFactionIconsComponent? oldSergeantComp = null; // For demotion
+
+        var query = AllEntityQuery<ShowFactionIconsComponent>();
+        while (query.MoveNext(out var otherUid, out var otherComp))
+        {
+            if (otherComp.AssignSquad && otherComp.AssignedSquadNameKey == squadName)
+            {
+                currentOccupantsInSquad++;
+                if (otherComp.IsSergeantInSquad)
+                {
+                    sergeantRoleFilledInSquad = true;
+                    existingSergeantUid = otherUid;
+                }
+            }
+        }
+
+        // Current state of the entity 'uid' being assigned
+        bool entityIsAlreadyInThisSquad = component.AssignSquad && component.AssignedSquadNameKey == squadName;
+        bool entityIsAlreadySergeantOfThisSquad = entityIsAlreadyInThisSquad && component.IsSergeantInSquad;
+
+        if (assignAsSergeant)
+        {
+            // Trying to make 'uid' the sergeant.
+            // If another sergeant exists and it's not 'uid', 'uid' will replace them (demotion handled later).
+            // Check if adding 'uid' (if not already in squad) would exceed MaxSize.
+            if (!entityIsAlreadyInThisSquad && currentOccupantsInSquad >= config.MaxSize)
+            {
+                Log.Debug($"Cannot assign {ToPrettyString(uid)} as Sergeant to squad {squadName}. Squad is full ({currentOccupantsInSquad}/{config.MaxSize}) and entity is not already in squad.");
+                return false; // Squad is full, cannot add a new person as sergeant.
+            }
+        }
+        else // Assigning as member
+        {
+            // Trying to make 'uid' a member.
+            if (entityIsAlreadySergeantOfThisSquad)
+            {
+                // 'uid' is demoting itself. Count doesn't change. Fine.
+            }
+            else if (entityIsAlreadyInThisSquad && !component.IsSergeantInSquad) // Already a member
+            {
+                // 'uid' is re-affirming member status. Count doesn't change. Fine.
+            }
+            else // 'uid' is not in this squad (or in another squad, or not assigned).
+            {
+                if (currentOccupantsInSquad >= config.MaxSize)
+                {
+                    Log.Debug($"Cannot assign {ToPrettyString(uid)} as Member to squad {squadName}. Squad is full ({currentOccupantsInSquad}/{config.MaxSize}).");
+                    return false; // Squad is full, cannot add a new member.
+                }
+            }
+        }
+
+        // --- Update component ---
+        component.AssignSquad = true;
+        component.AssignedSquadNameKey = squadName;
+        component.IsSergeantInSquad = assignAsSergeant;
+        component.SquadIcon = assignAsSergeant ? config.SergeantIconId : config.MemberIconId;
+        Dirty(uid, component); // Mark component as dirty to ensure state is synced
+
+        // If 'uid' became sergeant, and there was a *different* existing sergeant in this squad, demote the old one.
+        if (assignAsSergeant && sergeantRoleFilledInSquad && existingSergeantUid.HasValue && existingSergeantUid.Value != uid)
+        {
+            if (Resolve(existingSergeantUid.Value, ref oldSergeantComp, logMissing: false))
+            {
+                // Ensure this old sergeant was indeed for *this* squad before demoting.
+                if (oldSergeantComp.AssignSquad && oldSergeantComp.AssignedSquadNameKey == squadName && oldSergeantComp.IsSergeantInSquad)
+                {
+                    oldSergeantComp.IsSergeantInSquad = false;
+                    oldSergeantComp.SquadIcon = config.MemberIconId; // Demote to member icon
+                    // oldSergeantComp.AssignedSquadNameKey remains squadName
+                    Dirty(existingSergeantUid.Value, oldSergeantComp);
+                    Log.Info($"Demoted {ToPrettyString(existingSergeantUid.Value)} from sergeant in squad {squadName} as {ToPrettyString(uid)} took the role.");
+                }
+            }
+        }
+
+
+        Log.Info($"Assigned {ToPrettyString(uid)} to squad {squadName} as {(assignAsSergeant ? "Sergeant" : "Member")}. Icon: {component.SquadIcon}");
+        return true;
+    }
+
+    public virtual void RemoveFromSquad(EntityUid uid, ShowFactionIconsComponent? component = null)
+    {
+        if (!Resolve(uid, ref component, logMissing: false))
+            return;
+
+        component.AssignSquad = false;
+        component.SquadIcon = null;
+        component.AssignedSquadNameKey = null;
+        component.IsSergeantInSquad = false;
+        Dirty(uid, component);
+        Log.Info($"Removed {ToPrettyString(uid)} from squad.");
+    }
+}

+ 1 - 1
Content.Shared/_RMC14/Mortar/MortarComponent.cs

@@ -13,7 +13,7 @@ public sealed partial class MortarComponent : Component
     public string ContainerId = "rmc_mortar_container";
     public string ContainerId = "rmc_mortar_container";
 
 
     [DataField, AutoNetworkedField]
     [DataField, AutoNetworkedField]
-    public TimeSpan DeployDelay = TimeSpan.FromSeconds(4);
+    public TimeSpan DeployDelay = TimeSpan.FromSeconds(8);
 
 
     [DataField, AutoNetworkedField]
     [DataField, AutoNetworkedField]
     public TimeSpan TargetDelay = TimeSpan.FromSeconds(3);
     public TimeSpan TargetDelay = TimeSpan.FromSeconds(3);

+ 1 - 1
LICENSE.TXT

@@ -6,7 +6,7 @@ Most assets are licensed under CC-BY-SA 3.0, https://creativecommons.org/license
 unless stated otherwise. Assets have their license and the copyright in the metadata file.
 unless stated otherwise. Assets have their license and the copyright in the metadata file.
 
 
 Note that some assets are licensed under the non-commercial CC-BY-NC-SA 3.0,
 Note that some assets are licensed under the non-commercial CC-BY-NC-SA 3.0,
-https://creativecommons.org/licenses/by-nc-sa/3.0/,or similar non-commercial
+https://creativecommons.org/licenses/by-nc-sa/3.0/, or similar non-commercial
 licenses and will need to be removed if you wish to use this project commercially.
 licenses and will need to be removed if you wish to use this project commercially.
 
 
 Assets ported over from Civ13 are licenced under GNU Affero General Public License v3.0 (AGPLv3),
 Assets ported over from Civ13 are licenced under GNU Affero General Public License v3.0 (AGPLv3),

+ 3 - 0
Resources/Maps/civ/tdm/camp_ww2.yml

@@ -43,6 +43,9 @@ entities:
       maxResearch: 600
       maxResearch: 600
       researchLevel: 600
       researchLevel: 600
       researchEnabled: False
       researchEnabled: False
+    - type: CivTDMFactions
+      faction1Id: German
+      faction2Id: Soviet
   - uid: 2
   - uid: 2
     components:
     components:
     - type: MetaData
     - type: MetaData

+ 3 - 0
Resources/Maps/civ/tdm/hotel.yml

@@ -55,6 +55,9 @@ entities:
       researchLevel: 600
       researchLevel: 600
       researchEnabled: False
       researchEnabled: False
     - type: FTLDestination
     - type: FTLDestination
+    - type: CivTDMFactions
+      faction1Id: US
+      faction2Id: SovietCW
   - uid: 2
   - uid: 2
     components:
     components:
     - type: MetaData
     - type: MetaData

+ 3 - 0
Resources/Maps/civ/tdm/opushka.yml

@@ -43,6 +43,9 @@ entities:
       researchLevel: 600
       researchLevel: 600
       researchEnabled: False
       researchEnabled: False
     - type: FTLDestination
     - type: FTLDestination
+    - type: CivTDMFactions
+      faction1Id: German
+      faction2Id: Soviet
   - uid: 2
   - uid: 2
     components:
     components:
     - type: MetaData
     - type: MetaData

File diff suppressed because it is too large
+ 62 - 526
Resources/Prototypes/Civ14/Entities/Clothing/entities_clothing_accessories.yml


+ 48 - 184
Resources/Prototypes/Civ14/Entities/Clothing/entities_clothing_shoes.yml

@@ -8,15 +8,7 @@
       sprite: Civ14/Clothing/exported/shoes/white.rsi
       sprite: Civ14/Clothing/exported/shoes/white.rsi
     - type: Clothing
     - type: Clothing
       sprite: Civ14/Clothing/exported/shoes/white.rsi
       sprite: Civ14/Clothing/exported/shoes/white.rsi
-    - type: Armor
-      modifiers:
-        coefficients:
-          Blunt: 1
-          Slash: 1
-          Piercing: 1
-          Arrow: 1
-          Heat: 1
-          Radiation: 1
+
     - type: Construction
     - type: Construction
 
 
       graph: civ13_shoes_shoes
       graph: civ13_shoes_shoes
@@ -85,15 +77,7 @@
       sprite: Civ14/Clothing/exported/shoes/red.rsi
       sprite: Civ14/Clothing/exported/shoes/red.rsi
     - type: Clothing
     - type: Clothing
       sprite: Civ14/Clothing/exported/shoes/red.rsi
       sprite: Civ14/Clothing/exported/shoes/red.rsi
-    - type: Armor
-      modifiers:
-        coefficients:
-          Blunt: 1
-          Slash: 1
-          Piercing: 1
-          Arrow: 1
-          Heat: 1
-          Radiation: 1
+
     - type: Construction
     - type: Construction
 
 
       graph: civ13_shoes_red_shoes
       graph: civ13_shoes_red_shoes
@@ -111,15 +95,7 @@
       sprite: Civ14/Clothing/exported/shoes/orange.rsi
       sprite: Civ14/Clothing/exported/shoes/orange.rsi
     - type: Clothing
     - type: Clothing
       sprite: Civ14/Clothing/exported/shoes/orange.rsi
       sprite: Civ14/Clothing/exported/shoes/orange.rsi
-    - type: Armor
-      modifiers:
-        coefficients:
-          Blunt: 1
-          Slash: 1
-          Piercing: 1
-          Arrow: 1
-          Heat: 1
-          Radiation: 1
+
     - type: Construction
     - type: Construction
 
 
       graph: civ13_shoes_orange_shoes
       graph: civ13_shoes_orange_shoes
@@ -364,15 +340,7 @@
       sprite: Civ14/Clothing/exported/shoes/japboots_ww2_navy.rsi
       sprite: Civ14/Clothing/exported/shoes/japboots_ww2_navy.rsi
     - type: Clothing
     - type: Clothing
       sprite: Civ14/Clothing/exported/shoes/japboots_ww2_navy.rsi
       sprite: Civ14/Clothing/exported/shoes/japboots_ww2_navy.rsi
-    - type: Armor
-      modifiers:
-        coefficients:
-          Blunt: 1
-          Slash: 1
-          Piercing: 1
-          Arrow: 1
-          Heat: 1
-          Radiation: 1
+
     - type: Construction
     - type: Construction
 
 
       graph: civ13_shoes_Black_leather_boots
       graph: civ13_shoes_Black_leather_boots
@@ -465,17 +433,7 @@
       sprite: Civ14/Clothing/exported/shoes/sandals.rsi
       sprite: Civ14/Clothing/exported/shoes/sandals.rsi
     - type: Clothing
     - type: Clothing
       sprite: Civ14/Clothing/exported/shoes/sandals.rsi
       sprite: Civ14/Clothing/exported/shoes/sandals.rsi
-    - type: Armor
-      modifiers:
-        coefficients:
-          Blunt: 1
-          Slash: 1
-          Piercing: 1
-          Arrow: 1
-          Heat: 1
-          Radiation: 1
     - type: Construction
     - type: Construction
-
       graph: civ13_shoes_sandals
       graph: civ13_shoes_sandals
       node: end
       node: end
       cost: 1
       cost: 1
@@ -491,15 +449,7 @@
       sprite: Civ14/Clothing/exported/shoes/leather.rsi
       sprite: Civ14/Clothing/exported/shoes/leather.rsi
     - type: Clothing
     - type: Clothing
       sprite: Civ14/Clothing/exported/shoes/leather.rsi
       sprite: Civ14/Clothing/exported/shoes/leather.rsi
-    - type: Armor
-      modifiers:
-        coefficients:
-          Blunt: 1
-          Slash: 1
-          Piercing: 1
-          Arrow: 1
-          Heat: 1
-          Radiation: 1
+
     - type: Construction
     - type: Construction
 
 
       graph: civ13_shoes_leather_shoes
       graph: civ13_shoes_leather_shoes
@@ -517,15 +467,7 @@
       sprite: Civ14/Clothing/exported/shoes/black.rsi
       sprite: Civ14/Clothing/exported/shoes/black.rsi
     - type: Clothing
     - type: Clothing
       sprite: Civ14/Clothing/exported/shoes/black.rsi
       sprite: Civ14/Clothing/exported/shoes/black.rsi
-    - type: Armor
-      modifiers:
-        coefficients:
-          Blunt: 1
-          Slash: 1
-          Piercing: 1
-          Arrow: 1
-          Heat: 1
-          Radiation: 1
+
     - type: Construction
     - type: Construction
 
 
       graph: civ13_shoes_magic_shoes
       graph: civ13_shoes_magic_shoes
@@ -544,15 +486,7 @@
       sprite: Civ14/Clothing/exported/shoes/laceups.rsi
       sprite: Civ14/Clothing/exported/shoes/laceups.rsi
     - type: Clothing
     - type: Clothing
       sprite: Civ14/Clothing/exported/shoes/laceups.rsi
       sprite: Civ14/Clothing/exported/shoes/laceups.rsi
-    - type: Armor
-      modifiers:
-        coefficients:
-          Blunt: 1
-          Slash: 1
-          Piercing: 1
-          Arrow: 1
-          Heat: 1
-          Radiation: 1
+
     - type: Construction
     - type: Construction
 
 
       graph: civ13_shoes_laceup_shoes
       graph: civ13_shoes_laceup_shoes
@@ -573,8 +507,8 @@
     - type: Armor
     - type: Armor
       modifiers:
       modifiers:
         coefficients:
         coefficients:
-          Blunt: 0.8
-          Slash: 0.8
+          Blunt: 0.9
+          Slash: 0.9
           Arrow: 0.9
           Arrow: 0.9
           Heat: 0.75
           Heat: 0.75
           Radiation: 0.65
           Radiation: 0.65
@@ -595,15 +529,7 @@
       sprite: Civ14/Clothing/exported/shoes/gator_laceups.rsi
       sprite: Civ14/Clothing/exported/shoes/gator_laceups.rsi
     - type: Clothing
     - type: Clothing
       sprite: Civ14/Clothing/exported/shoes/gator_laceups.rsi
       sprite: Civ14/Clothing/exported/shoes/gator_laceups.rsi
-    - type: Armor
-      modifiers:
-        coefficients:
-          Blunt: 1
-          Slash: 1
-          Piercing: 1
-          Arrow: 1
-          Heat: 1
-          Radiation: 1
+
     - type: Construction
     - type: Construction
 
 
       graph: civ13_shoes_alligator_scale_laceup_shoes
       graph: civ13_shoes_alligator_scale_laceup_shoes
@@ -621,15 +547,7 @@
       sprite: Civ14/Clothing/exported/shoes/chad.rsi
       sprite: Civ14/Clothing/exported/shoes/chad.rsi
     - type: Clothing
     - type: Clothing
       sprite: Civ14/Clothing/exported/shoes/chad.rsi
       sprite: Civ14/Clothing/exported/shoes/chad.rsi
-    - type: Armor
-      modifiers:
-        coefficients:
-          Blunt: 1
-          Slash: 1
-          Piercing: 1
-          Arrow: 1
-          Heat: 1
-          Radiation: 1
+
     - type: Construction
     - type: Construction
 
 
       graph: civ13_shoes_chad_shoes
       graph: civ13_shoes_chad_shoes
@@ -647,15 +565,7 @@
       sprite: Civ14/Clothing/exported/shoes/flipflops.rsi
       sprite: Civ14/Clothing/exported/shoes/flipflops.rsi
     - type: Clothing
     - type: Clothing
       sprite: Civ14/Clothing/exported/shoes/flipflops.rsi
       sprite: Civ14/Clothing/exported/shoes/flipflops.rsi
-    - type: Armor
-      modifiers:
-        coefficients:
-          Blunt: 1
-          Slash: 1
-          Piercing: 1
-          Arrow: 1
-          Heat: 1
-          Radiation: 1
+
     - type: Construction
     - type: Construction
 
 
       graph: civ13_shoes_flip_flops
       graph: civ13_shoes_flip_flops
@@ -748,15 +658,7 @@
       sprite: Civ14/Clothing/exported/shoes/roman.rsi
       sprite: Civ14/Clothing/exported/shoes/roman.rsi
     - type: Clothing
     - type: Clothing
       sprite: Civ14/Clothing/exported/shoes/roman.rsi
       sprite: Civ14/Clothing/exported/shoes/roman.rsi
-    - type: Armor
-      modifiers:
-        coefficients:
-          Blunt: 0.4
-          Slash: 0.4
-          Arrow: 0.95
-          Heat: 0.75
     - type: Construction
     - type: Construction
-
       graph: civ13_shoes_sandals_1
       graph: civ13_shoes_sandals_1
       node: end
       node: end
       cost: 2
       cost: 2
@@ -772,14 +674,7 @@
       sprite: Civ14/Clothing/exported/shoes/aztec_sandals.rsi
       sprite: Civ14/Clothing/exported/shoes/aztec_sandals.rsi
     - type: Clothing
     - type: Clothing
       sprite: Civ14/Clothing/exported/shoes/aztec_sandals.rsi
       sprite: Civ14/Clothing/exported/shoes/aztec_sandals.rsi
-    - type: Armor
-      modifiers:
-        coefficients:
-          Blunt: 0.9
-          Slash: 0.9
-          Arrow: 0.95
     - type: Construction
     - type: Construction
-
       graph: civ13_shoes_aztec_sandals
       graph: civ13_shoes_aztec_sandals
       node: end
       node: end
       cost: 2
       cost: 2
@@ -798,8 +693,8 @@
     - type: Armor
     - type: Armor
       modifiers:
       modifiers:
         coefficients:
         coefficients:
-          Blunt: 0.8
-          Slash: 0.8
+          Blunt: 0.9
+          Slash: 0.9
           Arrow: 0.9
           Arrow: 0.9
           Heat: 0.75
           Heat: 0.75
           Radiation: 0.65
           Radiation: 0.65
@@ -823,8 +718,8 @@
     - type: Armor
     - type: Armor
       modifiers:
       modifiers:
         coefficients:
         coefficients:
-          Blunt: 0.8
-          Slash: 0.8
+          Blunt: 0.9
+          Slash: 0.9
           Arrow: 0.9
           Arrow: 0.9
           Heat: 0.75
           Heat: 0.75
           Radiation: 0.65
           Radiation: 0.65
@@ -848,10 +743,10 @@
     - type: Armor
     - type: Armor
       modifiers:
       modifiers:
         coefficients:
         coefficients:
-          Blunt: 0.25
-          Slash: 0.25
+          Blunt: 0.8
+          Slash: 0.8
           Piercing: 0.9
           Piercing: 0.9
-          Arrow: 0.4
+          Arrow: 0.8
           Heat: 0.92
           Heat: 0.92
     - type: Construction
     - type: Construction
 
 
@@ -1047,10 +942,10 @@
     - type: Armor
     - type: Armor
       modifiers:
       modifiers:
         coefficients:
         coefficients:
-          Blunt: 0.7
-          Slash: 0.7
+          Blunt: 0.95
+          Slash: 0.95
           Piercing: 0.9
           Piercing: 0.9
-          Arrow: 0.75
+          Arrow: 0.95
           Heat: 0.85
           Heat: 0.85
           Radiation: 0.95
           Radiation: 0.95
     - type: Construction
     - type: Construction
@@ -1073,9 +968,9 @@
     - type: Armor
     - type: Armor
       modifiers:
       modifiers:
         coefficients:
         coefficients:
-          Blunt: 0.7
-          Slash: 0.7
-          Arrow: 0.8
+          Blunt: 0.95
+          Slash: 0.95
+          Arrow: 0.95
           Heat: 0.75
           Heat: 0.75
     - type: Construction
     - type: Construction
 
 
@@ -1097,9 +992,9 @@
     - type: Armor
     - type: Armor
       modifiers:
       modifiers:
         coefficients:
         coefficients:
-          Blunt: 0.19
-          Slash: 0.19
-          Arrow: 0.8
+          Blunt: 0.95
+          Slash: 0.95
+          Arrow: 0.95
           Heat: 0.75
           Heat: 0.75
           Radiation: 0.7
           Radiation: 0.7
     - type: Construction
     - type: Construction
@@ -1122,8 +1017,8 @@
     - type: Armor
     - type: Armor
       modifiers:
       modifiers:
         coefficients:
         coefficients:
-          Blunt: 0.7
-          Slash: 0.7
+          Blunt: 0.9
+          Slash: 0.9
           Piercing: 0.9
           Piercing: 0.9
           Arrow: 0.8
           Arrow: 0.8
           Heat: 0.75
           Heat: 0.75
@@ -1147,9 +1042,9 @@
     - type: Armor
     - type: Armor
       modifiers:
       modifiers:
         coefficients:
         coefficients:
-          Blunt: 0.3
-          Slash: 0.3
-          Arrow: 0.6
+          Blunt: 0.95
+          Slash: 0.95
+          Arrow: 0.95
           Heat: 0.75
           Heat: 0.75
           Radiation: 0.75
           Radiation: 0.75
     - type: Construction
     - type: Construction
@@ -1172,9 +1067,9 @@
     - type: Armor
     - type: Armor
       modifiers:
       modifiers:
         coefficients:
         coefficients:
-          Blunt: 0.3
-          Slash: 0.3
-          Arrow: 0.6
+          Blunt: 0.95
+          Slash: 0.95
+          Arrow: 0.95
           Heat: 0.75
           Heat: 0.75
           Radiation: 0.75
           Radiation: 0.75
     - type: Construction
     - type: Construction
@@ -1197,9 +1092,9 @@
     - type: Armor
     - type: Armor
       modifiers:
       modifiers:
         coefficients:
         coefficients:
-          Blunt: 0.3
-          Slash: 0.3
-          Arrow: 0.6
+          Blunt: 0.95
+          Slash: 0.95
+          Arrow: 0.95
           Heat: 0.75
           Heat: 0.75
           Radiation: 0.75
           Radiation: 0.75
     - type: Construction
     - type: Construction
@@ -1222,9 +1117,9 @@
     - type: Armor
     - type: Armor
       modifiers:
       modifiers:
         coefficients:
         coefficients:
-          Blunt: 0.3
-          Slash: 0.3
-          Arrow: 0.6
+          Blunt: 0.95
+          Slash: 0.95
+          Arrow: 0.95
           Heat: 0.75
           Heat: 0.75
           Radiation: 0.75
           Radiation: 0.75
     - type: Construction
     - type: Construction
@@ -1247,9 +1142,9 @@
     - type: Armor
     - type: Armor
       modifiers:
       modifiers:
         coefficients:
         coefficients:
-          Blunt: 0.5
-          Slash: 0.5
-          Arrow: 0.7
+          Blunt: 0.95
+          Slash: 0.95
+          Arrow: 0.95
           Heat: 0.8
           Heat: 0.8
           Radiation: 0.8
           Radiation: 0.8
     - type: Construction
     - type: Construction
@@ -1391,13 +1286,6 @@
       sprite: Civ14/Clothing/exported/shoes/geta.rsi
       sprite: Civ14/Clothing/exported/shoes/geta.rsi
     - type: Clothing
     - type: Clothing
       sprite: Civ14/Clothing/exported/shoes/geta.rsi
       sprite: Civ14/Clothing/exported/shoes/geta.rsi
-    - type: Armor
-      modifiers:
-        coefficients:
-          Blunt: 0.95
-          Slash: 0.95
-          Arrow: 0.97
-          Heat: 0.95
     - type: Construction
     - type: Construction
 
 
       graph: civ13_shoes_geta_sandals
       graph: civ13_shoes_geta_sandals
@@ -1515,15 +1403,7 @@
       sprite: Civ14/Clothing/exported/shoes/lizard_ankleboots.rsi
       sprite: Civ14/Clothing/exported/shoes/lizard_ankleboots.rsi
     - type: Clothing
     - type: Clothing
       sprite: Civ14/Clothing/exported/shoes/lizard_ankleboots.rsi
       sprite: Civ14/Clothing/exported/shoes/lizard_ankleboots.rsi
-    - type: Armor
-      modifiers:
-        coefficients:
-          Blunt: 1
-          Slash: 1
-          Piercing: 1
-          Arrow: 1
-          Heat: 1
-          Radiation: 1
+
     - type: Construction
     - type: Construction
 
 
       graph: civ13_shoes_lizard_scale_ankle_boots
       graph: civ13_shoes_lizard_scale_ankle_boots
@@ -1541,15 +1421,7 @@
       sprite: Civ14/Clothing/exported/shoes/lizard_laceups.rsi
       sprite: Civ14/Clothing/exported/shoes/lizard_laceups.rsi
     - type: Clothing
     - type: Clothing
       sprite: Civ14/Clothing/exported/shoes/lizard_laceups.rsi
       sprite: Civ14/Clothing/exported/shoes/lizard_laceups.rsi
-    - type: Armor
-      modifiers:
-        coefficients:
-          Blunt: 1
-          Slash: 1
-          Piercing: 1
-          Arrow: 1
-          Heat: 1
-          Radiation: 1
+
     - type: Construction
     - type: Construction
 
 
       graph: civ13_shoes_lizard_scale_laceup_shoes
       graph: civ13_shoes_lizard_scale_laceup_shoes
@@ -1618,15 +1490,7 @@
       sprite: Civ14/Clothing/exported/shoes/football.rsi
       sprite: Civ14/Clothing/exported/shoes/football.rsi
     - type: Clothing
     - type: Clothing
       sprite: Civ14/Clothing/exported/shoes/football.rsi
       sprite: Civ14/Clothing/exported/shoes/football.rsi
-    - type: Armor
-      modifiers:
-        coefficients:
-          Blunt: 1
-          Slash: 1
-          Piercing: 1
-          Arrow: 1
-          Heat: 1
-          Radiation: 1
+
     - type: Construction
     - type: Construction
 
 
       graph: civ13_shoes_football_trainers
       graph: civ13_shoes_football_trainers

+ 18 - 18
Resources/Prototypes/Civ14/Entities/Objects/Explosives/Mortars/mortar_shells.yml

@@ -4,12 +4,12 @@
   id: MortarAmmoBase
   id: MortarAmmoBase
   name: base mortar shell
   name: base mortar shell
   components:
   components:
-  - type: Sprite
-    sprite: Civ14/Objects/Mortars/shells.rsi
-    state: mortar_ammo_he
-  - type: Item
-    size: Huge
-  - type: MortarShell
+    - type: Sprite
+      sprite: Civ14/Objects/Mortars/shells.rsi
+      state: mortar_ammo_he
+    - type: Item
+      size: Huge
+    - type: MortarShell
 
 
 - type: entity
 - type: entity
   parent: MortarAmmoBase
   parent: MortarAmmoBase
@@ -17,15 +17,15 @@
   name: high explosive mortar shell
   name: high explosive mortar shell
   description: A mortar shell packed with high explosive. Drop into a mortar tube to activate.
   description: A mortar shell packed with high explosive. Drop into a mortar tube to activate.
   components:
   components:
-  - type: Item
-  - type: Sprite
-    sprite: Civ14/Objects/Mortars/shells.rsi
-    state: mortar_ammo_he
-  - type: MortarShell
-  - type: Explosive
-    explosionType: Default
-    maxIntensity: 10 # these values need tuning to im sure
-    intensitySlope: 3
-    totalIntensity: 120
-    canCreateVacuum: false
-    deleteAfterExplosion: true
+    - type: Item
+    - type: Sprite
+      sprite: Civ14/Objects/Mortars/shells.rsi
+      state: mortar_ammo_he
+    - type: MortarShell
+    - type: Explosive
+      explosionType: Default
+      maxIntensity: 10 # these values need tuning to im sure
+      intensitySlope: 3
+      totalIntensity: 120
+      canCreateVacuum: false
+      deleteAfterExplosion: true

+ 53 - 55
Resources/Prototypes/Civ14/Entities/Objects/Explosives/Mortars/mortars.yml

@@ -4,60 +4,58 @@
   name: portable mortar
   name: portable mortar
   description: A support weapon capable of droping bombs on heads from a distance. This one seems rather modern.
   description: A support weapon capable of droping bombs on heads from a distance. This one seems rather modern.
   components:
   components:
-  - type: Sprite
-    sprite: Civ14/Objects/Mortars/mortar.rsi
-    layers:
-    - map: [ "mortar" ]
-      state: mortar_carry
-  - type: Fixtures
-    fixtures:
-      fix1:
-        shape:
-          !type:PhysShapeAabb
-          bounds: "-0.25,-0.25,0.25,0.25"
-        density: 20
-        mask:
-        - ItemMask
-        restitution: 0.3
-        friction: 0.2
-      mortar:
-        shape:
-          !type:PhysShapeAabb
-          bounds: "-0.49,-0.49,0.49,0.49"
-        density: 20
-        layer:
-        - Impassable
-        mask:
-        - Impassable
-        hard: false
-  - type: CollisionWake
-    enabled: false
-  - type: Anchorable
-    flags:
-    - Unanchorable
-  - type: Item
-    size: Huge
-  - type: Mortar
-  - type: Damageable
-    damageContainer: Inorganic
-  - type: UserInterface
-    interfaces:
-      enum.MortarUiKey.Key:
-        type: MortarBui
-  - type: ActivatableUI
-    key: enum.MortarUiKey.Key
-  - type: Appearance
-  - type: GenericVisualizer
-    visuals:
-      enum.MortarVisualLayers.State:
+    - type: Sprite
+      sprite: Civ14/Objects/Mortars/mortar.rsi
+      layers:
+        - map: ["mortar"]
+          state: mortar_carry
+    - type: Fixtures
+      fixtures:
+        fix1:
+          shape: !type:PhysShapeAabb
+            bounds: "-0.25,-0.25,0.25,0.25"
+          density: 20
+          mask:
+            - ItemMask
+          restitution: 0.3
+          friction: 0.2
         mortar:
         mortar:
-          Item: { state: mortar_carry }
-          Deployed: { state: mortar_deploy }
-  - type: MeleeSound
-    soundGroups:
-      Brute:
-        path:
-          "/Audio/Effects/metal_break1.ogg"
+          shape: !type:PhysShapeAabb
+            bounds: "-0.49,-0.49,0.49,0.49"
+          density: 20
+          layer:
+            - Impassable
+          mask:
+            - Impassable
+          hard: false
+    - type: CollisionWake
+      enabled: false
+    - type: Anchorable
+      flags:
+        - Unanchorable
+    - type: Item
+      size: Huge
+    - type: Mortar
+      fireDelay: 10
+    - type: Damageable
+      damageContainer: Inorganic
+    - type: UserInterface
+      interfaces:
+        enum.MortarUiKey.Key:
+          type: MortarBui
+    - type: ActivatableUI
+      key: enum.MortarUiKey.Key
+    - type: Appearance
+    - type: GenericVisualizer
+      visuals:
+        enum.MortarVisualLayers.State:
+          mortar:
+            Item: { state: mortar_carry }
+            Deployed: { state: mortar_deploy }
+    - type: MeleeSound
+      soundGroups:
+        Brute:
+          path: "/Audio/Effects/metal_break1.ogg"
 
 
 - type: entity
 - type: entity
   parent: MortarKit
   parent: MortarKit
@@ -65,5 +63,5 @@
   name: old portable mortar
   name: old portable mortar
   description: A support weapon capable of droping bombs on heads from a distance.
   description: A support weapon capable of droping bombs on heads from a distance.
   components:
   components:
-  - type: Sprite
-    sprite: Civ14/Objects/Mortars/mortar_old.rsi
+    - type: Sprite
+      sprite: Civ14/Objects/Mortars/mortar_old.rsi

+ 6 - 0
Resources/Prototypes/Civ14/Entities/Structures/Walls/walls.yml

@@ -781,6 +781,9 @@
   description: A modern, sturdy concrete wall.
   description: A modern, sturdy concrete wall.
   suffix: ""
   suffix: ""
   components:
   components:
+    - type: Damageable
+      damageContainer: StructuralInorganic
+      damageModifierSet: Inert
     - type: Destructible
     - type: Destructible
       thresholds:
       thresholds:
         - trigger: !type:DamageTrigger
         - trigger: !type:DamageTrigger
@@ -814,6 +817,9 @@
   description: A classic red brick wall.
   description: A classic red brick wall.
   suffix: ""
   suffix: ""
   components:
   components:
+    - type: Damageable
+      damageContainer: StructuralInorganic
+      damageModifierSet: Inert
     - type: Destructible
     - type: Destructible
       thresholds:
       thresholds:
         - trigger: !type:DamageTrigger
         - trigger: !type:DamageTrigger

+ 0 - 15
Resources/Prototypes/Civ14/StatusIcon/faction.yml

@@ -187,11 +187,6 @@
     components:
     components:
       - ShowAntagIcons
       - ShowAntagIcons
       - ShowFactionIcons
       - ShowFactionIcons
-      - ShowEnglishFactionIcons
-      - ShowFrenchFactionIcons
-      - ShowGermanFactionIcons
-      - ShowSovietFactionIcons
-      - ShowUsFactionIcons
   icon:
   icon:
     sprite: /Textures/Interface/Misc/civ_hud_countries.rsi
     sprite: /Textures/Interface/Misc/civ_hud_countries.rsi
     state: ger_basic
     state: ger_basic
@@ -522,11 +517,6 @@
     components:
     components:
       - ShowAntagIcons
       - ShowAntagIcons
       - ShowFactionIcons
       - ShowFactionIcons
-      - ShowEnglishFactionIcons
-      - ShowFrenchFactionIcons
-      - ShowGermanFactionIcons
-      - ShowSovietFactionIcons
-      - ShowUsFactionIcons
   icon:
   icon:
     sprite: /Textures/Interface/Misc/civ_hud_countries.rsi
     sprite: /Textures/Interface/Misc/civ_hud_countries.rsi
     state: sov_basic
     state: sov_basic
@@ -648,11 +638,6 @@
     components:
     components:
       - ShowAntagIcons
       - ShowAntagIcons
       - ShowFactionIcons
       - ShowFactionIcons
-      - ShowEnglishFactionIcons
-      - ShowFrenchFactionIcons
-      - ShowGermanFactionIcons
-      - ShowSovietFactionIcons
-      - ShowUsFactionIcons
   icon:
   icon:
     sprite: /Textures/Interface/Misc/civ_hud_countries.rsi
     sprite: /Textures/Interface/Misc/civ_hud_countries.rsi
     state: us_basic
     state: us_basic

+ 74 - 18
Resources/Prototypes/Civ14/StatusIcon/job.yml

@@ -1,5 +1,5 @@
 - type: jobIcon
 - type: jobIcon
-  locationPreference: Left
+  locationPreference: Right
   parent: JobIcon
   parent: JobIcon
   priority: 1
   priority: 1
   id: JobIconCommander
   id: JobIconCommander
@@ -9,7 +9,7 @@
   jobName: job-name-commander
   jobName: job-name-commander
 
 
 - type: jobIcon
 - type: jobIcon
-  locationPreference: Left
+  locationPreference: Right
   parent: JobIcon
   parent: JobIcon
   id: JobIconIMaj
   id: JobIconIMaj
   priority: 2
   priority: 2
@@ -19,7 +19,7 @@
   jobName: job-name-i-maj
   jobName: job-name-i-maj
 
 
 - type: jobIcon
 - type: jobIcon
-  locationPreference: Left
+  locationPreference: Right
   parent: JobIcon
   parent: JobIcon
   priority: 3
   priority: 3
   id: JobIconICpt
   id: JobIconICpt
@@ -29,7 +29,7 @@
   jobName: job-name-i-cpt
   jobName: job-name-i-cpt
 
 
 - type: jobIcon
 - type: jobIcon
-  locationPreference: Left
+  locationPreference: Right
   parent: JobIcon
   parent: JobIcon
   priority: 4
   priority: 4
   id: JobIconOfficer
   id: JobIconOfficer
@@ -39,7 +39,7 @@
   jobName: job-name-officer
   jobName: job-name-officer
 
 
 - type: jobIcon
 - type: jobIcon
-  locationPreference: Left
+  locationPreference: Right
   parent: JobIcon
   parent: JobIcon
   priority: 4
   priority: 4
   id: JobIconILt
   id: JobIconILt
@@ -49,7 +49,7 @@
   jobName: job-name-i-lt
   jobName: job-name-i-lt
 
 
 - type: jobIcon
 - type: jobIcon
-  locationPreference: Left
+  locationPreference: Right
   parent: JobIcon
   parent: JobIcon
   priority: 5
   priority: 5
   id: JobIconISsgt
   id: JobIconISsgt
@@ -59,7 +59,7 @@
   jobName: job-name-i-ssgt
   jobName: job-name-i-ssgt
 
 
 - type: jobIcon
 - type: jobIcon
-  locationPreference: Left
+  locationPreference: Right
   parent: JobIcon
   parent: JobIcon
   priority: 6
   priority: 6
   id: JobIconISgt
   id: JobIconISgt
@@ -68,7 +68,7 @@
     state: i_sgt
     state: i_sgt
   jobName: job-name-i-sgt
   jobName: job-name-i-sgt
 - type: jobIcon
 - type: jobIcon
-  locationPreference: Left
+  locationPreference: Right
   parent: JobIcon
   parent: JobIcon
   priority: 6
   priority: 6
   id: JobIconNco
   id: JobIconNco
@@ -77,7 +77,7 @@
     state: nco
     state: nco
   jobName: job-name-nco
   jobName: job-name-nco
 - type: jobIcon
 - type: jobIcon
-  locationPreference: Left
+  locationPreference: Right
   parent: JobIcon
   parent: JobIcon
   priority: 7
   priority: 7
   id: JobIconICpl
   id: JobIconICpl
@@ -86,7 +86,7 @@
     state: i_cpl
     state: i_cpl
   jobName: job-name-i-cpl
   jobName: job-name-i-cpl
 - type: jobIcon
 - type: jobIcon
-  locationPreference: Left
+  locationPreference: Right
   parent: JobIcon
   parent: JobIcon
   priority: 8
   priority: 8
   id: JobIconDesignatedMarksman
   id: JobIconDesignatedMarksman
@@ -96,7 +96,7 @@
   jobName: job-name-designated-marksman
   jobName: job-name-designated-marksman
 
 
 - type: jobIcon
 - type: jobIcon
-  locationPreference: Left
+  locationPreference: Right
   parent: JobIcon
   parent: JobIcon
   priority: 8
   priority: 8
   id: JobIconMedic
   id: JobIconMedic
@@ -106,7 +106,7 @@
   jobName: job-name-medic
   jobName: job-name-medic
 
 
 - type: jobIcon
 - type: jobIcon
-  locationPreference: Left
+  locationPreference: Right
   parent: JobIcon
   parent: JobIcon
   priority: 8
   priority: 8
   id: JobIconMg
   id: JobIconMg
@@ -116,7 +116,7 @@
   jobName: job-name-mg
   jobName: job-name-mg
 
 
 - type: jobIcon
 - type: jobIcon
-  locationPreference: Left
+  locationPreference: Right
   parent: JobIcon
   parent: JobIcon
   priority: 9
   priority: 9
   id: JobIconRifleman
   id: JobIconRifleman
@@ -126,7 +126,7 @@
   jobName: job-name-rifleman
   jobName: job-name-rifleman
 
 
 - type: jobIcon
 - type: jobIcon
-  locationPreference: Left
+  locationPreference: Right
   parent: JobIcon
   parent: JobIcon
   priority: 9
   priority: 9
   id: JobIconSoldier
   id: JobIconSoldier
@@ -136,7 +136,7 @@
   jobName: job-name-soldier
   jobName: job-name-soldier
 
 
 - type: jobIcon
 - type: jobIcon
-  locationPreference: Left
+  locationPreference: Right
   parent: JobIcon
   parent: JobIcon
   priority: 9
   priority: 9
   id: JobIconSword
   id: JobIconSword
@@ -146,7 +146,7 @@
   jobName: job-name-infantry-sword
   jobName: job-name-infantry-sword
 
 
 - type: jobIcon
 - type: jobIcon
-  locationPreference: Left
+  locationPreference: Right
   parent: JobIcon
   parent: JobIcon
   priority: 9
   priority: 9
   id: JobIconHeavy
   id: JobIconHeavy
@@ -156,7 +156,7 @@
   jobName: job-name-infantry-heavy
   jobName: job-name-infantry-heavy
 
 
 - type: jobIcon
 - type: jobIcon
-  locationPreference: Left
+  locationPreference: Right
   parent: JobIcon
   parent: JobIcon
   priority: 9
   priority: 9
   id: JobIconSpear
   id: JobIconSpear
@@ -166,7 +166,7 @@
   jobName: job-name-infantry-spear
   jobName: job-name-infantry-spear
 
 
 - type: jobIcon
 - type: jobIcon
-  locationPreference: Left
+  locationPreference: Right
   parent: JobIcon
   parent: JobIcon
   priority: 9
   priority: 9
   id: JobIconRanged
   id: JobIconRanged
@@ -174,3 +174,59 @@
     sprite: /Textures/Interface/Misc/civ_hud_squads.rsi
     sprite: /Textures/Interface/Misc/civ_hud_squads.rsi
     state: inf_ranged
     state: inf_ranged
   jobName: job-name-infantry-ranged
   jobName: job-name-infantry-ranged
+
+#squad icons
+- type: jobIcon
+  locationPreference: Right
+  parent: JobIcon
+  priority: 1
+  id: JobIconSquad1
+  icon:
+    sprite: /Textures/Interface/Misc/civ_hud_squads.rsi
+    state: squad_1
+  jobName: job-name-infantry-ranged
+- type: jobIcon
+  locationPreference: Right
+  parent: JobIcon
+  priority: 1
+  id: JobIconSquad2
+  icon:
+    sprite: /Textures/Interface/Misc/civ_hud_squads.rsi
+    state: squad_2
+  jobName: job-name-infantry-ranged
+- type: jobIcon
+  locationPreference: Right
+  parent: JobIcon
+  priority: 1
+  id: JobIconSquad3
+  icon:
+    sprite: /Textures/Interface/Misc/civ_hud_squads.rsi
+    state: squad_3
+  jobName: job-name-infantry-ranged
+- type: jobIcon
+  locationPreference: Right
+  parent: JobIcon
+  priority: 1
+  id: JobIconSquad4
+  icon:
+    sprite: /Textures/Interface/Misc/civ_hud_squads.rsi
+    state: squad_4
+  jobName: job-name-infantry-ranged
+- type: jobIcon
+  locationPreference: Right
+  parent: JobIcon
+  priority: 1
+  id: JobIconSquad5
+  icon:
+    sprite: /Textures/Interface/Misc/civ_hud_squads.rsi
+    state: squad_5
+  jobName: job-name-infantry-ranged
+- type: jobIcon
+  locationPreference: Right
+  parent: JobIcon
+  priority: 1
+  id: JobIconSquad6
+  icon:
+    sprite: /Textures/Interface/Misc/civ_hud_squads.rsi
+    state: squad_6
+  jobName: job-name-infantry-ranged

+ 0 - 3
Resources/Prototypes/Entities/Structures/Furniture/beds.yml

@@ -76,9 +76,6 @@
           Poison: -0.2
           Poison: -0.2
           Cold: -0.4
           Cold: -0.4
           Blunt: -0.2
           Blunt: -0.2
-    - type: Construction
-      graph: bed
-      node: medicalbed
     - type: GuideHelp
     - type: GuideHelp
       guides:
       guides:
         - Medical
         - Medical

+ 4 - 1
Resources/Prototypes/Entities/Structures/Walls/walls.yml

@@ -1376,10 +1376,13 @@
       cost: 6
       cost: 6
       delay: 8
       delay: 8
       fx: EffectRCDDeconstruct8
       fx: EffectRCDDeconstruct8
+    - type: Damageable
+      damageContainer: StructuralInorganic
+      damageModifierSet: Rock
     - type: Destructible
     - type: Destructible
       thresholds:
       thresholds:
         - trigger: !type:DamageTrigger
         - trigger: !type:DamageTrigger
-            damage: 100
+            damage: 350
           behaviors:
           behaviors:
             - !type:DoActsBehavior
             - !type:DoActsBehavior
               acts: ["Destruction"]
               acts: ["Destruction"]

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

@@ -18,7 +18,7 @@
         - type: NpcFactionMember
         - type: NpcFactionMember
           factions:
           factions:
             - England
             - England
-        - type: ShowEnglishFactionIcons
+        - type: ShowFactionIcons
           factionIcon: EnglishFaction
           factionIcon: EnglishFaction
 
 
 - type: playTimeTracker
 - type: playTimeTracker
@@ -54,7 +54,7 @@
         - type: NpcFactionMember
         - type: NpcFactionMember
           factions:
           factions:
             - England
             - England
-        - type: ShowEnglishFactionIcons
+        - type: ShowFactionIcons
           factionIcon: EnglishFaction
           factionIcon: EnglishFaction
 
 
 - type: playTimeTracker
 - type: playTimeTracker
@@ -91,7 +91,7 @@
         - type: NpcFactionMember
         - type: NpcFactionMember
           factions:
           factions:
             - England
             - England
-        - type: ShowEnglishFactionIcons
+        - type: ShowFactionIcons
           factionIcon: EnglishFaction
           factionIcon: EnglishFaction
 
 
 - type: playTimeTracker
 - type: playTimeTracker
@@ -138,7 +138,7 @@
         - type: NpcFactionMember
         - type: NpcFactionMember
           factions:
           factions:
             - England
             - England
-        - type: ShowEnglishFactionIcons
+        - type: ShowFactionIcons
           factionIcon: EnglishFaction
           factionIcon: EnglishFaction
 
 
 - type: playTimeTracker
 - type: playTimeTracker
@@ -185,7 +185,7 @@
         - type: NpcFactionMember
         - type: NpcFactionMember
           factions:
           factions:
             - England
             - England
-        - type: ShowEnglishFactionIcons
+        - type: ShowFactionIcons
           factionIcon: EnglishFaction
           factionIcon: EnglishFaction
 
 
 - type: playTimeTracker
 - type: playTimeTracker
@@ -259,7 +259,7 @@
         - type: NpcFactionMember
         - type: NpcFactionMember
           factions:
           factions:
             - England
             - England
-        - type: ShowEnglishFactionIcons
+        - type: ShowFactionIcons
           factionIcon: EnglishFaction
           factionIcon: EnglishFaction
 
 
 - type: playTimeTracker
 - type: playTimeTracker

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

@@ -18,7 +18,7 @@
         - type: NpcFactionMember
         - type: NpcFactionMember
           factions:
           factions:
             - France
             - France
-        - type: ShowFrenchFactionIcons
+        - type: ShowFactionIcons
           factionIcon: FrenchFaction
           factionIcon: FrenchFaction
 
 
 - type: playTimeTracker
 - type: playTimeTracker
@@ -53,7 +53,7 @@
         - type: NpcFactionMember
         - type: NpcFactionMember
           factions:
           factions:
             - France
             - France
-        - type: ShowFrenchFactionIcons
+        - type: ShowFactionIcons
           factionIcon: FrenchFaction
           factionIcon: FrenchFaction
 
 
 - type: playTimeTracker
 - type: playTimeTracker
@@ -90,7 +90,7 @@
         - type: NpcFactionMember
         - type: NpcFactionMember
           factions:
           factions:
             - France
             - France
-        - type: ShowFrenchFactionIcons
+        - type: ShowFactionIcons
           factionIcon: FrenchFaction
           factionIcon: FrenchFaction
 
 
 - type: playTimeTracker
 - type: playTimeTracker
@@ -137,7 +137,7 @@
         - type: NpcFactionMember
         - type: NpcFactionMember
           factions:
           factions:
             - France
             - France
-        - type: ShowFrenchFactionIcons
+        - type: ShowFactionIcons
           factionIcon: FrenchFaction
           factionIcon: FrenchFaction
 
 
 - type: playTimeTracker
 - type: playTimeTracker
@@ -185,7 +185,7 @@
         - type: NpcFactionMember
         - type: NpcFactionMember
           factions:
           factions:
             - France
             - France
-        - type: ShowFrenchFactionIcons
+        - type: ShowFactionIcons
           factionIcon: FrenchFaction
           factionIcon: FrenchFaction
 
 
 - type: playTimeTracker
 - type: playTimeTracker
@@ -259,7 +259,7 @@
         - type: NpcFactionMember
         - type: NpcFactionMember
           factions:
           factions:
             - France
             - France
-        - type: ShowFrenchFactionIcons
+        - type: ShowFactionIcons
           factionIcon: FrenchFaction
           factionIcon: FrenchFaction
 
 
 - type: playTimeTracker
 - type: playTimeTracker

+ 20 - 8
Resources/Prototypes/Roles/Jobs/Civ14/TDM/german.yml

@@ -18,8 +18,10 @@
         - type: NpcFactionMember
         - type: NpcFactionMember
           factions:
           factions:
             - Germany
             - Germany
-        - type: ShowGermanFactionIcons
+        - type: ShowFactionIcons
           factionIcon: GermanFaction
           factionIcon: GermanFaction
+          jobIcon: JobIconICpt
+          assignSquad: false
 
 
 - type: playTimeTracker
 - type: playTimeTracker
   id: JobGermanCaptain
   id: JobGermanCaptain
@@ -57,8 +59,10 @@
         - type: NpcFactionMember
         - type: NpcFactionMember
           factions:
           factions:
             - Germany
             - Germany
-        - type: ShowGermanFactionIcons
+        - type: ShowFactionIcons
           factionIcon: GermanFaction
           factionIcon: GermanFaction
+          jobIcon: JobIconISgt
+          assignSquad: true
 
 
 - type: playTimeTracker
 - type: playTimeTracker
   id: JobGermanSergeant
   id: JobGermanSergeant
@@ -87,7 +91,7 @@
   playTimeTracker: JobGermanSubmachineGunner
   playTimeTracker: JobGermanSubmachineGunner
   startingGear: GermanSubmachineGunnerGear
   startingGear: GermanSubmachineGunnerGear
   randomStartingGears: [GermanSubmachineGunnerGear, GermanSubmachineGunnerGear2]
   randomStartingGears: [GermanSubmachineGunnerGear, GermanSubmachineGunnerGear2]
-  icon: "JobIconICpl"
+  icon: "JobIconSoldier"
   supervisors: job-supervisors-cpt
   supervisors: job-supervisors-cpt
   special:
   special:
     - !type:AddComponentSpecial
     - !type:AddComponentSpecial
@@ -96,8 +100,10 @@
         - type: NpcFactionMember
         - type: NpcFactionMember
           factions:
           factions:
             - Germany
             - Germany
-        - type: ShowGermanFactionIcons
+        - type: ShowFactionIcons
           factionIcon: GermanFaction
           factionIcon: GermanFaction
+          jobIcon: JobIconRifleman
+          assignSquad: true
 
 
 - type: playTimeTracker
 - type: playTimeTracker
   id: JobGermanSubmachineGunner
   id: JobGermanSubmachineGunner
@@ -137,7 +143,7 @@
   playTimeTracker: JobGermanRifleman
   playTimeTracker: JobGermanRifleman
   startingGear: GermanRiflemanGear
   startingGear: GermanRiflemanGear
   randomStartingGears: [GermanRiflemanGear, GermanRiflemanGear2]
   randomStartingGears: [GermanRiflemanGear, GermanRiflemanGear2]
-  icon: "JobIconICpl"
+  icon: "JobIconSoldier"
   supervisors: job-supervisors-cpt
   supervisors: job-supervisors-cpt
   special:
   special:
     - !type:AddComponentSpecial
     - !type:AddComponentSpecial
@@ -146,8 +152,10 @@
         - type: NpcFactionMember
         - type: NpcFactionMember
           factions:
           factions:
             - Germany
             - Germany
-        - type: ShowGermanFactionIcons
+        - type: ShowFactionIcons
           factionIcon: GermanFaction
           factionIcon: GermanFaction
+          jobIcon: JobIconRifleman
+          assignSquad: true
 
 
 - type: playTimeTracker
 - type: playTimeTracker
   id: JobGermanRifleman
   id: JobGermanRifleman
@@ -196,8 +204,10 @@
         - type: NpcFactionMember
         - type: NpcFactionMember
           factions:
           factions:
             - Germany
             - Germany
-        - type: ShowGermanFactionIcons
+        - type: ShowFactionIcons
           factionIcon: GermanFaction
           factionIcon: GermanFaction
+          jobIcon: JobIconRifleman
+          assignSquad: true
 
 
 - type: playTimeTracker
 - type: playTimeTracker
   id: JobGermanMachinegunner
   id: JobGermanMachinegunner
@@ -245,8 +255,10 @@
         - type: NpcFactionMember
         - type: NpcFactionMember
           factions:
           factions:
             - Germany
             - Germany
-        - type: ShowGermanFactionIcons
+        - type: ShowFactionIcons
           factionIcon: GermanFaction
           factionIcon: GermanFaction
+          jobIcon: JobIconMedic
+          assignSquad: false
 
 
 - type: playTimeTracker
 - type: playTimeTracker
   id: JobGermanMedic
   id: JobGermanMedic

+ 20 - 8
Resources/Prototypes/Roles/Jobs/Civ14/TDM/soviet.yml

@@ -18,8 +18,10 @@
         - type: NpcFactionMember
         - type: NpcFactionMember
           factions:
           factions:
             - Soviet
             - Soviet
-        - type: ShowSovietFactionIcons
+        - type: ShowFactionIcons
           factionIcon: SovietFaction
           factionIcon: SovietFaction
+          jobIcon: JobIconICpt
+          assignSquad: false
 
 
 - type: playTimeTracker
 - type: playTimeTracker
   id: JobSovietCaptain
   id: JobSovietCaptain
@@ -56,8 +58,10 @@
         - type: NpcFactionMember
         - type: NpcFactionMember
           factions:
           factions:
             - Soviet
             - Soviet
-        - type: ShowSovietFactionIcons
+        - type: ShowFactionIcons
           factionIcon: SovietFaction
           factionIcon: SovietFaction
+          jobIcon: JobIconISgt
+          assignSquad: true
 
 
 - type: playTimeTracker
 - type: playTimeTracker
   id: JobSovietSergeant
   id: JobSovietSergeant
@@ -86,7 +90,7 @@
   playTimeTracker: JobSovietSubmachineGunner
   playTimeTracker: JobSovietSubmachineGunner
   startingGear: SovietSubmachineGunnerGear
   startingGear: SovietSubmachineGunnerGear
   randomStartingGears: [SovietSubmachineGunnerGear, SovietSubmachineGunnerGear2]
   randomStartingGears: [SovietSubmachineGunnerGear, SovietSubmachineGunnerGear2]
-  icon: "JobIconICpl"
+  icon: "JobIconSoldier"
   supervisors: job-supervisors-cpt
   supervisors: job-supervisors-cpt
   special:
   special:
     - !type:AddComponentSpecial
     - !type:AddComponentSpecial
@@ -95,8 +99,10 @@
         - type: NpcFactionMember
         - type: NpcFactionMember
           factions:
           factions:
             - Soviet
             - Soviet
-        - type: ShowSovietFactionIcons
+        - type: ShowFactionIcons
           factionIcon: SovietFaction
           factionIcon: SovietFaction
+          jobIcon: JobIconRifleman
+          assignSquad: true
 
 
 - type: playTimeTracker
 - type: playTimeTracker
   id: JobSovietSubmachineGunner
   id: JobSovietSubmachineGunner
@@ -138,7 +144,7 @@
   playTimeTracker: JobSovietRifleman
   playTimeTracker: JobSovietRifleman
   startingGear: SovietRiflemanGear
   startingGear: SovietRiflemanGear
   randomStartingGears: [SovietRiflemanGear, SovietRiflemanGear2]
   randomStartingGears: [SovietRiflemanGear, SovietRiflemanGear2]
-  icon: "JobIconICpl"
+  icon: "JobIconSoldier"
   supervisors: job-supervisors-cpt
   supervisors: job-supervisors-cpt
   special:
   special:
     - !type:AddComponentSpecial
     - !type:AddComponentSpecial
@@ -147,8 +153,10 @@
         - type: NpcFactionMember
         - type: NpcFactionMember
           factions:
           factions:
             - Soviet
             - Soviet
-        - type: ShowSovietFactionIcons
+        - type: ShowFactionIcons
           factionIcon: SovietFaction
           factionIcon: SovietFaction
+          jobIcon: JobIconRifleman
+          assignSquad: true
 
 
 - type: playTimeTracker
 - type: playTimeTracker
   id: JobSovietRifleman
   id: JobSovietRifleman
@@ -200,8 +208,10 @@
         - type: NpcFactionMember
         - type: NpcFactionMember
           factions:
           factions:
             - Soviet
             - Soviet
-        - type: ShowSovietFactionIcons
+        - type: ShowFactionIcons
           factionIcon: SovietFaction
           factionIcon: SovietFaction
+          jobIcon: JobIconRifleman
+          assignSquad: true
 
 
 - type: playTimeTracker
 - type: playTimeTracker
   id: JobSovietMachinegunner
   id: JobSovietMachinegunner
@@ -253,8 +263,10 @@
         - type: NpcFactionMember
         - type: NpcFactionMember
           factions:
           factions:
             - Soviet
             - Soviet
-        - type: ShowSovietFactionIcons
+        - type: ShowFactionIcons
           factionIcon: SovietFaction
           factionIcon: SovietFaction
+          jobIcon: JobIconMedic
+          assignSquad: false
 
 
 - type: playTimeTracker
 - type: playTimeTracker
   id: JobSovietMedic
   id: JobSovietMedic

+ 15 - 5
Resources/Prototypes/Roles/Jobs/Civ14/TDM/sovietCW.yml

@@ -18,8 +18,10 @@
         - type: NpcFactionMember
         - type: NpcFactionMember
           factions:
           factions:
             - SovietCW
             - SovietCW
-        - type: ShowSovietFactionIcons
+        - type: ShowFactionIcons
           factionIcon: SovietFaction
           factionIcon: SovietFaction
+          jobIcon: JobIconICpt
+          assignSquad: false
 
 
 - type: playTimeTracker
 - type: playTimeTracker
   id: JobSovietCWCaptain
   id: JobSovietCWCaptain
@@ -58,8 +60,10 @@
         - type: NpcFactionMember
         - type: NpcFactionMember
           factions:
           factions:
             - SovietCW
             - SovietCW
-        - type: ShowSovietFactionIcons
+        - type: ShowFactionIcons
           factionIcon: SovietFaction
           factionIcon: SovietFaction
+          jobIcon: JobIconISgt
+          assignSquad: true
 
 
 - type: playTimeTracker
 - type: playTimeTracker
   id: JobSovietCWSergeant
   id: JobSovietCWSergeant
@@ -97,8 +101,10 @@
         - type: NpcFactionMember
         - type: NpcFactionMember
           factions:
           factions:
             - SovietCW
             - SovietCW
-        - type: ShowSovietFactionIcons
+        - type: ShowFactionIcons
           factionIcon: SovietFaction
           factionIcon: SovietFaction
+          jobIcon: JobIconRifleman
+          assignSquad: true
 
 
 - type: playTimeTracker
 - type: playTimeTracker
   id: JobSovietCWRifleman
   id: JobSovietCWRifleman
@@ -150,8 +156,10 @@
         - type: NpcFactionMember
         - type: NpcFactionMember
           factions:
           factions:
             - SovietCW
             - SovietCW
-        - type: ShowSovietFactionIcons
+        - type: ShowFactionIcons
           factionIcon: SovietFaction
           factionIcon: SovietFaction
+          jobIcon: JobIconRifleman
+          assignSquad: true
 
 
 - type: playTimeTracker
 - type: playTimeTracker
   id: JobSovietCWMachinegunner
   id: JobSovietCWMachinegunner
@@ -203,8 +211,10 @@
         - type: NpcFactionMember
         - type: NpcFactionMember
           factions:
           factions:
             - SovietCW
             - SovietCW
-        - type: ShowSovietFactionIcons
+        - type: ShowFactionIcons
           factionIcon: SovietFaction
           factionIcon: SovietFaction
+          jobIcon: JobIconMedic
+          assignSquad: false
 
 
 - type: playTimeTracker
 - type: playTimeTracker
   id: JobSovietCWMedic
   id: JobSovietCWMedic

+ 13 - 5
Resources/Prototypes/Roles/Jobs/Civ14/TDM/usa.yml

@@ -17,8 +17,9 @@
         - type: NpcFactionMember
         - type: NpcFactionMember
           factions:
           factions:
             - US
             - US
-        - type: ShowUsFactionIcons
+        - type: ShowFactionIcons
           factionIcon: UsFaction
           factionIcon: UsFaction
+          jobIcon: JobIconICpt
 
 
 - type: playTimeTracker
 - type: playTimeTracker
   id: JobUSCaptain
   id: JobUSCaptain
@@ -54,8 +55,10 @@
         - type: NpcFactionMember
         - type: NpcFactionMember
           factions:
           factions:
             - US
             - US
-        - type: ShowUsFactionIcons
+        - type: ShowFactionIcons
           factionIcon: UsFaction
           factionIcon: UsFaction
+          jobIcon: JobIconISgt
+          assignSquad: true
 
 
 - type: playTimeTracker
 - type: playTimeTracker
   id: JobUSSergeant
   id: JobUSSergeant
@@ -91,8 +94,10 @@
         - type: NpcFactionMember
         - type: NpcFactionMember
           factions:
           factions:
             - US
             - US
-        - type: ShowUsFactionIcons
+        - type: ShowFactionIcons
           factionIcon: UsFaction
           factionIcon: UsFaction
+          jobIcon: JobIconRifleman
+          assignSquad: true
 
 
 - type: playTimeTracker
 - type: playTimeTracker
   id: JobUSRifleman
   id: JobUSRifleman
@@ -142,8 +147,10 @@
         - type: NpcFactionMember
         - type: NpcFactionMember
           factions:
           factions:
             - US
             - US
-        - type: ShowUsFactionIcons
+        - type: ShowFactionIcons
           factionIcon: UsFaction
           factionIcon: UsFaction
+          jobIcon: JobIconMg
+          assignSquad: true
 
 
 - type: playTimeTracker
 - type: playTimeTracker
   id: JobUSMachinegunner
   id: JobUSMachinegunner
@@ -192,8 +199,9 @@
         - type: NpcFactionMember
         - type: NpcFactionMember
           factions:
           factions:
             - US
             - US
-        - type: ShowUsFactionIcons
+        - type: ShowFactionIcons
           factionIcon: UsFaction
           factionIcon: UsFaction
+          jobIcon: JobIconMedic
 
 
 - type: playTimeTracker
 - type: playTimeTracker
   id: JobUSMedic
   id: JobUSMedic

+ 23 - 0
Resources/Textures/Civ14/Objects/medals.rsi/meta.json

@@ -0,0 +1,23 @@
+{
+    "version": 1,
+    "license": "AGPLv3",
+    "copyright": "Taislin",
+    "size": {
+        "x": 32,
+        "y": 32
+    },
+    "states": [
+        {
+            "name": "nomads_bronze",
+            "directions": 1
+        },
+        {
+            "name": "nomads_silver",
+            "directions": 1
+        },
+        {
+            "name": "nomads_gold",
+            "directions": 1
+        }
+    ]
+}

二進制
Resources/Textures/Civ14/Objects/medals.rsi/nomads_bronze.png


二進制
Resources/Textures/Civ14/Objects/medals.rsi/nomads_gold.png


二進制
Resources/Textures/Civ14/Objects/medals.rsi/nomads_silver.png


Some files were not shown because too many files changed in this diff