diff --git a/src/TSMapEditor/Config/UI/Windows/AITriggersWindow.ini b/src/TSMapEditor/Config/UI/Windows/AITriggersWindow.ini index 626063aa8..dea7b5c17 100644 --- a/src/TSMapEditor/Config/UI/Windows/AITriggersWindow.ini +++ b/src/TSMapEditor/Config/UI/Windows/AITriggersWindow.ini @@ -11,14 +11,15 @@ $CC02=lblAITriggers:XNALabel $CC03=btnNew:EditorButton $CC04=btnDelete:EditorButton $CC05=btnClone:EditorButton -$CC06=lbAITriggers:EditorListBox -$CC07=lblSelectedAITrigger:XNALabel -$CC08=tbName:EditorTextBox -$CC09=lblName:XNALabel -$CC10=ddSide:XNADropDown -$CC11=lblSide:XNALabel -$CC12=ddHouseType:XNADropDown -$CC13=lblHouse:XNALabel +$CC06=ddActions:XNADropDown +$CC07=lbAITriggers:EditorListBox +$CC08=lblSelectedAITrigger:XNALabel +$CC09=tbName:EditorTextBox +$CC10=lblName:XNALabel +$CC11=ddSide:XNADropDown +$CC12=lblSide:XNALabel +$CC13=ddHouseType:XNADropDown +$CC14=lblHouse:XNALabel $CCline1=panelLine1:XNAPanel $CCc1=lblConditionHeader:XNALabel $CCc2=ddConditionType:XNADropDown @@ -91,10 +92,15 @@ $Y=getBottom(btnDelete) + VERTICAL_SPACING $Width=getWidth(btnNew) Text=Clone -[lbAITriggers] +[ddActions] $X=getX(lblAITriggers) $Y=getBottom(btnClone) + VERTICAL_SPACING $Width=getWidth(btnNew) + +[lbAITriggers] +$X=getX(lblAITriggers) +$Y=getBottom(ddActions) + VERTICAL_SPACING +$Width=getWidth(btnNew) $Height=450 ; ************************************************ diff --git a/src/TSMapEditor/Helpers.cs b/src/TSMapEditor/Helpers.cs index 20565ea7f..0bb4879c1 100644 --- a/src/TSMapEditor/Helpers.cs +++ b/src/TSMapEditor/Helpers.cs @@ -586,6 +586,26 @@ public static IEnumerable GetFillAreaTiles(MapTile targetTile, Map map, return tilesToProcess; } + /// + /// Converts a name that includes a difficulty to instead have a different difficulty. + /// Useful for cloning purposes of any type of object named by users to additional difficulty levels. + /// + /// Original name to convert. + /// Current difficulty to convert the name from (replace). + /// New difficulty to convert the name to (replace). + /// New name after it was converted to the desired difficulty. + public static string ConvertNameToNewDifficulty(string name, Difficulty fromDifficulty, Difficulty toDifficulty) + { + string fromDifficultyString = fromDifficulty.ToString(); + string toDifficultyString = toDifficulty.ToString(); + + string newName = name.Replace(fromDifficultyString, toDifficultyString); + newName = newName.Replace($" {fromDifficultyString[0]}", $" {toDifficultyString[0]}"); + newName = newName.Replace($"{fromDifficultyString[0]} ", $"{toDifficultyString[0]} "); + + return newName; + } + /// /// Generates outline edges for a foundation of cells /// diff --git a/src/TSMapEditor/Models/Enums/Difficulty.cs b/src/TSMapEditor/Models/Enums/Difficulty.cs new file mode 100644 index 000000000..e5e9850c8 --- /dev/null +++ b/src/TSMapEditor/Models/Enums/Difficulty.cs @@ -0,0 +1,9 @@ +namespace TSMapEditor.Models +{ + public enum Difficulty + { + Easy, + Medium, + Hard + } +} diff --git a/src/TSMapEditor/UI/Windows/AITriggersWindow.cs b/src/TSMapEditor/UI/Windows/AITriggersWindow.cs index 391404c17..97d3ec14f 100644 --- a/src/TSMapEditor/UI/Windows/AITriggersWindow.cs +++ b/src/TSMapEditor/UI/Windows/AITriggersWindow.cs @@ -29,6 +29,7 @@ public AITriggersWindow(WindowManager windowManager, Map map) : base(windowManag public event EventHandler TeamTypeOpened; private EditorListBox lbAITriggers; + private XNADropDown ddActions; private EditorTextBox tbName; private XNADropDown ddSide; private XNADropDown ddHouseType; @@ -56,6 +57,7 @@ public override void Initialize() base.Initialize(); lbAITriggers = FindChild(nameof(lbAITriggers)); + ddActions = FindChild(nameof(ddActions)); tbName = FindChild(nameof(tbName)); ddSide = FindChild(nameof(ddSide)); ddHouseType = FindChild(nameof(ddHouseType)); @@ -89,9 +91,133 @@ public override void Initialize() var technoTypeDarkeningPanel = DarkeningPanel.InitializeAndAddToParentControlWithChild(WindowManager, Parent, selectTechnoTypeWindow); technoTypeDarkeningPanel.Hidden += TechnoTypeDarkeningPanel_Hidden; + ddActions.AddItem("Advanced..."); + ddActions.AddItem(new XNADropDownItem() { Text = "Clone for Easier Difficulties", Tag = new Action(CloneForEasierDifficulties) }); + ddActions.SelectedIndex = 0; + ddActions.SelectedIndexChanged += DdActions_SelectedIndexChanged; + lbAITriggers.SelectedIndexChanged += LbAITriggers_SelectedIndexChanged; } + private void CloneForEasierDifficulties() + { + if (editedAITrigger == null) + return; + + var messageBox = EditorMessageBox.Show(WindowManager, + "Are you sure?", + "Cloning this AI trigger for easier difficulties will create duplicate instances" + Environment.NewLine + + "of this AI trigger for Medium and Easy difficulties, setting the difficulty" + Environment.NewLine + + "setting for each AI trigger to Medium and Easy, respectively." + Environment.NewLine + + "This will set the current AI trigger's difficulty to Hard only." + Environment.NewLine + Environment.NewLine + + "In case the AI trigger references a Primary or Secondary TeamTypes," + Environment.NewLine + + "those TeamTypes and their TaskForoces would be duplicated for easier difficulties." + Environment.NewLine + + "If those duplicates already exist, this action will set the AI triggers to use those " + Environment.NewLine + + "TeamTypes instead." + Environment.NewLine + Environment.NewLine + + "The script assumes that this AI Trigger has the words 'H' or 'Hard'" + Environment.NewLine + + "in their name and in their respective TeamTypes and TaskForces." + Environment.NewLine + Environment.NewLine + + "No un-do is available. Do you want to continue?", MessageBoxButtons.YesNo); + + messageBox.YesClickedAction = _ => DoCloneForEasierDifficulties(); + } + + private void DoCloneForEasierDifficulties() + { + editedAITrigger.Hard = true; + editedAITrigger.Medium = false; + editedAITrigger.Easy = false; + + var mediumAITrigger = editedAITrigger.Clone(map.GetNewUniqueInternalId()); + mediumAITrigger.Hard = false; + mediumAITrigger.Medium = true; + + var easyAITrigger = editedAITrigger.Clone(map.GetNewUniqueInternalId()); + easyAITrigger.Hard = false; + easyAITrigger.Easy = true; + + mediumAITrigger.Name = Helpers.ConvertNameToNewDifficulty(editedAITrigger.Name, Difficulty.Hard, Difficulty.Medium); + easyAITrigger.Name = Helpers.ConvertNameToNewDifficulty(editedAITrigger.Name, Difficulty.Hard, Difficulty.Easy); + + map.AITriggerTypes.Add(mediumAITrigger); + map.AITriggerTypes.Add(easyAITrigger); + + CloneTeamTypesAndAttachToAITrigger(mediumAITrigger, Difficulty.Medium, true); + CloneTeamTypesAndAttachToAITrigger(mediumAITrigger, Difficulty.Medium, false); + CloneTeamTypesAndAttachToAITrigger(easyAITrigger, Difficulty.Easy, true); + CloneTeamTypesAndAttachToAITrigger(easyAITrigger, Difficulty.Easy, false); + + ListAITriggers(); + } + + private void CloneTeamTypesAndAttachToAITrigger(AITriggerType newAITrigger, Difficulty difficulty, bool isPrimaryTeamType) + { + var teamTypeToClone = isPrimaryTeamType ? editedAITrigger.PrimaryTeam : editedAITrigger.SecondaryTeam; + + if (teamTypeToClone == null) + return; + + // Check if its lower difficulty counterpart already exists, if it doesn't, create it + string newDifficultyName = Helpers.ConvertNameToNewDifficulty(teamTypeToClone.Name, Difficulty.Hard, difficulty); + + var newDifficultyTeamType = map.TeamTypes.Find(teamType => teamType.Name == newDifficultyName); + + if (newDifficultyTeamType == null) + { + // clone the teams type and give it a new name + newDifficultyTeamType = teamTypeToClone.Clone(map.GetNewUniqueInternalId()); + newDifficultyTeamType.Name = newDifficultyName; + + map.AddTeamType(newDifficultyTeamType); + + // If the team type has a task force, check if it has lower difficulty duplicate; if not, create it + if (teamTypeToClone.TaskForce != null) + { + var taskForceToClone = teamTypeToClone.TaskForce; + + newDifficultyName = Helpers.ConvertNameToNewDifficulty(taskForceToClone.Name, Difficulty.Hard, difficulty); + + var newDifficultyTaskForce = map.TaskForces.Find(taskForce => taskForce.Name == newDifficultyName); + + if (newDifficultyTaskForce == null) + { + newDifficultyTaskForce = taskForceToClone.Clone(map.GetNewUniqueInternalId()); + newDifficultyTaskForce.Name = newDifficultyName; + + map.AddTaskForce(newDifficultyTaskForce); + } + + newDifficultyTeamType.TaskForce = newDifficultyTaskForce; + } + } + + // Regardless: assign to relevant team to the new AI trigger + if (isPrimaryTeamType) + { + newAITrigger.PrimaryTeam = newDifficultyTeamType; + } + else + { + newAITrigger.SecondaryTeam = newDifficultyTeamType; + } + } + + private void DdActions_SelectedIndexChanged(object sender, EventArgs e) + { + var item = ddActions.SelectedItem; + if (item == null) + return; + + if (item.Tag == null) + return; + + if (item.Tag is Action action) + action(); + + ddActions.SelectedIndexChanged -= DdActions_SelectedIndexChanged; + ddActions.SelectedIndex = 0; + ddActions.SelectedIndexChanged += DdActions_SelectedIndexChanged; + } + private void BtnOpenPrimaryTeam_LeftClick(object sender, EventArgs e) { if (editedAITrigger == null || editedAITrigger.PrimaryTeam == null)