Changeset View
Standalone View
binaries/data/mods/public/gui/gamesetup/gamesetup.js
Show First 20 Lines • Show All 294 Lines • ▼ Show 20 Lines | |||||
var g_Autocomplete = []; | var g_Autocomplete = []; | ||||
/** | /** | ||||
* Array of strings formatted as displayed, including playername. | * Array of strings formatted as displayed, including playername. | ||||
*/ | */ | ||||
var g_ChatMessages = []; | var g_ChatMessages = []; | ||||
/** | /** | ||||
* Minimum amount of pixels required for the chat panel to be visible. | |||||
*/ | |||||
var g_MinChatWidth = 74; | |||||
/** | |||||
* Filename and translated title of all maps, given the currently selected | * Filename and translated title of all maps, given the currently selected | ||||
* maptype and filter. Sorted by title, shown in the dropdown. | * maptype and filter. Sorted by title, shown in the dropdown. | ||||
*/ | */ | ||||
var g_MapSelectionList = []; | var g_MapSelectionList = []; | ||||
/** | /** | ||||
* Cache containing the mapsettings. Just-in-time loading. | * Cache containing the mapsettings. Just-in-time loading. | ||||
*/ | */ | ||||
Show All 27 Lines | |||||
/** | /** | ||||
* Total number of units that the engine can run with smoothly. | * Total number of units that the engine can run with smoothly. | ||||
* It means a 4v4 with 150 population can still run nicely, but more than that might "lag". | * It means a 4v4 with 150 population can still run nicely, but more than that might "lag". | ||||
*/ | */ | ||||
var g_PopulationCapacityRecommendation = 1200; | var g_PopulationCapacityRecommendation = 1200; | ||||
/** | /** | ||||
* Vertical size of a tab button. | |||||
*/ | |||||
var g_TabButtonHeight = 30; | |||||
/** | |||||
* Vertical space between two tab buttons. | |||||
*/ | |||||
var g_TabButtonDist = 4; | |||||
/** | |||||
* Vertical size of a setting object. | |||||
*/ | |||||
var g_SettingHeight = 32; | |||||
/** | |||||
* Virtical space between two setting objects. | |||||
bb: typo | |||||
*/ | |||||
var g_SettingDist = 2; | |||||
/** | |||||
* Width of a column in the settings panel. | |||||
*/ | |||||
var g_ColumnWidth = 320; | |||||
/** | |||||
* Pixels per millisecond the settings panel slides when opening/closing. | |||||
*/ | |||||
var g_SlideSpeed = 1.2; | |||||
/** | |||||
* Store last tick time. | |||||
*/ | |||||
var g_LastTickTime = Date.now(); | |||||
Not Done Inline Actionsnukable bb: nukable | |||||
/** | |||||
* Order in which the GUI elements will be shown. | * Order in which the GUI elements will be shown. | ||||
* All valid options are required to appear here. | * All valid settings are required to appear here. | ||||
* The ones under "map" are shown in the map selection panel, | |||||
* the others in the "more options" dialog. | |||||
*/ | */ | ||||
var g_OptionOrderGUI = { | var g_SettingsTabsGUI = [ | ||||
"map": [ | { | ||||
Done Inline Actions"Toggle the %(name)s tab."? elexis: "Toggle the %(name)s tab."? | |||||
Not Done Inline Actions(getting some title case, but meh) bb: (getting some title case, but meh) | |||||
"label": translateWithContext("Match settings tab name", "Map"), | |||||
"settings": [ | |||||
"mapType", | "mapType", | ||||
Done Inline ActionsDon't overestimate the abilities of the string extraction python script. I see why you posted it here, but by definition word separators like " " are posted between two words. If you append the hotkey tooltip programmatically, you have several advantages:
elexis: Don't overestimate the abilities of the string extraction python script.
I see why you posted… | |||||
"mapFilter", | "mapFilter", | ||||
"mapSelection", | "mapSelection", | ||||
"numPlayers", | "mapSize", | ||||
"mapSize" | |||||
], | |||||
"more": [ | |||||
"triggerDifficulty", | |||||
"biome", | "biome", | ||||
ffffffffUnsubmitted Done Inline Actionsadd "nomad", for current sync ffffffff: add "nomad", for current sync | |||||
"gameSpeed", | "triggerDifficulty", | ||||
"disableTreasures", | |||||
"exploreMap", | |||||
"revealMap" | |||||
] | |||||
}, | |||||
Done Inline ActionstranslateWithContext to prevent transifex questions elexis: translateWithContext to prevent transifex questions | |||||
{ | |||||
"label": translateWithContext("Match settings tab name", "Player"), | |||||
"settings": [ | |||||
"numPlayers", | |||||
"populationCap", | |||||
"startingResources", | |||||
Done Inline ActionsGeneral == Miscellaneous. I guess it's hard to get it right with regards to the GUI space. elexis: General == Miscellaneous. I guess it's hard to get it right with regards to the GUI space. | |||||
Not Done Inline Actionsgeneral != misc bb: general != misc
Making a player tab absorbing the number of players above and popcap and… | |||||
"disableSpies" | |||||
] | |||||
}, | |||||
{ | |||||
"label": translateWithContext("Match settings tab name", "Victory Condition"), | |||||
Done Inline Actionssingular elexis: singular | |||||
"settings": [ | |||||
"victoryCondition", | "victoryCondition", | ||||
"relicCount", | "relicCount", | ||||
"relicDuration", | "relicDuration", | ||||
"wonderDuration", | "wonderDuration", | ||||
"populationCap", | "regicideGarrison" | ||||
"startingResources", | ] | ||||
}, | |||||
{ | |||||
"label": translateWithContext("Match settings tab name", "Miscellaneous"), | |||||
"settings": [ | |||||
"gameSpeed", | |||||
"ceasefire", | "ceasefire", | ||||
"regicideGarrison", | |||||
"exploreMap", | |||||
"revealMap", | |||||
"disableTreasures", | |||||
"disableSpies", | |||||
"lockTeams", | "lockTeams", | ||||
"lastManStanding", | "lastManStanding", | ||||
"enableCheats", | "enableCheats", | ||||
"enableRating" | "enableRating" | ||||
] | ] | ||||
}; | } | ||||
]; | |||||
Done Inline ActionsIf it doesn't contain only the order, it should be renamed. elexis: If it doesn't contain only the order, it should be renamed. | |||||
/** | /** | ||||
* Contains the logic of all multiple-choice gamesettings. | * Contains the logic of all multiple-choice gamesettings. | ||||
* | * | ||||
* Logic | * Logic | ||||
* ids - Array of identifier strings that indicate the selected value. | * ids - Array of identifier strings that indicate the selected value. | ||||
* default - Returns the index of the default value (not the value itself). | * default - Returns the index of the default value (not the value itself). | ||||
* defined - Whether a value for the setting is actually specified. | * defined - Whether a value for the setting is actually specified. | ||||
* get - The identifier of the currently selected value. | * get - The identifier of the currently selected value. | ||||
* select - Saves and processes the value of the selected index of the ids array. | * select - Saves and processes the value of the selected index of the ids array. | ||||
* | * | ||||
* GUI | * GUI | ||||
* title - The caption shown in the label. | * title - The caption shown in the label. | ||||
* tooltip - A description shown when hovering the dropdown or a specific item. | * tooltip - A description shown when hovering the dropdown or a specific item. | ||||
* labels - Array of translated strings selectable for this dropdown. | * labels - Array of translated strings selectable for this dropdown. | ||||
* colors - Optional array of colors to tint the according dropdown items with. | * colors - Optional array of colors to tint the according dropdown items with. | ||||
* hidden - If hidden, both the label and dropdown won't be visible. (default: false) | * hidden - If hidden, both the label and dropdown won't be visible. (default: false) | ||||
* enabled - Only the label will be shown if the setting is disabled. (default: true) | * enabled - Only the label will be shown if the setting is disabled. (default: true) | ||||
* autocomplete - Marks whether to autocomplete translated values of the string. (default: undefined) | * autocomplete - Marks whether to autocomplete translated values of the string. (default: undefined) | ||||
* If not undefined, must be a number that denotes the priority (higher numbers come first). | * If not undefined, must be a number that denotes the priority (higher numbers come first). | ||||
* If undefined, still autocompletes the translated title of the setting. | * If undefined, still autocompletes the translated title of the setting. | ||||
* initOrder - Options with lower values will be initialized first. | * initOrder - Settings with lower values will be initialized first. | ||||
*/ | */ | ||||
var g_Dropdowns = { | var g_Dropdowns = { | ||||
"mapType": { | "mapType": { | ||||
"title": () => translate("Map Type"), | "title": () => translate("Map Type"), | ||||
"tooltip": (hoverIdx) => g_MapTypes.Description[hoverIdx] || translate("Select a map type."), | "tooltip": (hoverIdx) => g_MapTypes.Description[hoverIdx] || translate("Select a map type."), | ||||
"labels": () => g_MapTypes.Title, | "labels": () => g_MapTypes.Title, | ||||
"ids": () => g_MapTypes.Name, | "ids": () => g_MapTypes.Name, | ||||
"default": () => g_MapTypes.Default, | "default": () => g_MapTypes.Default, | ||||
▲ Show 20 Lines • Show All 354 Lines • ▼ Show 20 Lines | "set": checked => { | ||||
g_GameAttributes.settings.RegicideGarrison = checked; | g_GameAttributes.settings.RegicideGarrison = checked; | ||||
}, | }, | ||||
"hidden": () => g_GameAttributes.settings.GameType != "regicide", | "hidden": () => g_GameAttributes.settings.GameType != "regicide", | ||||
"enabled": () => g_GameAttributes.mapType != "scenario", | "enabled": () => g_GameAttributes.mapType != "scenario", | ||||
"initOrder": 1000 | "initOrder": 1000 | ||||
}, | }, | ||||
"revealMap": { | "revealMap": { | ||||
"title": () => | "title": () => | ||||
// Translation: Make sure to differentiate between the revealed map and explored map options! | // Translation: Make sure to differentiate between the revealed map and explored map settings! | ||||
translate("Revealed Map"), | translate("Revealed Map"), | ||||
"tooltip": | "tooltip": | ||||
// Translation: Make sure to differentiate between the revealed map and explored map options! | // Translation: Make sure to differentiate between the revealed map and explored map settings! | ||||
() => translate("Toggle revealed map (see everything)."), | () => translate("Toggle revealed map (see everything)."), | ||||
"default": () => false, | "default": () => false, | ||||
"defined": () => g_GameAttributes.settings.RevealMap !== undefined, | "defined": () => g_GameAttributes.settings.RevealMap !== undefined, | ||||
"get": () => g_GameAttributes.settings.RevealMap, | "get": () => g_GameAttributes.settings.RevealMap, | ||||
"set": checked => { | "set": checked => { | ||||
g_GameAttributes.settings.RevealMap = checked; | g_GameAttributes.settings.RevealMap = checked; | ||||
if (checked) | if (checked) | ||||
g_Checkboxes.exploreMap.set(true); | g_Checkboxes.exploreMap.set(true); | ||||
}, | }, | ||||
"enabled": () => g_GameAttributes.mapType != "scenario", | "enabled": () => g_GameAttributes.mapType != "scenario", | ||||
"initOrder": 1000 | "initOrder": 1000 | ||||
}, | }, | ||||
"exploreMap": { | "exploreMap": { | ||||
"title": | "title": | ||||
// Translation: Make sure to differentiate between the revealed map and explored map options! | // Translation: Make sure to differentiate between the revealed map and explored map settings! | ||||
() => translate("Explored Map"), | () => translate("Explored Map"), | ||||
"tooltip": | "tooltip": | ||||
// Translation: Make sure to differentiate between the revealed map and explored map options! | // Translation: Make sure to differentiate between the revealed map and explored map settings! | ||||
() => translate("Toggle explored map (see initial map)."), | () => translate("Toggle explored map (see initial map)."), | ||||
"default": () => false, | "default": () => false, | ||||
"defined": () => g_GameAttributes.settings.ExploreMap !== undefined, | "defined": () => g_GameAttributes.settings.ExploreMap !== undefined, | ||||
"get": () => g_GameAttributes.settings.ExploreMap, | "get": () => g_GameAttributes.settings.ExploreMap, | ||||
"set": checked => { | "set": checked => { | ||||
g_GameAttributes.settings.ExploreMap = checked; | g_GameAttributes.settings.ExploreMap = checked; | ||||
}, | }, | ||||
"enabled": () => g_GameAttributes.mapType != "scenario" && !g_GameAttributes.settings.RevealMap, | "enabled": () => g_GameAttributes.mapType != "scenario" && !g_GameAttributes.settings.RevealMap, | ||||
▲ Show 20 Lines • Show All 86 Lines • ▼ Show 20 Lines | var g_Checkboxes = { | ||||
}, | }, | ||||
}; | }; | ||||
/** | /** | ||||
* For setting up arbitrary GUI objects. | * For setting up arbitrary GUI objects. | ||||
*/ | */ | ||||
var g_MiscControls = { | var g_MiscControls = { | ||||
"chatPanel": { | "chatPanel": { | ||||
"hidden": () => !g_IsNetworked, | "hidden": () => { | ||||
if (!g_IsNetworked) | |||||
return true; | |||||
let size = Engine.GetGUIObjectByName("chatPanel").getComputedSize(); | |||||
return size.right - size.left < g_MinChatWidth; | |||||
}, | |||||
Not Done Inline ActionsWe can't avoid the situation in which the panel becomes too small? elexis: We can't avoid the situation in which the panel becomes too small?
We can assume >= 1024 | |||||
Not Done Inline Actionsno look at 2 columns on 1024, no chat then iirc bb: no look at 2 columns on 1024, no chat then iirc
With scrolling added, it can be removed I guess. | |||||
}, | }, | ||||
"chatInput": { | "chatInput": { | ||||
"tooltip": () => colorizeAutocompleteHotkey(translate("Press %(hotkey)s to autocomplete playernames or settings.")), | "tooltip": () => colorizeAutocompleteHotkey(translate("Press %(hotkey)s to autocomplete playernames or settings.")), | ||||
}, | }, | ||||
"cheatWarningText": { | "cheatWarningText": { | ||||
"hidden": () => !g_IsNetworked || !g_GameAttributes.settings.CheatsEnabled, | "hidden": () => !g_IsNetworked || !g_GameAttributes.settings.CheatsEnabled, | ||||
}, | }, | ||||
"cancelGame": { | "cancelGame": { | ||||
Show All 20 Lines | "hidden": () => | ||||
!g_PlayerAssignments[Engine.GetPlayerGUID()] || | !g_PlayerAssignments[Engine.GetPlayerGUID()] || | ||||
g_PlayerAssignments[Engine.GetPlayerGUID()].player == -1 && !g_IsController, | g_PlayerAssignments[Engine.GetPlayerGUID()].player == -1 && !g_IsController, | ||||
}, | }, | ||||
"civResetButton": { | "civResetButton": { | ||||
"hidden": () => g_GameAttributes.mapType == "scenario" || !g_IsController, | "hidden": () => g_GameAttributes.mapType == "scenario" || !g_IsController, | ||||
}, | }, | ||||
"teamResetButton": { | "teamResetButton": { | ||||
"hidden": () => g_GameAttributes.mapType == "scenario" || !g_IsController, | "hidden": () => g_GameAttributes.mapType == "scenario" || !g_IsController, | ||||
}, | } | ||||
// Display these after having hidden every GUI object in the "More Options" dialog | |||||
"moreOptionsLabel": { | |||||
"hidden": () => false, | |||||
}, | |||||
"hideMoreOptions": { | |||||
"hidden": () => false, | |||||
}, | |||||
}; | }; | ||||
/** | /** | ||||
* Contains gui elements that are repeated for every player. | * Contains gui elements that are repeated for every player. | ||||
*/ | */ | ||||
var g_PlayerMiscElements = { | var g_PlayerMiscElements = { | ||||
"playerBox": { | "playerBox": { | ||||
"size": (playerIdx) => ["0", 32 * playerIdx, "100%", 32 * (playerIdx + 1)].join(" "), | "size": (playerIdx) => ["0", 32 * playerIdx, "100%", 32 * (playerIdx + 1)].join(" "), | ||||
▲ Show 20 Lines • Show All 114 Lines • ▼ Show 20 Lines | for (let i = 0; i < g_GameAttributes.settings.PlayerData.length; ++i) | ||||
g_PlayerDropdowns[dropdown].select(g_PlayerDropdowns[dropdown].default(i), i); | g_PlayerDropdowns[dropdown].select(g_PlayerDropdowns[dropdown].default(i), i); | ||||
} | } | ||||
/** | /** | ||||
* Called after the first tick. | * Called after the first tick. | ||||
*/ | */ | ||||
function initGUIObjects() | function initGUIObjects() | ||||
{ | { | ||||
for (let tab in g_SettingsTabsGUI) | |||||
g_SettingsTabsGUI[tab].tooltip = | |||||
sprintf(translate("Toggle the %(name)s settings tab."), { "name": g_SettingsTabsGUI[tab].label }) + | |||||
colorizeHotkey("\n" + translate("Use %(hotkey)s to move a settings tab down."), "tab.next") + | |||||
Not Done Inline Actionsspelling error bb: spelling error | |||||
colorizeHotkey("\n" + translate("Use %(hotkey)s to move a settings tab up."), "tab.prev"); | |||||
Done Inline Actions" " -> "\n" elexis: " " -> "\n"
Also mimo says D1180 is a must-have, so should likely get that in. | |||||
Not Done Inline ActionsCan always be changed when/if doing D1180 bb: Can always be changed when/if doing D1180 | |||||
// Copy all initOrder values into one object | // Copy all initOrder values into one object | ||||
let initOrder = {}; | let initOrder = {}; | ||||
for (let dropdown in g_Dropdowns) | for (let dropdown in g_Dropdowns) | ||||
initOrder[dropdown] = g_Dropdowns[dropdown].initOrder; | initOrder[dropdown] = g_Dropdowns[dropdown].initOrder; | ||||
for (let checkbox in g_Checkboxes) | for (let checkbox in g_Checkboxes) | ||||
initOrder[checkbox] = g_Checkboxes[checkbox].initOrder; | initOrder[checkbox] = g_Checkboxes[checkbox].initOrder; | ||||
// Sort the object on initOrder so we can init the options in an arbitrary order | // Sort the object on initOrder so we can init the settings in an arbitrary order | ||||
for (let option of Object.keys(initOrder).sort((a, b) => initOrder[a] - initOrder[b])) | for (let setting of Object.keys(initOrder).sort((a, b) => initOrder[a] - initOrder[b])) | ||||
if (g_Dropdowns[option]) | if (g_Dropdowns[setting]) | ||||
initDropdown(option); | initDropdown(setting); | ||||
else if (g_Checkboxes[option]) | else if (g_Checkboxes[setting]) | ||||
initCheckbox(option); | initCheckbox(setting); | ||||
else | else | ||||
warn('The option "' + option + '" is not defined.'); | warn('The setting "' + setting + '" is not defined.'); | ||||
for (let dropdown in g_PlayerDropdowns) | for (let dropdown in g_PlayerDropdowns) | ||||
initPlayerDropdowns(dropdown); | initPlayerDropdowns(dropdown); | ||||
resizeMoreOptionsWindow(); | let settingTabButtons = Engine.GetGUIObjectByName("settingTabButtons"); | ||||
let settingTabButtonsSize = settingTabButtons.size; | |||||
let settingTabButtonsBottom = settingTabButtonsSize.top + g_SettingsTabsGUI.length * (g_TabButtonHeight + g_TabButtonDist); | |||||
settingTabButtonsSize.bottom = settingTabButtonsBottom; | |||||
settingTabButtons.size = settingTabButtonsSize; | |||||
let gameDescription = Engine.GetGUIObjectByName("mapInfoDescriptionFrame"); | |||||
let gameDescriptionSize = gameDescription.size; | |||||
gameDescriptionSize.top = settingTabButtonsBottom + 3; | |||||
gameDescription.size = gameDescriptionSize; | |||||
placeTabButtons( | |||||
g_SettingsTabsGUI, | |||||
g_TabButtonHeight, | |||||
g_TabButtonDist, | |||||
category => { | |||||
selectPanel(category == g_TabCategorySelected ? undefined : category); | |||||
}, | |||||
displaySettings); | |||||
Not Done Inline ActionsDecoupled this from initGUIObjects in D2483. elexis: Decoupled this from initGUIObjects in D2483. | |||||
initSPTips(); | initSPTips(); | ||||
loadPersistMatchSettings(); | loadPersistMatchSettings(); | ||||
updateGameAttributes(); | updateGameAttributes(); | ||||
sendRegisterGameStanzaImmediate(); | sendRegisterGameStanzaImmediate(); | ||||
if (g_IsTutorial) | if (g_IsTutorial) | ||||
{ | { | ||||
launchTutorial(); | launchTutorial(); | ||||
return; | return; | ||||
} | } | ||||
// Don't lift the curtain until the controls are updated the first time | // Don't lift the curtain until the controls are updated the first time | ||||
if (!g_IsNetworked) | if (!g_IsNetworked) | ||||
hideLoadingWindow(); | hideLoadingWindow(); | ||||
} | } | ||||
function displaySettings() | |||||
{ | |||||
updateGUIObjects(); | |||||
Done Inline Actionslet optionTabButtons = Engine.GetGUIObjectByName("optionTabButtons"); This way we know which GUI object is modified without looking up this line. elexis: `let optionTabButtons = Engine.GetGUIObjectByName("optionTabButtons");`
This way we know which… | |||||
Not Done Inline Actionsmissing {number} and cap bb: missing `{number}` and cap | |||||
Engine.GetGUIObjectByName("settingsPanel").hidden = false; | |||||
} | |||||
Done Inline ActionsI don't like this function. It's name is extremely vague, sounds like it could do anything and nothing. From the naming it could be used everywhere. Just inline it (with a fat arrow or not) elexis: I don't like this function. It's name is extremely vague, sounds like it could do anything and… | |||||
Not Done Inline Actionsyup inline bb: yup inline | |||||
/** | |||||
* Slide settings panel. | |||||
*/ | |||||
function updateSettingsPanelPosition(dt) | |||||
ffffffffUnsubmitted Done Inline Actionsno explanation to dt? (maybe difftime)? ffffffff: no explanation to dt? (maybe difftime)? | |||||
bbAuthorUnsubmitted Not Done Inline Actionsmaybe to much of a physicist to not understand dt, so just added the comment bb: maybe to much of a physicist to not understand dt, so just added the comment | |||||
elexisUnsubmitted Not Done Inline Actions(configDB entry would be nice I suppose, to save some time) elexis: (configDB entry would be nice I suppose, to save some time) | |||||
bbAuthorUnsubmitted Not Done Inline ActionsAs in a config item for the speed (a slider), or for on/off (checkbox)? bb: As in a config item for the speed (a slider), or for on/off (checkbox)? | |||||
{ | |||||
let settingsPanel = Engine.GetGUIObjectByName("settingsPanel"); | |||||
Not Done Inline ActionsEasier to keep track of object if they have the same name in JS and XML, i.e let foo = Engine.GetGUIObjectByName("foo"); elexis: Easier to keep track of object if they have the same name in JS and XML, i.e `let foo = Engine. | |||||
let rightBorder = Engine.GetGUIObjectByName("settingTabButtons").size.left; | |||||
let offset = 0; | |||||
if (g_TabCategorySelected === undefined) | |||||
Done Inline ActionsIs there some mnemonic for the abstract for the abstract equality comparison test https://www.ecma-international.org/ecma-262/5.1/#sec-11.9.3 or should we always use a strict comparison === when testing against falsy values? (same below) elexis: Is there some mnemonic for the abstract for the abstract equality comparison test https://www. | |||||
{ | |||||
let maxOffset = rightBorder - settingsPanel.size.left; | |||||
if (maxOffset > 0) | |||||
offset = Math.min(g_SlideSpeed * dt, maxOffset); | |||||
} | |||||
else if (rightBorder > settingsPanel.size.right) | |||||
offset = Math.min(g_SlideSpeed * dt, rightBorder - settingsPanel.size.right); | |||||
else | |||||
{ | |||||
let maxOffset = settingsPanel.size.right - rightBorder; | |||||
if (maxOffset > 0) | |||||
offset = -Math.min(g_SlideSpeed * dt, maxOffset); | |||||
} | |||||
let size = settingsPanel.size; | |||||
size.left += offset; | |||||
size.right += offset; | |||||
settingsPanel.size = size; | |||||
let settingsBackground = Engine.GetGUIObjectByName("settingsBackground"); | |||||
let backgroundSize = settingsBackground.size; | |||||
backgroundSize.left = size.left; | |||||
settingsBackground.size = backgroundSize; | |||||
Done Inline ActionsCan that be replaced with a chatPanel hidden test? I.e. testing what we want to test for by definition, rather than the coincidentally equal value. elexis: Can that be replaced with a chatPanel hidden test? I.e. testing what we want to test for by… | |||||
Not Done Inline ActionsThe whole check should be removed, checking for hidden won't work as the panel can be hidden due to the small size bb: The whole check should be removed, checking for hidden won't work as the panel can be hidden… | |||||
Not Done Inline ActionsDecoupled chatPanel from settingTabs code in D2483. elexis: Decoupled chatPanel from settingTabs code in D2483. | |||||
let chatPanel = Engine.GetGUIObjectByName("chatPanel"); | |||||
let chatSize = chatPanel.size; | |||||
chatSize.right += offset; | |||||
chatPanel.size = chatSize; | |||||
chatPanel.hidden = g_MiscControls.chatPanel.hidden(); | |||||
let spTips = Engine.GetGUIObjectByName("spTips") | |||||
ffffffffUnsubmitted Done Inline Actions; ffffffff: ; | |||||
spTips.hidden = g_IsNetworked || | |||||
Engine.ConfigDB_GetValue("user", "gui.gamesetup.enabletips") !== "true" || | |||||
spTips.size.right > settingsPanel.getComputedSize().left; | |||||
} | |||||
Done Inline ActionsDon't add a second place that define state-dependent logic to determine the visibility of the SP tips. It should be set in g_MiscControls and you can call the function in that object if needed. elexis: Don't add a second place that define state-dependent logic to determine the visibility of the… | |||||
function hideLoadingWindow() | function hideLoadingWindow() | ||||
Done Inline ActionsIt's the third GUI page with this code? elexis: It's the third GUI page with this code?
gui/common/tab_buttons.js? | |||||
Not Done Inline Actionsnot the 4th? (summary, credits, options, this) bb: not the 4th? (summary, credits, options, this) | |||||
{ | { | ||||
let loadingWindow = Engine.GetGUIObjectByName("loadingWindow"); | let loadingWindow = Engine.GetGUIObjectByName("loadingWindow"); | ||||
if (loadingWindow.hidden) | if (loadingWindow.hidden) | ||||
return; | return; | ||||
loadingWindow.hidden = true; | loadingWindow.hidden = true; | ||||
Engine.GetGUIObjectByName("setupWindow").hidden = false; | Engine.GetGUIObjectByName("setupWindow").hidden = false; | ||||
Engine.GetGUIObjectByName("chatInput").focus(); | Engine.GetGUIObjectByName("chatInput").focus(); | ||||
} | } | ||||
/** | /** | ||||
* Options in the "More Options" or "Map" panel use a generic name. | * Settings under the settings tabs use a generic name. | ||||
* Player settings use custom names. | * Player settings use custom names. | ||||
*/ | */ | ||||
function getGUIObjectNameFromSetting(name) | function getGUIObjectNameFromSetting(setting) | ||||
{ | { | ||||
for (let panel in g_OptionOrderGUI) | let idxOffset = 0; | ||||
for (let category of g_SettingsTabsGUI) | |||||
{ | { | ||||
let idx = g_OptionOrderGUI[panel].indexOf(name); | let idx = category.settings.indexOf(setting); | ||||
if (idx != -1) | if (idx != -1) | ||||
return [ | return [ | ||||
panel + "Option", | "setting", | ||||
g_Dropdowns[name] ? "Dropdown" : "Checkbox", | g_Dropdowns[setting] ? "Dropdown" : "Checkbox", | ||||
"[" + idx + "]" | "[" + (idx + idxOffset) + "]" | ||||
]; | ]; | ||||
idxOffset += category.settings.length; | |||||
} | } | ||||
Not Done Inline Actionssounds right. GUI order != init order. elexis: sounds right. GUI order != init order. | |||||
// Assume there is a GUI object with exactly that setting name | // Assume there is a GUI object with exactly that setting name | ||||
return [name, "", ""]; | return [setting, "", ""]; | ||||
} | } | ||||
function initDropdown(name, playerIdx) | function initDropdown(name, playerIdx) | ||||
{ | { | ||||
let [guiName, guiType, guiIdx] = getGUIObjectNameFromSetting(name); | let [guiName, guiType, guiIdx] = getGUIObjectNameFromSetting(name); | ||||
let idxName = playerIdx === undefined ? "" : "[" + playerIdx + "]"; | let idxName = playerIdx === undefined ? "" : "[" + playerIdx + "]"; | ||||
let data = (playerIdx === undefined ? g_Dropdowns : g_PlayerDropdowns)[name]; | let data = (playerIdx === undefined ? g_Dropdowns : g_PlayerDropdowns)[name]; | ||||
▲ Show 20 Lines • Show All 65 Lines • ▼ Show 20 Lines | |||||
function saveSPTipsSetting() | function saveSPTipsSetting() | ||||
{ | { | ||||
let enabled = String(Engine.GetGUIObjectByName("displaySPTips").checked); | let enabled = String(Engine.GetGUIObjectByName("displaySPTips").checked); | ||||
Engine.ConfigDB_CreateValue("user", "gui.gamesetup.enabletips", enabled); | Engine.ConfigDB_CreateValue("user", "gui.gamesetup.enabletips", enabled); | ||||
Engine.ConfigDB_WriteValueToFile("user", "gui.gamesetup.enabletips", enabled, "config/user.cfg"); | Engine.ConfigDB_WriteValueToFile("user", "gui.gamesetup.enabletips", enabled, "config/user.cfg"); | ||||
} | } | ||||
function verticallyDistributeGUIObjects(parent, objectHeight, ignore) | /** | ||||
* Distribute the currently visible settings over the settings panel. | |||||
* First calculate the number of columns required, then place the objects. | |||||
*/ | |||||
function distributeSettings() | |||||
{ | { | ||||
let yPos; | let settingsPanel = Engine.GetGUIObjectByName("settingsPanel"); | ||||
let actualSettingsPanelSize = settingsPanel.getComputedSize(); | |||||
let parentObject = Engine.GetGUIObjectByName(parent); | let maxPerColumn = Math.floor((actualSettingsPanelSize.bottom - actualSettingsPanelSize.top) / g_SettingHeight); | ||||
for (let child of parentObject.children) | let childs = 0; | ||||
{ | for (let child of settingsPanel.children) | ||||
if (ignore.indexOf(child.name) != -1) | if (child.hidden) | ||||
continue; | ++childs; | ||||
Done Inline Actionslet childCount = settingsPanel.children.filter(child => child.hidden).length? Maybe even a reduce call to merge more stuff? elexis: `let childCount = settingsPanel.children.filter(child => child.hidden).length`?
Maybe even a… | |||||
Not Done Inline Actionsmissing negation bb: missing negation | |||||
let childSize = child.size; | let perColumn = childs / Math.ceil(childs / maxPerColumn); | ||||
yPos = yPos || childSize.top; | |||||
let yPos = g_SettingDist; | |||||
let column = 0; | |||||
let thisColumn = 0; | |||||
let settingsPanelSize = settingsPanel.size; | |||||
Not Done Inline ActionsDubious about this feature. elexis: Dubious about this feature.
IMO it's more clear to have two columns.
| |||||
Not Done Inline ActionsCoded it before using multiple columns, but left it in to avoid unused gui space and avoid multiple columns as much as possible (notice that two columns on 1024 will hide the chat). bb: Coded it before using multiple columns, but left it in to avoid unused gui space and avoid… | |||||
for (let child of settingsPanel.children) | |||||
{ | |||||
if (child.hidden) | if (child.hidden) | ||||
continue; | continue; | ||||
childSize.top = yPos; | if (thisColumn >= perColumn) | ||||
childSize.bottom = yPos + objectHeight - 2; | |||||
child.size = childSize; | |||||
yPos += objectHeight; | |||||
} | |||||
return yPos; | |||||
} | |||||
/** | |||||
* Remove empty space in case of hidden options (like cheats, rating or victory duration) | |||||
*/ | |||||
function resizeMoreOptionsWindow() | |||||
{ | { | ||||
Done Inline ActionsIf ES6 wouldn't provide startsWith, I'd still have recommended "optionDropdown."length to replace the magic 14. Is it even the right string? (See that's why we dont use magic numbers) elexis: If ES6 wouldn't provide `startsWith`, I'd still have recommended `"optionDropdown."length` to… | |||||
verticallyDistributeGUIObjects("mapOptions", 32, []); | yPos = g_SettingDist; | ||||
++column; | |||||
thisColumn = 0; | |||||
} | |||||
let yPos = verticallyDistributeGUIObjects("moreOptions", 32, ["moreOptionsLabel"]); | let childSize = child.size; | ||||
child.size = new GUISize( | |||||
column * g_ColumnWidth, | |||||
yPos, | |||||
column * g_ColumnWidth + g_ColumnWidth - 10, | |||||
yPos + g_SettingHeight - g_SettingDist); | |||||
yPos += g_SettingHeight; | |||||
++thisColumn; | |||||
} | |||||
// Resize the vertically centered window containing the options | let oldColumns = Math.round((actualSettingsPanelSize.right - actualSettingsPanelSize.left) / g_ColumnWidth) - 1; | ||||
let moreOptions = Engine.GetGUIObjectByName("moreOptions"); | settingsPanelSize.right += (column - oldColumns) * g_ColumnWidth; | ||||
let mSize = moreOptions.size; | settingsPanel.size = settingsPanelSize; | ||||
mSize.bottom = mSize.top + yPos + 20; | |||||
moreOptions.size = mSize; | |||||
} | } | ||||
/** | /** | ||||
* Called when the client disconnects. | * Called when the client disconnects. | ||||
* The other cases from NetClient should never occur in the gamesetup. | * The other cases from NetClient should never occur in the gamesetup. | ||||
*/ | */ | ||||
function handleNetStatusMessage(message) | function handleNetStatusMessage(message) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 278 Lines • ▼ Show 20 Lines | g_BiomeList = biomeList && prepareForDropdown( | ||||
}].concat(biomeList.map(biome => ({ | }].concat(biomeList.map(biome => ({ | ||||
"Id": biome.Id, | "Id": biome.Id, | ||||
"Title": biome.Title, | "Title": biome.Title, | ||||
"Description": biome.Description, | "Description": biome.Description, | ||||
"Color": g_ColorRegular | "Color": g_ColorRegular | ||||
})))); | })))); | ||||
initDropdown("biome"); | initDropdown("biome"); | ||||
updateGUIDropdown("biome"); | |||||
distributeSettings(); | |||||
Not Done Inline Actions(how I love these hardcodings) elexis: (how I love these hardcodings) | |||||
Not Done Inline Actionswell the first line is actually a current bug, only unnoticed since when changing the map the more options window is closed, second line is a bit unfortunate bb: well the first line is actually a current bug, only unnoticed since when changing the map the… | |||||
Not Done Inline ActionsDecoupled biome, TriggerDifficulties and SettingTabsPanel in D2483. elexis: Decoupled biome, TriggerDifficulties and SettingTabsPanel in D2483. | |||||
} | } | ||||
function reloadTriggerDifficulties() | function reloadTriggerDifficulties() | ||||
{ | { | ||||
g_TriggerDifficultyList = undefined; | g_TriggerDifficultyList = undefined; | ||||
if (!g_GameAttributes.settings.SupportedTriggerDifficulties) | if (!g_GameAttributes.settings.SupportedTriggerDifficulties) | ||||
return; | return; | ||||
Show All 13 Lines | g_TriggerDifficultyList = prepareForDropdown( | ||||
triggerDifficultyList.map(diff => ({ | triggerDifficultyList.map(diff => ({ | ||||
"Id": diff.Difficulty, | "Id": diff.Difficulty, | ||||
"Title": diff.Title, | "Title": diff.Title, | ||||
"Description": diff.Tooltip, | "Description": diff.Tooltip, | ||||
"Default": diff.Name == g_GameAttributes.settings.SupportedTriggerDifficulties.Default | "Default": diff.Name == g_GameAttributes.settings.SupportedTriggerDifficulties.Default | ||||
}))); | }))); | ||||
initDropdown("triggerDifficulty"); | initDropdown("triggerDifficulty"); | ||||
updateGUIDropdown("triggerDifficulty"); | |||||
distributeSettings(); | |||||
} | } | ||||
function reloadGameSpeedChoices() | function reloadGameSpeedChoices() | ||||
{ | { | ||||
g_GameSpeeds = getGameSpeedChoices(Object.keys(g_PlayerAssignments).every(guid => g_PlayerAssignments[guid].player == -1)); | g_GameSpeeds = getGameSpeedChoices(Object.keys(g_PlayerAssignments).every(guid => g_PlayerAssignments[guid].player == -1)); | ||||
initDropdown("gameSpeed"); | initDropdown("gameSpeed"); | ||||
supplementDefaults(); | supplementDefaults(); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 146 Lines • ▼ Show 20 Lines | function onTick() | ||||
{ | { | ||||
initGUIObjects(); | initGUIObjects(); | ||||
++g_LoadingState; | ++g_LoadingState; | ||||
} | } | ||||
else if (g_LoadingState == 2) | else if (g_LoadingState == 2) | ||||
handleNetMessages(); | handleNetMessages(); | ||||
updateTimers(); | updateTimers(); | ||||
let now = Date.now(); | |||||
let tickLength = now - g_LastTickTime; | |||||
g_LastTickTime = now; | |||||
updateSettingsPanelPosition(tickLength); | |||||
Not Done Inline Actions(Could avoid tickLength helper variable if we neglect the duration spent in updateOptionsPanelPosition, likely messy to do so though) elexis: (Could avoid `tickLength` helper variable if we neglect the duration spent in… | |||||
Not Done Inline ActionsHad the same thought when coding, but this is equivalent to the code for the main menu sliding bb: Had the same thought when coding, but this is equivalent to the code for the main menu sliding | |||||
Not Done Inline ActionsEquivalent code you said? :-) elexis: Equivalent code you said? :-) | |||||
Not Done Inline Actions(Yes I had plans to merge them together, but that will take a nice main-menu rewrite and so meh-ed it for now) bb: (Yes I had plans to merge them together, but that will take a nice main-menu rewrite and so meh… | |||||
} | } | ||||
Done Inline ActionsGuess this can be inlined elexis: Guess this can be inlined | |||||
/** | /** | ||||
* Handles all pending messages sent by the net client. | * Handles all pending messages sent by the net client. | ||||
*/ | */ | ||||
function handleNetMessages() | function handleNetMessages() | ||||
{ | { | ||||
while (g_IsNetworked) | while (g_IsNetworked) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 91 Lines • ▼ Show 20 Lines | function updateGUIDropdown(name, playerIdx = undefined) | ||||
let title = Engine.GetGUIObjectByName(guiName + "Title" + guiIdx + idxName); | let title = Engine.GetGUIObjectByName(guiName + "Title" + guiIdx + idxName); | ||||
if (guiType == "Dropdown") | if (guiType == "Dropdown") | ||||
Engine.GetGUIObjectByName(guiName + "Checkbox" + guiIdx).hidden = true; | Engine.GetGUIObjectByName(guiName + "Checkbox" + guiIdx).hidden = true; | ||||
let indexHidden = isControlArrayElementHidden(playerIdx); | let indexHidden = isControlArrayElementHidden(playerIdx); | ||||
let obj = (playerIdx === undefined ? g_Dropdowns : g_PlayerDropdowns)[name]; | let obj = (playerIdx === undefined ? g_Dropdowns : g_PlayerDropdowns)[name]; | ||||
let selected = indexHidden ? -1 : dropdown.list_data.indexOf(String(obj.get(playerIdx))); | |||||
let enabled = !indexHidden && (!obj.enabled || obj.enabled(playerIdx)); | |||||
let hidden = indexHidden || obj.hidden && obj.hidden(playerIdx); | let hidden = indexHidden || obj.hidden && obj.hidden(playerIdx); | ||||
let selected = hidden ? -1 : dropdown.list_data.indexOf(String(obj.get(playerIdx))); | |||||
let enabled = !indexHidden && (!obj.enabled || obj.enabled(playerIdx)); | |||||
dropdown.enabled = g_IsController && enabled; | |||||
Not Done Inline Actionsmaybe do the same for checkboxes? only what should the value of checked be? bb: maybe do the same for checkboxes? only what should the value of `checked` be? | |||||
Not Done Inline ActionsYou mean showing disabled checkboxes to non-controllers? Maybe there hadn't been an accoridng sprite at the time. Anyway out of scope. elexis: You mean showing disabled checkboxes to non-controllers? Maybe there hadn't been an accoridng… | |||||
dropdown.hidden = !g_IsController || !enabled || hidden; | dropdown.hidden = !g_IsController || !enabled || hidden; | ||||
dropdown.selected = selected; | dropdown.selected = selected; | ||||
dropdown.tooltip = !indexHidden && obj.tooltip ? obj.tooltip(-1, playerIdx) : ""; | dropdown.tooltip = !indexHidden && obj.tooltip ? obj.tooltip(-1, playerIdx) : ""; | ||||
if (frame) | if (frame) | ||||
frame.hidden = hidden; | frame.hidden = hidden; | ||||
if (title && obj.title && !indexHidden) | if (title && obj.title && !indexHidden) | ||||
title.caption = sprintf(translate("%(option)s:"), { "option": obj.title(playerIdx) }); | title.caption = sprintf(translate("%(setting)s:"), { "setting": obj.title(playerIdx) }); | ||||
if (label && !indexHidden) | if (label && !indexHidden) | ||||
{ | { | ||||
label.hidden = g_IsController && enabled || hidden; | label.hidden = g_IsController && enabled || hidden; | ||||
label.caption = selected == -1 ? translateWithContext("option value", "Unknown") : dropdown.list[selected]; | label.caption = selected == -1 ? translateWithContext("settings value", "Unknown") : dropdown.list[selected]; | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* Not used for the player assignments, so playerCheckboxes are not implemented, | * Not used for the player assignments, so playerCheckboxes are not implemented, | ||||
* hence no index. | * hence no index. | ||||
*/ | */ | ||||
function updateGUICheckbox(name) | function updateGUICheckbox(name) | ||||
Show All 9 Lines | function updateGUICheckbox(name) | ||||
let label = Engine.GetGUIObjectByName(guiName + "Text" + guiIdx); | let label = Engine.GetGUIObjectByName(guiName + "Text" + guiIdx); | ||||
let frame = Engine.GetGUIObjectByName(guiName + "Frame" + guiIdx); | let frame = Engine.GetGUIObjectByName(guiName + "Frame" + guiIdx); | ||||
let title = Engine.GetGUIObjectByName(guiName + "Title" + guiIdx); | let title = Engine.GetGUIObjectByName(guiName + "Title" + guiIdx); | ||||
if (guiType == "Checkbox") | if (guiType == "Checkbox") | ||||
Engine.GetGUIObjectByName(guiName + "Dropdown" + guiIdx).hidden = true; | Engine.GetGUIObjectByName(guiName + "Dropdown" + guiIdx).hidden = true; | ||||
checkbox.checked = checked; | checkbox.checked = checked; | ||||
checkbox.enabled = enabled; | checkbox.enabled = g_IsController && enabled; | ||||
checkbox.hidden = hidden || !g_IsController; | checkbox.hidden = hidden || !g_IsController; | ||||
checkbox.tooltip = obj.tooltip ? obj.tooltip() : ""; | checkbox.tooltip = obj.tooltip ? obj.tooltip() : ""; | ||||
label.caption = checked ? translate("Yes") : translate("No"); | label.caption = checked ? translate("Yes") : translate("No"); | ||||
label.hidden = hidden || g_IsController; | label.hidden = hidden || g_IsController; | ||||
if (frame) | if (frame) | ||||
frame.hidden = hidden; | frame.hidden = hidden; | ||||
if (title && obj.title) | if (title && obj.title) | ||||
title.caption = sprintf(translate("%(option)s:"), { "option": obj.title() }); | title.caption = sprintf(translate("%(setting)s:"), { "setting": obj.title() }); | ||||
elexisUnsubmitted Done Inline Actionsstring context or comment elexis: string context or comment | |||||
} | } | ||||
function updateGUIMiscControl(name, playerIdx) | function updateGUIMiscControl(name, playerIdx) | ||||
{ | { | ||||
let idxName = playerIdx === undefined ? "" : "[" + playerIdx + "]"; | let idxName = playerIdx === undefined ? "" : "[" + playerIdx + "]"; | ||||
let obj = (playerIdx === undefined ? g_MiscControls : g_PlayerMiscElements)[name]; | let obj = (playerIdx === undefined ? g_MiscControls : g_PlayerMiscElements)[name]; | ||||
let control = Engine.GetGUIObjectByName(name + idxName); | let control = Engine.GetGUIObjectByName(name + idxName); | ||||
▲ Show 20 Lines • Show All 138 Lines • ▼ Show 20 Lines | function updateGUIObjects() | ||||
g_IsInGuiUpdate = true; | g_IsInGuiUpdate = true; | ||||
reloadMapFilterList(); | reloadMapFilterList(); | ||||
reloadMapSpecific(); | reloadMapSpecific(); | ||||
reloadGameSpeedChoices(); | reloadGameSpeedChoices(); | ||||
reloadPlayerAssignmentChoices(); | reloadPlayerAssignmentChoices(); | ||||
// Hide exceeding dropdowns and checkboxes | // Hide exceeding dropdowns and checkboxes | ||||
for (let panel in g_OptionOrderGUI) | for (let setting of Engine.GetGUIObjectByName("settingsPanel").children) | ||||
for (let child of Engine.GetGUIObjectByName(panel + "Options").children) | setting.hidden = true; | ||||
child.hidden = true; | |||||
// Show the relevant ones | // Show the relevant ones | ||||
if (g_TabCategorySelected !== undefined) | |||||
{ | |||||
for (let name in g_Dropdowns) | for (let name in g_Dropdowns) | ||||
if (g_SettingsTabsGUI[g_TabCategorySelected].settings.indexOf(name) != -1) | |||||
updateGUIDropdown(name); | updateGUIDropdown(name); | ||||
for (let name in g_Checkboxes) | for (let name in g_Checkboxes) | ||||
if (g_SettingsTabsGUI[g_TabCategorySelected].settings.indexOf(name) != -1) | |||||
updateGUICheckbox(name); | updateGUICheckbox(name); | ||||
} | |||||
Not Done Inline Actionsexplicit checks for undefined or casual negation ! as != undefined is equal to the latter, jshint confirmed iirc. See also falsy on MDN elexis: explicit checks for undefined or casual negation `!` as `!= undefined` is equal to the latter… | |||||
Not Done Inline Actionsbut g_SelectedCategory can be 0 so if (g_SelectedCategory) would return false in that case... bb: but g_SelectedCategory can be 0 so if (g_SelectedCategory) would return false in that case... | |||||
for (let i = 0; i < g_MaxPlayers; ++i) | for (let i = 0; i < g_MaxPlayers; ++i) | ||||
{ | { | ||||
for (let name in g_PlayerDropdowns) | for (let name in g_PlayerDropdowns) | ||||
updateGUIDropdown(name, i); | updateGUIDropdown(name, i); | ||||
for (let name in g_PlayerMiscElements) | for (let name in g_PlayerMiscElements) | ||||
updateGUIMiscControl(name, i); | updateGUIMiscControl(name, i); | ||||
} | } | ||||
for (let name in g_MiscControls) | for (let name in g_MiscControls) | ||||
updateGUIMiscControl(name); | updateGUIMiscControl(name); | ||||
updateGameDescription(); | updateGameDescription(); | ||||
resizeMoreOptionsWindow(); | distributeSettings(); | ||||
rightAlignCancelButton(); | rightAlignCancelButton(); | ||||
updateAutocompleteEntries(); | updateAutocompleteEntries(); | ||||
g_IsInGuiUpdate = false; | g_IsInGuiUpdate = false; | ||||
// Refresh AI config page | // Refresh AI config page | ||||
if (g_LastViewedAIPlayer != -1) | if (g_LastViewedAIPlayer != -1) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 236 Lines • ▼ Show 20 Lines | text = sprintf(translate("%(time)s %(message)s"), { | ||||
"message": text | "message": text | ||||
}); | }); | ||||
g_ChatMessages.push(text); | g_ChatMessages.push(text); | ||||
Engine.GetGUIObjectByName("chatText").caption = g_ChatMessages.join("\n"); | Engine.GetGUIObjectByName("chatText").caption = g_ChatMessages.join("\n"); | ||||
} | } | ||||
function showMoreOptions(show) | |||||
{ | |||||
Engine.GetGUIObjectByName("moreOptionsFade").hidden = !show; | |||||
Engine.GetGUIObjectByName("moreOptions").hidden = !show; | |||||
} | |||||
function resetCivilizations() | function resetCivilizations() | ||||
{ | { | ||||
for (let i in g_GameAttributes.settings.PlayerData) | for (let i in g_GameAttributes.settings.PlayerData) | ||||
g_GameAttributes.settings.PlayerData[i].Civ = "random"; | g_GameAttributes.settings.PlayerData[i].Civ = "random"; | ||||
updateGameAttributes(); | updateGameAttributes(); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 153 Lines • Show Last 20 Lines |
typo