Rewrite Gamesetup AIConfig page to use class syntax, decouple settings and move it to the Gamesetup subfolder context, refs #5322, #5387.

This establishes a code architecture where only one class and only one
page is responsible per AI setting,
removes the hardcodings from the XML and JS file,
allowing future patches and mods to insert, remove and edit independent
AI settings without having to overwrite the existing code.

Differential Revision: https://code.wildfiregames.com/D2577
See also 0550315161/D2581 and comments linked there.

This was SVN commit r23419.
This commit is contained in:
elexis 2020-01-20 09:29:43 +00:00
parent d33f1c7321
commit 5ca68a38ef
36 changed files with 569 additions and 413 deletions

View File

@ -1,82 +0,0 @@
/**
* Is this user in control of game settings (i.e. is a network server, or offline player).
*/
const g_IsController = !Engine.HasNetClient() || Engine.HasNetServer();
var g_PlayerSlot;
var g_AIDescriptions = [{
"id": "",
"data": {
"name": translateWithContext("ai", "None"),
"description": translate("AI will be disabled for this player.")
}
}].concat(g_Settings.AIDescriptions);
var g_AIControls = {
"aiSelection": {
"labels": g_AIDescriptions.map(ai => ai.data.name),
"selected": settings => g_AIDescriptions.findIndex(ai => ai.id == settings.id)
},
"aiDifficulty": {
"labels": prepareForDropdown(g_Settings.AIDifficulties).Title,
"selected": settings => settings.difficulty
},
"aiBehavior": {
"labels": prepareForDropdown(g_Settings.AIBehaviors).Title,
"selected": settings => g_Settings.AIBehaviors.findIndex(b => b.Name == settings.behavior)
}
};
function init(settings)
{
// Remember the player ID that we change the AI settings for
g_PlayerSlot = settings.playerSlot;
let enabled = g_IsController && !settings.fixed;
for (let name in g_AIControls)
{
let control = Engine.GetGUIObjectByName(name);
control.list = g_AIControls[name].labels;
control.selected = g_AIControls[name].selected(settings);
control.hidden = !enabled;
let label = Engine.GetGUIObjectByName(name + "Text");
label.caption = control.list[control.selected];
label.hidden = enabled;
}
checkBehavior();
}
function selectAI(idx)
{
Engine.GetGUIObjectByName("aiDescription").caption = g_AIDescriptions[idx].data.description;
}
/** Behavior choice does not apply for Sandbox level */
function checkBehavior()
{
if (g_Settings.AIDifficulties[Engine.GetGUIObjectByName("aiDifficulty").selected].Name != "sandbox")
{
Engine.GetGUIObjectByName("aiBehavior").enabled = true;
return;
}
let aiBehavior = Engine.GetGUIObjectByName("aiBehavior");
aiBehavior.enabled = false;
aiBehavior.selected = g_Settings.AIBehaviors.findIndex(b => b.Name == "balanced");
}
function returnAI(save = true)
{
let idx = Engine.GetGUIObjectByName("aiSelection").selected;
Engine.PopGuiPage({
"save": save,
"id": g_AIDescriptions[idx].id,
"name": g_AIDescriptions[idx].data.name,
"difficulty": Engine.GetGUIObjectByName("aiDifficulty").selected,
"behavior": g_Settings.AIBehaviors[Engine.GetGUIObjectByName("aiBehavior").selected].Name,
"playerSlot": g_PlayerSlot
});
}

View File

@ -1,56 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<objects>
<script directory="gui/common/"/>
<script directory="gui/aiconfig/"/>
<!-- Add a translucent black background to fade out the menu page -->
<object type="image" sprite="ModernFade"/>
<object type="image" style="ModernDialog" size="50%-290 50%-200 50%+290 50%+200">
<object style="ModernLabelText" type="text" size="50%-128 -18 50%+128 14">
<translatableAttribute id="caption">AI Configuration</translatableAttribute>
</object>
<object size="50%-200 30 50%+200 100">
<object type="text" style="ModernRightLabelText" size="50%-290 0 50%-6 50%">
<translatableAttribute id="caption">AI Player:</translatableAttribute>
</object>
<object name="aiSelection" type="dropdown" style="ModernDropDown" size="50%+6 0 50%+190 28">
<action on="SelectionChange">selectAI(this.selected);</action>
</object>
<object name="aiSelectionText" type="text" style="ModernLeftLabelText" size="50%+6 0 50%+190 28"/>
<object type="text" style="ModernRightLabelText" size="50%-290 35 50%-6 50%+35">
<translatableAttribute id="caption">AI Difficulty:</translatableAttribute>
</object>
<object name="aiDifficulty" type="dropdown" style="ModernDropDown" size="50%+6 35 50%+190 63">
<action on="SelectionChange">checkBehavior();</action>
</object>
<object name="aiDifficultyText" type="text" style="ModernLeftLabelText" size="50%+6 35 50%+190 63"/>
<object type="text" style="ModernRightLabelText" size="50%-290 70 50%-6 50%+70">
<translatableAttribute id="caption">AI Behavior:</translatableAttribute>
</object>
<object name="aiBehavior" type="dropdown" style="ModernDropDown" size="50%+6 70 50%+190 98"/>
<object name="aiBehaviorText" type="text" style="ModernLeftLabelText" size="50%+6 70 50%+190 98"/>
</object>
<object name="aiDescription" type="text" style="ModernLabelText" size="8% 110 92% 100%-30"/>
<object type="button" style="ModernButtonRed" size="18 100%-45 50%-5 100%-17" hotkey="cancel">
<translatableAttribute id="caption">Cancel</translatableAttribute>
<action on="Press">returnAI(false);</action>
</object>
<object type="button" style="ModernButtonRed" size="50%+5 100%-45 100%-18 100%-17">
<translatableAttribute id="caption">OK</translatableAttribute>
<action on="Press">returnAI(true);</action>
</object>
</object>
</objects>

View File

