Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions src/TSMapEditor/Config/Default/UI/Windows/AITargetTypesWindow.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
[AITargetTypesWindow]
Width=920
Height=560
Enabled=yes
$CC0=lblAITargetTypes:XNALabel
$CC1=btnNewAITargetType:EditorButton
$CC2=btnDeleteAITargetType:EditorButton
$CC3=btnCloneAITargetType:EditorButton
$CC4=lbAITargetTypes:EditorListBox
$CC5=lblTechnoTypes:XNALabel
$CC6=btnAddTechno:EditorButton
$CC7=btnDeleteTechno:EditorButton
$CC8=lbTechnoEntries:EditorListBox
$CC9=lblAvailableTechnos:XNALabel
$CC10=tbSearchTechno:EditorSuggestionTextBox
$CC11=lbAvailableTechnos:EditorListBox
HasCloseButton=yes

[lblAITargetTypes]
$X=EMPTY_SPACE_SIDES
$Y=EMPTY_SPACE_TOP
FontIndex=1
$Text=translate(AITargetTypes:)

[btnNewAITargetType]
$X=EMPTY_SPACE_SIDES
$Y=getBottom(lblAITargetTypes) + EMPTY_SPACE_TOP
$Width=300
$Text=translate(New AITargetType)

[btnDeleteAITargetType]
$X=EMPTY_SPACE_SIDES
$Y=getBottom(btnNewAITargetType) + VERTICAL_SPACING
$Width=getWidth(btnNewAITargetType)
$Text=translate(Delete AITargetType)

[lbAITargetTypes]
$X=EMPTY_SPACE_SIDES
$Y=getBottom(btnCloneAITargetType) + VERTICAL_SPACING
$Width=getWidth(btnNewAITargetType)
$Height=getHeight(AITargetTypesWindow) - getY(lbAITargetTypes) - EMPTY_SPACE_BOTTOM

[lblTechnoTypes]
$X=getRight(lbAITargetTypes) + (HORIZONTAL_SPACING * 2)
$Y=getY(lblAITargetTypes)
$Text=translate(TechnoTypes:)

[btnAddTechno]
$X=getX(lblTechnoTypes)
$Y=getBottom(lblTechnoTypes) + EMPTY_SPACE_TOP
$Width=220
$Text=translate(Add Techno)

[btnDeleteTechno]
$X=getX(btnAddTechno)
$Y=getBottom(btnAddTechno) + VERTICAL_SPACING
$Width=getWidth(btnAddTechno)
$Text=translate(Delete Techno)

[btnCloneAITargetType]
$X=EMPTY_SPACE_SIDES
$Y=getBottom(btnDeleteAITargetType) + VERTICAL_SPACING
$Width=getWidth(btnNewAITargetType)
$Text=translate(Clone AITargetType)

[lblAvailableTechnos]
$X=getRight(lbTechnoEntries) + (HORIZONTAL_SPACING * 2)
$Y=getY(lblTechnoTypes)
$Text=translate(Available TechnoTypes:)

[tbSearchTechno]
$X=getX(lblAvailableTechnos)
$Y=getBottom(lblAvailableTechnos) + EMPTY_SPACE_TOP
$Width=getWidth(AITargetTypesWindow) - getX(tbSearchTechno) - EMPTY_SPACE_SIDES

[lbAvailableTechnos]
$X=getX(tbSearchTechno)
$Y=getBottom(tbSearchTechno) + EMPTY_SPACE_TOP
$Width=getWidth(tbSearchTechno)
$Height=getHeight(AITargetTypesWindow) - getY(lbAvailableTechnos) - EMPTY_SPACE_BOTTOM

