Changeset View
Standalone View
binaries/data/mods/public/gui/campaign/simple_campaign/mainmenu.js
- This file was added.
var g_SelectedLevel = null; | |||||
elexis: `var g_SelectedLevel;` since the linter complains about `= undefined` being unneeded. (`null`… | |||||
Not Done Inline ActionsGood that campaigns can come with custom GUi pages. elexis: Good that campaigns can come with custom GUi pages.
Maybe simple -> default.
Interface ->… | |||||
Not Done Inline ActionsI'm not sure we want the list interface to be the default one. I had an AOE-2 like campaign map in mind for the default. wraitii: I'm not sure we want the list interface to be the default one. I had an AOE-2 like campaign map… | |||||
var g_SavedGamesMetadata = []; | |||||
function init(data) | |||||
{ | |||||
if (!data) | |||||
{ | |||||
warn("Loading campaign menu without a campaign loaded") | |||||
return false; | |||||
} | |||||
g_CampaignID = data.ID; | |||||
g_CampaignTemplate = data.template; | |||||
g_CampaignSave = data.save; | |||||
g_CampaignData = data.data; | |||||
generateLevelList(); | |||||
selectionChanged(); | |||||
Engine.GetGUIObjectByName("mapPreview").sprite = "cropped:" + 400/512 + "," + 300/512 + ":session/icons/mappreview/nopreview.png"; | |||||
Not Done Inline ActionssetMapPreviewImage elexis: setMapPreviewImage | |||||
let gameSelection = Engine.GetGUIObjectByName("gameSelection"); | |||||
let savedGames = Engine.GetSavedGames().sort(sortDecreasingDate).filter(game => game.metadata.initAttributes && game.metadata.initAttributes.campaignData && game.metadata.initAttributes.campaignData.ID == g_CampaignID); | |||||
gameSelection.enabled = !!savedGames.length; | |||||
if (!savedGames.length) | |||||
{ | |||||
gameSelection.list = [translate("No saved games found")]; | |||||
gameSelection.selected = -1; | |||||
return; | |||||
} | |||||
// Get current game version and loaded mods | |||||
let engineInfo = Engine.GetEngineInfo(); | |||||
g_SavedGamesMetadata = savedGames.map(game => game.metadata); | |||||
gameSelection.list = savedGames.map(game => generateCampaignLabel(game.metadata, engineInfo)); | |||||
gameSelection.list_data = savedGames.map(game => game.id); | |||||
saveSelectionChanged(); | |||||
} | |||||
function generateLevelList() | |||||
{ | |||||
// TODO: remember old selection? | |||||
let selection = Engine.GetGUIObjectByName("levelSelection"); | |||||
let list = []; | |||||
for (let key in g_CampaignTemplate.Levels) | |||||
{ | |||||
let level = g_CampaignTemplate.Levels[key]; | |||||
if (!("ShowUnavailable" in g_CampaignTemplate) || !g_CampaignTemplate.ShowUnavailable && !hasRequirements(level)) | |||||
continue; | |||||
let status = ""; | |||||
let name = level.Name; | |||||
if (!hasRequirements(level)) | |||||
{ | |||||
status = "not unlocked yet"; | |||||
name = "[color=\"gray\"]" + name + "[/color]"; | |||||
Done Inline Actionstranslate elexis: translate | |||||
Not Done Inline ActionssetStringTags(caption, { "color": "gray" }) elexis: `setStringTags(caption, { "color": "gray" })` | |||||
} | |||||
list.push({ "ID" : key, "name" : name, "status" : status }); | |||||
} | |||||
list.sort((a, b) => g_CampaignTemplate.Order.indexOf(a.ID) - g_CampaignTemplate.Order.indexOf(b.ID)); | |||||
// change array of object into object of array. | |||||
list = prepareForDropdown(list); | |||||
// Push to GUI | |||||
selection.selected = -1; | |||||
selection.list_name = list.name || []; | |||||
selection.list_status = list.status || []; | |||||
// Change these last, otherwise crash | |||||
// TODO: do we need both of those? I'm unsure. | |||||
selection.list = list.ID || []; | |||||
Done Inline Actionslist and list_data come from the inherited CList whereas the other list_column name ones come from COList. elexis: list and list_data come from the inherited CList whereas the other list_column name ones come… | |||||
selection.list_data = list.ID || []; | |||||
// replaySelection.selected = replaySelection.list.findIndex(directory => directory == g_SelectedReplayDirectory); | |||||
// displayReplayDetails(); | |||||
} | |||||
Done Inline Actionsforgot that setMapPreviewImage fallbacks on its own. wraitii: forgot that setMapPreviewImage fallbacks on its own. | |||||
function displayLevelDetails(levelID) | |||||
{ | |||||
let level = g_CampaignTemplate.Levels[levelID]; | |||||
// TODO: load from map file if not present | |||||
Engine.GetGUIObjectByName("scenarioName").caption = translate(level.Name); | |||||
Engine.GetGUIObjectByName("scenarioDesc").caption = translate(level.Description); | |||||
// todo: ibidem | |||||
if (level.Preview) | |||||
Not Done Inline ActionsEngine.GetGUIObjectByName("startButton").enabled = meetsRequirements(level); elexis: Engine.GetGUIObjectByName("startButton").enabled = meetsRequirements(level); | |||||
Engine.GetGUIObjectByName("mapPreview").sprite = "cropped:" + 400/512 + "," + 300/512 + ":" + level.Preview; | |||||
else | |||||
Engine.GetGUIObjectByName("mapPreview").sprite = "cropped:" + 400/512 + "," + 300/512 + ":session/icons/mappreview/nopreview.png"; | |||||
g_SelectedLevel = levelID; | |||||
if (!hasRequirements(level)) | |||||
{ | |||||
Engine.GetGUIObjectByName("startButton").enabled = false; | |||||
return; | |||||
} | |||||
Engine.GetGUIObjectByName("startButton").enabled = true; | |||||
} | |||||
function selectionChanged() | |||||
Not Done Inline Actionssame as above elexis: same as above | |||||
{ | |||||
let selection = Engine.GetGUIObjectByName("levelSelection"); | |||||
Not Done Inline Actionslet gameSelection = Engine.GetGUIObjectByName("gameSelection"); (makes it easier to keep track of GUIObjects if the variable names correlate with the GUIObject names globally) elexis: let gameSelection = Engine.GetGUIObjectByName("gameSelection"); (makes it easier to keep track… | |||||
if (selection.selected === -1) | |||||
{ | |||||
Engine.GetGUIObjectByName("startButton").enabled = false; | |||||
Engine.GetGUIObjectByName("startButton").hidden = false; | |||||
Engine.GetGUIObjectByName("loadSavedButton").hidden = true; | |||||
return; | |||||
} | |||||
Engine.GetGUIObjectByName("loadSavedButton").hidden = true; | |||||
Engine.GetGUIObjectByName("startButton").hidden = false; | |||||
let selec = Engine.GetGUIObjectByName("gameSelection"); | |||||
selec.selected = -1; | |||||
displayLevelDetails(selection.list[selection.selected]); | |||||
} | |||||
function saveSelectionChanged() | |||||
{ | |||||
let metadata = g_SavedGamesMetadata[Engine.GetGUIObjectByName("gameSelection").selected]; | |||||
if (!metadata) | |||||
Not Done Inline ActionsWould have proposed Array function find, but why does it loop at all? elexis: Would have proposed Array function `find`, but why does it loop at all? | |||||
return; | |||||
// fetch campaign scenario metadata if present. | |||||
let scenarioID = metadata.initAttributes.campaignData.level; | |||||
let selection = Engine.GetGUIObjectByName("levelSelection"); | |||||
selection.selected = -1; | |||||
for (let level of selection.list_data) | |||||
Not Done Inline ActionsgenerateSavegameDateString to avoid duplication that is patched by some temple diff elexis: `generateSavegameDateString` to avoid duplication that is patched by some temple diff | |||||
if (level == scenarioID) | |||||
{ | |||||
displayLevelDetails(level); | |||||
break; | |||||
} | |||||
Engine.GetGUIObjectByName("loadSavedButton").hidden = false; | |||||
Engine.GetGUIObjectByName("startButton").hidden = true; | |||||
Not Done Inline ActionsShould be red as well. (Also in the future we should not just state theyre incompatible but provide an auto-launch of the needed mods if they exist) elexis: Should be red as well. (Also in the future we should not just state theyre incompatible but… | |||||
/* | |||||
Engine.GetGUIObjectByName("savedMapName").caption = translate(metadata.initAttributes.settings.Name); | |||||
Done Inline Actionsdelete, can be beautified later elexis: delete, can be beautified later | |||||
let mapData = getMapDescriptionAndPreview(metadata.initAttributes.mapType, metadata.initAttributes.map); | |||||
setMapPreviewImage("savedInfoPreview", mapData.preview); | |||||
Engine.GetGUIObjectByName("savedPlayers").caption = metadata.initAttributes.settings.PlayerData.length - 1; | |||||
Engine.GetGUIObjectByName("savedPlayedTime").caption = timeToString(metadata.gui.timeElapsed ? metadata.gui.timeElapsed : 0); | |||||
Engine.GetGUIObjectByName("savedMapType").caption = translateMapType(metadata.initAttributes.mapType); | |||||
Engine.GetGUIObjectByName("savedMapSize").caption = translateMapSize(metadata.initAttributes.settings.Size); | |||||
Engine.GetGUIObjectByName("savedVictory").caption = translateVictoryCondition(metadata.initAttributes.settings.GameType); | |||||
let caption = sprintf(translate("Mods: %(mods)s"), { "mods": metadata.mods.join(translate(", ")) }); | |||||
Not Done Inline ActionsgenerateSavegameLabel. (Reveals a bit how the patch was written) elexis: `generateSavegameLabel`. (Reveals a bit how the patch was written) | |||||
if (!hasSameMods(metadata, Engine.GetEngineInfo())) | |||||
caption = "[color=\"orange\"]" + caption + "[/color]"; | |||||
Engine.GetGUIObjectByName("savedMods").caption = caption; | |||||
Engine.GetGUIObjectByName("savedPlayersNames").caption = formatPlayerInfo( | |||||
metadata.initAttributes.settings.PlayerData, | |||||
metadata.gui.states | |||||
);*/ | |||||
} | |||||
function generateCampaignLabel(metadata, engineInfo) | |||||
Not Done Inline ActionsApplication exit is in the main menu, not in every menu elexis: Application exit is in the main menu, not in every menu | |||||
{ | |||||
let dateTimeString = Engine.FormatMillisecondsIntoDateString(metadata.time*1000, translate("yyyy-MM-dd HH:mm:ss")); | |||||
let dateString = sprintf(translate("\\[%(date)s]"), { "date": dateTimeString }); | |||||
if (engineInfo) | |||||
{ | |||||
if (!hasSameSavegameVersion(metadata, engineInfo) || !hasSameEngineVersion(metadata, engineInfo)) | |||||
dateString = "[color=\"red\"]" + dateString + "[/color]"; | |||||
else if (!hasSameMods(metadata, engineInfo)) | |||||
dateString = "[color=\"orange\"]" + dateString + "[/color]"; | |||||
} | |||||
return sprintf( | |||||
Not Done Inline Actionstype was removed recently. Going through the gamesetup is healthy as it avoids 10 gamesetup rewrites. elexis: `type` was removed recently.
Going through the gamesetup is healthy as it avoids 10 gamesetup… | |||||
metadata.description ? | |||||
translate("%(dateString)s %(level)s - %(description)s") : | |||||
translate("%(dateString)s %(level)s"), | |||||
{ | |||||
"dateString": dateString, | |||||
"level": metadata.initAttributes.campaignData.template.Levels[metadata.initAttributes.campaignData.level].Name, | |||||
"description": metadata.description || "" | |||||
} | |||||
); | |||||
} | |||||
function exitCampaignMode(exitGame = false) | |||||
{ | |||||
// TODO: should this be here? | |||||
saveCurrentCampaign(); | |||||
Not Done Inline ActionsIt's a design question when to save things. Not sure if saving should be enforced in some cases, it sounds better to only save the campaign state when requested by the user. elexis: It's a design question when to save things. Not sure if saving should be enforced in some cases… | |||||
Not Done Inline ActionsA dialog asking whether the player would like to save would be nice; though just always saving works just as well for the simple interface. leper: A dialog asking whether the player would like to save would be nice; though just always saving… | |||||
Not Done Inline Actionsrephrase the TODO comment then elexis: rephrase the TODO comment then | |||||
if (exitGame) | |||||
{ | |||||
messageBox( | |||||
400, 200, | |||||
translate("Are you sure you want to quit 0 A.D.?"), | |||||
translate("Confirmation"), | |||||
[translate("No"), translate("Yes")], | |||||
[null, Engine.Exit] | |||||
); | |||||
return; | |||||
} | |||||
Engine.SwitchGuiPage("page_pregame.xml", {}); | |||||
} |
var g_SelectedLevel; since the linter complains about = undefined being unneeded. (null has a use case once its meaning differs from the default undefined.)