@ -0,0 +1,69 @@
/**
* This class contains all controls modifying the AI settings of a player.
*/
class AIGameSettingControls
{
}
SetupWindowPages.AIConfigPage = class
{
constructor(setupWindow)
{
this.gameSettingsControl = setupWindow.controls.gameSettingsControl;
this.playerIndex = undefined;
this.row = 0;
this.openPageHandlers = new Set();
this.AIGameSettingControls = {};
for (let name of this.AIGameSettingControlOrder)
this.AIGameSettingControls[name] =
new AIGameSettingControls[name](this, undefined, undefined, setupWindow);
this.aiDescription = new AIDescription(this, setupWindow);
this.aiConfigPage = Engine.GetGUIObjectByName("aiConfigPage");
Engine.GetGUIObjectByName("aiConfigOkButton").onPress = this.closePage.bind(this);
this.gameSettingsControl.registerGameAttributesBatchChangeHandler(
this.onGameAttributesBatchChange.bind(this));
}
registerOpenPageHandler(handler)
{
this.openPageHandlers.add(handler);
}
getRow()
{
return this.row++;
}
openPage(playerIndex)
{
this.playerIndex = playerIndex;
for (let handler of this.openPageHandlers)
handler(playerIndex);
this.aiConfigPage.hidden = false;
}
onGameAttributesBatchChange()
{
let pData = this.gameSettingsControl.getPlayerData(g_GameAttributes, this.playerIndex);
if (!pData)
this.closePage();
}
closePage()
{
this.aiConfigPage.hidden = true;
}
}
SetupWindowPages.AIConfigPage.prototype.AIGameSettingControlOrder = [
"AISelection",
"AIDifficulty",
"AIBehavior"
];

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<object name="aiConfigPage" hidden="true" z="200">
<object type="image" sprite="ModernFade"/>
<object type="image" style="ModernDialog" size="50%-290 50%-200 50%+290 50%+200">
<object style="ModernLabelText" type="text" size="50%-128 -18 50%+128 14">
<translatableAttribute id="caption">AI Configuration</translatableAttribute>
</object>
<object size="50%-200 30 50%+200 100">
<repeat count="10" var="n">
<object name="aiSettingFrame[n]" size="50% 0 50% 28" hidden="true">
<object type="text" style="ModernRightLabelText" size="-290 0 -6 100%"/>
<object type="dropdown" style="ModernDropDown" size="6 0 190 100%"/>
<object type="text" style="ModernLeftLabelText" size="6 0 190 100%"/>
</object>
</repeat>
</object>
<object name="aiDescription" type="text" style="ModernLabelText" size="8% 110 92% 100%-30"/>
<object name="aiConfigOkButton" type="button" style="ModernButtonRed" size="100%-220 100%-45 100%-20 100%-17" hotkey="cancel">
<translatableAttribute id="caption">OK</translatableAttribute>
</object>
</object>
</object>

View File

@ -0,0 +1,37 @@
class AIDescription
{
constructor(aiConfigPage, setupWindow)
{
this.playerIndex = undefined;
this.aiDescription = Engine.GetGUIObjectByName("aiDescription");
this.gameSettingsControl = setupWindow.controls.gameSettingsControl;
this.gameSettingsControl.registerGameAttributesBatchChangeHandler(this.onGameAttributesBatchChange.bind(this));
aiConfigPage.registerOpenPageHandler(this.onOpenPage.bind(this));
}
onOpenPage(playerIndex)
{
this.playerIndex = playerIndex;
this.updateSelectedValue();
}
onGameAttributesBatchChange()
{
this.updateSelectedValue();
}
updateSelectedValue()
{
let pData = this.gameSettingsControl.getPlayerData(g_GameAttributes, this.playerIndex);
if (!pData)
return;
let AI = g_Settings.AIDescriptions.find(AI => AI.id == pData.AI);
this.aiDescription.caption = AI ? AI.data.description : this.NoAIDescription;
}
}
AIDescription.prototype.NoAIDescription =
translate("AI will be disabled for this player.");

View File

@ -0,0 +1,50 @@
class AIGameSettingControlDropdown extends GameSettingControlDropdown
{
constructor(...args)
{
super(...args);
this.gameSettingsControl.registerAssignPlayerHandler(this.onAssignPlayer.bind(this));
}
setControl(aiConfigPage)
{
aiConfigPage.registerOpenPageHandler(this.onOpenPage.bind(this));
let i = aiConfigPage.getRow();
this.frame = Engine.GetGUIObjectByName("aiSettingFrame[" + i + "]");
this.title = this.frame.children[0];
this.dropdown = this.frame.children[1];
this.label = this.frame.children[2];
let size = this.frame.size;
size.top = i * (this.Height + this.Margin);
size.bottom = size.top + this.Height;
this.frame.size = size;
this.setHidden(false);
}
onOpenPage(playerIndex)
{
this.playerIndex = playerIndex;
this.updateSelectedValue();
this.updateVisibility();
}
onGameAttributesChange()
{
for (let playerIndex = 0; playerIndex < g_MaxPlayers; ++playerIndex)
this.onGameAttributesChangePlayer(playerIndex);
}
onGameAttributesBatchChange()
{
this.updateSelectedValue();
}
}
AIGameSettingControlDropdown.prototype.Height= 28;
AIGameSettingControlDropdown.prototype.Margin= 7;

View File