[lbTechnoEntries]
$X=getX(btnAddTechno)
$Y=getBottom(btnDeleteTechno) + VERTICAL_SPACING
$Width=getWidth(btnAddTechno)
$Height=getHeight(AITargetTypesWindow) - getY(lbTechnoEntries) - EMPTY_SPACE_BOTTOM
3 changes: 3 additions & 0 deletions src/TSMapEditor/TSMapEditor.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,9 @@
<None Update="Config\Default\UI\Windows\AITriggersWindow.ini">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Config\Default\UI\Windows\AITargetTypesWindow.ini">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Config\Default\UI\Windows\ApplyINICodeWindow.ini">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
Expand Down
2 changes: 2 additions & 0 deletions src/TSMapEditor/UI/TopBar/TopBarMenu.cs
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,8 @@ public override void Initialize()
scriptingContextMenu.AddItem(Translate(this, "Scripting.TeamTypes", "TeamTypes"), () => windowController.TeamTypesWindow.Open(), null, null, null);
scriptingContextMenu.AddItem(Translate(this, "Scripting.LocalVariables", "Local Variables"), () => windowController.LocalVariablesWindow.Open(), null, null, null);
scriptingContextMenu.AddItem(Translate(this, "Scripting.AITriggers", "AITriggers"), () => windowController.AITriggersWindow.Open(), null, null, null, null);
if (Constants.IsRA2YR)
scriptingContextMenu.AddItem(Translate(this, "Scripting.AITargetTypes", "AITargetTypes"), () => windowController.AITargetTypesWindow.Open(), null, null, null);

var scriptingButton = new MenuButton(WindowManager, scriptingContextMenu);
scriptingButton.Name = nameof(scriptingButton);
Expand Down
271 changes: 271 additions & 0 deletions src/TSMapEditor/UI/Windows/AITargetTypesWindow.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,271 @@
using Rampastring.XNAUI;
using Rampastring.XNAUI.XNAControls;
using System;
using System.Collections.Generic;
using System.Linq;
using TSMapEditor.Models;
using TSMapEditor.UI;
using TSMapEditor.UI.Controls;

