diff --git a/binaries/data/mods/public/gui/common/functions_utility.js b/binaries/data/mods/public/gui/common/functions_utility.js index 59dc8bfef7..ff6c4fb65e 100644 --- a/binaries/data/mods/public/gui/common/functions_utility.js +++ b/binaries/data/mods/public/gui/common/functions_utility.js @@ -267,13 +267,12 @@ function timeToString(time) function removeDupes(array) { - for (var i = 0; i < array.length; i++) + // loop backwards to make splice operations cheaper + var i = array.length; + while (i--) { - if (array.indexOf(array[i]) < i) - { + if (array.indexOf(array[i]) != i) array.splice(i, 1); - i--; - } } } diff --git a/binaries/data/mods/public/gui/session/selection_panels.js b/binaries/data/mods/public/gui/session/selection_panels.js index fd9e4d3479..6965cbb923 100644 --- a/binaries/data/mods/public/gui/session/selection_panels.js +++ b/binaries/data/mods/public/gui/session/selection_panels.js @@ -83,8 +83,9 @@ g_SelectionPanels.Barter = { }, "setTooltip": function(data) { - data.button.Buy.tooltip = sprintf(translate("Buy %(resource)s"), {"resource": translate(data.item)}); - data.button.Sell.tooltip = sprintf(translate("Sell %(resource)s"), {"resource": translate(data.item)}); + var resource = getLocalizedResourceName("WithinSentence", data.item); + data.button.Buy.tooltip = sprintf(translate("Buy %(resource)s"), {"resource": resource}); + data.button.Sell.tooltip = sprintf(translate("Sell %(resource)s"), {"resource": resource}); }, "setAction": function(data) { @@ -127,7 +128,16 @@ g_SelectionPanels.Command = { }, "getItems": function(unitEntState) { - return getEntityCommandsList(unitEntState) + var commands = []; + for (var c in entityCommands) + { + var info = g_EntityCommands[c].getInfo(entState); + if (!info) + continue; + info.name = c; + commands.push(info); + } + return commands; }, "setTooltip": function(data) { @@ -546,7 +556,9 @@ g_SelectionPanels.Queue = { var numRows = Math.ceil(numberOfItems / rowLength); var panel = Engine.GetGUIObjectByName("unitQueuePanel"); var size = panel.size; - size.top = (UNIT_PANEL_BASE - ((numRows-1)*UNIT_PANEL_HEIGHT)); + var buttonSize = Engine.GetGUIObjectByName("unitQueueButton[0]").size.bottom; + var margin = 4; + size.top = size.bottom - numRows*buttonSize - (numRows+2)*margin; panel.size = size; }, "addData": function(data) diff --git a/binaries/data/mods/public/gui/session/selection_panels_helpers.js b/binaries/data/mods/public/gui/session/selection_panels_helpers.js new file mode 100644 index 0000000000..acf8a01c42 --- /dev/null +++ b/binaries/data/mods/public/gui/session/selection_panels_helpers.js @@ -0,0 +1,143 @@ +// Constants +// Barter constants +const BARTER_RESOURCE_AMOUNT_TO_SELL = 100; +const BARTER_BUNCH_MULTIPLIER = 5; +const BARTER_RESOURCES = ["food", "wood", "stone", "metal"]; +const BARTER_ACTIONS = ["Sell", "Buy"]; + +// Gate constants +const GATE_ACTIONS = ["lock", "unlock"]; + +// ============================================== +// BARTER HELPERS +// Resources to sell on barter panel +var g_barterSell = "food"; + +// FORMATION HELPERS +// Check if the selection can move into formation, and cache the result +function canMoveSelectionIntoFormation(formationTemplate) +{ + if (!(formationTemplate in g_canMoveIntoFormation)) + { + g_canMoveIntoFormation[formationTemplate] = Engine.GuiInterfaceCall("CanMoveEntsIntoFormation", { + "ents": g_Selection.toList(), + "formationTemplate": formationTemplate + }); + } + return g_canMoveIntoFormation[formationTemplate]; +} + +// ============================================== +// STANCE HELPERS + +function getStanceDisplayName(name) +{ + var displayName; + switch(name) + { + case "violent": + displayName = translateWithContext("stance", "Violent"); + break; + case "aggressive": + displayName = translateWithContext("stance", "Aggressive"); + break; + case "passive": + displayName = translateWithContext("stance", "Passive"); + break; + case "defensive": + displayName = translateWithContext("stance", "Defensive"); + break; + case "standground": + displayName = translateWithContext("stance", "Standground"); + break; + default: + warn(sprintf("Internationalization: Unexpected stance found with code ‘%(stance)s’. This stance must be internationalized.", { stance: name })); + displayName = name; + break; + } + return displayName; +} + +// ============================================== +// TRAINING / CONSTRUCTION HELPERS +/** + * Format entity count/limit message for the tooltip + */ +function formatLimitString(trainEntLimit, trainEntCount, trainEntLimitChangers) +{ + if (trainEntLimit == undefined) + return ""; + var text = "\n\n" + sprintf(translate("Current Count: %(count)s, Limit: %(limit)s."), { count: trainEntCount, limit: trainEntLimit }); + if (trainEntCount >= trainEntLimit) + text = "[color=\"red\"]" + text + "[/color]"; + for (var c in trainEntLimitChangers) + { + if (trainEntLimitChangers[c] > 0) + text += "\n" + sprintf(translate("%(changer)s enlarges the limit with %(change)s."), { changer: translate(c), change: trainEntLimitChangers[c] }); + else if (trainEntLimitChangers[c] < 0) + text += "\n" + sprintf(translate("%(changer)s lessens the limit with %(change)s."), { changer: translate(c), change: (-trainEntLimitChangers[c]) }); + } + return text; +} + +/** + * Format batch training string for the tooltip + * Examples: + * buildingsCountToTrainFullBatch = 1, fullBatchSize = 5, remainderBatch = 0: + * "Shift-click to train 5" + * buildingsCountToTrainFullBatch = 2, fullBatchSize = 5, remainderBatch = 0: + * "Shift-click to train 10 (2*5)" + * buildingsCountToTrainFullBatch = 1, fullBatchSize = 15, remainderBatch = 12: + * "Shift-click to train 27 (15 + 12)" + */ +function formatBatchTrainingString(buildingsCountToTrainFullBatch, fullBatchSize, remainderBatch) +{ + var totalBatchTrainingCount = buildingsCountToTrainFullBatch * fullBatchSize + remainderBatch; + // Don't show the batch training tooltip if either units of this type can't be trained at all + // or only one unit can be trained + if (totalBatchTrainingCount < 2) + return ""; + var batchTrainingString = ""; + var fullBatchesString = ""; + if (buildingsCountToTrainFullBatch > 0) + { + if (buildingsCountToTrainFullBatch > 1) + fullBatchesString = sprintf(translate("%(buildings)s*%(batchSize)s"), { + buildings: buildingsCountToTrainFullBatch, + batchSize: fullBatchSize + }); + else + fullBatchesString = fullBatchSize; + } + var remainderBatchString = remainderBatch > 0 ? remainderBatch : ""; + var batchDetailsString = ""; + var action = "[font=\"sans-bold-13\"]" + translate("Shift-click") + "[/font][font=\"sans-13\"]" + + // We need to display the batch details part if there is either more than + // one building with full batch or one building with the full batch and + // another with a partial batch + if (buildingsCountToTrainFullBatch > 1 || + (buildingsCountToTrainFullBatch == 1 && remainderBatch > 0)) + { + if (remainderBatch > 0) + return "\n[font=\"sans-13\"]" + sprintf(translate("%(action)s to train %(number)s (%(fullBatch)s + %(remainderBatch)s)."), { + action: action, + number: totalBatchTrainingCount, + fullBatch: fullBatchesString, + remainderBatch: remainderBatch + }) + "[/font]"; + + return "\n[font=\"sans-13\"]" + sprintf(translate("%(action)s to train %(number)s (%(fullBatch)s)."), { + action: action, + number: totalBatchTrainingCount, + fullBatch: fullBatchesString + }) + "[/font]"; + } + + return "\n[font=\"sans-13\"]" + sprintf(translate("%(action)s to train %(number)s."), { + action: action, + number: totalBatchTrainingCount + }) + "[/font]"; +} + + diff --git a/binaries/data/mods/public/gui/session/unit_actions.js b/binaries/data/mods/public/gui/session/unit_actions.js index 6c386b1f4b..7dc7d51583 100644 --- a/binaries/data/mods/public/gui/session/unit_actions.js +++ b/binaries/data/mods/public/gui/session/unit_actions.js @@ -625,7 +625,7 @@ var unitActions = * Info and actions for the entity commands * Currently displayed in the bottom of the central pane */ -var entityCommands = +var g_EntityCommands = { // Unload "unload-all": { diff --git a/binaries/data/mods/public/gui/session/unit_commands.js b/binaries/data/mods/public/gui/session/unit_commands.js index ce532c1e44..ea162bb5e7 100644 --- a/binaries/data/mods/public/gui/session/unit_commands.js +++ b/binaries/data/mods/public/gui/session/unit_commands.js @@ -1,43 +1,6 @@ -// Panel types -const SELECTION = "Selection"; -const QUEUE = "Queue"; -const GARRISON = "Garrison"; -const FORMATION = "Formation"; -const TRAINING = "Training"; -const RESEARCH = "Research"; -const CONSTRUCTION = "Construction"; -const COMMAND = "Command"; -const STANCE = "Stance"; -const GATE = "Gate"; -const PACK = "Pack"; - -// Constants -const UNIT_PANEL_BASE = -52; // QUEUE: The offset above the main panel (will often be negative) -const UNIT_PANEL_HEIGHT = 44; // QUEUE: The height needed for a row of buttons - -// Trading constants -const TRADING_RESOURCES = [ - markForTranslation("food"), - markForTranslation("wood"), - markForTranslation("stone"), - markForTranslation("metal") -]; - -// Barter constants -const BARTER_RESOURCE_AMOUNT_TO_SELL = 100; -const BARTER_BUNCH_MULTIPLIER = 5; -const BARTER_RESOURCES = ["food", "wood", "stone", "metal"]; -const BARTER_ACTIONS = ["Sell", "Buy"]; - -// Gate constants -const GATE_ACTIONS = ["lock", "unlock"]; - // The number of currently visible buttons (used to optimise showing/hiding) var g_unitPanelButtons = {"Selection": 0, "Queue": 0, "Formation": 0, "Garrison": 0, "Training": 0, "Research": 0, "Barter": 0, "Construction": 0, "Command": 0, "Stance": 0, "Gate": 0, "Pack": 0}; -// Resources to sell on barter panel -var g_barterSell = "food"; - /** * Set the position of a panel object according to the index, * from left to right, from top to bottom. @@ -61,119 +24,12 @@ function setPanelObjectPosition(object, index, rowLength, vMargin = 1, hMargin = } /** - * Format entity count/limit message for the tooltip - */ -function formatLimitString(trainEntLimit, trainEntCount, trainEntLimitChangers) -{ - if (trainEntLimit == undefined) - return ""; - var text = "\n\n" + sprintf(translate("Current Count: %(count)s, Limit: %(limit)s."), { count: trainEntCount, limit: trainEntLimit }); - if (trainEntCount >= trainEntLimit) - text = "[color=\"red\"]" + text + "[/color]"; - for (var c in trainEntLimitChangers) - { - if (trainEntLimitChangers[c] > 0) - text += "\n" + sprintf(translate("%(changer)s enlarges the limit with %(change)s."), { changer: translate(c), change: trainEntLimitChangers[c] }); - else if (trainEntLimitChangers[c] < 0) - text += "\n" + sprintf(translate("%(changer)s lessens the limit with %(change)s."), { changer: translate(c), change: (-trainEntLimitChangers[c]) }); - } - return text; -} - -/** - * Format batch training string for the tooltip - * Examples: - * buildingsCountToTrainFullBatch = 1, fullBatchSize = 5, remainderBatch = 0: - * "Shift-click to train 5" - * buildingsCountToTrainFullBatch = 2, fullBatchSize = 5, remainderBatch = 0: - * "Shift-click to train 10 (2*5)" - * buildingsCountToTrainFullBatch = 1, fullBatchSize = 15, remainderBatch = 12: - * "Shift-click to train 27 (15 + 12)" - */ -function formatBatchTrainingString(buildingsCountToTrainFullBatch, fullBatchSize, remainderBatch) -{ - var totalBatchTrainingCount = buildingsCountToTrainFullBatch * fullBatchSize + remainderBatch; - // Don't show the batch training tooltip if either units of this type can't be trained at all - // or only one unit can be trained - if (totalBatchTrainingCount < 2) - return ""; - var batchTrainingString = ""; - var fullBatchesString = ""; - if (buildingsCountToTrainFullBatch > 0) - { - if (buildingsCountToTrainFullBatch > 1) - fullBatchesString = sprintf(translate("%(buildings)s*%(batchSize)s"), { - buildings: buildingsCountToTrainFullBatch, - batchSize: fullBatchSize - }); - else - fullBatchesString = fullBatchSize; - } - var remainderBatchString = remainderBatch > 0 ? remainderBatch : ""; - var batchDetailsString = ""; - var action = "[font=\"sans-bold-13\"]" + translate("Shift-click") + "[/font][font=\"sans-13\"]" - - // We need to display the batch details part if there is either more than - // one building with full batch or one building with the full batch and - // another with a partial batch - if (buildingsCountToTrainFullBatch > 1 || - (buildingsCountToTrainFullBatch == 1 && remainderBatch > 0)) - { - if (remainderBatch > 0) - return "\n[font=\"sans-13\"]" + sprintf(translate("%(action)s to train %(number)s (%(fullBatch)s + %(remainderBatch)s)."), { - action: action, - number: totalBatchTrainingCount, - fullBatch: fullBatchesString, - remainderBatch: remainderBatch - }) + "[/font]"; - - return "\n[font=\"sans-13\"]" + sprintf(translate("%(action)s to train %(number)s (%(fullBatch)s)."), { - action: action, - number: totalBatchTrainingCount, - fullBatch: fullBatchesString - }) + "[/font]"; - } - - return "\n[font=\"sans-13\"]" + sprintf(translate("%(action)s to train %(number)s."), { - action: action, - number: totalBatchTrainingCount - }) + "[/font]"; -} - -function getStanceDisplayName(name) -{ - var displayName; - switch(name) - { - case "violent": - displayName = translateWithContext("stance", "Violent"); - break; - case "aggressive": - displayName = translateWithContext("stance", "Aggressive"); - break; - case "passive": - displayName = translateWithContext("stance", "Passive"); - break; - case "defensive": - displayName = translateWithContext("stance", "Defensive"); - break; - case "standground": - displayName = translateWithContext("stance", "Standground"); - break; - default: - warn(sprintf("Internationalization: Unexpected stance found with code ‘%(stance)s’. This stance must be internationalized.", { stance: name })); - displayName = name; - break; - } - return displayName; -} - -/** - * Helper function for updateUnitCommands; sets up "unit panels" (i.e. panels with rows of icons) for the currently selected - * unit. + * Helper function for updateUnitCommands; sets up "unit panels" + * (i.e. panels with rows of icons) for the currently selected unit. * - * @param guiName Short identifier string of this panel; see constants defined at the top of this file. + * @param guiName Short identifier string of this panel. See g_SelectionPanels. * @param unitEntState Entity state of the (first) selected unit. + * @param payerState Player state */ function setupUnitPanel(guiName, unitEntState, playerState) { @@ -301,12 +157,15 @@ function resourcesToAlphaMask(neededResources) } /** - * Updates the right hand side "Unit Commands" panel. Runs in the main session loop via updateSelectionDetails(). - * Delegates to setupUnitPanel to set up individual subpanels, appropriately activated depending on the selected - * unit's state. + * Updates the selection panels where buttons are supposed to + * depend on the context. + * Runs in the main session loop via updateSelectionDetails(). + * Delegates to setupUnitPanel to set up individual subpanels, + * appropriately activated depending on the selected unit's state. * * @param entState Entity state of the (first) selected unit. - * @param supplementalDetailsPanel Reference to the "supplementalSelectionDetails" GUI Object + * @param supplementalDetailsPanel Reference to the + * "supplementalSelectionDetails" GUI Object * @param commandsPanel Reference to the "commandsPanel" GUI Object * @param selection Array of currently selected entity IDs. */ @@ -343,7 +202,7 @@ function updateUnitCommands(entState, supplementalDetailsPanel, commandsPanel, s { // TODO if there's a second panel needed for a different player // we should consider adding the players list to g_SelectionPanels - setupUnitPanel(GARRISON, entState, playerState); + setupUnitPanel("Garrison", entState, playerState); if (g_SelectionPanels["Garrison"].used) supplementalDetailsPanel.hidden = false; else @@ -419,33 +278,6 @@ function getAllBuildableEntitiesFromSelection() return g_allBuildableEntities; } -// Check if the selection can move into formation, and cache the result -function canMoveSelectionIntoFormation(formationTemplate) -{ - if (!(formationTemplate in g_canMoveIntoFormation)) - { - g_canMoveIntoFormation[formationTemplate] = Engine.GuiInterfaceCall("CanMoveEntsIntoFormation", { - "ents": g_Selection.toList(), - "formationTemplate": formationTemplate - }); - } - return g_canMoveIntoFormation[formationTemplate]; -} - -function getVisibleEntityClassesFormatted(template) -{ - var r = "" - if (template.visibleIdentityClasses && template.visibleIdentityClasses.length) - { - r += "\n[font=\"sans-bold-13\"]" + translate("Classes:") + "[/font] "; - r += "[font=\"sans-13\"]" + translate(template.visibleIdentityClasses[0]) ; - for (var c = 1; c < template.visibleIdentityClasses.length; c++) - r += ", " + translate(template.visibleIdentityClasses[c]); - r += "[/font]"; - } - return r; -} - function getNumberOfRightPanelButtons() { var sum = 0; diff --git a/binaries/data/mods/public/gui/session/utility_functions.js b/binaries/data/mods/public/gui/session/utility_functions.js index 07ddea36dd..37b3050f34 100644 --- a/binaries/data/mods/public/gui/session/utility_functions.js +++ b/binaries/data/mods/public/gui/session/utility_functions.js @@ -12,9 +12,9 @@ const COST_DISPLAY_NAMES = { "time": "[icon=\"iconTime\"]" }; -//-------------------------------- -------------------------------- -------------------------------- +//-------------------------------- -------------------------------- // Utility functions -//-------------------------------- -------------------------------- -------------------------------- +//-------------------------------- -------------------------------- function toTitleCase(word) { @@ -32,6 +32,14 @@ function toTitleCase(word) return word; } +function rgbToGuiColor(color) +{ + return color.r + " " + color.g + " " + color.b; +} + +//=============================================== +// Player functions + // Get the basic player data function getPlayerData(playerAssignments) { @@ -89,11 +97,6 @@ function getPlayerData(playerAssignments) return players; } -function rgbToGuiColor(color) -{ - return color.r + " " + color.g + " " + color.b; -} - function findGuidForPlayerID(playerAssignments, player) { for (var playerGuid in playerAssignments) @@ -124,8 +127,11 @@ function updatePlayerDataRemove(players, hostGuid) player.offline = true; } +//=============================================== +// Identity functions function hasClass(entState, className) { + // note: use the functions in globalscripts/Templates.js for more versatile matching if (entState.identity) { var classes = entState.identity.classes; @@ -135,6 +141,8 @@ function hasClass(entState, className) return false; } +//=============================================== +// Atack/Armour functions // For the unit details panel function damageValues(dmg) { @@ -284,23 +292,58 @@ function armorTypesToText(dmg) return dmgArray.join("[font=\"sans-12\"]" + translate(", ") + "[/font]"); } -function getEntityCommandsList(entState) +function getAttackTypeLabel(type) { - var commands = []; - for (var c in entityCommands) - { - var info = entityCommands[c].getInfo(entState); - if (!info) - continue; - info.name = c; - commands.push(info); - } - return commands; + if (type === "Charge") return translate("Charge Attack:"); + if (type === "Melee") return translate("Melee Attack:"); + if (type === "Ranged") return translate("Ranged Attack:"); + + warn(sprintf("Internationalization: Unexpected attack type found with code ‘%(attackType)s’. This attack type must be internationalized.", { attackType: type })); + return translate("Attack:"); } +function getEntityAttack(template) +{ + var attacks = []; + if (template.attack) + { + // Don't show slaughter attack + delete template.attack['Slaughter']; + for (var type in template.attack) + { + if (type == "Charge") + continue; // Charging isn't implemented yet and shouldn't be displayed. + var attack = ""; + var attackLabel = "[font=\"sans-bold-13\"]" + getAttackTypeLabel(type) + "[/font]"; + if (type == "Ranged") + { + // Show max attack range if ranged attack, also convert to tiles (4m per tile) + attack = sprintf(translate("%(attackLabel)s %(damageTypes)s, %(rangeLabel)s %(range)s"), { + attackLabel: attackLabel, + damageTypes: damageTypesToText(template.attack[type]), + rangeLabel: "[font=\"sans-bold-13\"]" + translate("Range:") + "[/font]", + range: Math.round(template.attack[type].maxRange) + "[font=\"sans-10\"][color=\"orange\"] " + translate("meters") + "[/color][/font]" + }); + } + else + { + attack = sprintf(translate("%(attackLabel)s %(damageTypes)s"), { + attackLabel: attackLabel, + damageTypes: damageTypesToText(template.attack[type]) + }); + } + attacks.push(attack); + } + } + return attacks.join(translate(", ")); +} + +// ============================================== +// Cost + /** - * Translates a cost component identifier as they are used internally (e.g. "population", "food", etc.) to proper - * display names. + * Translates a cost component identifier as they are used internally + * (e.g. "population", "food", etc.) to proper display names. */ function getCostComponentDisplayName(costComponentName) { @@ -474,58 +517,8 @@ function getNeededResourcesTooltip(resources) return "\n\n[font=\"sans-bold-13\"][color=\"red\"]" + translate("Insufficient resources:") + "[/color][/font]\n" + formatted.join(translate(" ")); } -function getEntitySpeed(template) -{ - var speed = ""; - if (template.speed) - { - var label = "[font=\"sans-bold-13\"]" + translate("Speed:") + "[/font]"; - var speeds = []; - if (template.speed.walk) - speeds.push(sprintf(translate("%(speed)s %(movementType)s"), { speed: template.speed.walk, movementType: "[font=\"sans-10\"][color=\"orange\"]" + translate("Walk") + "[/color][/font]"})); - if (template.speed.run) - speeds.push(sprintf(translate("%(speed)s %(movementType)s"), { speed: template.speed.run, movementType: "[font=\"sans-10\"][color=\"orange\"]" + translate("Run") + "[/color][/font]"})); - - speed = sprintf(translate("%(label)s %(speeds)s"), { label: label, speeds: speeds.join(translate(", ")) }) - } - return speed; -} - -function getEntityAttack(template) -{ - var attacks = []; - if (template.attack) - { - // Don't show slaughter attack - delete template.attack['Slaughter']; - for (var type in template.attack) - { - if (type == "Charge") - continue; // Charging isn't implemented yet and shouldn't be displayed. - var attack = ""; - var attackLabel = "[font=\"sans-bold-13\"]" + getAttackTypeLabel(type) + "[/font]"; - if (type == "Ranged") - { - // Show max attack range if ranged attack, also convert to tiles (4m per tile) - attack = sprintf(translate("%(attackLabel)s %(damageTypes)s, %(rangeLabel)s %(range)s"), { - attackLabel: attackLabel, - damageTypes: damageTypesToText(template.attack[type]), - rangeLabel: "[font=\"sans-bold-13\"]" + translate("Range:") + "[/font]", - range: Math.round(template.attack[type].maxRange) + "[font=\"sans-10\"][color=\"orange\"] " + translate("meters") + "[/color][/font]" - }); - } - else - { - attack = sprintf(translate("%(attackLabel)s %(damageTypes)s"), { - attackLabel: attackLabel, - damageTypes: damageTypesToText(template.attack[type]) - }); - } - attacks.push(attack); - } - } - return attacks.join(translate(", ")); -} +// ============================================== +// IDENTITY INFO function getEntityNames(template) { @@ -567,6 +560,20 @@ function getEntityNamesFormatted(template) return names; } +function getVisibleEntityClassesFormatted(template) +{ + var r = "" + if (template.visibleIdentityClasses && template.visibleIdentityClasses.length) + { + r += "\n[font=\"sans-bold-13\"]" + translate("Classes:") + "[/font] "; + r += "[font=\"sans-13\"]" + translate(template.visibleIdentityClasses[0]) ; + for (var c = 1; c < template.visibleIdentityClasses.length; c++) + r += ", " + translate(template.visibleIdentityClasses[c]); + r += "[/font]"; + } + return r; +} + function getEntityRankedName(entState) { var template = GetTemplateData(entState.template) @@ -589,6 +596,25 @@ function getRankIconSprite(entState) return ""; } +// ============================================== +// OTHER INFO +function getEntitySpeed(template) +{ + var speed = ""; + if (template.speed) + { + var label = "[font=\"sans-bold-13\"]" + translate("Speed:") + "[/font]"; + var speeds = []; + if (template.speed.walk) + speeds.push(sprintf(translate("%(speed)s %(movementType)s"), { speed: template.speed.walk, movementType: "[font=\"sans-10\"][color=\"orange\"]" + translate("Walk") + "[/color][/font]"})); + if (template.speed.run) + speeds.push(sprintf(translate("%(speed)s %(movementType)s"), { speed: template.speed.run, movementType: "[font=\"sans-10\"][color=\"orange\"]" + translate("Run") + "[/color][/font]"})); + + speed = sprintf(translate("%(label)s %(speeds)s"), { label: label, speeds: speeds.join(translate(", ")) }) + } + return speed; +} + /** * Returns a message with the details of the trade gain. */ @@ -619,15 +645,7 @@ function getTradingTooltip(gain) return tooltip; } -function getAttackTypeLabel(type) -{ - if (type === "Charge") return translate("Charge Attack:"); - if (type === "Melee") return translate("Melee Attack:"); - if (type === "Ranged") return translate("Ranged Attack:"); - warn(sprintf("Internationalization: Unexpected attack type found with code ‘%(attackType)s’. This attack type must be internationalized.", { attackType: type })); - return translate("Attack:"); -} /** * Returns the entity itself except when garrisoned where it returns its garrisonHolder @@ -642,81 +660,77 @@ function getEntityOrHolder(ent) return ent; } + function getLocalizedResourceName(resourceCode, context) { - if (context == "firstWord") - { - switch(resourceCode) - { - // Translation: Word as used at the beginning of a sentence or as a single-word sentence. - case "food": return translateWithContext("firstWord", "Food"); - // Translation: Word as used at the beginning of a sentence or as a single-word sentence. - case "meat": return translateWithContext("firstWord", "Meat"); - // Translation: Word as used at the beginning of a sentence or as a single-word sentence. - case "metal": return translateWithContext("firstWord", "Metal"); - // Translation: Word as used at the beginning of a sentence or as a single-word sentence. - case "ore": return translateWithContext("firstWord", "Ore"); - // Translation: Word as used at the beginning of a sentence or as a single-word sentence. - case "rock": return translateWithContext("firstWord", "Rock"); - // Translation: Word as used at the beginning of a sentence or as a single-word sentence. - case "ruins": return translateWithContext("firstWord", "Ruins"); - // Translation: Word as used at the beginning of a sentence or as a single-word sentence. - case "stone": return translateWithContext("firstWord", "Stone"); - // Translation: Word as used at the beginning of a sentence or as a single-word sentence. - case "treasure": return translateWithContext("firstWord", "Treasure"); - // Translation: Word as used at the beginning of a sentence or as a single-word sentence. - case "tree": return translateWithContext("firstWord", "Tree"); - // Translation: Word as used at the beginning of a sentence or as a single-word sentence. - case "wood": return translateWithContext("firstWord", "Wood"); - // Translation: Word as used at the beginning of a sentence or as a single-word sentence. - case "fruit": return translateWithContext("firstWord", "Fruit"); - // Translation: Word as used at the beginning of a sentence or as a single-word sentence. - case "grain": return translateWithContext("firstWord", "Grain"); - // Translation: Word as used at the beginning of a sentence or as a single-word sentence. - case "fish": return translateWithContext("firstWord", "Fish"); - default: - warn(sprintf("Internationalization: Unexpected resource type found with code ‘%(resource)s’. This resource type must be internationalized.", { resource: resourceCode })); - return resourceCode; // It should never get here. - } - } - else if (context == "withinSentence") - { - switch(resourceCode) - { - // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language). - case "food": return translateWithContext("withinSentence", "Food"); - // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language). - case "meat": return translateWithContext("withinSentence", "Meat"); - // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language). - case "metal": return translateWithContext("withinSentence", "Metal"); - // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language). - case "ore": return translateWithContext("withinSentence", "Ore"); - // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language). - case "rock": return translateWithContext("withinSentence", "Rock"); - // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language). - case "ruins": return translateWithContext("withinSentence", "Ruins"); - // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language). - case "stone": return translateWithContext("withinSentence", "Stone"); - // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language). - case "treasure": return translateWithContext("withinSentence", "Treasure"); - // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language). - case "tree": return translateWithContext("withinSentence", "Tree"); - // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language). - case "wood": return translateWithContext("withinSentence", "Wood"); - // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language). - case "fruit": return translateWithContext("withinSentence", "Fruit"); - // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language). - case "grain": return translateWithContext("withinSentence", "Grain"); - // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language). - case "fish": return translateWithContext("withinSentence", "Fish"); - default: - warn(sprintf("Internationalization: Unexpected resource type found with code ‘%(resource)s’. This resource type must be internationalized.", { resource: resourceCode })); - return resourceCode; // It should never get here. - } - } - else - { - warn(sprintf("Internationalization: Unexpected context for resource type localization found: ‘%(context)s’. This context is not supported.", { context: context })); - return resourceCode; // It should never get here. - } + if (!context in localisedResourceNames) + { + warn("Internationalization: Unexpected context for resource type localization found: ‘" + context + "’. This context is not supported."); + return resourceCode; + } + if (!resourceCode in localisedResourceNames[context]) + { + warn("Internationalization: Unexpected resource type found with code ‘" + resourceCode + ". This resource type must be internationalized."); + return resourceCode; + } + return localisedResourceNames[context][resourceCode]; } + +var localisedResourceNames = {}; +localisedResourceNames.firstWord = { + // Translation: Word as used at the beginning of a sentence or as a single-word sentence. + "food": translateWithContext("firstWord", "Food"), + // Translation: Word as used at the beginning of a sentence or as a single-word sentence. + "meat": translateWithContext("firstWord", "Meat"), + // Translation: Word as used at the beginning of a sentence or as a single-word sentence. + "metal": translateWithContext("firstWord", "Metal"), + // Translation: Word as used at the beginning of a sentence or as a single-word sentence. + "ore": translateWithContext("firstWord", "Ore"), + // Translation: Word as used at the beginning of a sentence or as a single-word sentence. + "rock": translateWithContext("firstWord", "Rock"), + // Translation: Word as used at the beginning of a sentence or as a single-word sentence. + "ruins": translateWithContext("firstWord", "Ruins"), + // Translation: Word as used at the beginning of a sentence or as a single-word sentence. + "stone": translateWithContext("firstWord", "Stone"), + // Translation: Word as used at the beginning of a sentence or as a single-word sentence. + "treasure": translateWithContext("firstWord", "Treasure"), + // Translation: Word as used at the beginning of a sentence or as a single-word sentence. + "tree": translateWithContext("firstWord", "Tree"), + // Translation: Word as used at the beginning of a sentence or as a single-word sentence. + "wood": translateWithContext("firstWord", "Wood"), + // Translation: Word as used at the beginning of a sentence or as a single-word sentence. + "fruit": translateWithContext("firstWord", "Fruit"), + // Translation: Word as used at the beginning of a sentence or as a single-word sentence. + "grain": translateWithContext("firstWord", "Grain"), + // Translation: Word as used at the beginning of a sentence or as a single-word sentence. + "fish": translateWithContext("firstWord", "Fish"), +}; + +localisedResourceNames.WithinSentence = { + // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language). + "food": translateWithContext("withinSentence", "Food"), + // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language). + "meat": translateWithContext("withinSentence", "Meat"), + // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language). + "metal": translateWithContext("withinSentence", "Metal"), + // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language). + "ore": translateWithContext("withinSentence", "Ore"), + // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language). + "rock": translateWithContext("withinSentence", "Rock"), + // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language). + "ruins": translateWithContext("withinSentence", "Ruins"), + // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language). + "stone": translateWithContext("withinSentence", "Stone"), + // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language). + "treasure": translateWithContext("withinSentence", "Treasure"), + // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language). + "tree": translateWithContext("withinSentence", "Tree"), + // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language). + "wood": translateWithContext("withinSentence", "Wood"), + // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language). + "fruit": translateWithContext("withinSentence", "Fruit"), + // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language). + "grain": translateWithContext("withinSentence", "Grain"), + // Translation: Word as used in the middle of a sentence (which may require using lowercase for your language). + "fish": translateWithContext("withinSentence", "Fish"), +};