@ -0,0 +1,93 @@
AIGameSettingControls.AIBehavior = class extends AIGameSettingControlDropdown
{
constructor(...args)
{
super(...args);
this.fixedAIBehavior = [];
this.defaultBehavior = Engine.ConfigDB_GetValue("user", this.ConfigBehavior);
this.dropdown.list = g_Settings.AIBehaviors.map(AIBehavior => AIBehavior.Title);
this.dropdown.list_data = g_Settings.AIBehaviors.map(AIBehavior => AIBehavior.Name);
}
onAssignPlayer(source, target)
{
if (source && target.AIBehavior)
source.AIBehavior = target.AIBehavior;
delete target.AIBehavior;
}
onMapChange(mapData)
{
for (let playerIndex = 0; playerIndex < g_MaxPlayers; ++playerIndex)
{
let mapPData = this.gameSettingsControl.getPlayerData(mapData, playerIndex);
this.fixedAIBehavior[playerIndex] =
mapPData && mapPData.AI ?
(mapPData.AIBehavior !== undefined ?
mapPData.AIBehavior :
g_Settings.PlayerDefaults[this.playerIndex + 1].AIBehavior) :
undefined;
}
}
onGameAttributesChangePlayer(playerIndex)
{
let pData = this.gameSettingsControl.getPlayerData(g_GameAttributes, playerIndex);
if (!pData)
return;
if (pData.AI)
{
if (this.fixedAIBehavior[playerIndex] && pData.AIBehavior !== this.fixedAIBehavior[playerIndex])
{
pData.AIBehavior = this.fixedAIBehavior[playerIndex];
this.gameSettingsControl.updateGameAttributes();
}
else if (pData.AIDiff !== undefined &&
g_Settings.AIDifficulties[pData.AIDiff].Name == "sandbox" &&
pData.AIBehavior != "balanced")
{
pData.AIBehavior = "balanced";
this.gameSettingsControl.updateGameAttributes();
}
else if (pData.AIBehavior === undefined)
{
pData.AIBehavior = this.defaultBehavior;
this.gameSettingsControl.updateGameAttributes();
}
}
else if (pData.AIBehavior !== undefined)
{
delete pData.AIBehavior;
this.gameSettingsControl.updateGameAttributes();
}
}
updateSelectedValue()
{
let pData = this.gameSettingsControl.getPlayerData(g_GameAttributes, this.playerIndex);
this.setHidden(!pData || !pData.AI || g_Settings.AIDifficulties[pData.AIDiff].Name == "sandbox");
if (pData && pData.AI && pData.AIDiff !== undefined && pData.AIBehavior !== undefined)
this.setSelectedValue(pData.AIBehavior);
}
onSelectionChange(itemIdx)
{
let pData = this.gameSettingsControl.getPlayerData(g_GameAttributes, this.playerIndex);
if (!g_IsController || !pData)
return;
pData.AIBehavior = g_Settings.AIBehaviors[itemIdx].Name;
this.gameSettingsControl.updateGameAttributes();
this.gameSettingsControl.setNetworkGameAttributes();
}
}
AIGameSettingControls.AIBehavior.prototype.ConfigBehavior =
"gui.gamesetup.aibehavior";
AIGameSettingControls.AIBehavior.prototype.TitleCaption =
translate("AI Behavior");

View File

@ -0,0 +1,87 @@
AIGameSettingControls.AIDifficulty = class extends AIGameSettingControlDropdown
{
constructor(...args)
{
super(...args);
this.fixedAIDiff = [];
this.defaultAIDiff = +Engine.ConfigDB_GetValue("user", this.ConfigDifficulty);
this.dropdown.list = g_Settings.AIDifficulties.map(AI => AI.Title);
this.dropdown.list_data = g_Settings.AIDifficulties.map((AI, i) => i);
}
onAssignPlayer(source, target)
{
if (source && target.AIDiff !== undefined)
source.AIDiff = target.AIDiff;
delete target.AIDiff;
}
onMapChange(mapData)
{
for (let playerIndex = 0; playerIndex < g_MaxPlayers; ++playerIndex)
{
let mapPData = this.gameSettingsControl.getPlayerData(mapData, playerIndex);
this.fixedAIDiff[playerIndex] =
mapPData && mapPData.AI ?
(mapPData.AIDiff !== undefined ?
mapPData.AIDiff :
g_Settings.PlayerDefaults[this.playerIndex + 1].AIDiff) :
undefined;
}
}
onGameAttributesChangePlayer(playerIndex)
{
let pData = this.gameSettingsControl.getPlayerData(g_GameAttributes, playerIndex);
if (!pData)
return;
if (pData.AI)
{
if (this.fixedAIDiff[playerIndex] !== undefined && pData.AIDiff !== this.fixedAIDiff[playerIndex])
{
pData.AIDiff = this.fixedAIDiff[playerIndex];
this.gameSettingsControl.updateGameAttributes();
}
else if (pData.AIDiff === undefined)
{
pData.AIDiff = this.defaultAIDiff;
this.gameSettingsControl.updateGameAttributes();
}
}
else if (pData.AIDiff !== undefined)
{
delete pData.AIDiff;
this.gameSettingsControl.updateGameAttributes();
}
}
updateSelectedValue()
{
let pData = this.gameSettingsControl.getPlayerData(g_GameAttributes, this.playerIndex);
this.setHidden(!pData || !pData.AI);
if (pData && pData.AIDiff !== undefined)
this.setSelectedValue(pData.AIDiff);
}
onSelectionChange(itemIdx)
{
let pData = this.gameSettingsControl.getPlayerData(g_GameAttributes, this.playerIndex);
if (!g_IsController || !pData)
return;
pData.AIDiff = itemIdx;
this.gameSettingsControl.updateGameAttributes();
this.gameSettingsControl.setNetworkGameAttributes();
}
};
AIGameSettingControls.AIDifficulty.prototype.ConfigDifficulty =
"gui.gamesetup.aidifficulty";
AIGameSettingControls.AIDifficulty.prototype.TitleCaption =
translate("AI Difficulty");

View File

@ -0,0 +1,91 @@
AIGameSettingControls.AISelection = class extends AIGameSettingControlDropdown
{
constructor(...args)
{
super(...args);
this.fixedAI = [];
this.values = prepareForDropdown([
this.NoAI,
...g_Settings.AIDescriptions.map(AI => ({
"Title": AI.data.name,
"Id": AI.id
}))
]);
this.dropdown.list = this.values.Title;
this.dropdown.list_data = this.values.Id.map((v, i) => i);
}
onAssignPlayer(source, target)
{
if (source && target.AI)
source.AI = target.AI;
target.AI = false;
}
onMapChange(mapData)
{
for (let playerIndex = 0; playerIndex < g_MaxPlayers; ++playerIndex)
{
let mapPData = this.gameSettingsControl.getPlayerData(mapData, playerIndex);
this.fixedAI[playerIndex] = mapPData && mapPData.AI || undefined;
}
}
onGameAttributesChangePlayer(playerIndex)
{
let pData = this.gameSettingsControl.getPlayerData(g_GameAttributes, playerIndex);
if (!pData)
return;
if (this.fixedAI[playerIndex] && pData.AI !== this.fixedAI[playerIndex])
{
pData.AI = this.fixedAI[playerIndex];
this.gameSettingsControl.updateGameAttributes();
}
else if (pData.AI === undefined)
{
let assignedGUID;
for (let guid in g_PlayerAssignments)
if (g_PlayerAssignments[guid].player == playerIndex + 1)
{
assignedGUID = guid;
break;
}
pData.AI = assignedGUID ? false : g_Settings.PlayerDefaults[playerIndex + 1].AI;
this.gameSettingsControl.updateGameAttributes();
}
}
updateSelectedValue()
{
let pData = this.gameSettingsControl.getPlayerData(g_GameAttributes, this.playerIndex);
if (!pData || pData.AI === undefined)
return;
this.setSelectedValue(this.values.Id.indexOf(pData.AI));
}
onSelectionChange(itemIdx)
{
let pData = this.gameSettingsControl.getPlayerData(g_GameAttributes, this.playerIndex);
if (!pData)
return;
pData.AI = this.values.Id[itemIdx];
this.gameSettingsControl.updateGameAttributes();
this.gameSettingsControl.setNetworkGameAttributes();
}
}
AIGameSettingControls.AISelection.prototype.NoAI = {
"Title": translateWithContext("ai", "None"),
"Id": false
};
AIGameSettingControls.AISelection.prototype.TitleCaption =
translate("AI Player");

