Make the barter panel uniform with the others, clean up more gui code.
This was SVN commit r15375.
This commit is contained in:
parent
ce3b11a3fe
commit
013ab4bda7
@ -203,6 +203,11 @@ function translateObjectKeys(object, keys) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function is used by the extract-messages tool.
|
||||
* So it may only be used on a plain string,
|
||||
* it won't have any effect on a calculated string.
|
||||
*/
|
||||
function markForTranslation(message) {
|
||||
return message;
|
||||
}
|
||||
|
@ -285,7 +285,7 @@ function determineAction(x, y, fromMinimap)
|
||||
// if two actions are possible, the first one is taken
|
||||
// so the most specific should appear first
|
||||
var actions = Object.keys(unitActions).slice();
|
||||
actions.sort(function(a, b) {return unitActions[a].specificness > unitActions[b].specificness;});
|
||||
actions.sort(function(a, b) {return unitActions[a].specificness - unitActions[b].specificness;});
|
||||
|
||||
var actionInfo = undefined;
|
||||
if (preSelectedAction != ACTION_NONE)
|
||||
@ -1195,7 +1195,7 @@ function handleMinimapEvent(target)
|
||||
// @param buildTemplate Template name of the entity the user wants to build
|
||||
function startBuildingPlacement(buildTemplate, playerState)
|
||||
{
|
||||
if(getEntityLimitAndCount(playerState, buildTemplate)[2] == 0)
|
||||
if(getEntityLimitAndCount(playerState, buildTemplate).canBeAddedCount == 0)
|
||||
return;
|
||||
|
||||
// TODO: we should clear any highlight selection rings here. If the mouse was over an entity before going onto the GUI
|
||||
@ -1314,24 +1314,26 @@ function getBuildingsWhichCanTrainEntity(entitiesToCheck, trainEntType)
|
||||
|
||||
function getEntityLimitAndCount(playerState, entType)
|
||||
{
|
||||
var r = {
|
||||
"entLimit": undefined,
|
||||
"entCount": undefined,
|
||||
"entLimitChangers": undefined,
|
||||
"canBeAddedCount": undefined
|
||||
};
|
||||
var template = GetTemplateData(entType);
|
||||
var entCategory = null;
|
||||
if (template.trainingRestrictions)
|
||||
entCategory = template.trainingRestrictions.category;
|
||||
else if (template.buildRestrictions)
|
||||
entCategory = template.buildRestrictions.category;
|
||||
var entLimit = undefined;
|
||||
var entCount = undefined;
|
||||
var entLimitChangers = undefined;
|
||||
var canBeAddedCount = undefined;
|
||||
if (entCategory && playerState.entityLimits[entCategory] != null)
|
||||
{
|
||||
entLimit = playerState.entityLimits[entCategory];
|
||||
entCount = playerState.entityCounts[entCategory];
|
||||
entLimitChangers = playerState.entityLimitChangers[entCategory];
|
||||
canBeAddedCount = Math.max(entLimit - entCount, 0);
|
||||
r.entLimit = playerState.entityLimits[entCategory] || Infinity;
|
||||
r.entCount = playerState.entityCounts[entCategory] || 0;
|
||||
r.entLimitChangers = playerState.entityLimitChangers[entCategory];
|
||||
r.canBeAddedCount = Math.max(r.entLimit - r.entCount, 0);
|
||||
}
|
||||
return [entLimit, entCount, canBeAddedCount, entLimitChangers];
|
||||
return r;
|
||||
}
|
||||
|
||||
// Add the unit shown at position to the training queue for all entities in the selection
|
||||
@ -1363,10 +1365,10 @@ function addTrainingToQueue(selection, trainEntType, playerState)
|
||||
var appropriateBuildings = getBuildingsWhichCanTrainEntity(selection, trainEntType);
|
||||
|
||||
// Check trainEntType entity limit and count
|
||||
var [trainEntLimit, trainEntCount, canBeTrainedCount] = getEntityLimitAndCount(playerState, trainEntType)
|
||||
var limits = getEntityLimitAndCount(playerState, trainEntType);
|
||||
|
||||
// Batch training possible if we can train at least 2 units
|
||||
var batchTrainingPossible = canBeTrainedCount == undefined || canBeTrainedCount > 1;
|
||||
var batchTrainingPossible = limits.canBeAddedCount == undefined || limits.canBeAddedCount > 1;
|
||||
|
||||
var decrement = Engine.HotkeyIsPressed("selection.remove");
|
||||
if (!decrement)
|
||||
@ -1398,8 +1400,8 @@ function addTrainingToQueue(selection, trainEntType, playerState)
|
||||
if (batchTrainingCount <= 0)
|
||||
inputState = INPUT_NORMAL;
|
||||
}
|
||||
else if (canBeTrainedCount == undefined ||
|
||||
canBeTrainedCount > batchTrainingCount * appropriateBuildings.length)
|
||||
else if (limits.canBeAddedCount == undefined ||
|
||||
limits.canBeAddedCount > batchTrainingCount * appropriateBuildings.length)
|
||||
{
|
||||
if (Engine.GuiInterfaceCall("GetNeededResources", multiplyEntityCosts(
|
||||
template, batchTrainingCount + batchIncrementSize)))
|
||||
@ -1407,7 +1409,7 @@ function addTrainingToQueue(selection, trainEntType, playerState)
|
||||
|
||||
batchTrainingCount += batchIncrementSize;
|
||||
}
|
||||
batchTrainingEntityAllowedCount = canBeTrainedCount;
|
||||
batchTrainingEntityAllowedCount = limits.canBeAddedCount;
|
||||
return;
|
||||
}
|
||||
// Otherwise start a new one
|
||||
@ -1426,7 +1428,7 @@ function addTrainingToQueue(selection, trainEntType, playerState)
|
||||
inputState = INPUT_BATCHTRAINING;
|
||||
batchTrainingEntities = selection;
|
||||
batchTrainingType = trainEntType;
|
||||
batchTrainingEntityAllowedCount = canBeTrainedCount;
|
||||
batchTrainingEntityAllowedCount = limits.canBeAddedCount;
|
||||
batchTrainingCount = batchIncrementSize;
|
||||
}
|
||||
else
|
||||
@ -1434,8 +1436,8 @@ function addTrainingToQueue(selection, trainEntType, playerState)
|
||||
// Non-batched - just create a single entity in each building
|
||||
// (but no more than entity limit allows)
|
||||
var buildingsForTraining = appropriateBuildings;
|
||||
if (trainEntLimit)
|
||||
buildingsForTraining = buildingsForTraining.slice(0, canBeTrainedCount);
|
||||
if (limits.entLimit)
|
||||
buildingsForTraining = buildingsForTraining.slice(0, limits.canBeAddedCount);
|
||||
Engine.PostNetworkCommand({"type": "train", "template": trainEntType,
|
||||
"count": 1, "entities": buildingsForTraining});
|
||||
}
|
||||
@ -1462,27 +1464,27 @@ function getTrainingBatchStatus(playerState, entity, trainEntType, selection)
|
||||
{
|
||||
nextBatchTrainingCount = batchTrainingCount;
|
||||
currentBatchTrainingCount = batchTrainingCount;
|
||||
var canBeTrainedCount = batchTrainingEntityAllowedCount;
|
||||
var limits = {
|
||||
"canBeAddedCount": batchTrainingEntityAllowedCount
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
var [trainEntLimit, trainEntCount, canBeTrainedCount] =
|
||||
getEntityLimitAndCount(playerState, trainEntType);
|
||||
var batchSize = Math.min(canBeTrainedCount, batchIncrementSize);
|
||||
var limits = getEntityLimitAndCount(playerState, trainEntType);
|
||||
}
|
||||
// We need to calculate count after the next increment if it's possible
|
||||
if (canBeTrainedCount == undefined ||
|
||||
canBeTrainedCount > nextBatchTrainingCount * appropriateBuildings.length)
|
||||
if (limits.canBeAddedCount == undefined ||
|
||||
limits.canBeAddedCount > nextBatchTrainingCount * appropriateBuildings.length)
|
||||
nextBatchTrainingCount += batchIncrementSize;
|
||||
// If training limits don't allow us to train batchTrainingCount in each appropriate building
|
||||
// train as many full batches as we can and remainer in one more building.
|
||||
var buildingsCountToTrainFullBatch = appropriateBuildings.length;
|
||||
var remainderToTrain = 0;
|
||||
if (canBeTrainedCount !== undefined &&
|
||||
canBeTrainedCount < nextBatchTrainingCount * appropriateBuildings.length)
|
||||
if (limits.canBeAddedCount !== undefined &&
|
||||
limits.canBeAddedCount < nextBatchTrainingCount * appropriateBuildings.length)
|
||||
{
|
||||
buildingsCountToTrainFullBatch = Math.floor(canBeTrainedCount / nextBatchTrainingCount);
|
||||
remainderToTrain = canBeTrainedCount % nextBatchTrainingCount;
|
||||
buildingsCountToTrainFullBatch = Math.floor(limits.canBeAddedCount / nextBatchTrainingCount);
|
||||
remainderToTrain = limits.canBeAddedCount % nextBatchTrainingCount;
|
||||
}
|
||||
return [buildingsCountToTrainFullBatch, nextBatchTrainingCount, remainderToTrain, currentBatchTrainingCount];
|
||||
}
|
||||
|
@ -61,6 +61,7 @@ EntityGroups.prototype.add = function(ents)
|
||||
var templateName = entState.template;
|
||||
var key = GetTemplateData(templateName).selectionGroupName || templateName;
|
||||
|
||||
// TODO ugly hack, just group them by player too.
|
||||
// Prefix garrisoned unit's selection name with the player they belong to
|
||||
var index = templateName.indexOf("&");
|
||||
if (index != -1 && key.indexOf("&") == -1)
|
||||
@ -139,6 +140,23 @@ EntityGroups.prototype.getEntsByName = function(templateName)
|
||||
return ents;
|
||||
};
|
||||
|
||||
/**
|
||||
* get a list of entities grouped by templateName
|
||||
*/
|
||||
EntityGroups.prototype.getEntsGrouped = function()
|
||||
{
|
||||
var templateNames = this.getTemplateNames();
|
||||
var list = [];
|
||||
for (var t of templateNames)
|
||||
{
|
||||
list.push({
|
||||
"ents": this.getEntsByName(t),
|
||||
"template": t,
|
||||
});
|
||||
}
|
||||
return list;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets all ents in every group except ones of the specified group
|
||||
*/
|
||||
|
@ -428,8 +428,5 @@ function updateSelectionDetails()
|
||||
{
|
||||
// Fill out commands panel for specific unit selected (or first unit of primary group)
|
||||
updateUnitCommands(entState, supplementalDetailsPanel, commandsPanel, selection);
|
||||
// Show panels
|
||||
supplementalDetailsPanel.hidden = false;
|
||||
commandsPanel.hidden = false;
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,128 @@
|
||||
/**
|
||||
* Contains the layout and button settings per selection panel
|
||||
*
|
||||
* addData is called first, and can be used to abort going any furter
|
||||
* by returning false. Else it should always return true.
|
||||
* getItems returns a list of basic items used to fill the panel.
|
||||
* This method is obligated. If the items list is empty, the panel
|
||||
* won't be rendered.
|
||||
*
|
||||
* Then there's a loop over all items provided. In the loop,
|
||||
* the item and some other standard data is added to a data object.
|
||||
*
|
||||
* addData is used to add data to the data object that can be used in the
|
||||
* content setter functions.
|
||||
* The standard data is
|
||||
* var data = {
|
||||
* "i": index
|
||||
* "item": item coming from the getItems function
|
||||
* "selection": list of currently selected items
|
||||
* "playerState": playerState
|
||||
* "unitEntState": first selected entity state
|
||||
* "rowLength": rowLength
|
||||
* "numberOfItems": number of items that will be processed
|
||||
* "button": gui Button object
|
||||
* "affordableMask": gui Unaffordable overlay
|
||||
* "icon": gui Icon object
|
||||
* "guiSelection": gui button Selection overlay
|
||||
* "countDisplay": gui caption space
|
||||
* };
|
||||
*
|
||||
* Then, addData is called, and can be used to abort the processing
|
||||
* of the current item by returning false.
|
||||
* It should return true if you want the panel to be filled.
|
||||
*
|
||||
* addData is used to add data to the data object on top
|
||||
* (or instead of) the standard data.
|
||||
* addData is not obligated, the function will just continue
|
||||
* with the content setters if no addData is present.
|
||||
*
|
||||
* After the addData, all functions starting with "set" are called.
|
||||
* These are used to set various parts of content.
|
||||
*/
|
||||
|
||||
var g_SelectionPanels = {};
|
||||
|
||||
// BARTER
|
||||
g_SelectionPanels.Barter = {
|
||||
"maxNumberOfItems": 4,
|
||||
"rowLength": 4,
|
||||
"getItems": function(unitEntState, selection)
|
||||
{
|
||||
if (!unitEntState.barterMarket)
|
||||
return [];
|
||||
// ["food", "wood", "stone", "metal"]
|
||||
return BARTER_RESOURCES;
|
||||
},
|
||||
"addData": function(data)
|
||||
{
|
||||
// data.item is the resource name in this case
|
||||
data.button = {};
|
||||
data.icon = {};
|
||||
data.amount = {};
|
||||
for (var a of BARTER_ACTIONS)
|
||||
{
|
||||
data.button[a] = Engine.GetGUIObjectByName("unitBarter"+a+"Button["+data.i+"]");
|
||||
data.icon[a] = Engine.GetGUIObjectByName("unitBarter"+a+"Icon["+data.i+"]");
|
||||
data.amount[a] = Engine.GetGUIObjectByName("unitBarter"+a+"Amount["+data.i+"]");
|
||||
}
|
||||
data.selection = Engine.GetGUIObjectByName("unitBarterSellSelection["+data.i+"]");
|
||||
data.affordableMask = Engine.GetGUIObjectByName("unitBarterSellUnaffordable["+data.i+"]");
|
||||
|
||||
data.amountToSell = BARTER_RESOURCE_AMOUNT_TO_SELL;
|
||||
if (Engine.HotkeyIsPressed("session.massbarter"))
|
||||
data.amountToSell *= BARTER_BUNCH_MULTIPLIER;
|
||||
data.isSelected = data.item == g_barterSell;
|
||||
return true;
|
||||
},
|
||||
"setCountDisplay": function(data)
|
||||
{
|
||||
data.amount.Sell.caption = "-" + data.amountToSell;
|
||||
var sellPrice = data.unitEntState.barterMarket.prices["sell"][g_barterSell];
|
||||
var buyPrice = data.unitEntState.barterMarket.prices["buy"][data.item];
|
||||
data.amount.Buy.caption = "+" + Math.round(sellPrice / buyPrice * data.amountToSell);
|
||||
},
|
||||
"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)});
|
||||
},
|
||||
"setAction": function(data)
|
||||
{
|
||||
data.button.Sell.onPress = function() { g_barterSell = data.item; };
|
||||
var exchangeResourcesParameters = {
|
||||
"sell": g_barterSell,
|
||||
"buy": data.item,
|
||||
"amount": data.amountToSell
|
||||
};
|
||||
data.button.Buy.onPress = function() { exchangeResources(exchangeResourcesParameters); };
|
||||
},
|
||||
"setGraphics": function(data)
|
||||
{
|
||||
var grayscale = data.isSelected ? "grayscale:" : "";
|
||||
data.button.Buy.hidden = data.isSelected;
|
||||
data.button.Sell.hidden = false;
|
||||
for each (var icon in data.icon)
|
||||
icon.sprite = "stretched:"+grayscale+"session/icons/resources/" + data.item + ".png";
|
||||
|
||||
var neededRes = {};
|
||||
neededRes[data.item] = data.amountToSell;
|
||||
if (Engine.GuiInterfaceCall("GetNeededResources", neededRes))
|
||||
data.affordableMask.hidden = false;
|
||||
else
|
||||
data.affordableMask.hidden = true;
|
||||
data.selection.hidden = !data.isSelected;
|
||||
},
|
||||
"setPosition": function(data)
|
||||
{
|
||||
setPanelObjectPosition(data.button.Sell, data.i, data.rowLength);
|
||||
setPanelObjectPosition(data.button.Buy, data.i + data.rowLength, data.rowLength);
|
||||
},
|
||||
},
|
||||
|
||||
// COMMAND
|
||||
g_SelectionPanels.Command = {
|
||||
"maxNumberOfItems": 6,
|
||||
"getItems": function(unitEntState)
|
||||
{
|
||||
return getEntityCommandsList(unitEntState)
|
||||
},
|
||||
"setTooltip": function(data)
|
||||
{
|
||||
if (data.item.tooltip)
|
||||
@ -20,12 +130,13 @@ g_SelectionPanels.Command = {
|
||||
else
|
||||
data.button.tooltip = toTitleCase(data.item.name);
|
||||
},
|
||||
"setAction": function(data)
|
||||
{
|
||||
data.button.onPress = function() { data.item.callback ? data.item.callback(data.item) : performCommand(data.unitEntState.id, data.item.name); };
|
||||
},
|
||||
"setCountDisplay": function(data)
|
||||
{
|
||||
var count = 0;
|
||||
if (data.item.name == "unload-all")
|
||||
count = data.garrisonGroups.getTotalCount();
|
||||
data.countDisplay.caption = count || "";
|
||||
data.countDisplay.caption = data.item.count || "";
|
||||
},
|
||||
"setGraphics": function(data)
|
||||
{
|
||||
@ -48,6 +159,11 @@ g_SelectionPanels.Command = {
|
||||
// CONSTRUCTION
|
||||
g_SelectionPanels.Construction = {
|
||||
"maxNumberOfItems": 24,
|
||||
"conflictsWith": ["Gate", "Pack", "Training"],
|
||||
"getItems": function()
|
||||
{
|
||||
return getAllBuildableEntitiesFromSelection();
|
||||
},
|
||||
"addData": function(data)
|
||||
{
|
||||
data.entType = data.item;
|
||||
@ -60,8 +176,13 @@ g_SelectionPanels.Construction = {
|
||||
var totalCost = multiplyEntityCosts(data.template, 1);
|
||||
data.neededResources = Engine.GuiInterfaceCall("GetNeededResources", totalCost);
|
||||
}
|
||||
data.limits = getEntityLimitAndCount(data.playerState, data.entType);
|
||||
return true;
|
||||
},
|
||||
"setAction": function(data)
|
||||
{
|
||||
data.button.onPress = function () { startBuildingPlacement(data.item, data.playerState); };
|
||||
},
|
||||
"setTooltip": function(data)
|
||||
{
|
||||
var tooltip = getEntityNamesFormatted(data.template);
|
||||
@ -73,13 +194,7 @@ g_SelectionPanels.Construction = {
|
||||
tooltip += "\n" + getEntityCostTooltip(data.template);
|
||||
tooltip += getPopulationBonusTooltip(data.template);
|
||||
|
||||
var limits = getEntityLimitAndCount(data.playerState, data.entType);
|
||||
data.entLimit = limits[0];
|
||||
data.entCount = limits[1];
|
||||
data.canBeAddedCount = limits[2];
|
||||
data.entLimitChangers = limits[3];
|
||||
|
||||
tooltip += formatLimitString(data.entLimit, data.entCount, data.entLimitChangers);
|
||||
tooltip += formatLimitString(data.limits.entLimit, data.limits.entCount, data.limits.entLimitChangers);
|
||||
if (!data.technologyEnabled)
|
||||
{
|
||||
var techName = getEntityNames(GetTechnologyData(data.template.requiredTechnology));
|
||||
@ -93,7 +208,7 @@ g_SelectionPanels.Construction = {
|
||||
"setGraphics": function(data)
|
||||
{
|
||||
var grayscale = "";
|
||||
if (!data.technologyEnabled || data.canBeAddedCount == 0)
|
||||
if (!data.technologyEnabled || data.limits.canBeAddedCount == 0)
|
||||
{
|
||||
data.button.enabled = false;
|
||||
grayscale = "grayscale:";
|
||||
@ -115,6 +230,13 @@ g_SelectionPanels.Construction = {
|
||||
g_SelectionPanels.Formation = {
|
||||
"maxNumberOfItems": 16,
|
||||
"rowLength": 4,
|
||||
"conflictsWith": ["Garrison"],
|
||||
"getItems": function(unitEntState)
|
||||
{
|
||||
if (!hasClass(unitEntState, "Unit") || hasClass(unitEntState, "Animal"))
|
||||
return [];
|
||||
return Engine.GuiInterfaceCall("GetAvailableFormations");
|
||||
},
|
||||
"addData": function(data)
|
||||
{
|
||||
data.formationInfo = Engine.GuiInterfaceCall("GetFormationInfoFromTemplate", {"templateName": data.item});
|
||||
@ -125,9 +247,13 @@ g_SelectionPanels.Formation = {
|
||||
});
|
||||
return true;
|
||||
},
|
||||
"setAction": function(data)
|
||||
{
|
||||
data.button.onPress = function() { performFormation(data.unitEntState.id, data.item); };
|
||||
},
|
||||
"setTooltip": function(data)
|
||||
{
|
||||
var tooltip = translate(data.formationInfo.name);
|
||||
var tooltip = translate(data.formationInfo.name);
|
||||
if (!data.formationOk && data.formationInfo.tooltip)
|
||||
tooltip += "\n" + "[color=\"red\"]" + translate(data.formationInfo.tooltip) + "[/color]";
|
||||
data.button.tooltip = tooltip;
|
||||
@ -145,16 +271,33 @@ g_SelectionPanels.Formation = {
|
||||
g_SelectionPanels.Garrison = {
|
||||
"maxNumberOfItems": 12,
|
||||
"rowLength": 4,
|
||||
"getItems": function(unitEntState, selection)
|
||||
{
|
||||
if (!unitEntState.garrisonHolder)
|
||||
return [];
|
||||
var groups = new EntityGroups();
|
||||
for (var ent of selection)
|
||||
{
|
||||
var state = GetEntityState(ent);
|
||||
if (state.garrisonHolder)
|
||||
groups.add(state.garrisonHolder.entities)
|
||||
}
|
||||
return groups.getEntsGrouped();
|
||||
},
|
||||
"addData": function(data)
|
||||
{
|
||||
data.entType = data.item;
|
||||
data.entType = data.item.template;
|
||||
data.template = GetTemplateData(data.entType);
|
||||
if (!data.template)
|
||||
return false;
|
||||
data.name = getEntityNames(data.template);
|
||||
data.count = data.garrisonGroups.getCount(data.item);
|
||||
data.count = data.item.ents.length;
|
||||
return true;
|
||||
},
|
||||
"setAction": function(data)
|
||||
{
|
||||
data.button.onPress = function() { unloadTemplate(data.item.template); };
|
||||
},
|
||||
"setTooltip": function(data)
|
||||
{
|
||||
var tooltip = sprintf(translate("Unload %(name)s"), { name: data.name }) + "\n";
|
||||
@ -168,7 +311,7 @@ g_SelectionPanels.Garrison = {
|
||||
"setGraphics": function(data)
|
||||
{
|
||||
var grayscale = "";
|
||||
var ents = data.garrisonGroups.getEntsByName(data.item);
|
||||
var ents = data.item.ents;
|
||||
var entplayer = GetEntityState(ents[0]).player;
|
||||
data.button.sprite = "colour: " + rgbToGuiColor(g_Players[entplayer].color);
|
||||
|
||||
@ -188,6 +331,70 @@ g_SelectionPanels.Garrison = {
|
||||
// GATE
|
||||
g_SelectionPanels.Gate = {
|
||||
"maxNumberOfItems": 8,
|
||||
"conflictsWith": ["Construction", "Pack", "Training"],
|
||||
"getItems": function(unitEntState, selection)
|
||||
{
|
||||
if (unitEntState.foundation)
|
||||
return [];
|
||||
if (!hasClass(unitEntState, "LongWall") && !unitEntState.gate)
|
||||
return [];
|
||||
// Allow long wall pieces to be converted to gates
|
||||
var longWallTypes = {};
|
||||
var walls = [];
|
||||
var gates = [];
|
||||
for (var i in selection)
|
||||
{
|
||||
var state = GetEntityState(selection[i]);
|
||||
if (hasClass(state, "LongWall") && !state.gate && !longWallTypes[state.template])
|
||||
{
|
||||
var gateTemplate = getWallGateTemplate(state.id);
|
||||
if (gateTemplate)
|
||||
{
|
||||
var tooltipString = GetTemplateDataWithoutLocalization(state.template).gateConversionTooltip;
|
||||
if (!tooltipString)
|
||||
{
|
||||
warn(state.template + " is supposed to be convertable to a gate, but it's missing the GateConversionTooltip in the Identity template");
|
||||
tooltipString = "";
|
||||
}
|
||||
walls.push({
|
||||
"tooltip": translate(tooltipString),
|
||||
"template": gateTemplate,
|
||||
"callback": function (item) { transformWallToGate(item.template); }
|
||||
});
|
||||
}
|
||||
|
||||
// We only need one entity per type.
|
||||
longWallTypes[state.template] = true;
|
||||
}
|
||||
else if (state.gate && !gates.length)
|
||||
{
|
||||
gates.push({
|
||||
"gate": state.gate,
|
||||
"tooltip": translate("Lock Gate"),
|
||||
"locked": true,
|
||||
"callback": function (item) { lockGate(item.locked); }
|
||||
});
|
||||
gates.push({
|
||||
"gate": state.gate,
|
||||
"tooltip": translate("Unlock Gate"),
|
||||
"locked": false,
|
||||
"callback": function (item) { lockGate(item.locked); }
|
||||
});
|
||||
}
|
||||
// Show both 'locked' and 'unlocked' as active if the selected gates have both lock states.
|
||||
else if (state.gate && state.gate.locked != gates[0].gate.locked)
|
||||
for (var j = 0; j < gates.length; ++j)
|
||||
delete gates[j].gate.locked;
|
||||
}
|
||||
|
||||
// Place wall conversion options after gate lock/unlock icons.
|
||||
var items = gates.concat(walls);
|
||||
return items;
|
||||
},
|
||||
"setAction": function(data)
|
||||
{
|
||||
data.button.onPress = function() {data.item.callback(data.item); };
|
||||
},
|
||||
"setTooltip": function(data)
|
||||
{
|
||||
var tooltip = data.item.tooltip;
|
||||
@ -229,7 +436,7 @@ g_SelectionPanels.Gate = {
|
||||
var template = GetTemplateData(data.item.template);
|
||||
if (!template)
|
||||
return;
|
||||
gateIcon = data.template.icon ? "portraits/" + data.template.icon : "icons/gate_closed.png";
|
||||
gateIcon = data.template.icon ? "portraits/" + data.template.icon : "icons/gate_closed.png";
|
||||
data.guiSelection.hidden = true;
|
||||
}
|
||||
|
||||
@ -240,6 +447,48 @@ g_SelectionPanels.Gate = {
|
||||
// PACK
|
||||
g_SelectionPanels.Pack = {
|
||||
"maxNumberOfItems": 8,
|
||||
"conflictsWith": ["Construction", "Gate", "Training"],
|
||||
"getItems": function(unitEntState, selection)
|
||||
{
|
||||
if (!unitEntState.pack)
|
||||
return [];
|
||||
var checks = {};
|
||||
for (var ent of selection)
|
||||
{
|
||||
var state = GetEntityState(ent);
|
||||
if (!state.pack)
|
||||
continue;
|
||||
if (state.pack.progress == 0)
|
||||
{
|
||||
if (!state.pack.packed)
|
||||
checks.packButton = true;
|
||||
else if (state.pack.packed)
|
||||
checks.unpackButton = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Already un/packing - show cancel button
|
||||
if (!state.pack.packed)
|
||||
checks.packCancelButton = true;
|
||||
else if (state.pack.packed)
|
||||
checks.unpackCancelButton = true;
|
||||
}
|
||||
}
|
||||
var items = [];
|
||||
if (checks.packButton)
|
||||
items.push({ "packing": false, "packed": false, "tooltip": translate("Pack"), "callback": function() { packUnit(true); } });
|
||||
if (checks.unpackButton)
|
||||
items.push({ "packing": false, "packed": true, "tooltip": translate("Unpack"), "callback": function() { packUnit(false); } });
|
||||
if (checks.packCancelButton)
|
||||
items.push({ "packing": true, "packed": false, "tooltip": translate("Cancel Packing"), "callback": function() { cancelPackUnit(true); } });
|
||||
if (checks.unpackCancelButton)
|
||||
items.push({ "packing": true, "packed": true, "tooltip": translate("Cancel Unpacking"), "callback": function() { cancelPackUnit(false); } });
|
||||
return items;
|
||||
},
|
||||
"setAction": function(data)
|
||||
{
|
||||
data.button.onPress = function() {data.item.callback(data.item); };
|
||||
},
|
||||
"setTooltip": function(data)
|
||||
{
|
||||
data.button.tooltip = data.item.tooltip;
|
||||
@ -258,6 +507,20 @@ g_SelectionPanels.Pack = {
|
||||
// QUEUE
|
||||
g_SelectionPanels.Queue = {
|
||||
"maxNumberOfItems": 16,
|
||||
"getItems": function(unitEntState)
|
||||
{
|
||||
if (!unitEntState.production)
|
||||
return [];
|
||||
return unitEntState.production.queue;
|
||||
},
|
||||
"resizePanel": function(numberOfItems, rowLength)
|
||||
{
|
||||
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));
|
||||
panel.size = size;
|
||||
},
|
||||
"addData": function(data)
|
||||
{
|
||||
// differentiate between units and techs
|
||||
@ -275,6 +538,10 @@ g_SelectionPanels.Queue = {
|
||||
data.progress = Math.round(data.item.progress*100) + "%";
|
||||
return data.template;
|
||||
},
|
||||
"setAction": function(data)
|
||||
{
|
||||
data.button.onPress = function() { removeFromProductionQueue(data.unitEntState.id, data.item.id); };
|
||||
},
|
||||
"setTooltip": function(data)
|
||||
{
|
||||
var tooltip = getEntityNames(data.template);
|
||||
@ -313,6 +580,15 @@ g_SelectionPanels.Queue = {
|
||||
// RESEARCH
|
||||
g_SelectionPanels.Research = {
|
||||
"maxNumberOfItems": 8,
|
||||
"getItems": function(unitEntState, selection)
|
||||
{
|
||||
if (!unitEntState.production)
|
||||
return [];
|
||||
// TODO 8 is the row lenght, make variable
|
||||
if (getNumberOfRightPanelButtons() > 8 && selection.length > 1)
|
||||
return [];
|
||||
return unitEntState.production.technologies;
|
||||
},
|
||||
"hideItem": function(i, rowLength) // called when no item is found
|
||||
{
|
||||
Engine.GetGUIObjectByName("unitResearchButton["+i+"]").hidden = true;
|
||||
@ -393,7 +669,7 @@ g_SelectionPanels.Research = {
|
||||
data.button[i].tooltip = tooltip;
|
||||
}
|
||||
},
|
||||
"setActions": function(data)
|
||||
"setAction": function(data)
|
||||
{
|
||||
for (var i in data.entType)
|
||||
{
|
||||
@ -401,7 +677,9 @@ g_SelectionPanels.Research = {
|
||||
var others = Object.keys(data.template);
|
||||
others.splice(i, 1);
|
||||
var button = data.button[i];
|
||||
button.onpress = (function(e){ return function() { data.callback(e) } })(data.entType[i]);
|
||||
// as we're in a loop, we need to limit the scope with a closure
|
||||
// else the last value of the loop will be taken, rather than the current one
|
||||
button.onpress = (function(template) { return function () { addResearchToQueue(data.unitEntState.id, template); }; })(data.entType[i]);
|
||||
// on mouse enter, show a cross over the other icons
|
||||
button.onmouseenter = (function(others, icons) {
|
||||
return function() {
|
||||
@ -445,7 +723,7 @@ g_SelectionPanels.Research = {
|
||||
if (data.template[i].icon)
|
||||
data.icon[i].sprite = "stretched:" + grayscale + "session/portraits/" + data.template[i].icon;
|
||||
}
|
||||
for (var button of data.buttonsToHide)
|
||||
for (var button of data.buttonsToHide)
|
||||
button.hidden = true;
|
||||
// show the tech connector
|
||||
data.pair.hidden = data.item.pair == null;
|
||||
@ -462,6 +740,12 @@ g_SelectionPanels.Research = {
|
||||
g_SelectionPanels.Selection = {
|
||||
"maxNumberOfItems": 16,
|
||||
"rowLength": 4,
|
||||
"getItems": function(unitEntState, selection)
|
||||
{
|
||||
if (selection.length < 2)
|
||||
return [];
|
||||
return g_Selection.groups.getTemplateNames();
|
||||
},
|
||||
"addData": function(data)
|
||||
{
|
||||
data.entType = data.item;
|
||||
@ -480,10 +764,10 @@ g_SelectionPanels.Selection = {
|
||||
{
|
||||
data.countDisplay.caption = data.count || "";
|
||||
},
|
||||
"setActions": function(data)
|
||||
"setAction": function(data)
|
||||
{
|
||||
data.button.onpressright = (function(e){return function() {data.callback(e, true) } })(data.item);
|
||||
data.button.onpress = (function(e){ return function() {data.callback(e, false) } })(data.item);
|
||||
data.button.onpressright = function() { changePrimarySelectionGroup(data.item, true); };
|
||||
data.button.onpress = function() { changePrimarySelectionGroup(data.item, false); };
|
||||
},
|
||||
"setGraphics": function(data)
|
||||
{
|
||||
@ -495,6 +779,12 @@ g_SelectionPanels.Selection = {
|
||||
// STANCE
|
||||
g_SelectionPanels.Stance = {
|
||||
"maxNumberOfItems": 5,
|
||||
"getItems": function(unitEntState)
|
||||
{
|
||||
if (!unitEntState.unitAI || !hasClass(unitEntState, "Unit") || hasClass(unitEntState, "Animal"))
|
||||
return [];
|
||||
return unitEntState.unitAI.possibleStances;
|
||||
},
|
||||
"addData": function(data)
|
||||
{
|
||||
data.stanceSelected = Engine.GuiInterfaceCall("IsStanceSelected", {
|
||||
@ -503,6 +793,10 @@ g_SelectionPanels.Stance = {
|
||||
});
|
||||
return true;
|
||||
},
|
||||
"setAction": function(data)
|
||||
{
|
||||
data.button.onPress = function() { performStance(data.unitEntState, data.item); };
|
||||
},
|
||||
"setTooltip": function(data)
|
||||
{
|
||||
data.button.tooltip = getStanceDisplayName(data.item);
|
||||
@ -517,6 +811,11 @@ g_SelectionPanels.Stance = {
|
||||
// TRAINING
|
||||
g_SelectionPanels.Training = {
|
||||
"maxNumberOfItems": 24,
|
||||
"conflictsWith": ["Construction", "Gate", "Pack"],
|
||||
"getItems": function()
|
||||
{
|
||||
return getAllTrainableEntitiesFromSelection();
|
||||
},
|
||||
"addData": function(data)
|
||||
{
|
||||
data.entType = data.item;
|
||||
@ -542,6 +841,10 @@ g_SelectionPanels.Training = {
|
||||
|
||||
return true;
|
||||
},
|
||||
"setAction": function(data)
|
||||
{
|
||||
data.button.onPress = function() { addTrainingToQueue(data.selection, data.item, data.playerState); };
|
||||
},
|
||||
"setCountDisplay": function(data)
|
||||
{
|
||||
var count = "";
|
||||
@ -574,14 +877,9 @@ g_SelectionPanels.Training = {
|
||||
|
||||
tooltip += "\n" + getEntityCostTooltip(data.template, data.trainNum, data.unitEntState.id);
|
||||
|
||||
// TODO make the getEntityLimitAndCount method return something nicer than an array
|
||||
var limits = getEntityLimitAndCount(data.playerState, data.entType);
|
||||
data.entLimit = limits[0];
|
||||
data.entCount = limits[1];
|
||||
data.canBeAddedCount = limits[2];
|
||||
data.entLimitChangers = limits[3];
|
||||
data.limits = getEntityLimitAndCount(data.playerState, data.entType);
|
||||
|
||||
tooltip += formatLimitString(data.entLimit, data.entCount, data.entLimitChangers);
|
||||
tooltip += formatLimitString(data.limits.entLimit, data.limits.entCount, data.limits.entLimitChangers);
|
||||
if (Engine.ConfigDB_GetValue("user", "showdetailedtooltips") === "true")
|
||||
{
|
||||
if (data.template.health)
|
||||
@ -608,3 +906,30 @@ g_SelectionPanels.Training = {
|
||||
"setGraphics": g_SelectionPanels.Construction.setGraphics,
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* If two panels need the same space, so they collide,
|
||||
* the one appearing first in the order is rendered.
|
||||
*
|
||||
* Note that the panel needs to appear in the list to get rendered.
|
||||
*/
|
||||
var g_PanelsOrder = [
|
||||
// LEFT PANE
|
||||
"Barter", // must always be visible on markets
|
||||
"Garrison", // more important than Formation, as you want to see the garrisoned units in ships
|
||||
"Formation",
|
||||
"Stance", // normal together with formation
|
||||
|
||||
// RIGHT PANE
|
||||
"Gate", // must always be shown on gates
|
||||
"Pack", // must always be shown on packable entities
|
||||
"Training", // lets hope training and construction never happen together
|
||||
"Construction",
|
||||
"Research", // normal together with training
|
||||
|
||||
// UNIQUE PANES (importance doesn't matter)
|
||||
"Command",
|
||||
"Queue",
|
||||
"Selection",
|
||||
];
|
||||
|
@ -860,21 +860,18 @@
|
||||
<object ghost="true" style="resourceText" type="text" size="0 0 100% 20">
|
||||
<translatableAttribute id="tooltip">Exchange resources:</translatableAttribute>
|
||||
</object>
|
||||
<object size="0 32 100% 78">
|
||||
<object size="0 32 100% 124">
|
||||
<repeat count="4">
|
||||
<!-- sell -->
|
||||
<object name="unitBarterSellButton[n]" style="iconButton" type="button" size="0 0 46 46" tooltip_style="sessionToolTipBottomBold">
|
||||
<object name="unitBarterSellIcon[n]" type="image" ghost="true" size="3 3 43 43"/>
|
||||
<object name="unitBarterSellUnaffordable[n]" hidden="true" type="image" ghost="true" size="3 3 43 43" sprite="colour: 255 0 0 60"/>
|
||||
<object name="unitBarterSellAmount[n]" ghost="true" style="resourceText" type="text" size="0 0 100% 50%"/>
|
||||
<object name="unitBarterSellSelection[n]" hidden="true" type="image" ghost="true" size="3 3 43 43" sprite="stretched:session/icons/corners.png"/>
|
||||
</object>
|
||||
</repeat>
|
||||
</object>
|
||||
<object size="0 78 100% 124">
|
||||
<repeat count="4">
|
||||
<!-- buy -->
|
||||
<object name="unitBarterBuyButton[n]" style="iconButton" type="button" size="0 0 46 46" tooltip_style="sessionToolTipBottomBold">
|
||||
<object name="unitBarterBuyIcon[n]" type="image" ghost="true" size="3 3 43 43"/>
|
||||
<object name="unitBarterBuyUnaffordable[n]" hidden="true" type="image" ghost="true" size="3 3 43 43" sprite="colour: 255 0 0 60"/>
|
||||
<object name="unitBarterBuyAmount[n]" ghost="true" style="resourceText" type="text" size="0 0 100% 50%"/>
|
||||
</object>
|
||||
</repeat>
|
||||
|
@ -633,9 +633,18 @@ var entityCommands =
|
||||
{
|
||||
if (!entState.garrisonHolder)
|
||||
return false;
|
||||
var selection = g_Selection.toList();
|
||||
var count = 0;
|
||||
for (var ent of selection)
|
||||
{
|
||||
var state = GetEntityState(ent);
|
||||
if (state.garrisonHolder)
|
||||
count += state.garrisonHolder.entities.length;
|
||||
}
|
||||
return {
|
||||
"tooltip": translate("Unload All"),
|
||||
"icon": "garrison-out.png"
|
||||
"icon": "garrison-out.png",
|
||||
"count": count,
|
||||
};
|
||||
},
|
||||
"execute": function(entState)
|
||||
|
@ -16,7 +16,12 @@ const UNIT_PANEL_BASE = -52; // QUEUE: The offset above the main panel (will oft
|
||||
const UNIT_PANEL_HEIGHT = 44; // QUEUE: The height needed for a row of buttons
|
||||
|
||||
// Trading constants
|
||||
const TRADING_RESOURCES = ["food", "wood", "stone", "metal"];
|
||||
const TRADING_RESOURCES = [
|
||||
markForTranslation("food"),
|
||||
markForTranslation("wood"),
|
||||
markForTranslation("stone"),
|
||||
markForTranslation("metal")
|
||||
];
|
||||
|
||||
// Barter constants
|
||||
const BARTER_RESOURCE_AMOUNT_TO_SELL = 100;
|
||||
@ -30,12 +35,15 @@ 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};
|
||||
|
||||
// Unit panels are panels with row(s) of buttons
|
||||
var g_unitPanels = ["Selection", "Queue", "Formation", "Garrison", "Training", "Barter", "Construction", "Research", "Stance", "Command", "Gate", "Pack"];
|
||||
|
||||
// Indexes of resources to sell and buy on barter panel
|
||||
var g_barterSell = 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.
|
||||
* Will wrap around to subsequent rows if the index
|
||||
* is larger than rowLength.
|
||||
*/
|
||||
function setPanelObjectPosition(object, index, rowLength, vMargin = 1, hMargin = 1)
|
||||
{
|
||||
var size = object.size;
|
||||
@ -165,24 +173,23 @@ function getStanceDisplayName(name)
|
||||
* unit.
|
||||
*
|
||||
* @param guiName Short identifier string of this panel; see constants defined at the top of this file.
|
||||
* @param usedPanels Output object; usedPanels[guiName] will be set to 1 to indicate that this panel was used during this
|
||||
* run of updateUnitCommands and should not be hidden. TODO: why is this done this way instead of having
|
||||
* updateUnitCommands keep track of this?
|
||||
* @param unitEntState Entity state of the (first) selected unit.
|
||||
* @param items Panel-specific data to construct the icons with.
|
||||
* @param callback Callback function to argument to execute when an item's icon gets clicked. Takes a single 'item' argument.
|
||||
*/
|
||||
function setupUnitPanel(guiName, usedPanels, unitEntState, playerState, items, callback)
|
||||
function setupUnitPanel(guiName, unitEntState, playerState)
|
||||
{
|
||||
if (!g_SelectionPanels[guiName])
|
||||
{
|
||||
error("unknown guiName used '" + guiName + "'");
|
||||
return;
|
||||
}
|
||||
usedPanels[guiName] = 1;
|
||||
var selection = g_Selection.toList();
|
||||
|
||||
var items = g_SelectionPanels[guiName].getItems(unitEntState, selection);
|
||||
|
||||
if (!items || !items.length)
|
||||
return;
|
||||
|
||||
var numberOfItems = items.length;
|
||||
var selection = g_Selection.toList();
|
||||
var garrisonGroups = new EntityGroups();
|
||||
|
||||
// Determine how many buttons there should be
|
||||
@ -193,26 +200,8 @@ function setupUnitPanel(guiName, usedPanels, unitEntState, playerState, items, c
|
||||
else
|
||||
var rowLength = 8;
|
||||
|
||||
// TODO get this out of here
|
||||
// Common code for garrison and 'unload all' button counts.
|
||||
if (guiName == GARRISON || guiName == COMMAND)
|
||||
{
|
||||
for (var i = 0; i < selection.length; ++i)
|
||||
{
|
||||
var state = GetEntityState(selection[i]);
|
||||
if (state.garrisonHolder)
|
||||
garrisonGroups.add(state.garrisonHolder.entities)
|
||||
}
|
||||
}
|
||||
// Resize Queue panel if needed
|
||||
if (guiName == QUEUE) // or garrison
|
||||
{
|
||||
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));
|
||||
panel.size = size;
|
||||
}
|
||||
if (g_SelectionPanels[guiName].resizePanel)
|
||||
g_SelectionPanels[guiName].resizePanel(numberOfItems, rowLength);
|
||||
|
||||
// Make buttons
|
||||
for (var i = 0; i < numberOfItems; i++)
|
||||
@ -220,9 +209,10 @@ function setupUnitPanel(guiName, usedPanels, unitEntState, playerState, items, c
|
||||
var item = items[i];
|
||||
|
||||
// If a tech has been researched it leaves an empty slot
|
||||
if (!item && g_SelectionPanels[guiName].hideItem)
|
||||
if (!item)
|
||||
{
|
||||
g_SelectionPanels[guiName].hideItem(i, rowLength);
|
||||
if (g_SelectionPanels[guiName].hideItem)
|
||||
g_SelectionPanels[guiName].hideItem(i, rowLength);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -234,14 +224,10 @@ function setupUnitPanel(guiName, usedPanels, unitEntState, playerState, items, c
|
||||
"selection": selection,
|
||||
"playerState": playerState,
|
||||
"unitEntState": unitEntState,
|
||||
"callback": callback,
|
||||
"rowLength": rowLength,
|
||||
"numberOfItems": numberOfItems,
|
||||
};
|
||||
|
||||
if (garrisonGroups)
|
||||
data.garrisonGroups = garrisonGroups;
|
||||
|
||||
// add standard gui objects to the data
|
||||
// depending on the actual XML, some of this may be undefined
|
||||
data.button = Engine.GetGUIObjectByName("unit"+guiName+"Button["+i+"]");
|
||||
@ -252,15 +238,13 @@ function setupUnitPanel(guiName, usedPanels, unitEntState, playerState, items, c
|
||||
|
||||
|
||||
// DEFAULTS
|
||||
data.button.hidden = false;
|
||||
data.button.enabled = true;
|
||||
data.button.tooltip = "";
|
||||
data.button.caption = "";
|
||||
|
||||
// Items can have a callback element that overrides the normal
|
||||
// caller-supplied callback function. Button Function
|
||||
// (need nested functions to get the closure right)
|
||||
data.button.onpress = (function(e){ return function() { e.callback ? e.callback(e) : callback(e) } })(item);
|
||||
if (data.button)
|
||||
{
|
||||
data.button.hidden = false;
|
||||
data.button.enabled = true;
|
||||
data.button.tooltip = "";
|
||||
data.button.caption = "";
|
||||
}
|
||||
|
||||
if (data.affordableMask)
|
||||
data.affordableMask.hidden = true; // actually used for the red "lack of resource" overlay, and darkening if unavailable. Sort of a hack.
|
||||
@ -287,7 +271,7 @@ function setupUnitPanel(guiName, usedPanels, unitEntState, playerState, items, c
|
||||
setPanelObjectPosition(data.button, i, rowLength);
|
||||
|
||||
// TODO: we should require all entities to have icons, so this case never occurs
|
||||
if (!data.icon.sprite)
|
||||
if (data.icon && !data.icon.sprite)
|
||||
data.icon.sprite = "bkFillBlack";
|
||||
|
||||
}
|
||||
@ -301,6 +285,7 @@ function setupUnitPanel(guiName, usedPanels, unitEntState, playerState, items, c
|
||||
|
||||
// remember the number of items
|
||||
g_unitPanelButtons[guiName] = numberOfItems;
|
||||
g_SelectionPanels[guiName].used = true;
|
||||
}
|
||||
|
||||
function resourcesToAlphaMask(neededResources)
|
||||
@ -313,83 +298,6 @@ function resourcesToAlphaMask(neededResources)
|
||||
return "colour: 255 0 0 " + (alpha);
|
||||
}
|
||||
|
||||
// Sets up "unit barter panel" - special case for setupUnitPanel
|
||||
function setupUnitBarterPanel(unitEntState, playerState)
|
||||
{
|
||||
// Amount of player's resource to exchange
|
||||
var amountToSell = BARTER_RESOURCE_AMOUNT_TO_SELL;
|
||||
if (Engine.HotkeyIsPressed("session.massbarter"))
|
||||
amountToSell *= BARTER_BUNCH_MULTIPLIER;
|
||||
// One pass for each resource
|
||||
for (var i = 0; i < BARTER_RESOURCES.length; i++)
|
||||
{
|
||||
var resource = BARTER_RESOURCES[i];
|
||||
// One pass for 'sell' row and another for 'buy'
|
||||
for (var j = 0; j < 2; j++)
|
||||
{
|
||||
var action = BARTER_ACTIONS[j];
|
||||
|
||||
if (j == 0)
|
||||
{
|
||||
// Display the selection overlay
|
||||
var selection = Engine.GetGUIObjectByName("unitBarter" + action + "Selection["+i+"]");
|
||||
selection.hidden = !(i == g_barterSell);
|
||||
}
|
||||
|
||||
// We gray out the not selected icons in 'sell' row
|
||||
var grayscale = (j == 0 && i != g_barterSell) ? "grayscale:" : "";
|
||||
var icon = Engine.GetGUIObjectByName("unitBarter" + action + "Icon["+i+"]");
|
||||
|
||||
var button = Engine.GetGUIObjectByName("unitBarter" + action + "Button["+i+"]");
|
||||
button.size = (i * 46) + " 0 " + ((i + 1) * 46) + " 46";
|
||||
var amountToBuy;
|
||||
// We don't display a button in 'buy' row if the same resource is selected in 'sell' row
|
||||
if (j == 1 && i == g_barterSell)
|
||||
{
|
||||
button.hidden = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
button.hidden = false;
|
||||
button.tooltip = action + " " + resource;
|
||||
icon.sprite = "stretched:"+grayscale+"session/icons/resources/" + resource + ".png";
|
||||
var sellPrice = unitEntState.barterMarket.prices["sell"][BARTER_RESOURCES[g_barterSell]];
|
||||
var buyPrice = unitEntState.barterMarket.prices["buy"][resource];
|
||||
amountToBuy = "+" + Math.round(sellPrice / buyPrice * amountToSell);
|
||||
}
|
||||
|
||||
var amount;
|
||||
if (j == 0)
|
||||
{
|
||||
button.onpress = (function(i){ return function() { g_barterSell = i; } })(i);
|
||||
if (i == g_barterSell)
|
||||
{
|
||||
amount = "-" + amountToSell;
|
||||
|
||||
var neededRes = {};
|
||||
neededRes[resource] = amountToSell;
|
||||
var neededResources = Engine.GuiInterfaceCall("GetNeededResources", neededRes);
|
||||
var hidden = neededResources ? false : true;
|
||||
for (var ii = 0; ii < BARTER_RESOURCES.length; ii++)
|
||||
{
|
||||
var affordableMask = Engine.GetGUIObjectByName("unitBarterBuyUnaffordable["+ii+"]");
|
||||
affordableMask.hidden = hidden;
|
||||
}
|
||||
}
|
||||
else
|
||||
amount = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
var exchangeResourcesParameters = { "sell": BARTER_RESOURCES[g_barterSell], "buy": BARTER_RESOURCES[i], "amount": amountToSell };
|
||||
button.onpress = (function(exchangeResourcesParameters){ return function() { exchangeResources(exchangeResourcesParameters); } })(exchangeResourcesParameters);
|
||||
amount = amountToBuy;
|
||||
}
|
||||
Engine.GetGUIObjectByName("unitBarter" + action + "Amount["+i+"]").caption = amount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@ -402,8 +310,8 @@ function setupUnitBarterPanel(unitEntState, playerState)
|
||||
*/
|
||||
function updateUnitCommands(entState, supplementalDetailsPanel, commandsPanel, selection)
|
||||
{
|
||||
// Panels that are active
|
||||
var usedPanels = {};
|
||||
for each (var panel in g_SelectionPanels)
|
||||
panel.used = false;
|
||||
|
||||
// If the selection is friendly units, add the command panels
|
||||
var player = Engine.GetPlayerID();
|
||||
@ -415,218 +323,29 @@ function updateUnitCommands(entState, supplementalDetailsPanel, commandsPanel, s
|
||||
|
||||
if (entState.player == player || g_DevSettings.controlAll)
|
||||
{
|
||||
if (selection.length > 1)
|
||||
setupUnitPanel(SELECTION, usedPanels, entState, playerState, g_Selection.groups.getTemplateNames(),
|
||||
function (entType, rightPressed) { changePrimarySelectionGroup(entType, rightPressed); } );
|
||||
|
||||
var commands = getEntityCommandsList(entState);
|
||||
if (commands.length)
|
||||
setupUnitPanel(COMMAND, usedPanels, entState, playerState, commands,
|
||||
function (item) { performCommand(entState.id, item.name); } );
|
||||
|
||||
if (entState.garrisonHolder)
|
||||
for (var guiName of g_PanelsOrder)
|
||||
{
|
||||
var groups = new EntityGroups();
|
||||
for (var i in selection)
|
||||
{
|
||||
var state = GetEntityState(selection[i]);
|
||||
if (state.garrisonHolder)
|
||||
groups.add(state.garrisonHolder.entities)
|
||||
}
|
||||
if (
|
||||
g_SelectionPanels[guiName].conflictsWith &&
|
||||
g_SelectionPanels[guiName].conflictsWith.some(function (p) { return g_SelectionPanels[p].used; })
|
||||
)
|
||||
continue;
|
||||
|
||||
setupUnitPanel(GARRISON, usedPanels, entState, playerState, groups.getTemplateNames(),
|
||||
function (item) { unloadTemplate(item); } );
|
||||
setupUnitPanel(guiName, entState, playerState);
|
||||
}
|
||||
|
||||
var formations = Engine.GuiInterfaceCall("GetAvailableFormations");
|
||||
if (hasClass(entState, "Unit") && !hasClass(entState, "Animal") && !entState.garrisonHolder && formations.length)
|
||||
{
|
||||
setupUnitPanel(FORMATION, usedPanels, entState, playerState, formations,
|
||||
function (item) { performFormation(entState.id, item); } );
|
||||
}
|
||||
|
||||
// TODO: probably should load the stance list from a data file,
|
||||
// and/or vary depending on what units are selected
|
||||
var stances = ["violent", "aggressive", "passive", "defensive", "standground"];
|
||||
if (hasClass(entState, "Unit") && !hasClass(entState, "Animal") && stances.length)
|
||||
{
|
||||
setupUnitPanel(STANCE, usedPanels, entState, playerState, stances,
|
||||
function (item) { performStance(entState.id, item); } );
|
||||
}
|
||||
|
||||
Engine.GetGUIObjectByName("unitBarterPanel").hidden = !entState.barterMarket;
|
||||
if (entState.barterMarket)
|
||||
{
|
||||
usedPanels["Barter"] = 1;
|
||||
setupUnitBarterPanel(entState, playerState);
|
||||
}
|
||||
|
||||
var buildableEnts = getAllBuildableEntitiesFromSelection();
|
||||
var trainableEnts = getAllTrainableEntitiesFromSelection();
|
||||
|
||||
// Whether the GUI's right panel has been filled.
|
||||
var rightUsed = true;
|
||||
|
||||
// The first selected entity's type has priority.
|
||||
if (entState.buildEntities)
|
||||
setupUnitPanel(CONSTRUCTION, usedPanels, entState, playerState, buildableEnts,
|
||||
function (trainEntType) { startBuildingPlacement(trainEntType, playerState); } );
|
||||
else if (entState.production && entState.production.entities)
|
||||
setupUnitPanel(TRAINING, usedPanels, entState, playerState, trainableEnts,
|
||||
function (trainEntType) { addTrainingToQueue(selection, trainEntType, playerState); } );
|
||||
else if (!entState.foundation && entState.gate || hasClass(entState, "LongWall"))
|
||||
{
|
||||
// Allow long wall pieces to be converted to gates
|
||||
var longWallTypes = {};
|
||||
var walls = [];
|
||||
var gates = [];
|
||||
for (var i in selection)
|
||||
{
|
||||
var state = GetEntityState(selection[i]);
|
||||
if (hasClass(state, "LongWall") && !state.gate && !longWallTypes[state.template])
|
||||
{
|
||||
var gateTemplate = getWallGateTemplate(state.id);
|
||||
if (gateTemplate)
|
||||
{
|
||||
var tooltipString = GetTemplateDataWithoutLocalization(state.template).gateConversionTooltip;
|
||||
if (!tooltipString)
|
||||
{
|
||||
warn(state.template + " is supposed to be convertable to a gate, but it's missing the GateConversionTooltip in the Identity template");
|
||||
tooltipString = "";
|
||||
}
|
||||
walls.push({
|
||||
"tooltip": translate(tooltipString),
|
||||
"template": gateTemplate,
|
||||
"callback": function (item) { transformWallToGate(item.template); }
|
||||
});
|
||||
}
|
||||
|
||||
// We only need one entity per type.
|
||||
longWallTypes[state.template] = true;
|
||||
}
|
||||
else if (state.gate && !gates.length)
|
||||
{
|
||||
gates.push({
|
||||
"gate": state.gate,
|
||||
"tooltip": translate("Lock Gate"),
|
||||
"locked": true,
|
||||
"callback": function (item) { lockGate(item.locked); }
|
||||
});
|
||||
gates.push({
|
||||
"gate": state.gate,
|
||||
"tooltip": translate("Unlock Gate"),
|
||||
"locked": false,
|
||||
"callback": function (item) { lockGate(item.locked); }
|
||||
});
|
||||
}
|
||||
// Show both 'locked' and 'unlocked' as active if the selected gates have both lock states.
|
||||
else if (state.gate && state.gate.locked != gates[0].gate.locked)
|
||||
for (var j = 0; j < gates.length; ++j)
|
||||
delete gates[j].gate.locked;
|
||||
}
|
||||
|
||||
// Place wall conversion options after gate lock/unlock icons.
|
||||
var items = gates.concat(walls);
|
||||
if (items.length)
|
||||
setupUnitPanel(GATE, usedPanels, entState, playerState, items);
|
||||
else
|
||||
rightUsed = false;
|
||||
}
|
||||
else if (entState.pack)
|
||||
{
|
||||
var items = [];
|
||||
var packButton = false;
|
||||
var unpackButton = false;
|
||||
var packCancelButton = false;
|
||||
var unpackCancelButton = false;
|
||||
for (var i in selection)
|
||||
{
|
||||
// Find un/packable entities
|
||||
var state = GetEntityState(selection[i]);
|
||||
if (state.pack)
|
||||
{
|
||||
if (state.pack.progress == 0)
|
||||
{
|
||||
if (!state.pack.packed)
|
||||
packButton = true;
|
||||
else if (state.pack.packed)
|
||||
unpackButton = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Already un/packing - show cancel button
|
||||
if (!state.pack.packed)
|
||||
packCancelButton = true;
|
||||
else if (state.pack.packed)
|
||||
unpackCancelButton = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (packButton)
|
||||
items.push({ "packing": false, "packed": false, "tooltip": translate("Pack"), "callback": function() { packUnit(true); } });
|
||||
if (unpackButton)
|
||||
items.push({ "packing": false, "packed": true, "tooltip": translate("Unpack"), "callback": function() { packUnit(false); } });
|
||||
if (packCancelButton)
|
||||
items.push({ "packing": true, "packed": false, "tooltip": translate("Cancel Packing"), "callback": function() { cancelPackUnit(true); } });
|
||||
if (unpackCancelButton)
|
||||
items.push({ "packing": true, "packed": true, "tooltip": translate("Cancel Unpacking"), "callback": function() { cancelPackUnit(false); } });
|
||||
|
||||
if (items.length)
|
||||
setupUnitPanel(PACK, usedPanels, entState, playerState, items);
|
||||
else
|
||||
rightUsed = false;
|
||||
}
|
||||
else
|
||||
rightUsed = false;
|
||||
|
||||
if (!rightUsed)
|
||||
{
|
||||
// The right pane is empty. Fill the pane with a sane type.
|
||||
// Prefer buildables for units and trainables for structures.
|
||||
if (buildableEnts.length && (hasClass(entState, "Unit") || !trainableEnts.length))
|
||||
setupUnitPanel(CONSTRUCTION, usedPanels, entState, playerState, buildableEnts,
|
||||
function (trainEntType) { startBuildingPlacement(trainEntType, playerState); });
|
||||
else if (trainableEnts.length)
|
||||
setupUnitPanel(TRAINING, usedPanels, entState, playerState, trainableEnts,
|
||||
function (trainEntType) { addTrainingToQueue(selection, trainEntType, playerState); } );
|
||||
}
|
||||
// Show technologies if the active panel has at most one row of icons.
|
||||
if (entState.production && entState.production.technologies.length)
|
||||
{
|
||||
var activepane = usedPanels[CONSTRUCTION] ? buildableEnts.length : trainableEnts.length;
|
||||
if (selection.length == 1 || activepane <= 8)
|
||||
setupUnitPanel(RESEARCH, usedPanels, entState, playerState, entState.production.technologies,
|
||||
function (researchType) { addResearchToQueue(entState.id, researchType); } );
|
||||
}
|
||||
|
||||
if (entState.production && entState.production.queue.length)
|
||||
setupUnitPanel(QUEUE, usedPanels, entState, playerState, entState.production.queue,
|
||||
function (item) { removeFromProductionQueue(entState.id, item.id); } );
|
||||
|
||||
supplementalDetailsPanel.hidden = false;
|
||||
commandsPanel.hidden = false;
|
||||
}
|
||||
else if (playerState.isMutualAlly[entState.player]) // owned by allied player
|
||||
{
|
||||
if (entState.garrisonHolder)
|
||||
{
|
||||
var groups = new EntityGroups();
|
||||
for (var i in selection)
|
||||
{
|
||||
var state = GetEntityState(selection[i]);
|
||||
if (state.garrisonHolder)
|
||||
groups.add(state.garrisonHolder.entities)
|
||||
}
|
||||
|
||||
setupUnitPanel(GARRISON, usedPanels, entState, playerState, groups.getTemplateNames(),
|
||||
function (item) { unloadTemplate(item); } );
|
||||
|
||||
// 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);
|
||||
if (g_SelectionPanels["Garrison"].used)
|
||||
supplementalDetailsPanel.hidden = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
supplementalDetailsPanel.hidden = true;
|
||||
}
|
||||
|
||||
commandsPanel.hidden = true;
|
||||
}
|
||||
@ -637,21 +356,14 @@ function updateUnitCommands(entState, supplementalDetailsPanel, commandsPanel, s
|
||||
}
|
||||
|
||||
// Hides / unhides Unit Panels (panels should be grouped by type, not by order, but we will leave that for another time)
|
||||
var offset = 0;
|
||||
for each (var panelName in g_unitPanels)
|
||||
{
|
||||
var panel = Engine.GetGUIObjectByName("unit" + panelName + "Panel");
|
||||
if (usedPanels[panelName])
|
||||
panel.hidden = false;
|
||||
else
|
||||
panel.hidden = true;
|
||||
}
|
||||
for (var panelName in g_SelectionPanels)
|
||||
Engine.GetGUIObjectByName("unit" + panelName + "Panel").hidden = !g_SelectionPanels[panelName].used;
|
||||
}
|
||||
|
||||
// Force hide commands panels
|
||||
function hideUnitCommands()
|
||||
{
|
||||
for each (var panelName in g_unitPanels)
|
||||
for (var panelName in g_SelectionPanels)
|
||||
Engine.GetGUIObjectByName("unit" + panelName + "Panel").hidden = true;
|
||||
}
|
||||
|
||||
@ -730,4 +442,18 @@ function getVisibleEntityClassesFormatted(template)
|
||||
r += "[/font]";
|
||||
}
|
||||
return r;
|
||||
};
|
||||
}
|
||||
|
||||
function getNumberOfRightPanelButtons()
|
||||
{
|
||||
var sum = 0;
|
||||
if (g_SelectionPanels["Construction"].used)
|
||||
sum += g_unitPanelButtons["Construction"];
|
||||
if (g_SelectionPanels["Training"].used)
|
||||
sum += g_unitPanelButtons["Training"];
|
||||
if (g_SelectionPanels["Pack"].used)
|
||||
sum += g_unitPanelButtons["Pack"];
|
||||
if (g_SelectionPanels["Gate"].used)
|
||||
sum += g_unitPanelButtons["Gate"];
|
||||
return sum;
|
||||
}
|
||||
|
@ -288,6 +288,7 @@ GuiInterface.prototype.GetEntityState = function(player, ent)
|
||||
"hasWorkOrders": cmpUnitAI.HasWorkOrders(),
|
||||
"canGuard": cmpUnitAI.CanGuard(),
|
||||
"isGuarding": cmpUnitAI.IsGuardOf(),
|
||||
"possibleStances": cmpUnitAI.GetPossibleStances(),
|
||||
};
|
||||
// Add some information needed for ungarrisoning
|
||||
if (cmpUnitAI.IsGarrisoned() && ret.player !== undefined)
|
||||
|
@ -5439,6 +5439,11 @@ UnitAI.prototype.GetStance = function()
|
||||
return g_Stances[this.stance];
|
||||
};
|
||||
|
||||
UnitAI.prototype.GetPossibleStances = function()
|
||||
{
|
||||
return Object.keys(g_Stances);
|
||||
};
|
||||
|
||||
UnitAI.prototype.GetStanceName = function()
|
||||
{
|
||||
return this.stance;
|
||||
|
Loading…
Reference in New Issue
Block a user