namespace TSMapEditor.UI.Windows
{
public class AITargetTypesWindow : INItializableWindow
{
public AITargetTypesWindow(WindowManager windowManager, Map map) : base(windowManager)
{
this.map = map;
}

private readonly Map map;

private EditorListBox lbAITargetTypes;
private EditorListBox lbTechnoEntries;
private EditorListBox lbAvailableTechnos;
private EditorSuggestionTextBox tbSearchTechno;

private readonly List<GameObjectType> allAvailableTechnos = new List<GameObjectType>();
private int editedIndex = -1;

public override void Initialize()
{
Name = nameof(AITargetTypesWindow);
base.Initialize();

lbAITargetTypes = FindChild<EditorListBox>(nameof(lbAITargetTypes));
lbTechnoEntries = FindChild<EditorListBox>(nameof(lbTechnoEntries));
lbAvailableTechnos = FindChild<EditorListBox>(nameof(lbAvailableTechnos));
tbSearchTechno = FindChild<EditorSuggestionTextBox>(nameof(tbSearchTechno));

UIHelpers.AddSearchTipsBoxToControl(tbSearchTechno);

FindChild<EditorButton>("btnNewAITargetType").LeftClick += BtnNewAITargetType_LeftClick;
FindChild<EditorButton>("btnDeleteAITargetType").LeftClick += BtnDeleteAITargetType_LeftClick;
FindChild<EditorButton>("btnCloneAITargetType").LeftClick += BtnCloneAITargetType_LeftClick;
FindChild<EditorButton>("btnAddTechno").LeftClick += BtnAddTechno_LeftClick;
FindChild<EditorButton>("btnDeleteTechno").LeftClick += BtnDeleteTechno_LeftClick;

lbAITargetTypes.SelectedIndexChanged += LbAITargetTypes_SelectedIndexChanged;
lbTechnoEntries.SelectedIndexChanged += (s, e) => { }; // used for delete button only

tbSearchTechno.TextChanged += (s, e) => ApplyTechnoFilter();

ListAvailableTechnos();
ListAITargetTypes();
}

public void Open()
{
ListAvailableTechnos();
ListAITargetTypes();
Show();
}

private void ListAITargetTypes()
{
lbAITargetTypes.Clear();

var section = map.LoadedINI.GetSection("AITargetTypes");
if (section == null)
return;

for (int i = 0; ; i++)
{
string value = section.GetStringValue(i.ToString(), string.Empty);
if (string.IsNullOrEmpty(value))
break;

lbAITargetTypes.AddItem(new XNAListBoxItem { Text = $"{i}: {value}", Tag = i });
}
}

private void LbAITargetTypes_SelectedIndexChanged(object sender, EventArgs e)
{
if (lbAITargetTypes.SelectedItem == null)
{
editedIndex = -1;
lbTechnoEntries.Clear();
return;
}

editedIndex = (int)lbAITargetTypes.SelectedItem.Tag;

var section = map.LoadedINI.GetSection("AITargetTypes");
string value = section?.GetStringValue(editedIndex.ToString(), string.Empty) ?? string.Empty;
PopulateTechnoEntries(value);
}

private void PopulateTechnoEntries(string value)
{
lbTechnoEntries.Clear();
if (string.IsNullOrWhiteSpace(value))
return;

var tokens = value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var token in tokens)
{
var trimmed = token.Trim();
var match = allAvailableTechnos.FirstOrDefault(t => string.Equals(t.ININame, trimmed, StringComparison.CurrentCultureIgnoreCase));
lbTechnoEntries.AddItem(new XNAListBoxItem { Text = trimmed, Tag = (object)match ?? trimmed });
}
}

private void ListAvailableTechnos()
{
allAvailableTechnos.Clear();
allAvailableTechnos.AddRange(map.Rules.UnitTypes);
allAvailableTechnos.AddRange(map.Rules.InfantryTypes);
allAvailableTechnos.AddRange(map.Rules.BuildingTypes);
allAvailableTechnos.AddRange(map.Rules.AircraftTypes);
allAvailableTechnos.Sort((a, b) => string.Compare(a.ININame, b.ININame, StringComparison.OrdinalIgnoreCase));

ApplyTechnoFilter();
}

private void ApplyTechnoFilter()
{
if (lbAvailableTechnos == null)
return;

lbAvailableTechnos.Clear();

string filter = tbSearchTechno?.Text?.Trim() ?? string.Empty;
bool showAll = string.IsNullOrWhiteSpace(filter) || filter.Equals(tbSearchTechno.Suggestion, StringComparison.CurrentCultureIgnoreCase);

foreach (var techno in allAvailableTechnos)
{
if (!showAll && !techno.ININame.Contains(filter, StringComparison.CurrentCultureIgnoreCase) && !techno.GetEditorDisplayName().Contains(filter, StringComparison.CurrentCultureIgnoreCase))
continue;

lbAvailableTechnos.AddItem(new XNAListBoxItem { Text = $"{techno.ININame} ({techno.GetEditorDisplayName()})", Tag = techno });
}
}

private void BtnNewAITargetType_LeftClick(object sender, EventArgs e)
{
var section = map.LoadedINI.GetSection("AITargetTypes");
if (section == null)
{
map.LoadedINI.AddSection("AITargetTypes");
section = map.LoadedINI.GetSection("AITargetTypes");
}

int newIndex = 0;
while (!string.IsNullOrEmpty(section.GetStringValue(newIndex.ToString(), string.Empty)))
newIndex++;

section.SetStringValue(newIndex.ToString(), "E1");
ListAITargetTypes();
lbAITargetTypes.SelectedIndex = lbAITargetTypes.Items.Count - 1;
}

private void BtnDeleteAITargetType_LeftClick(object sender, EventArgs e)
{
if (editedIndex == -1)
return;

var section = map.LoadedINI.GetSection("AITargetTypes");
if (section == null)
return;

int current = editedIndex;
while (true)
{
string nextValue = section.GetStringValue((current + 1).ToString(), string.Empty);
if (string.IsNullOrEmpty(nextValue))
{
section.RemoveKey(current.ToString());
break;
}

section.SetStringValue(current.ToString(), nextValue);
current++;
}

ListAITargetTypes();
if (lbAITargetTypes.Items.Count == 0)
editedIndex = -1;
else
lbAITargetTypes.SelectedIndex = Math.Min(current, lbAITargetTypes.Items.Count - 1);
}

private void BtnCloneAITargetType_LeftClick(object sender, EventArgs e)
{
if (editedIndex == -1)
return;

var section = map.LoadedINI.GetSection("AITargetTypes");
if (section == null)
{
map.LoadedINI.AddSection("AITargetTypes");
section = map.LoadedINI.GetSection("AITargetTypes");
}

string value = section.GetStringValue(editedIndex.ToString(), string.Empty);
int newIndex = 0;
while (!string.IsNullOrEmpty(section.GetStringValue(newIndex.ToString(), string.Empty)))
newIndex++;

section.SetStringValue(newIndex.ToString(), value);
ListAITargetTypes();
editedIndex = newIndex;
SelectCurrentEntry();
}

private void BtnAddTechno_LeftClick(object sender, EventArgs e)
{
if (editedIndex == -1 || lbAvailableTechnos.SelectedItem == null)
return;

var techno = (GameObjectType)lbAvailableTechnos.SelectedItem.Tag;
lbTechnoEntries.AddItem(new XNAListBoxItem { Text = techno.ININame, Tag = techno });
CommitTechnoEntries();
}

private void BtnDeleteTechno_LeftClick(object sender, EventArgs e)
{
if (editedIndex == -1 || lbTechnoEntries.SelectedItem == null)
return;

int selected = lbTechnoEntries.SelectedIndex;
var remaining = lbTechnoEntries.Items.Where((item, index) => index != selected).Select(item => item.Text).ToList();

lbTechnoEntries.Clear();
foreach (var entry in remaining)
lbTechnoEntries.AddItem(new XNAListBoxItem { Text = entry, Tag = entry });

CommitTechnoEntries();
lbTechnoEntries.SelectedIndex = Math.Max(0, selected - 1);
}

private void CommitTechnoEntries()
{
if (editedIndex == -1)
return;

string combined = string.Join(",", lbTechnoEntries.Items.Select(item => item.Text).Where(text => !string.IsNullOrWhiteSpace(text)));

var section = map.LoadedINI.GetSection("AITargetTypes");
if (section == null)
{
map.LoadedINI.AddSection("AITargetTypes");
section = map.LoadedINI.GetSection("AITargetTypes");
}

section.SetStringValue(editedIndex.ToString(), combined);
ListAITargetTypes();
SelectCurrentEntry();
}

private void SelectCurrentEntry()
{
for (int i = 0; i < lbAITargetTypes.Items.Count; i++)
{
if ((int)lbAITargetTypes.Items[i].Tag == editedIndex)
{
lbAITargetTypes.SelectedIndex = i;
return;
}
}
}
}
}
4 changes: 4 additions & 0 deletions src/TSMapEditor/UI/Windows/WindowController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public class WindowController
public TeamTypesWindow TeamTypesWindow { get; private set; }
public TriggersWindow TriggersWindow { get; private set; }
public AITriggersWindow AITriggersWindow { get; private set; }
public AITargetTypesWindow AITargetTypesWindow { get; private set; }
public PlaceWaypointWindow PlaceWaypointWindow { get; private set; }
public LocalVariablesWindow LocalVariablesWindow { get; private set; }
public StructureOptionsWindow StructureOptionsWindow { get; private set; }
Expand Down Expand Up @@ -125,6 +126,9 @@ public void Initialize(IWindowParentControl windowParentControl, Map map, Editor
AITriggersWindow = new AITriggersWindow(windowParentControl.WindowManager, map);
Windows.Add(AITriggersWindow);

AITargetTypesWindow = new AITargetTypesWindow(windowParentControl.WindowManager, map);
Windows.Add(AITargetTypesWindow);

PlaceWaypointWindow = new PlaceWaypointWindow(windowParentControl.WindowManager, map, cursorActionTarget.MutationManager, cursorActionTarget.MutationTarget);
Windows.Add(PlaceWaypointWindow);

Expand Down
Loading