View File

@ -25,19 +25,19 @@ class GameSettingControl
{
// The constructor and inherited constructors shall not modify game attributes,
// since all GameSettingControl shall be able to subscribe to any gamesetting change.
constructor(gameSettingControlManager, category, playerIndex, setupWindow, gameSettingsControl, mapCache, mapFilters, netMessages, playerAssignmentsControl)
constructor(gameSettingControlManager, category, playerIndex, setupWindow)
{
// Store arguments
{
this.category = category;
if (playerIndex !== undefined)
this.playerIndex = playerIndex;
this.playerIndex = playerIndex;
this.setupWindow = setupWindow;
this.gameSettingsControl = gameSettingsControl;
this.mapCache = mapCache;
this.mapFilters = mapFilters;
this.netMessages = netMessages;
this.playerAssignmentsControl = playerAssignmentsControl;
this.gameSettingsControl = setupWindow.controls.gameSettingsControl;
this.mapCache = setupWindow.controls.mapCache;
this.mapFilters = setupWindow.controls.mapFilters;
this.netMessages = setupWindow.controls.netMessages;
this.playerAssignmentsControl = setupWindow.controls.playerAssignmentsControl;
}
// enabled and hidden should only be modified through their setters or
@ -60,28 +60,28 @@ class GameSettingControl
this.setHidden(false);
if (this.onMapChange)
gameSettingsControl.registerMapChangeHandler(this.onMapChange.bind(this));
this.gameSettingsControl.registerMapChangeHandler(this.onMapChange.bind(this));
if (this.onLoad)
setupWindow.registerLoadHandler(this.onLoad.bind(this));
this.setupWindow.registerLoadHandler(this.onLoad.bind(this));
if (this.onGameAttributesChange)
gameSettingsControl.registerGameAttributesChangeHandler(this.onGameAttributesChange.bind(this));
this.gameSettingsControl.registerGameAttributesChangeHandler(this.onGameAttributesChange.bind(this));
if (this.onGameAttributesBatchChange)
gameSettingsControl.registerGameAttributesBatchChangeHandler(this.onGameAttributesBatchChange.bind(this));
this.gameSettingsControl.registerGameAttributesBatchChangeHandler(this.onGameAttributesBatchChange.bind(this));
if (this.onAssignPlayer && this.playerIndex === 0)
this.gameSettingsControl.registerAssignPlayerHandler(this.onAssignPlayer.bind(this));
if (this.onPickRandomItems)
gameSettingsControl.registerPickRandomItemsHandler(this.onPickRandomItems.bind(this));
this.gameSettingsControl.registerPickRandomItemsHandler(this.onPickRandomItems.bind(this));
if (this.onGameAttributesFinalize)
gameSettingsControl.registerGameAttributesFinalizeHandler(this.onGameAttributesFinalize.bind(this));
this.gameSettingsControl.registerGameAttributesFinalizeHandler(this.onGameAttributesFinalize.bind(this));
if (this.onPlayerAssignmentsChange)
playerAssignmentsControl.registerPlayerAssignmentsChangeHandler(this.onPlayerAssignmentsChange.bind(this));
this.playerAssignmentsControl.registerPlayerAssignmentsChangeHandler(this.onPlayerAssignmentsChange.bind(this));
}
setTitle(titleCaption)

View File

@ -11,30 +11,30 @@ class GameSettingControls
*/
class GameSettingControlManager
{
constructor(setupWindow, gameSettingsControl, mapCache, mapFilters, netMessages, playerAssignmentsControl)
constructor(setupWindow)
{
this.setupWindow = setupWindow;
this.rows = {};
this.gameSettingControls = {};
let args = Array.from(arguments);
let getCategory = name =>
g_GameSettingsLayout.findIndex(category => category.settings.indexOf(name) != -1);
for (let name in GameSettingControls)
this.gameSettingControls[name] =
new GameSettingControls[name](
this, getCategory(name), undefined, ...args);
this, getCategory(name), undefined, setupWindow);
for (let victoryCondition of g_VictoryConditions)
this.gameSettingControls[victoryCondition.Name] =
new VictoryConditionCheckbox(
victoryCondition, this, getCategory(victoryCondition.Name), undefined, ...args);
victoryCondition, this, getCategory(victoryCondition.Name), undefined, setupWindow);
this.playerSettingControlManagers = Array.from(
new Array(g_MaxPlayers),
(value, playerIndex) =>
new PlayerSettingControlManager(playerIndex, ...args));
new PlayerSettingControlManager(playerIndex, setupWindow));
}
getNextRow(name)

View File

