mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-06-20 07:13:56 -07:00
Correctly handle commands and production for multiple units and mixed selections. Patch by Imarok, reviewed by Itms, fixes #3823. Fixes #3492, #3288, #3668.
This was SVN commit r18773.
This commit is contained in:
parent
a867fca514
commit
a754b1bad4
8 changed files with 269 additions and 230 deletions
|
|
@ -6,7 +6,7 @@
|
|||
</object>
|
||||
|
||||
<object hotkey="camera.rallypointfocus">
|
||||
<action on="Press">performCommand(g_Selection.getFirstSelected(), "focus-rally");</action>
|
||||
<action on="Press">performCommand(GetExtendedEntityState(g_Selection.getFirstSelected()), "focus-rally");</action>
|
||||
</object>
|
||||
|
||||
<!-- Camera jumping - press a hotkey to mark a position and another hotkey to jump back there -->
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@
|
|||
</object>
|
||||
|
||||
<object hotkey="session.kill">
|
||||
<action on="Press">performCommand(g_Selection.getFirstSelected(), "delete");</action>
|
||||
<action on="Press">performCommand(GetExtendedEntityState(g_Selection.getFirstSelected()), "delete");</action>
|
||||
</object>
|
||||
|
||||
<object hotkey="session.unload">
|
||||
|
|
|
|||
|
|
@ -228,7 +228,7 @@ function getActionInfo(action, target)
|
|||
if (unitActions[action] && unitActions[action].getActionInfo)
|
||||
{
|
||||
var r = unitActions[action].getActionInfo(entState, targetState, simState);
|
||||
if (r) // return true if it's possible for one of the entities
|
||||
if (r && r.possible) // return true if it's possible for one of the entities
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
|
@ -1452,20 +1452,21 @@ function addResearchToQueue(entity, researchType)
|
|||
Engine.PostNetworkCommand({ "type": "research", "entity": entity, "template": researchType });
|
||||
}
|
||||
|
||||
// Returns the number of units that will be present in a batch if the user clicks
|
||||
// the training button with shift down
|
||||
function getTrainingBatchStatus(playerState, entity, trainEntType, selection)
|
||||
/**
|
||||
* Returns the number of units that will be present in a batch if the user clicks
|
||||
* the training button with shift down
|
||||
*/
|
||||
function getTrainingBatchStatus(playerState, trainEntType, selection)
|
||||
{
|
||||
let batchIncrementSize = +Engine.ConfigDB_GetValue("user", "gui.session.batchtrainingsize");
|
||||
var appropriateBuildings = [entity];
|
||||
if (selection && selection.indexOf(entity) != -1)
|
||||
var appropriateBuildings = [];
|
||||
if (selection)
|
||||
appropriateBuildings = getBuildingsWhichCanTrainEntity(selection, trainEntType);
|
||||
var nextBatchTrainingCount = 0;
|
||||
var currentBatchTrainingCount = 0;
|
||||
|
||||
var limits;
|
||||
if (inputState == INPUT_BATCHTRAINING && batchTrainingEntities.indexOf(entity) != -1 &&
|
||||
batchTrainingType == trainEntType)
|
||||
if (inputState == INPUT_BATCHTRAINING && batchTrainingType == trainEntType)
|
||||
{
|
||||
nextBatchTrainingCount = batchTrainingCount;
|
||||
currentBatchTrainingCount = batchTrainingCount;
|
||||
|
|
@ -1507,11 +1508,10 @@ function changePrimarySelectionGroup(templateName, deselectGroup)
|
|||
g_Selection.makePrimarySelection(templateName, Engine.HotkeyIsPressed("session.deselectgroup") || deselectGroup);
|
||||
}
|
||||
|
||||
function performCommand(entity, commandName)
|
||||
function performCommand(entState, commandName)
|
||||
{
|
||||
if (!entity)
|
||||
if (!entState)
|
||||
return;
|
||||
var entState = GetExtendedEntityState(entity);
|
||||
|
||||
if (!controlsPlayer(entState.player) &&
|
||||
!(g_IsObserver && commandName == "focus-rally"))
|
||||
|
|
@ -1535,12 +1535,12 @@ function performAllyCommand(entity, commandName)
|
|||
g_AllyEntityCommands[commandName].execute(entState);
|
||||
}
|
||||
|
||||
function performFormation(entity, formationTemplate)
|
||||
function performFormation(entities, formationTemplate)
|
||||
{
|
||||
if (entity)
|
||||
if (entities)
|
||||
Engine.PostNetworkCommand({
|
||||
"type": "formation",
|
||||
"entities": g_Selection.toList(),
|
||||
"entities": entities,
|
||||
"name": formationTemplate
|
||||
});
|
||||
}
|
||||
|
|
@ -1582,17 +1582,14 @@ function performGroup(action, groupId)
|
|||
}
|
||||
}
|
||||
|
||||
function performStance(entity, stanceName)
|
||||
function performStance(entities, stanceName)
|
||||
{
|
||||
if (entity)
|
||||
{
|
||||
var selection = g_Selection.toList();
|
||||
if (entities)
|
||||
Engine.PostNetworkCommand({
|
||||
"type": "stance",
|
||||
"entities": selection,
|
||||
"entities": entities,
|
||||
"name": stanceName
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function lockGate(lock)
|
||||
|
|
@ -1817,10 +1814,22 @@ function removeGuard()
|
|||
Engine.PostNetworkCommand({ "type": "remove-guard", "entities": entities });
|
||||
}
|
||||
|
||||
function raiseAlert()
|
||||
{
|
||||
let entities = g_Selection.toList().filter(e => {
|
||||
let state = GetEntityState(e);
|
||||
return state && state.alertRaiser && !state.alertRaiser.hasRaisedAlert;
|
||||
});
|
||||
|
||||
Engine.PostNetworkCommand({ "type": "increase-alert-level", "entities": entities });
|
||||
}
|
||||
|
||||
function increaseAlertLevel()
|
||||
{
|
||||
var entities = g_Selection.toList().filter(e => {
|
||||
var state = GetEntityState(e);
|
||||
raiseAlert();
|
||||
|
||||
let entities = g_Selection.toList().filter(e => {
|
||||
let state = GetEntityState(e);
|
||||
return state && state.alertRaiser && state.alertRaiser.canIncreaseLevel;
|
||||
});
|
||||
|
||||
|
|
@ -1829,8 +1838,8 @@ function increaseAlertLevel()
|
|||
|
||||
function endOfAlert()
|
||||
{
|
||||
var entities = g_Selection.toList().filter(e => {
|
||||
var state = GetEntityState(e);
|
||||
let entities = g_Selection.toList().filter(e => {
|
||||
let state = GetEntityState(e);
|
||||
return state && state.alertRaiser && state.alertRaiser.hasRaisedAlert;
|
||||
});
|
||||
|
||||
|
|
@ -1849,35 +1858,3 @@ function clearSelection()
|
|||
preSelectedAction = ACTION_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all items in the productionqueue of the selection
|
||||
* @param selection List with entity ids
|
||||
*/
|
||||
function getTrainingQueueItems(selection)
|
||||
{
|
||||
var entStates = [];
|
||||
for (var ent of selection)
|
||||
{
|
||||
var entState = GetEntityState(ent);
|
||||
if (entState.production)
|
||||
entStates.push(entState);
|
||||
}
|
||||
var queue = [];
|
||||
var i = 0;
|
||||
do
|
||||
{
|
||||
var foundNewItems = false;
|
||||
for (entState of entStates)
|
||||
{
|
||||
if (!entState.production.queue[i])
|
||||
continue;
|
||||
var item = entState.production.queue[i];
|
||||
item.producingEnt = entState.id;
|
||||
queue.push(item);
|
||||
foundNewItems = true;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
while (foundNewItems);
|
||||
return queue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,14 +20,14 @@ function getResourceTypeDisplayName(resourceType)
|
|||
}
|
||||
|
||||
// Updates the health bar of garrisoned units
|
||||
function updateGarrisionHealthBar(entState, selection)
|
||||
function updateGarrisonHealthBar(entState, selection)
|
||||
{
|
||||
if (!entState.garrisonHolder)
|
||||
return;
|
||||
|
||||
// Summing up the Health of every single unit
|
||||
let totalGarrisionHealth = 0;
|
||||
let maxGarrisionHealth = 0;
|
||||
let totalGarrisonHealth = 0;
|
||||
let maxGarrisonHealth = 0;
|
||||
for (let selEnt of selection)
|
||||
{
|
||||
let selEntState = GetEntityState(selEnt);
|
||||
|
|
@ -35,24 +35,24 @@ function updateGarrisionHealthBar(entState, selection)
|
|||
for (let ent of selEntState.garrisonHolder.entities)
|
||||
{
|
||||
let state = GetEntityState(ent);
|
||||
totalGarrisionHealth += state.hitpoints || 0;
|
||||
maxGarrisionHealth += state.maxHitpoints || 0;
|
||||
totalGarrisonHealth += state.hitpoints || 0;
|
||||
maxGarrisonHealth += state.maxHitpoints || 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Configuring the health bar
|
||||
let healthGarrison = Engine.GetGUIObjectByName("healthGarrison");
|
||||
healthGarrison.hidden = totalGarrisionHealth <= 0;
|
||||
if (totalGarrisionHealth > 0)
|
||||
healthGarrison.hidden = totalGarrisonHealth <= 0;
|
||||
if (totalGarrisonHealth > 0)
|
||||
{
|
||||
let healthBarGarrison = Engine.GetGUIObjectByName("healthBarGarrison");
|
||||
let healthSize = healthBarGarrison.size;
|
||||
healthSize.rtop = 100-100*Math.max(0, Math.min(1, totalGarrisionHealth / maxGarrisionHealth));
|
||||
healthSize.rtop = 100-100*Math.max(0, Math.min(1, totalGarrisonHealth / maxGarrisonHealth));
|
||||
healthBarGarrison.size = healthSize;
|
||||
healthGarrison.tooltip = sprintf(translate("%(label)s %(current)s / %(max)s"), {
|
||||
"label": "[font=\"sans-bold-13\"]" + translate("Hitpoints:") + "[/font]",
|
||||
"current": Math.ceil(totalGarrisionHealth),
|
||||
"max": Math.ceil(maxGarrisionHealth)
|
||||
"current": Math.ceil(totalGarrisonHealth),
|
||||
"max": Math.ceil(maxGarrisonHealth)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -313,7 +313,7 @@ function displaySingle(entState)
|
|||
}
|
||||
|
||||
// Fills out information for multiple entities
|
||||
function displayMultiple(selection)
|
||||
function displayMultiple(entStates)
|
||||
{
|
||||
let averageHealth = 0;
|
||||
let maxHealth = 0;
|
||||
|
|
@ -323,11 +323,8 @@ function displayMultiple(selection)
|
|||
let totalCarrying = {};
|
||||
let totalLoot = {};
|
||||
|
||||
for (let i = 0; i < selection.length; ++i)
|
||||
for (let entState of entStates)
|
||||
{
|
||||
let entState = GetExtendedEntityState(selection[i]);
|
||||
if (!entState)
|
||||
continue;
|
||||
playerID = entState.player; // trust that all selected entities have the same owner
|
||||
if (entState.hitpoints)
|
||||
{
|
||||
|
|
@ -403,7 +400,7 @@ function displayMultiple(selection)
|
|||
}
|
||||
|
||||
let numberOfUnits = Engine.GetGUIObjectByName("numberOfUnits");
|
||||
numberOfUnits.caption = selection.length;
|
||||
numberOfUnits.caption = entStates.length;
|
||||
numberOfUnits.tooltip = "";
|
||||
|
||||
if (Object.keys(totalCarrying).length)
|
||||
|
|
@ -434,9 +431,17 @@ function updateSelectionDetails()
|
|||
let detailsPanel = Engine.GetGUIObjectByName("selectionDetails");
|
||||
let commandsPanel = Engine.GetGUIObjectByName("unitCommands");
|
||||
|
||||
let selection = g_Selection.toList();
|
||||
let entStates = [];
|
||||
|
||||
if (selection.length == 0)
|
||||
for (let sel of g_Selection.toList())
|
||||
{
|
||||
let entState = GetExtendedEntityState(sel);
|
||||
if (!entState)
|
||||
continue;
|
||||
entStates.push(entState);
|
||||
}
|
||||
|
||||
if (entStates.length == 0)
|
||||
{
|
||||
Engine.GetGUIObjectByName("detailsAreaMultiple").hidden = true;
|
||||
Engine.GetGUIObjectByName("detailsAreaSingle").hidden = true;
|
||||
|
|
@ -448,26 +453,19 @@ function updateSelectionDetails()
|
|||
return;
|
||||
}
|
||||
|
||||
/* If the unit has no data (e.g. it was killed), don't try displaying any
|
||||
data for it. (TODO: it should probably be removed from the selection too;
|
||||
also need to handle multi-unit selections) */
|
||||
let entState = GetExtendedEntityState(selection[0]);
|
||||
if (!entState)
|
||||
return;
|
||||
|
||||
// Fill out general info and display it
|
||||
if (selection.length == 1)
|
||||
displaySingle(entState);
|
||||
if (entStates.length == 1)
|
||||
displaySingle(entStates[0]);
|
||||
else
|
||||
displayMultiple(selection);
|
||||
displayMultiple(entStates);
|
||||
|
||||
// Show basic details.
|
||||
detailsPanel.hidden = false;
|
||||
|
||||
// Fill out commands panel for specific unit selected (or first unit of primary group)
|
||||
updateUnitCommands(entState, supplementalDetailsPanel, commandsPanel, selection);
|
||||
updateUnitCommands(entStates, supplementalDetailsPanel, commandsPanel);
|
||||
|
||||
// Show health bar for garrisoned units if the garrison panel is visible
|
||||
if (Engine.GetGUIObjectByName("unitGarrisonPanel") && !Engine.GetGUIObjectByName("unitGarrisonPanel").hidden)
|
||||
updateGarrisionHealthBar(entState, selection);
|
||||
updateGarrisonHealthBar(entStates[0], g_Selection.toList());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,9 +12,8 @@
|
|||
* {
|
||||
* "i": index
|
||||
* "item": item coming from the getItems function
|
||||
* "selection": list of currently selected items
|
||||
* "playerState": playerState
|
||||
* "unitEntState": first selected entity state
|
||||
* "unitEntStates": states of the selected entities
|
||||
* "rowLength": rowLength
|
||||
* "numberOfItems": number of items that will be processed
|
||||
* "button": gui Button object
|
||||
|
|
@ -37,49 +36,59 @@ let g_SelectionPanels = {};
|
|||
g_SelectionPanels.Alert = {
|
||||
"getMaxNumberOfItems": function()
|
||||
{
|
||||
return 2;
|
||||
return 3;
|
||||
},
|
||||
"getItems": function(unitEntState)
|
||||
"conflictsWith": ["Barter"],
|
||||
"getItems": function(unitEntStates)
|
||||
{
|
||||
if (!unitEntState.alertRaiser)
|
||||
return [];
|
||||
return ["increase", "end"];
|
||||
let ret = [];
|
||||
|
||||
if (unitEntStates.some(state => state.alertRaiser && !state.alertRaiser.hasRaisedAlert))
|
||||
ret.push("raise");
|
||||
|
||||
if (unitEntStates.some(state => state.alertRaiser && state.alertRaiser.hasRaisedAlert && state.alertRaiser.canIncreaseLevel))
|
||||
ret.push("increase");
|
||||
|
||||
if (unitEntStates.some(state => state.alertRaiser && state.alertRaiser.hasRaisedAlert))
|
||||
ret.push("end");
|
||||
|
||||
return ret;
|
||||
},
|
||||
"setupButton": function(data)
|
||||
{
|
||||
data.button.onPress = function() {
|
||||
if (data.item == "increase")
|
||||
switch (data.item)
|
||||
{
|
||||
case "raise":
|
||||
raiseAlert();
|
||||
return;
|
||||
case "increase":
|
||||
increaseAlertLevel();
|
||||
else if (data.item == "end")
|
||||
return;
|
||||
case "end":
|
||||
endOfAlert();
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
if (data.item == "increase")
|
||||
switch (data.item)
|
||||
{
|
||||
if (data.unitEntState.alertRaiser.hasRaisedAlert)
|
||||
data.button.tooltip = translate("Increase the alert level to protect more units");
|
||||
else
|
||||
data.button.tooltip = translate("Raise an alert!");
|
||||
}
|
||||
else if (data.item == "end")
|
||||
case "raise":
|
||||
data.icon.sprite = "stretched:session/icons/bell_level1.png";
|
||||
data.button.tooltip = translate("Raise an alert!");
|
||||
break;
|
||||
case "increase":
|
||||
data.icon.sprite = "stretched:session/icons/bell_level2.png";
|
||||
data.button.tooltip = translate("Increase the alert level to protect more units");
|
||||
break;
|
||||
case "end":
|
||||
data.button.tooltip = translate("End of alert.");
|
||||
|
||||
if (data.item == "increase")
|
||||
{
|
||||
data.button.hidden = !data.unitEntState.alertRaiser.canIncreaseLevel;
|
||||
if (data.unitEntState.alertRaiser.hasRaisedAlert)
|
||||
data.icon.sprite = "stretched:session/icons/bell_level2.png";
|
||||
else
|
||||
data.icon.sprite = "stretched:session/icons/bell_level1.png";
|
||||
}
|
||||
else if (data.item == "end")
|
||||
{
|
||||
data.button.hidden = !data.unitEntState.alertRaiser.hasRaisedAlert;
|
||||
data.icon.sprite = "stretched:session/icons/bell_level0.png";
|
||||
break;
|
||||
}
|
||||
data.button.enabled = !data.button.hidden && controlsPlayer(data.unitEntState.player);
|
||||
data.button.enabled = controlsPlayer(data.player);
|
||||
|
||||
setPanelObjectPosition(data.button, data.i, data.rowLength);
|
||||
setPanelObjectPosition(data.button, this.getMaxNumberOfItems() - data.i - 1, data.rowLength);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
|
@ -90,9 +99,10 @@ g_SelectionPanels.Barter = {
|
|||
return 4;
|
||||
},
|
||||
"rowLength": 4,
|
||||
"getItems": function(unitEntState, selection)
|
||||
"conflictsWith": ["Alert", "Garrison"],
|
||||
"getItems": function(unitEntStates)
|
||||
{
|
||||
if (!unitEntState.barterMarket)
|
||||
if (unitEntStates.every(state => !state.barterMarket))
|
||||
return [];
|
||||
// ["food", "wood", "stone", "metal"]
|
||||
return BARTER_RESOURCES;
|
||||
|
|
@ -116,7 +126,14 @@ g_SelectionPanels.Barter = {
|
|||
amountToSell *= BARTER_BUNCH_MULTIPLIER;
|
||||
|
||||
amount.Sell.caption = "-" + amountToSell;
|
||||
let prices = data.unitEntState.barterMarket.prices;
|
||||
let prices;
|
||||
for (let state of data.unitEntStates)
|
||||
if (state.barterMarket)
|
||||
{
|
||||
prices = state.barterMarket.prices;
|
||||
break;
|
||||
}
|
||||
|
||||
amount.Buy.caption = "+" + Math.round(prices.sell[g_BarterSell] / prices.buy[data.item] * amountToSell);
|
||||
|
||||
let resource = getLocalizedResourceName(data.item, "withinSentence");
|
||||
|
|
@ -145,7 +162,7 @@ g_SelectionPanels.Barter = {
|
|||
neededRes[data.item] = amountToSell;
|
||||
let canSellCurrent = Engine.GuiInterfaceCall("GetNeededResources", {
|
||||
"cost": neededRes,
|
||||
"player": data.unitEntState.player
|
||||
"player": data.player
|
||||
}) ? "color:255 0 0 80:" : "";
|
||||
|
||||
// Let's see if we have enough resources to barter.
|
||||
|
|
@ -153,14 +170,14 @@ g_SelectionPanels.Barter = {
|
|||
neededRes[g_BarterSell] = amountToSell;
|
||||
let canBuyAny = Engine.GuiInterfaceCall("GetNeededResources", {
|
||||
"cost": neededRes,
|
||||
"player": data.unitEntState.player
|
||||
"player": data.player
|
||||
}) ? "color:255 0 0 80:" : "";
|
||||
|
||||
icon.Sell.sprite = canSellCurrent + "stretched:" + grayscale + "session/icons/resources/" + data.item + ".png";
|
||||
icon.Buy.sprite = canBuyAny + "stretched:" + grayscale + "session/icons/resources/" + data.item + ".png";
|
||||
|
||||
button.Buy.hidden = isSelected;
|
||||
button.Buy.enabled = controlsPlayer(data.unitEntState.player);
|
||||
button.Buy.enabled = controlsPlayer(data.player);
|
||||
button.Sell.hidden = false;
|
||||
selectionIcon.hidden = !isSelected;
|
||||
|
||||
|
|
@ -175,18 +192,22 @@ g_SelectionPanels.Command = {
|
|||
{
|
||||
return 6;
|
||||
},
|
||||
"getItems": function(unitEntState)
|
||||
"getItems": function(unitEntStates)
|
||||
{
|
||||
let commands = [];
|
||||
|
||||
for (let c in g_EntityCommands)
|
||||
for (let command in g_EntityCommands)
|
||||
{
|
||||
let info = g_EntityCommands[c].getInfo(unitEntState);
|
||||
if (!info)
|
||||
continue;
|
||||
|
||||
info.name = c;
|
||||
commands.push(info);
|
||||
for (let state of unitEntStates)
|
||||
{
|
||||
let info = g_EntityCommands[command].getInfo(state);
|
||||
if (info)
|
||||
{
|
||||
info.name = command;
|
||||
commands.push(info);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return commands;
|
||||
},
|
||||
|
|
@ -198,15 +219,15 @@ g_SelectionPanels.Command = {
|
|||
if (data.item.callback)
|
||||
data.item.callback(data.item);
|
||||
else
|
||||
performCommand(data.unitEntState.id, data.item.name);
|
||||
performCommand(data.unitEntStates[0], data.item.name);
|
||||
};
|
||||
|
||||
data.countDisplay.caption = data.item.count || "";
|
||||
|
||||
data.button.enabled =
|
||||
g_IsObserver && data.item.name == "focus-rally" ||
|
||||
controlsPlayer(data.unitEntState.player) &&
|
||||
(data.item.name != "delete" || !isUndeletable(data.unitEntState));
|
||||
controlsPlayer(data.player) && (data.item.name != "delete" ||
|
||||
data.unitEntStates.some(state => !isUndeletable(state)));
|
||||
|
||||
data.icon.sprite = "stretched:session/icons/" + data.item.icon;
|
||||
|
||||
|
|
@ -229,16 +250,21 @@ g_SelectionPanels.AllyCommand = {
|
|||
return 2;
|
||||
},
|
||||
"conflictsWith": ["Command"],
|
||||
"getItems": function(unitEntState)
|
||||
"getItems": function(unitEntStates)
|
||||
{
|
||||
let commands = [];
|
||||
for (let c in g_AllyEntityCommands)
|
||||
for (let command in g_AllyEntityCommands)
|
||||
{
|
||||
let info = g_AllyEntityCommands[c].getInfo(unitEntState);
|
||||
if (!info)
|
||||
continue;
|
||||
info.name = c;
|
||||
commands.push(info);
|
||||
for (let state of unitEntStates)
|
||||
{
|
||||
let info = g_AllyEntityCommands[command].getInfo(state);
|
||||
if (info)
|
||||
{
|
||||
info.name = command;
|
||||
commands.push(info);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return commands;
|
||||
},
|
||||
|
|
@ -250,7 +276,7 @@ g_SelectionPanels.AllyCommand = {
|
|||
if (data.item.callback)
|
||||
data.item.callback(data.item);
|
||||
else
|
||||
performAllyCommand(data.unitEntState.id, data.item.name);
|
||||
performAllyCommand(data.unitEntStates[0].id, data.item.name);
|
||||
};
|
||||
|
||||
data.countDisplay.caption = data.item.count || "";
|
||||
|
|
@ -292,14 +318,14 @@ g_SelectionPanels.Construction = {
|
|||
|
||||
let technologyEnabled = Engine.GuiInterfaceCall("IsTechnologyResearched", {
|
||||
"tech": template.requiredTechnology,
|
||||
"player": data.unitEntState.player
|
||||
"player": data.player
|
||||
});
|
||||
|
||||
let neededResources;
|
||||
if (template.cost)
|
||||
neededResources = Engine.GuiInterfaceCall("GetNeededResources", {
|
||||
"cost": multiplyEntityCosts(template, 1),
|
||||
"player": data.unitEntState.player
|
||||
"player": data.player
|
||||
});
|
||||
|
||||
if (template.wallSet)
|
||||
|
|
@ -341,7 +367,7 @@ g_SelectionPanels.Construction = {
|
|||
modifier += resourcesToAlphaMask(neededResources) +":";
|
||||
}
|
||||
else
|
||||
data.button.enabled = controlsPlayer(data.unitEntState.player);
|
||||
data.button.enabled = controlsPlayer(data.player);
|
||||
|
||||
if (template.icon)
|
||||
data.icon.sprite = modifier + "stretched:session/portraits/" + template.icon;
|
||||
|
|
@ -359,13 +385,13 @@ g_SelectionPanels.Formation = {
|
|||
},
|
||||
"rowLength": 4,
|
||||
"conflictsWith": ["Garrison"],
|
||||
"getItems": function(unitEntState)
|
||||
"getItems": function(unitEntStates)
|
||||
{
|
||||
if (!hasClass(unitEntState, "Unit") || hasClass(unitEntState, "Animal"))
|
||||
if (unitEntStates.some(state => !hasClass(state, "Unit") || hasClass(state, "Animal")))
|
||||
return [];
|
||||
if (!g_AvailableFormations.has(unitEntState.player))
|
||||
g_AvailableFormations.set(unitEntState.player, Engine.GuiInterfaceCall("GetAvailableFormations", unitEntState.player));
|
||||
return g_AvailableFormations.get(unitEntState.player);
|
||||
if (!g_AvailableFormations.has(unitEntStates[0].player))
|
||||
g_AvailableFormations.set(unitEntStates[0].player, Engine.GuiInterfaceCall("GetAvailableFormations", unitEntStates[0].player));
|
||||
return g_AvailableFormations.get(unitEntStates[0].player);
|
||||
},
|
||||
"setupButton": function(data)
|
||||
{
|
||||
|
|
@ -375,18 +401,20 @@ g_SelectionPanels.Formation = {
|
|||
let formationInfo = g_FormationsInfo.get(data.item);
|
||||
let formationOk = canMoveSelectionIntoFormation(data.item);
|
||||
let formationSelected = Engine.GuiInterfaceCall("IsFormationSelected", {
|
||||
"ents": data.selection,
|
||||
"ents": data.unitEntStates.map(state => state.id),
|
||||
"formationTemplate": data.item
|
||||
});
|
||||
|
||||
data.button.onPress = function() { performFormation(data.unitEntState.id, data.item); };
|
||||
data.button.onPress = function() {
|
||||
performFormation(data.unitEntStates.map(state => state.id), data.item);
|
||||
};
|
||||
|
||||
let tooltip = translate(formationInfo.name);
|
||||
if (!formationOk && formationInfo.tooltip)
|
||||
tooltip += "\n" + "[color=\"red\"]" + translate(formationInfo.tooltip) + "[/color]";
|
||||
data.button.tooltip = tooltip;
|
||||
|
||||
data.button.enabled = formationOk && controlsPlayer(data.unitEntState.player);
|
||||
data.button.enabled = formationOk && controlsPlayer(data.player);
|
||||
let grayscale = formationOk ? "" : "grayscale:";
|
||||
data.guiSelection.hidden = !formationSelected;
|
||||
data.icon.sprite = "stretched:" + grayscale + "session/icons/" + formationInfo.icon;
|
||||
|
|
@ -402,19 +430,17 @@ g_SelectionPanels.Garrison = {
|
|||
return 12;
|
||||
},
|
||||
"rowLength": 4,
|
||||
"getItems": function(unitEntState, selection)
|
||||
"conflictsWith": ["Barter"],
|
||||
"getItems": function(unitEntStates)
|
||||
{
|
||||
if (!unitEntState.garrisonHolder)
|
||||
if (unitEntStates.every(state => !state.garrisonHolder))
|
||||
return [];
|
||||
|
||||
let groups = new EntityGroups();
|
||||
|
||||
for (let ent of selection)
|
||||
{
|
||||
let state = GetEntityState(ent);
|
||||
for (let state of unitEntStates)
|
||||
if (state.garrisonHolder)
|
||||
groups.add(state.garrisonHolder.entities);
|
||||
}
|
||||
|
||||
return groups.getEntsGrouped();
|
||||
},
|
||||
|
|
@ -433,7 +459,7 @@ g_SelectionPanels.Garrison = {
|
|||
let garrisonedUnitOwner = GetEntityState(data.item.ents[0]).player;
|
||||
|
||||
let canUngarrison =
|
||||
g_ViewedPlayer == data.unitEntState.player ||
|
||||
g_ViewedPlayer == data.player ||
|
||||
g_ViewedPlayer == garrisonedUnitOwner;
|
||||
|
||||
data.button.enabled = canUngarrison && controlsPlayer(g_ViewedPlayer);
|
||||
|
|
@ -470,12 +496,11 @@ g_SelectionPanels.Gate = {
|
|||
{
|
||||
return 24 - getNumberOfRightPanelButtons();
|
||||
},
|
||||
"getItems": function(unitEntState, selection)
|
||||
"getItems": function(unitEntStates)
|
||||
{
|
||||
let gates = [];
|
||||
for (let ent of selection)
|
||||
for (let state of unitEntStates)
|
||||
{
|
||||
let state = GetEntityState(ent);
|
||||
if (state.gate && !gates.length)
|
||||
{
|
||||
gates.push({
|
||||
|
|
@ -505,7 +530,7 @@ g_SelectionPanels.Gate = {
|
|||
|
||||
data.button.tooltip = data.item.tooltip;
|
||||
|
||||
data.button.enabled = controlsPlayer(data.unitEntState.player);
|
||||
data.button.enabled = controlsPlayer(data.player);
|
||||
let gateIcon;
|
||||
if (data.item.gate)
|
||||
{
|
||||
|
|
@ -530,12 +555,11 @@ g_SelectionPanels.Pack = {
|
|||
{
|
||||
return 24 - getNumberOfRightPanelButtons();
|
||||
},
|
||||
"getItems": function(unitEntState, selection)
|
||||
"getItems": function(unitEntStates)
|
||||
{
|
||||
let checks = {};
|
||||
for (let ent of selection)
|
||||
for (let state of unitEntStates)
|
||||
{
|
||||
let state = GetEntityState(ent);
|
||||
if (!state.pack)
|
||||
continue;
|
||||
|
||||
|
|
@ -603,7 +627,7 @@ g_SelectionPanels.Pack = {
|
|||
else
|
||||
data.icon.sprite = "stretched:session/icons/pack.png";
|
||||
|
||||
data.button.enabled = controlsPlayer(data.unitEntState.player);
|
||||
data.button.enabled = controlsPlayer(data.player);
|
||||
|
||||
let index = data.i + getNumberOfRightPanelButtons();
|
||||
setPanelObjectPosition(data.button, index, data.rowLength);
|
||||
|
|
@ -616,9 +640,29 @@ g_SelectionPanels.Queue = {
|
|||
{
|
||||
return 16;
|
||||
},
|
||||
"getItems": function(unitEntState, selection)
|
||||
/**
|
||||
* Returns a list of all items in the productionqueue of the selection
|
||||
* The first entry of every entity's production queue will come before
|
||||
* the second entry of every entity's production queue
|
||||
*/
|
||||
"getItems": function(unitEntStates)
|
||||
{
|
||||
return getTrainingQueueItems(selection);
|
||||
let queue = [];
|
||||
let foundNew = true;
|
||||
for (let i = 0; foundNew; ++i)
|
||||
{
|
||||
foundNew = false;
|
||||
for (let state of unitEntStates)
|
||||
{
|
||||
if (!state.production || !state.production.queue[i])
|
||||
continue;
|
||||
let item = state.production.queue[i];
|
||||
item.producingEnt = state.id;
|
||||
queue.push(item);
|
||||
foundNew = true;
|
||||
}
|
||||
}
|
||||
return queue;
|
||||
},
|
||||
"resizePanel": function(numberOfItems, rowLength)
|
||||
{
|
||||
|
|
@ -671,7 +715,7 @@ g_SelectionPanels.Queue = {
|
|||
if (template.icon)
|
||||
data.icon.sprite = "stretched:session/portraits/" + template.icon;
|
||||
|
||||
data.button.enabled = controlsPlayer(data.unitEntState.player);
|
||||
data.button.enabled = controlsPlayer(data.player);
|
||||
|
||||
setPanelObjectPosition(data.button, data.i, data.rowLength);
|
||||
return true;
|
||||
|
|
@ -683,23 +727,37 @@ g_SelectionPanels.Research = {
|
|||
{
|
||||
return 8;
|
||||
},
|
||||
"getItems": function(unitEntState, selection)
|
||||
"getItems": function(unitEntStates)
|
||||
{
|
||||
// Tech-pairs require two rows. Thus only show techs when there is only one row in use.
|
||||
// TODO Use a reference instead of a magic number
|
||||
if (getNumberOfRightPanelButtons() > 8 && selection.length > 1)
|
||||
return [];
|
||||
|
||||
for (let ent of selection)
|
||||
{
|
||||
let entState = GetEntityState(ent);
|
||||
if (entState.production && entState.production.technologies.length)
|
||||
return entState.production.technologies.map(tech => ({
|
||||
let ret = [];
|
||||
if (unitEntStates.length == 1)
|
||||
return !unitEntStates[0].production || !unitEntStates[0].production.technologies ? ret :
|
||||
unitEntStates[0].production.technologies.map(tech => ({
|
||||
"tech": tech,
|
||||
"techCostMultiplier": entState.production.techCostMultiplier
|
||||
"techCostMultiplier": unitEntStates[0].production.techCostMultiplier,
|
||||
"researchFacilityId": unitEntStates[0].id
|
||||
}));
|
||||
|
||||
for (let state of unitEntStates)
|
||||
{
|
||||
if (!state.production || !state.production.technologies)
|
||||
continue;
|
||||
// Remove the techs we already have in ret (with the same name and techCostMultiplier)
|
||||
let filteredTechs = state.production.technologies.filter(
|
||||
tech => tech != null && !ret.some(
|
||||
item => item.tech == tech && Object.keys(item.techCostMultiplier).every(
|
||||
k => item.techCostMultiplier[k] == state.production.techCostMultiplier[k]
|
||||
)));
|
||||
|
||||
if (filteredTechs.length + ret.length <= this.getMaxNumberOfItems() &&
|
||||
getNumberOfRightPanelButtons() <= this.getMaxNumberOfItems() * (filteredTechs.some(tech => !!tech.pair) ? 1 : 2))
|
||||
ret = ret.concat(filteredTechs.map(tech => ({
|
||||
"tech": tech,
|
||||
"techCostMultiplier": state.production.techCostMultiplier,
|
||||
"researchFacilityId": state.id
|
||||
})));
|
||||
}
|
||||
return [];
|
||||
return ret;
|
||||
},
|
||||
"hideItem": function(i, rowLength) // Called when no item is found
|
||||
{
|
||||
|
|
@ -729,7 +787,7 @@ g_SelectionPanels.Research = {
|
|||
pair.hidden = data.item.tech.pair == null;
|
||||
setPanelObjectPosition(pair, data.i, data.rowLength);
|
||||
|
||||
// Handle one or two techs
|
||||
// Handle one or two techs (tech pair)
|
||||
for (let i in techs)
|
||||
{
|
||||
let tech = techs[i];
|
||||
|
|
@ -742,12 +800,12 @@ g_SelectionPanels.Research = {
|
|||
|
||||
let neededResources = Engine.GuiInterfaceCall("GetNeededResources", {
|
||||
"cost": template.cost,
|
||||
"player": data.unitEntState.player
|
||||
"player": data.player
|
||||
});
|
||||
|
||||
let requirementsPassed = Engine.GuiInterfaceCall("CheckTechnologyRequirements", {
|
||||
"tech": tech,
|
||||
"player": data.unitEntState.player
|
||||
"player": data.player
|
||||
});
|
||||
|
||||
let button = Engine.GetGUIObjectByName("unitResearchButton[" + position + "]");
|
||||
|
|
@ -764,7 +822,7 @@ g_SelectionPanels.Research = {
|
|||
let tip = template.requirementsTooltip;
|
||||
if (template.classRequirements)
|
||||
{
|
||||
let player = data.unitEntState.player;
|
||||
let player = data.player;
|
||||
let current = GetSimState().players[player].classCounts[template.classRequirements.class] || 0;
|
||||
let remaining = template.classRequirements.number - current;
|
||||
tip += " " + sprintf(translatePlural("Remaining: %(number)s to build.", "Remaining: %(number)s to build.", remaining), {
|
||||
|
|
@ -777,7 +835,7 @@ g_SelectionPanels.Research = {
|
|||
button.tooltip = tooltips.filter(tip => tip).join("\n");
|
||||
|
||||
button.onPress = function () {
|
||||
addResearchToQueue(data.unitEntState.id, tech);
|
||||
addResearchToQueue(data.item.researchFacilityId, tech);
|
||||
};
|
||||
|
||||
if (data.item.tech.pair)
|
||||
|
|
@ -806,7 +864,7 @@ g_SelectionPanels.Research = {
|
|||
modifier += resourcesToAlphaMask(neededResources) + ":";
|
||||
}
|
||||
else
|
||||
button.enabled = controlsPlayer(data.unitEntState.player);
|
||||
button.enabled = controlsPlayer(data.player);
|
||||
|
||||
if (template.icon)
|
||||
icon.sprite = modifier + "stretched:session/portraits/" + template.icon;
|
||||
|
|
@ -827,9 +885,9 @@ g_SelectionPanels.Selection = {
|
|||
return 16;
|
||||
},
|
||||
"rowLength": 4,
|
||||
"getItems": function(unitEntState, selection)
|
||||
"getItems": function(unitEntStates)
|
||||
{
|
||||
if (selection.length < 2)
|
||||
if (unitEntStates.length < 2)
|
||||
return [];
|
||||
return g_Selection.groups.getTemplateNames();
|
||||
},
|
||||
|
|
@ -898,25 +956,26 @@ g_SelectionPanels.Stance = {
|
|||
{
|
||||
return 5;
|
||||
},
|
||||
"getItems": function(unitEntState)
|
||||
"getItems": function(unitEntStates)
|
||||
{
|
||||
if (!unitEntState.unitAI || !hasClass(unitEntState, "Unit") || hasClass(unitEntState, "Animal"))
|
||||
if (unitEntStates.some(state => !state.unitAI || !hasClass(state, "Unit") || hasClass(state, "Animal")))
|
||||
return [];
|
||||
return unitEntState.unitAI.possibleStances;
|
||||
|
||||
return unitEntStates[0].unitAI.possibleStances;
|
||||
},
|
||||
"setupButton": function(data)
|
||||
{
|
||||
data.button.onPress = function() { performStance(data.unitEntState, data.item); };
|
||||
data.button.onPress = function() { performStance(data.unitEntStates.map(state => state.id), data.item); };
|
||||
|
||||
data.button.tooltip = getStanceDisplayName(data.item) + "\n" +
|
||||
"[font=\"sans-13\"]" + getStanceTooltip(data.item) + "[/font]";
|
||||
|
||||
data.guiSelection.hidden = !Engine.GuiInterfaceCall("IsStanceSelected", {
|
||||
"ents": data.selection,
|
||||
"ents": data.unitEntStates.map(state => state.id),
|
||||
"stance": data.item
|
||||
});
|
||||
data.icon.sprite = "stretched:session/icons/stances/" + data.item + ".png";
|
||||
data.button.enabled = controlsPlayer(data.unitEntState.player);
|
||||
data.button.enabled = controlsPlayer(data.player);
|
||||
|
||||
setPanelObjectPosition(data.button, data.i, data.rowLength);
|
||||
return true;
|
||||
|
|
@ -940,11 +999,11 @@ g_SelectionPanels.Training = {
|
|||
|
||||
let technologyEnabled = Engine.GuiInterfaceCall("IsTechnologyResearched", {
|
||||
"tech": template.requiredTechnology,
|
||||
"player": data.unitEntState.player
|
||||
"player": data.player
|
||||
});
|
||||
|
||||
let [buildingsCountToTrainFullBatch, fullBatchSize, remainderBatch] =
|
||||
getTrainingBatchStatus(data.playerState, data.unitEntState.id, data.item, data.selection);
|
||||
getTrainingBatchStatus(data.playerState, data.item, data.unitEntStates.map(status => status.id));
|
||||
|
||||
let trainNum = buildingsCountToTrainFullBatch || 1;
|
||||
if (Engine.HotkeyIsPressed("session.batchtrain"))
|
||||
|
|
@ -954,10 +1013,12 @@ g_SelectionPanels.Training = {
|
|||
if (template.cost)
|
||||
neededResources = Engine.GuiInterfaceCall("GetNeededResources", {
|
||||
"cost": multiplyEntityCosts(template, trainNum),
|
||||
"player": data.unitEntState.player
|
||||
"player": data.player
|
||||
});
|
||||
|
||||
data.button.onPress = function() { addTrainingToQueue(data.selection, data.item, data.playerState); };
|
||||
data.button.onPress = function() {
|
||||
addTrainingToQueue(data.unitEntStates.map(state => state.id), data.item, data.playerState);
|
||||
};
|
||||
|
||||
data.countDisplay.caption = trainNum > 1 ? trainNum : "";
|
||||
|
||||
|
|
@ -968,7 +1029,7 @@ g_SelectionPanels.Training = {
|
|||
getVisibleEntityClassesFormatted(template),
|
||||
getAurasTooltip(template),
|
||||
getEntityTooltip(template),
|
||||
getEntityCostTooltip(template, trainNum, data.unitEntState.id)
|
||||
getEntityCostTooltip(template, trainNum, data.unitEntStates[0].id)
|
||||
];
|
||||
|
||||
let limits = getEntityLimitAndCount(data.playerState, data.item);
|
||||
|
|
@ -1013,7 +1074,7 @@ g_SelectionPanels.Training = {
|
|||
modifier = resourcesToAlphaMask(neededResources) +":";
|
||||
}
|
||||
else
|
||||
data.button.enabled = controlsPlayer(data.unitEntState.player);
|
||||
data.button.enabled = controlsPlayer(data.player);
|
||||
|
||||
if (template.icon)
|
||||
data.icon.sprite = modifier + "stretched:session/portraits/" + template.icon;
|
||||
|
|
@ -1030,14 +1091,13 @@ g_SelectionPanels.Upgrade = {
|
|||
{
|
||||
return 24 - getNumberOfRightPanelButtons();
|
||||
},
|
||||
"getItems": function(unitEntState, selection)
|
||||
"getItems": function(unitEntStates)
|
||||
{
|
||||
// Interface becomes complicated with multiple units and this is meant per-entity, so prevent it if the selection has multiple units.
|
||||
// TODO: if the units are all the same, this should probably still be possible.
|
||||
if (selection.length > 1)
|
||||
// Interface becomes complicated with multiple different units and this is meant per-entity, so prevent it if the selection has multiple different units.
|
||||
if (unitEntStates.some(state => state.template != unitEntStates[0].template))
|
||||
return false;
|
||||
|
||||
return unitEntState.upgrade && unitEntState.upgrade.upgrades;
|
||||
return unitEntStates[0].upgrade && unitEntStates[0].upgrade.upgrades;
|
||||
},
|
||||
"setupButton" : function(data)
|
||||
{
|
||||
|
|
@ -1050,19 +1110,19 @@ g_SelectionPanels.Upgrade = {
|
|||
if (data.item.requiredTechnology)
|
||||
technologyEnabled = Engine.GuiInterfaceCall("IsTechnologyResearched", {
|
||||
"tech": data.item.requiredTechnology,
|
||||
"player": data.unitEntState.player
|
||||
"player": data.player
|
||||
});
|
||||
|
||||
let neededResources;
|
||||
if (data.item.cost)
|
||||
neededResources = Engine.GuiInterfaceCall("GetNeededResources", {
|
||||
"cost": data.item.cost,
|
||||
"player": data.unitEntState.player
|
||||
"player": data.player
|
||||
});
|
||||
|
||||
let limits = getEntityLimitAndCount(data.playerState, data.item.entity);
|
||||
let progress = data.unitEntState.upgrade.progress || 0;
|
||||
let isUpgrading = data.unitEntState.upgrade.template == data.item.entity;
|
||||
let progress = data.unitEntStates[0].upgrade.progress || 0;
|
||||
let isUpgrading = data.unitEntStates[0].upgrade.template == data.item.entity;
|
||||
|
||||
let tooltip;
|
||||
if (!progress)
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@
|
|||
size="4 100%-43 100%-4 100%-4"
|
||||
type="text"
|
||||
>
|
||||
<object size="100%-72 2 100% 100%">
|
||||
<repeat count="2">
|
||||
<object size="100%-110 2 100% 100%-2">
|
||||
<repeat count="3">
|
||||
<object name="unitAlertButton[n]" hidden="true" style="iconButton" type="button" size="0 0 36 36" tooltip_style="sessionToolTipBottomBold" z="100">
|
||||
<object name="unitAlertIcon[n]" type="image" ghost="true" size="3 3 33 33"/>
|
||||
</object>
|
||||
|
|
|
|||
|
|
@ -44,10 +44,10 @@ function setPanelObjectPosition(object, index, rowLength, vMargin = 1, hMargin =
|
|||
* (i.e. panels with rows of icons) for the currently selected unit.
|
||||
*
|
||||
* @param guiName Short identifier string of this panel. See g_SelectionPanels.
|
||||
* @param unitEntState Entity state of the selected unit with the lowest id.
|
||||
* @param payerState Player state
|
||||
* @param unitEntStates Entity states of the selected units
|
||||
* @param playerState Player state
|
||||
*/
|
||||
function setupUnitPanel(guiName, unitEntState, playerState)
|
||||
function setupUnitPanel(guiName, unitEntStates, playerState)
|
||||
{
|
||||
if (!g_SelectionPanels[guiName])
|
||||
{
|
||||
|
|
@ -56,7 +56,7 @@ function setupUnitPanel(guiName, unitEntState, playerState)
|
|||
}
|
||||
|
||||
let selection = g_Selection.toList();
|
||||
let items = g_SelectionPanels[guiName].getItems(unitEntState, selection);
|
||||
let items = g_SelectionPanels[guiName].getItems(unitEntStates);
|
||||
|
||||
if (!items || !items.length)
|
||||
return;
|
||||
|
|
@ -72,9 +72,9 @@ function setupUnitPanel(guiName, unitEntState, playerState)
|
|||
let data = {
|
||||
"i": i,
|
||||
"item": items[i],
|
||||
"selection": selection,
|
||||
"playerState": playerState,
|
||||
"unitEntState": unitEntState,
|
||||
"player": unitEntStates[0].player,
|
||||
"unitEntStates": unitEntStates,
|
||||
"rowLength": rowLength,
|
||||
"numberOfItems": numberOfItems,
|
||||
// depending on the XML, some of the GUI objects may be undefined
|
||||
|
|
@ -119,13 +119,12 @@ function setupUnitPanel(guiName, unitEntState, playerState)
|
|||
* Delegates to setupUnitPanel to set up individual subpanels,
|
||||
* appropriately activated depending on the selected unit's state.
|
||||
*
|
||||
* @param entState Entity state of the selected unit with the lowest id.
|
||||
* @param entStates Entity states of the selected units
|
||||
* @param supplementalDetailsPanel Reference to the
|
||||
* "supplementalSelectionDetails" GUI Object
|
||||
* @param commandsPanel Reference to the "commandsPanel" GUI Object
|
||||
* @param selection Array of currently selected entity IDs.
|
||||
*/
|
||||
function updateUnitCommands(entState, supplementalDetailsPanel, commandsPanel, selection)
|
||||
function updateUnitCommands(entStates, supplementalDetailsPanel, commandsPanel)
|
||||
{
|
||||
for (let panel in g_SelectionPanels)
|
||||
g_SelectionPanels[panel].used = false;
|
||||
|
|
@ -137,7 +136,7 @@ function updateUnitCommands(entState, supplementalDetailsPanel, commandsPanel, s
|
|||
let playerStates = GetSimState().players;
|
||||
let playerState = playerStates[Engine.GetPlayerID()];
|
||||
|
||||
if (controlsPlayer(entState.player) || g_IsObserver)
|
||||
if (g_IsObserver || entStates.every(entState => controlsPlayer(entState.player)))
|
||||
{
|
||||
for (var guiName of g_PanelsOrder)
|
||||
{
|
||||
|
|
@ -145,18 +144,18 @@ function updateUnitCommands(entState, supplementalDetailsPanel, commandsPanel, s
|
|||
g_SelectionPanels[guiName].conflictsWith.some(p => g_SelectionPanels[p].used))
|
||||
continue;
|
||||
|
||||
setupUnitPanel(guiName, entState, playerStates[entState.player]);
|
||||
setupUnitPanel(guiName, entStates, playerStates[entStates[0].player]);
|
||||
}
|
||||
|
||||
supplementalDetailsPanel.hidden = false;
|
||||
commandsPanel.hidden = false;
|
||||
}
|
||||
else if (playerState.isMutualAlly[entState.player]) // owned by allied player
|
||||
else if (playerState.isMutualAlly[entStates[0].player]) // owned by allied player
|
||||
{
|
||||
// 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("AllyCommand", entState, playerState);
|
||||
setupUnitPanel("Garrison", entStates, playerState);
|
||||
setupUnitPanel("AllyCommand", entStates, playerState);
|
||||
|
||||
supplementalDetailsPanel.hidden = !g_SelectionPanels.Garrison.used;
|
||||
|
||||
|
|
|
|||
|
|
@ -337,6 +337,11 @@ ProductionQueue.prototype.AddBatch = function(templateName, type, count, metadat
|
|||
var template = cmpDataTemplateManager.GetTechnologyTemplate(templateName);
|
||||
if (!template)
|
||||
return;
|
||||
if (this.GetTechnologiesList().indexOf(templateName) == -1)
|
||||
{
|
||||
warn("This entity cannot research " + JSON.stringify(templateName));
|
||||
return;
|
||||
}
|
||||
var cmpPlayer = QueryOwnerInterface(this.entity);
|
||||
let techCostMultiplier = this.GetTechCostMultiplier();
|
||||
let time = techCostMultiplier.time * template.researchTime * cmpPlayer.GetCheatTimeMultiplier();
|
||||
|
|
|
|||
Loading…
Reference in a new issue