From 0213a349cbfffa629c188d1d23af774ecaf31d01 Mon Sep 17 00:00:00 2001 From: Shush Date: Fri, 10 Apr 2026 18:46:24 +0300 Subject: [PATCH 1/2] Add HandleCloneNaming and use for clones Introduce Helpers.HandleCloneNaming to centralize clone naming behavior: if a name contains a number the first numeric part is incremented; otherwise a localized " (Clone)" suffix is appended. Replace ad-hoc Name + Translate(...) usages in AITriggerType, Script, TaskForce, TeamType, and Trigger to use the new helper. Add/update the "CloneName" translation key in English and zh-Hans (consolidating previous per-type entries) to support localization. --- .../Config/Translations/en/Translation_en.ini | 1 + .../zh-Hans/Translation_zh-Hans.ini | 5 +--- src/TSMapEditor/Helpers.cs | 24 +++++++++++++++++++ src/TSMapEditor/Models/AITriggerType.cs | 2 +- src/TSMapEditor/Models/Script.cs | 2 +- src/TSMapEditor/Models/TaskForce.cs | 2 +- src/TSMapEditor/Models/TeamType.cs | 2 +- src/TSMapEditor/Models/Trigger.cs | 2 +- 8 files changed, 31 insertions(+), 9 deletions(-) diff --git a/src/TSMapEditor/Config/Translations/en/Translation_en.ini b/src/TSMapEditor/Config/Translations/en/Translation_en.ini index 86eb302f..53b45396 100644 --- a/src/TSMapEditor/Config/Translations/en/Translation_en.ini +++ b/src/TSMapEditor/Config/Translations/en/Translation_en.ini @@ -372,6 +372,7 @@ WindowController.NoTriggerAttached.Title=No trigger attached WindowController.NoTriggerAttached.Description=The specified Tag has no attached Trigger! ListExtensions.TaskForceParseError=Failed to load TaskForce {0}. It might be missing a section or be otherwise invalid. ListExtensions.TeamTypes.TaskForceNotFound=TeamType {0} has an invalid TaskForce ({1}) specified! +CloneName=\s(Clone) ; ************************************************* ; Hint texts diff --git a/src/TSMapEditor/Config/Translations/zh-Hans/Translation_zh-Hans.ini b/src/TSMapEditor/Config/Translations/zh-Hans/Translation_zh-Hans.ini index e87bfe69..33a06533 100644 --- a/src/TSMapEditor/Config/Translations/zh-Hans/Translation_zh-Hans.ini +++ b/src/TSMapEditor/Config/Translations/zh-Hans/Translation_zh-Hans.ini @@ -2385,8 +2385,5 @@ SetMapDifficultySettingsWindow.lblTeamDelayEasy.Text=简单: SetMapDifficultySettingsWindow.btnApply.Text=应用 TriggersWindow.UnknownSpeech=\s- 未知语音 -Trigger.CloneName=\s(副本) -TaskForce.CloneName=\s(副本) -TeamType.CloneName=\s(副本) -Script.CloneName=\s(副本) +CloneName=\s(副本) TeamTypes.Global=(全局)\s diff --git a/src/TSMapEditor/Helpers.cs b/src/TSMapEditor/Helpers.cs index 509e0853..e4c0ef76 100644 --- a/src/TSMapEditor/Helpers.cs +++ b/src/TSMapEditor/Helpers.cs @@ -847,5 +847,29 @@ public static string DifficultyToTranslatedString(Difficulty difficulty) throw new NotImplementedException(nameof(DifficultyToTranslatedString) + ": Unknown difficulty level " + difficulty); } } + + /// + /// Shared helper function used by Triggers, TaskForces, Scripts, TeamTypes, and AI Triggers. + /// Used to generate the name of the instance during the cloning process of those entities. + /// If the provided name contains a number, the number is incremented and the name is returned as is. + /// Otherwise, a localized " (Clone)" suffix is appended to the name. + /// If there are multiple numbers in the name, only the first is incremented. + /// + public static string HandleCloneNaming(string name) + { + string[] parts = name.Split(" "); + int numPart = -1; + + for (int i = 0; i < parts.Length; i++) + { + if (int.TryParse(parts[i], out numPart) && numPart >= 0) + { + parts[i] = (numPart + 1).ToString(); + return string.Join(" ", parts); + } + } + + return name + Translate("CloneName", " (Clone)"); + } } } diff --git a/src/TSMapEditor/Models/AITriggerType.cs b/src/TSMapEditor/Models/AITriggerType.cs index 8c5d829e..44ef4eda 100644 --- a/src/TSMapEditor/Models/AITriggerType.cs +++ b/src/TSMapEditor/Models/AITriggerType.cs @@ -96,7 +96,7 @@ public AITriggerType(string iniName) public AITriggerType Clone(string newUniqueId) { var clonedAITrigger = (AITriggerType)MemberwiseClone(); - clonedAITrigger.Name = Name + " (Clone)"; + clonedAITrigger.Name = Helpers.HandleCloneNaming(Name); clonedAITrigger.ININame = newUniqueId; return clonedAITrigger; } diff --git a/src/TSMapEditor/Models/Script.cs b/src/TSMapEditor/Models/Script.cs index 367d5286..15187b52 100644 --- a/src/TSMapEditor/Models/Script.cs +++ b/src/TSMapEditor/Models/Script.cs @@ -96,7 +96,7 @@ public string EditorColor public Script Clone(string iniName) { var script = new Script(iniName); - script.Name = Name + Translate(this, "CloneName", " (Clone)"); + script.Name = Helpers.HandleCloneNaming(Name); script.EditorColor = EditorColor; foreach (var action in Actions) diff --git a/src/TSMapEditor/Models/TaskForce.cs b/src/TSMapEditor/Models/TaskForce.cs index 72d61f41..9517d8f0 100644 --- a/src/TSMapEditor/Models/TaskForce.cs +++ b/src/TSMapEditor/Models/TaskForce.cs @@ -160,7 +160,7 @@ public string GetHintText() public TaskForce Clone(string iniName) { var newTaskForce = new TaskForce(iniName); - newTaskForce.Name = Name + Translate(this, "CloneName", " (Clone)"); + newTaskForce.Name = Helpers.HandleCloneNaming(Name); newTaskForce.Group = Group; for (int i = 0; i < TechnoTypes.Length; i++) diff --git a/src/TSMapEditor/Models/TeamType.cs b/src/TSMapEditor/Models/TeamType.cs index c2b14644..93ec00b4 100644 --- a/src/TSMapEditor/Models/TeamType.cs +++ b/src/TSMapEditor/Models/TeamType.cs @@ -132,7 +132,7 @@ public TeamType Clone(string iniName) { var clone = MemberwiseClone() as TeamType; clone.ININame = iniName; - clone.Name = Name + Translate(this, "CloneName", " (Clone)"); + clone.Name = Helpers.HandleCloneNaming(Name); clone.EnabledTeamTypeFlags = new List(EnabledTeamTypeFlags); diff --git a/src/TSMapEditor/Models/Trigger.cs b/src/TSMapEditor/Models/Trigger.cs index 500deb35..472c9b9d 100644 --- a/src/TSMapEditor/Models/Trigger.cs +++ b/src/TSMapEditor/Models/Trigger.cs @@ -87,7 +87,7 @@ public Trigger Clone(string uniqueId) { Trigger clone = (Trigger)MemberwiseClone(); clone.ID = uniqueId; - clone.Name = Name + Translate(this, "CloneName", " (Clone)"); + clone.Name = Helpers.HandleCloneNaming(Name); // Deep clone the events and actions From 45d8ac4f5e19c9279f3dd00bfddb5307cf110d33 Mon Sep 17 00:00:00 2001 From: Shush Date: Fri, 10 Apr 2026 19:58:21 +0300 Subject: [PATCH 2/2] Post PR review fixes --- src/TSMapEditor/Helpers.cs | 4 ++-- src/TSMapEditor/Models/AITriggerType.cs | 2 +- src/TSMapEditor/Models/Script.cs | 2 +- src/TSMapEditor/Models/TaskForce.cs | 2 +- src/TSMapEditor/Models/TeamType.cs | 2 +- src/TSMapEditor/Models/Trigger.cs | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/TSMapEditor/Helpers.cs b/src/TSMapEditor/Helpers.cs index e4c0ef76..b3333863 100644 --- a/src/TSMapEditor/Helpers.cs +++ b/src/TSMapEditor/Helpers.cs @@ -855,7 +855,7 @@ public static string DifficultyToTranslatedString(Difficulty difficulty) /// Otherwise, a localized " (Clone)" suffix is appended to the name. /// If there are multiple numbers in the name, only the first is incremented. /// - public static string HandleCloneNaming(string name) + public static string GetNameForClone(string name) { string[] parts = name.Split(" "); int numPart = -1; @@ -864,7 +864,7 @@ public static string HandleCloneNaming(string name) { if (int.TryParse(parts[i], out numPart) && numPart >= 0) { - parts[i] = (numPart + 1).ToString(); + parts[i] = (numPart + 1).ToString(CultureInfo.InvariantCulture); return string.Join(" ", parts); } } diff --git a/src/TSMapEditor/Models/AITriggerType.cs b/src/TSMapEditor/Models/AITriggerType.cs index 44ef4eda..679f1cdd 100644 --- a/src/TSMapEditor/Models/AITriggerType.cs +++ b/src/TSMapEditor/Models/AITriggerType.cs @@ -96,7 +96,7 @@ public AITriggerType(string iniName) public AITriggerType Clone(string newUniqueId) { var clonedAITrigger = (AITriggerType)MemberwiseClone(); - clonedAITrigger.Name = Helpers.HandleCloneNaming(Name); + clonedAITrigger.Name = Helpers.GetNameForClone(Name); clonedAITrigger.ININame = newUniqueId; return clonedAITrigger; } diff --git a/src/TSMapEditor/Models/Script.cs b/src/TSMapEditor/Models/Script.cs index 15187b52..ae71be7c 100644 --- a/src/TSMapEditor/Models/Script.cs +++ b/src/TSMapEditor/Models/Script.cs @@ -96,7 +96,7 @@ public string EditorColor public Script Clone(string iniName) { var script = new Script(iniName); - script.Name = Helpers.HandleCloneNaming(Name); + script.Name = Helpers.GetNameForClone(Name); script.EditorColor = EditorColor; foreach (var action in Actions) diff --git a/src/TSMapEditor/Models/TaskForce.cs b/src/TSMapEditor/Models/TaskForce.cs index 9517d8f0..ab9b8c30 100644 --- a/src/TSMapEditor/Models/TaskForce.cs +++ b/src/TSMapEditor/Models/TaskForce.cs @@ -160,7 +160,7 @@ public string GetHintText() public TaskForce Clone(string iniName) { var newTaskForce = new TaskForce(iniName); - newTaskForce.Name = Helpers.HandleCloneNaming(Name); + newTaskForce.Name = Helpers.GetNameForClone(Name); newTaskForce.Group = Group; for (int i = 0; i < TechnoTypes.Length; i++) diff --git a/src/TSMapEditor/Models/TeamType.cs b/src/TSMapEditor/Models/TeamType.cs index 93ec00b4..5c243c6b 100644 --- a/src/TSMapEditor/Models/TeamType.cs +++ b/src/TSMapEditor/Models/TeamType.cs @@ -132,7 +132,7 @@ public TeamType Clone(string iniName) { var clone = MemberwiseClone() as TeamType; clone.ININame = iniName; - clone.Name = Helpers.HandleCloneNaming(Name); + clone.Name = Helpers.GetNameForClone(Name); clone.EnabledTeamTypeFlags = new List(EnabledTeamTypeFlags); diff --git a/src/TSMapEditor/Models/Trigger.cs b/src/TSMapEditor/Models/Trigger.cs index 472c9b9d..9a244f3f 100644 --- a/src/TSMapEditor/Models/Trigger.cs +++ b/src/TSMapEditor/Models/Trigger.cs @@ -87,7 +87,7 @@ public Trigger Clone(string uniqueId) { Trigger clone = (Trigger)MemberwiseClone(); clone.ID = uniqueId; - clone.Name = Helpers.HandleCloneNaming(Name); + clone.Name = Helpers.GetNameForClone(Name); // Deep clone the events and actions