@ -4,185 +4,29 @@ PlayerSettingControls.AIConfigButton = class extends GameSettingControl
{
super(...args);
this.playerConfig = Engine.GetGUIObjectByName("playerConfig[" + this.playerIndex + "]");
this.isPageOpen = false;
this.guid = undefined;
this.fixedAI = undefined;
this.defaultAIDiff = +Engine.ConfigDB_GetValue("user", this.ConfigDifficulty);
this.defaultBehavior = Engine.ConfigDB_GetValue("user", this.ConfigBehavior);
this.aiConfigButton = Engine.GetGUIObjectByName("aiConfigButton[" + this.playerIndex + "]");
// Save little performance by not reallocating every call
this.sprintfArgs = {};
this.playerConfig.onPress = this.openConfigPage.bind(this, this.playerIndex);
}
onMapChange(mapData)
onLoad()
{
let pData = this.gameSettingsControl.getPlayerData(g_GameAttributes, this.playerIndex);
if (!pData)
return;
let isScenario = g_GameAttributes.mapType == "scenario";
let mapPData = this.gameSettingsControl.getPlayerData(mapData, this.playerIndex);
if (mapPData && mapPData.AI)
{
let defaultPData = g_Settings.PlayerDefaults[this.playerIndex + 1];
this.fixedAI = {
"AI": mapPData.AI,
"AIDiff":
mapPData.AIDiff !== undefined ?
mapPData.AIDiff :
defaultPData.AIDiff,
"AIBehavior":
mapPData.AIBehavior !== undefined ?
mapPData.AIBehavior :
defaultPData.AIBehavior
};
}
else
this.fixedAI = undefined;
}
onAssignPlayer(source, target)
{
if (source && target.AI)
{
source.AI = target.AI;
source.AIDiff = target.AIDiff;
source.AIBehavior = target.AIBehavior;
}
target.AI = false;
delete target.AIDiff;
delete target.AIBehavior;
}
onPlayerAssignmentsChange()
{
this.guid = undefined;
for (let guid in g_PlayerAssignments)
if (g_PlayerAssignments[guid].player == this.playerIndex + 1)
this.guid = guid;
}
onGameAttributesChange()
{
let pData = this.gameSettingsControl.getPlayerData(g_GameAttributes, this.playerIndex);
if (!pData)
return;
// Enforce map specified AI
if (this.fixedAI &&
(pData.AI !== this.fixedAI.AI ||
pData.AIDiff !== this.fixedAI.AIDiff ||
pData.AIBehavior !== this.fixedAI.AIBehavior))
{
pData.AI = this.fixedAI.AI;
pData.AIDiff = this.fixedAI.AIDiff;
pData.AIBehavior = this.fixedAI.AIBehavior;
this.gameSettingsControl.updateGameAttributes();
}
// Sanitize, make AI state self-consistent
if (pData.AI)
{
if (pData.AIDiff === undefined || pData.AIBehavior === undefined)
{
if (pData.AIDiff === undefined)
pData.AIDiff = this.defaultAIDiff;
if (pData.AIBehavior === undefined)
pData.AIBehavior = this.defaultBehavior;
this.gameSettingsControl.updateGameAttributes();
}
}
else if (pData.AI === undefined)
{
if (this.guid)
pData.AI = false;
else
{
pData.AI = g_Settings.PlayerDefaults[this.playerIndex + 1].AI;
pData.AIDiff = this.defaultAIDiff;
pData.AIBehavior = this.defaultBehavior;
}
this.gameSettingsControl.updateGameAttributes();
}
else if (pData.AIBehavior !== undefined || pData.AIDiff !== undefined)
{
pData.AI = false;
delete pData.AIBehavior;
delete pData.AIDiff;
this.gameSettingsControl.updateGameAttributes();
}
let aiConfigPage = this.setupWindow.pages.AIConfigPage;
this.aiConfigButton.onPress = aiConfigPage.openPage.bind(aiConfigPage, this.playerIndex);
}
onGameAttributesBatchChange()
{
let isPageOpen = this.isPageOpen;
if (isPageOpen)
Engine.PopGuiPage();
let pData = this.gameSettingsControl.getPlayerData(g_GameAttributes, this.playerIndex);
if (!pData)
return;
this.sprintfArgs.description = translateAISettings(pData);
this.playerConfig.tooltip = sprintf(this.Tooltip, this.sprintfArgs);
this.playerConfig.hidden = !pData.AI;
if (isPageOpen)
this.openConfigPage();
}
openConfigPage()
{
let pData = this.gameSettingsControl.getPlayerData(g_GameAttributes, this.playerIndex);
if (!pData || !pData.AI)
return;
this.isPageOpen = true;
Engine.PushGuiPage(
"page_aiconfig.xml",
{
"playerSlot": this.playerIndex,
"id": pData.AI,
"difficulty": pData.AIDiff,
"behavior": pData.AIBehavior,
"fixed": !!this.fixedAI
},
this.onConfigPageClosed.bind(this));
}
onConfigPageClosed(data)
{
this.isPageOpen = false;
let pData = this.gameSettingsControl.getPlayerData(g_GameAttributes, this.playerIndex);
if (!data || !data.save || !g_IsController || !pData)
return;
pData.AI = data.id;
pData.AIDiff = data.difficulty;
pData.AIBehavior = data.behavior;
this.gameSettingsControl.updateGameAttributes();
this.gameSettingsControl.setNetworkGameAttributes();
this.aiConfigButton.tooltip = sprintf(this.Tooltip, this.sprintfArgs);
this.aiConfigButton.hidden = !pData.AI;
}
};
PlayerSettingControls.AIConfigButton.prototype.Tooltip =
translate("Configure AI: %(description)s.");
PlayerSettingControls.AIConfigButton.prototype.ConfigDifficulty =
"gui.gamesetup.aidifficulty";
PlayerSettingControls.AIConfigButton.prototype.ConfigBehavior =
"gui.gamesetup.aibehavior";

View File

@ -41,7 +41,7 @@
<object name="playerAssignment[n]" type="dropdown" style="ModernDropDown" size="22%+37 2 50%+35 30" tooltip_style="onscreenToolTip"/>
<object name="playerAssignmentText[n]" type="text" style="ModernLabelText" size="22%+37 0 50%+35 30"/>
<object name="playerConfig[n]" type="button" style="StoneButton" size="50%+40 4 50%+64 28" tooltip_style="onscreenToolTip" font="sans-bold-stroke-12" sprite="ModernGear" sprite_over="ModernGearHover" sprite_pressed="ModernGearPressed"/>
<object name="aiConfigButton[n]" type="button" style="StoneButton" size="50%+40 4 50%+64 28" tooltip_style="onscreenToolTip" font="sans-bold-stroke-12" sprite="ModernGear" sprite_over="ModernGearHover" sprite_pressed="ModernGearPressed"/>
<object name="playerCiv[n]" type="dropdown" style="ModernDropDown" size="50%+69 2 85% 30" tooltip_style="onscreenToolTip" dropdown_size="424"/>
<object name="playerCivText[n]" type="text" style="ModernLabelText" size="50%+65 0 85% 30"/>

View File

@ -11,14 +11,12 @@ class PlayerSettingControls
*/
class PlayerSettingControlManager
{
constructor(playerIndex, setupWindow, gameSettingsControl, mapCache, mapFilters, netMessages, playerAssignmentsControl)
constructor(...args)
{
this.playerSettingControls = {};
for (let name in PlayerSettingControls)
this.playerSettingControls[name] =
new PlayerSettingControls[name](
undefined, undefined, playerIndex, setupWindow, gameSettingsControl, mapCache, mapFilters, netMessages, playerAssignmentsControl);
this.playerSettingControls[name] = new PlayerSettingControls[name](undefined, undefined, ...args);
}
addAutocompleteEntries(autocomplete)

View File

@ -1,22 +1,21 @@
/**
* This class owns all handlers of the gamesetup page, excluding controllers that apply to all subpages and handlers for specific subpages.
*/
class GameSetupPage
SetupWindowPages.GameSetupPage = class
{
constructor(setupWindow, gameSettingsControl, playerAssignmentsControl, netMessages, gameRegisterStanza, mapCache, mapFilters, startGameControl, readyControl)
constructor(setupWindow)
{
Engine.ProfileStart("GameSetupPage");
// This class instance owns all gamesetting GUI controls such as dropdowns and checkboxes visible in this page.
this.gameSettingControlManager =
new GameSettingControlManager(setupWindow, gameSettingsControl, mapCache, mapFilters, netMessages, playerAssignmentsControl);
this.gameSettingControlManager = new GameSettingControlManager(setupWindow);
// These classes manage GUI buttons.
{
let startGameButton = new StartGameButton(setupWindow, startGameControl, netMessages, readyControl, playerAssignmentsControl);
let readyButton = new ReadyButton(readyControl, netMessages, playerAssignmentsControl);
let startGameButton = new StartGameButton(setupWindow);
let readyButton = new ReadyButton(setupWindow);
this.panelButtons = {
"cancelButton": new CancelButton(setupWindow, startGameButton, readyButton, gameRegisterStanza),
"cancelButton": new CancelButton(setupWindow, startGameButton, readyButton),
"civInfoButton": new CivInfoButton(),
"lobbyButton": new LobbyButton(),
"readyButton": readyButton,
@ -28,18 +27,18 @@ class GameSetupPage
{
let gameSettingTabs = new GameSettingTabs(setupWindow, this.panelButtons.lobbyButton);
let gameSettingsPanel = new GameSettingsPanel(
setupWindow, gameSettingTabs, gameSettingsControl, this.gameSettingControlManager);
setupWindow, gameSettingTabs, this.gameSettingControlManager);
this.panels = {
"chatPanel": new ChatPanel(this.gameSettingControlManager, gameSettingsControl, netMessages, playerAssignmentsControl, readyControl, gameSettingsPanel),
"gameSettingWarning": new GameSettingWarning(gameSettingsControl, this.panelButtons.cancelButton),
"gameDescription": new GameDescription(mapCache, gameSettingTabs, gameSettingsControl),
"chatPanel": new ChatPanel(setupWindow, this.gameSettingControlManager, gameSettingsPanel),
"gameSettingWarning": new GameSettingWarning(setupWindow, this.panelButtons.cancelButton),
"gameDescription": new GameDescription(setupWindow, gameSettingTabs),
"gameSettingsPanel": gameSettingsPanel,
"gameSettingsTabs": gameSettingTabs,
"mapPreview": new MapPreview(gameSettingsControl, mapCache),
"resetCivsButton": new ResetCivsButton(gameSettingsControl),
"resetTeamsButton": new ResetTeamsButton(gameSettingsControl),
"soundNotification": new SoundNotification(netMessages, playerAssignmentsControl),
"mapPreview": new MapPreview(setupWindow),
"resetCivsButton": new ResetCivsButton(setupWindow),
"resetTeamsButton": new ResetTeamsButton(setupWindow),
"soundNotification": new SoundNotification(setupWindow),
"tipsPanel": new TipsPanel(gameSettingsPanel),
"tooltip": new Tooltip(this.panelButtons.cancelButton)
};

View File

@ -1,11 +1,8 @@
class CancelButton
{
constructor(setupWindow, startGameButton, readyButton, gameSettingsControl)
constructor(setupWindow, startGameButton, readyButton)
{
this.setupWindow = setupWindow;
this.startGameButton = startGameButton;
this.readyButton = readyButton;
this.gameSettingsControl = gameSettingsControl;
this.cancelButtonResizeHandlers = new Set();

View File

@ -1,8 +1,8 @@
class ReadyButton
{
constructor(readyControl, netMessages, playerAssignmentsControl)
constructor(setupWindow)
{
this.readyControl = readyControl;
this.readyControl = setupWindow.controls.readyControl;
this.hidden = undefined;
@ -13,8 +13,8 @@ class ReadyButton
this.readyButton.onPress = this.onPress.bind(this);
this.readyButton.onPressRight = this.onPressRight.bind(this);
playerAssignmentsControl.registerPlayerAssignmentsChangeHandler(this.onPlayerAssignmentsChange.bind(this));
netMessages.registerNetMessageHandler("netstatus", this.onNetStatusMessage.bind(this));
setupWindow.controls.playerAssignmentsControl.registerPlayerAssignmentsChangeHandler(this.onPlayerAssignmentsChange.bind(this));
setupWindow.controls.netMessages.registerNetMessageHandler("netstatus", this.onNetStatusMessage.bind(this));
if (g_IsController && g_IsNetworked)
this.readyControl.setReady(this.readyControl.StayReady, true);

View File

@ -1,8 +1,8 @@
class ResetCivsButton
{
constructor(gameSettingsControl)
constructor(setupWindow)
{
this.gameSettingsControl = gameSettingsControl;
this.gameSettingsControl = setupWindow.controls.gameSettingsControl;
this.gameSettingsControl.registerGameAttributesBatchChangeHandler(this.onGameAttributesBatchChange.bind(this));
this.civResetButton = Engine.GetGUIObjectByName("civResetButton");

View File

@ -1,8 +1,8 @@
class ResetTeamsButton
{
constructor(gameSettingsControl)
constructor(setupWindow)
{
this.gameSettingsControl = gameSettingsControl;
this.gameSettingsControl = setupWindow.controls.gameSettingsControl;
this.gameSettingsControl.registerGameAttributesBatchChangeHandler(this.onGameAttributesBatchChange.bind(this));
this.teamResetButton = Engine.GetGUIObjectByName("teamResetButton");

View File

@ -1,9 +1,8 @@
class StartGameButton
{
constructor(setupWindow, startGameControl, netMessages, readyControl, playerAssignmentsControl)
constructor(setupWindow)
{
this.startGameControl = startGameControl;
this.readyControl = readyControl;
this.setupWindow = setupWindow;
this.gameStarted = false;
this.buttonHiddenChangeHandlers = new Set();
@ -13,7 +12,7 @@ class StartGameButton
this.startGameButton.onPress = this.onPress.bind(this);
setupWindow.registerLoadHandler(this.onLoad.bind(this));
playerAssignmentsControl.registerPlayerAssignmentsChangeHandler(this.update.bind(this));
setupWindow.controls.playerAssignmentsControl.registerPlayerAssignmentsChangeHandler(this.update.bind(this));
}
registerButtonHiddenChangeHandler(handler)
@ -45,7 +44,7 @@ class StartGameButton
for (let guid in g_PlayerAssignments)
if (g_PlayerAssignments[guid].player != -1 &&
g_PlayerAssignments[guid].status == this.readyControl.NotReady)
g_PlayerAssignments[guid].status == this.setupWindow.controls.readyControl.NotReady)
return false;
return true;
@ -58,7 +57,7 @@ class StartGameButton
this.gameStarted = true;
this.update();
this.startGameControl.launchGame();
this.setupWindow.controls.startGameControl.launchGame();
}
}

View File

@ -1,15 +1,16 @@
ChatMessageEvents.ClientChat = class
{
constructor(chatMessagesPanel, netMessages)
constructor(setupWindow, chatMessagesPanel)
{
this.chatMessagesPanel = chatMessagesPanel;
netMessages.registerNetMessageHandler("chat", this.onClientChat.bind(this));
this.usernameArgs = {};
this.messageArgs = {};
// TODO: Remove this global required by gui/common/
global.colorizePlayernameByGUID = this.colorizePlayernameByGUID.bind(this);
setupWindow.controls.netMessages.registerNetMessageHandler("chat", this.onClientChat.bind(this));
}
onClientChat(message)

View File

@ -1,11 +1,11 @@
ChatMessageEvents.ClientConnection = class
{
constructor(chatMessagesPanel, netMessages, gameSettingsControl, playerAssignmentsControl)
constructor(setupWindow, chatMessagesPanel)
{
this.chatMessagesPanel = chatMessagesPanel;
playerAssignmentsControl.registerClientJoinHandler(this.onClientJoin.bind(this));
playerAssignmentsControl.registerClientLeaveHandler(this.onClientLeave.bind(this));
setupWindow.controls.playerAssignmentsControl.registerClientJoinHandler(this.onClientJoin.bind(this));
setupWindow.controls.playerAssignmentsControl.registerClientLeaveHandler(this.onClientLeave.bind(this));
this.args = {};
}

View File

@ -1,12 +1,12 @@
ChatMessageEvents.ClientKicked = class
{
constructor(chatMessagesPanel, netMessages)
constructor(setupWindow, chatMessagesPanel)
{
this.chatMessagesPanel = chatMessagesPanel;
this.messageArgs = {};
netMessages.registerNetMessageHandler("kicked", this.onClientKicked.bind(this));
setupWindow.controls.netMessages.registerNetMessageHandler("kicked", this.onClientKicked.bind(this));
}
onClientKicked(message)

View File

@ -1,12 +1,12 @@
ChatMessageEvents.ClientReady = class
{
constructor(chatMessagesPanel, netMessages, gameSettingsControl, playerAssignmentsControl, readyControl)
constructor(setupWindow, chatMessagesPanel)
{
this.chatMessagesPanel = chatMessagesPanel;
this.args = {};
netMessages.registerNetMessageHandler("ready", this.onReadyMessage.bind(this));
setupWindow.controls.netMessages.registerNetMessageHandler("ready", this.onReadyMessage.bind(this));
}
onReadyMessage(message)

View File

@ -3,12 +3,12 @@
*/
ChatMessageEvents.GameSettingsChanged = class
{
constructor(chatMessagesPanel, netMessages, gameSettingsControl, playerAssignmentsControl, readyControl)
constructor(setupWindow, chatMessagesPanel)
{
this.readyControl = readyControl;
this.readyControl = setupWindow.controls.readyControl;
this.chatMessagesPanel = chatMessagesPanel;
readyControl.registerResetReadyHandler(this.onResetReady.bind(this));
this.readyControl.registerResetReadyHandler(this.onResetReady.bind(this));
}
onResetReady()

View File

@ -10,17 +10,20 @@ class ChatMessageEvents
class ChatPanel
{
constructor(gameSettingControlManager, gameSettingsControl, netMessages, playerAssignmentsControl, readyControl, gameSettingsPanel)
constructor(setupWindow, gameSettingControlManager, gameSettingsPanel)
{
this.statusMessageFormat = new StatusMessageFormat();
this.chatMessagesPanel = new ChatMessagesPanel(gameSettingsPanel);
this.chatInputAutocomplete = new ChatInputAutocomplete(gameSettingControlManager, gameSettingsControl, playerAssignmentsControl);
this.chatInputPanel = new ChatInputPanel(netMessages, this.chatInputAutocomplete);
this.chatInputAutocomplete = new ChatInputAutocomplete(
gameSettingControlManager, setupWindow.controls.gameSettingsControl, setupWindow.controls.playerAssignmentsControl);
this.chatInputPanel = new ChatInputPanel(
setupWindow.controls.netMessages, this.chatInputAutocomplete);
this.chatMessageEvents = [];
for (let name in ChatMessageEvents)
this.chatMessageEvents.push(new ChatMessageEvents[name](
this.chatMessagesPanel, netMessages, gameSettingsControl, playerAssignmentsControl, readyControl));
this.chatMessageEvents.push(new ChatMessageEvents[name](setupWindow, this.chatMessagesPanel));
}
}

View File

@ -1,13 +1,13 @@
class GameDescription
{
constructor(mapCache, gameSettingTabs, gameSettingsControl)
constructor(setupWindow, gameSettingTabs)
{
this.mapCache = mapCache;
this.mapCache = setupWindow.controls.mapCache;
this.gameDescriptionFrame = Engine.GetGUIObjectByName("gameDescriptionFrame");
this.gameDescription = Engine.GetGUIObjectByName("gameDescription");
gameSettingsControl.registerGameAttributesBatchChangeHandler(this.onGameAttributesBatchChange.bind(this));
setupWindow.controls.gameSettingsControl.registerGameAttributesBatchChangeHandler(this.onGameAttributesBatchChange.bind(this));
gameSettingTabs.registerTabsResizeHandler(this.onTabsResize.bind(this));
}

View File

@ -1,13 +1,13 @@
class GameSettingWarning
{
constructor(gameSettingsControl, cancelButton)
constructor(setupWindow, cancelButton)
{
if (!g_IsNetworked)
return;
this.gameSettingWarning = Engine.GetGUIObjectByName("gameSettingWarning");
gameSettingsControl.registerGameAttributesBatchChangeHandler(this.onGameAttributesBatchChange.bind(this));
setupWindow.controls.gameSettingsControl.registerGameAttributesBatchChangeHandler(this.onGameAttributesBatchChange.bind(this));
cancelButton.registerCancelButtonResizeHandler(this.onCancelButtonResize.bind(this));
}

View File

@ -1,6 +1,6 @@
class GameSettingsPanel
{
constructor(setupWindow, gameSettingTabs, gameSettingsControl, gameSettingControlManager)
constructor(setupWindow, gameSettingTabs, gameSettingControlManager)
{
this.centerRightPanel = Engine.GetGUIObjectByName("centerRightPanel");
this.settingTabButtonsFrame = Engine.GetGUIObjectByName("settingTabButtonsFrame");
@ -19,7 +19,7 @@ class GameSettingsPanel
this.lastTickTime = undefined;
gameSettingTabs.registerTabSelectHandler(this.updateSize.bind(this));
gameSettingsControl.registerGameAttributesBatchChangeHandler(this.updateSize.bind(this));
setupWindow.controls.gameSettingsControl.registerGameAttributesBatchChangeHandler(this.updateSize.bind(this));
setupWindow.registerLoadHandler(this.triggerResizeHandlers.bind(this));
}

View File

@ -1,15 +1,15 @@
class MapPreview
{
constructor(gameSettingsControl, mapCache)
constructor(setupWindow)
{
this.gameSettingsControl = gameSettingsControl;
this.mapCache = mapCache;
this.gameSettingsControl = setupWindow.controls.gameSettingsControl;
this.mapCache = setupWindow.controls.mapCache;
this.mapInfoName = Engine.GetGUIObjectByName("mapInfoName");
this.mapPreview = Engine.GetGUIObjectByName("mapPreview");
gameSettingsControl.registerMapChangeHandler(this.onMapChange.bind(this));
gameSettingsControl.registerGameAttributesBatchChangeHandler(this.onGameAttributesBatchChange.bind(this));
this.gameSettingsControl.registerMapChangeHandler(this.onMapChange.bind(this));
this.gameSettingsControl.registerGameAttributesBatchChangeHandler(this.onGameAttributesBatchChange.bind(this));
}
onMapChange(mapData)

View File

@ -1,9 +1,9 @@
class SoundNotification
{
constructor(netMessages, playerAssignmentsControl)
constructor(setupWindow)
{
netMessages.registerNetMessageHandler("chat", this.onClientChat.bind(this));
playerAssignmentsControl.registerClientJoinHandler(this.onClientJoin.bind(this));
setupWindow.controls.netMessages.registerNetMessageHandler("chat", this.onClientChat.bind(this));
setupWindow.controls.playerAssignmentsControl.registerClientJoinHandler(this.onClientJoin.bind(this));
}
onClientJoin(guid)

View File

@ -3,12 +3,12 @@
* This is not technically necessary, but only performed to avoid confusion or irritation when showing the clients first the
* default settings and then switching to the server settings quickly thereafter.
*/
class LoadingPage
SetupWindowPages.LoadingPage = class
{
constructor(netMessages)
constructor(setupWindow)
{
if (g_IsNetworked)
netMessages.registerNetMessageHandler("gamesetup", this.hideLoadingPage.bind(this));
setupWindow.controls.netMessages.registerNetMessageHandler("gamesetup", this.hideLoadingPage.bind(this));
else
this.hideLoadingPage();
}

View File

@ -1,3 +1,10 @@
/**
* This class stores the GameSetupPage and every subpage that is shown in the gamesetup.
*/
class SetupWindowPages
{
}
/**
* The SetupWindow is the root class owning all other class instances.
* The class shall be ineligible to perform any GUI object logic and shall defer that task to owned classes.
@ -30,11 +37,7 @@ class SetupWindow
"mapCache": mapCache,
"mapFilters": mapFilters,
"readyControl": readyControl,
"startGameControl": startGameControl
};
// These class instances are interfaces to networked messages and do not manage any GUI Object.
this.networkControls = {
"startGameControl": startGameControl,
"netMessages": netMessages,
"gameRegisterStanza":
Engine.HasXmppClient() &&
@ -43,10 +46,9 @@ class SetupWindow
};
// These are the pages within the setup window that may use the controls defined above
this.pages = {
"loadingPage": new LoadingPage(netMessages),
"gameSetupPage": new GameSetupPage(this, gameSettingsControl, playerAssignmentsControl, netMessages, this.networkControls.gameRegisterStanza, mapCache, mapFilters, startGameControl, readyControl)
};
this.pages = {};
for (let name in SetupWindowPages)
this.pages[name] = new SetupWindowPages[name](this);
setTimeout(displayGamestateNotifications, 1000);
Engine.GetGUIObjectByName("setupWindow").onTick = updateTimers;

View File

@ -17,6 +17,8 @@
<script directory="gui/gamesetup/Pages/GameSetupPage/Panels/Chat/"/>
<script directory="gui/gamesetup/Pages/GameSetupPage/Panels/Chat/ChatMessages/"/>
<script directory="gui/gamesetup/Pages/LoadingPage/"/>
<script directory="gui/gamesetup/Pages/AIConfigPage/"/>
<script directory="gui/gamesetup/Pages/AIConfigPage/Controls/"/>
<object type="image" style="ModernWindow">
@ -26,6 +28,7 @@
<include file="gui/gamesetup/Pages/LoadingPage/LoadingPage.xml"/>
<include file="gui/gamesetup/Pages/GameSetupPage/GameSetupPage.xml"/>
<include file="gui/gamesetup/Pages/AIConfigPage/AIConfigPage.xml"/>
</object>
</objects>

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<page>
<include>common/modern/setup.xml</include>
<include>common/modern/styles.xml</include>
<include>common/modern/sprites.xml</include>
<include>aiconfig/aiconfig.xml</include>
</page>

View File

@ -74,7 +74,6 @@
{
"extractor": "javascript",
"filemasks": [
"gui/aiconfig/**.js",
"gui/gamesetup/**.js",
"gui/gamesetup_mp/**.js",
"gui/loading/**.js"
@ -98,7 +97,6 @@
{
"extractor": "xml",
"filemasks": [
"gui/aiconfig/**.xml",
"gui/gamesetup/**.xml",
"gui/gamesetup_mp/**.xml",
"gui/loading/**.xml"