Combine "EntityCommand" and "AllyEntityCommand".

By specifying the players which are allowed to use(/see) a command
button and adding an enabled/disabled property to the info.

Differential revision: D2343
Comments by: @Angen, @Stan
This was SVN commit r24501.
This commit is contained in:
Freagarach
2021-01-02 07:19:17 +00:00
parent 7f7a3edfae
commit 32583008a0
5 changed files with 118 additions and 174 deletions
@@ -112,7 +112,7 @@ g_SelectionPanels.Command = {
for (let command in g_EntityCommands) for (let command in g_EntityCommands)
{ {
let info = g_EntityCommands[command].getInfo(unitEntStates); let info = getCommandInfo(command, unitEntStates);
if (info) if (info)
{ {
info.name = command; info.name = command;
@@ -134,10 +134,7 @@ g_SelectionPanels.Command = {
data.countDisplay.caption = data.item.count || ""; data.countDisplay.caption = data.item.count || "";
data.button.enabled = data.button.enabled = data.item.enabled == true;
g_IsObserver && data.item.name == "focus-rally" ||
controlsPlayer(data.player) && (data.item.name != "delete" ||
data.unitEntStates.some(state => !isUndeletable(state)));
data.icon.sprite = "stretched:session/icons/" + data.item.icon; data.icon.sprite = "stretched:session/icons/" + data.item.icon;
@@ -153,59 +150,6 @@ g_SelectionPanels.Command = {
} }
}; };
g_SelectionPanels.AllyCommand = {
"getMaxNumberOfItems": function()
{
return 2;
},
"conflictsWith": ["Command"],
"getItems": function(unitEntStates)
{
let commands = [];
for (let command in g_AllyEntityCommands)
for (let state of unitEntStates)
{
let info = g_AllyEntityCommands[command].getInfo(state);
if (info)
{
info.name = command;
commands.push(info);
break;
}
}
return commands;
},
"setupButton": function(data)
{
data.button.tooltip = data.item.tooltip;
data.button.onPress = function() {
if (data.item.callback)
data.item.callback(data.item);
else
performAllyCommand(data.unitEntStates[0].id, data.item.name);
};
data.countDisplay.caption = data.item.count || "";
data.button.enabled = !!data.item.count;
let grayscale = data.button.enabled ? "" : "grayscale:";
data.icon.sprite = "stretched:" + grayscale + "session/icons/" + data.item.icon;
let size = data.button.size;
// relative to the center ( = 50%)
size.rleft = 50;
size.rright = 50;
// offset from the center calculation, count on square buttons, so size.bottom is the width too
size.left = (data.i - data.numberOfItems / 2) * (size.bottom + 1);
size.right = size.left + size.bottom;
data.button.size = size;
return true;
}
};
g_SelectionPanels.Construction = { g_SelectionPanels.Construction = {
"getMaxNumberOfItems": function() "getMaxNumberOfItems": function()
{ {
@@ -1249,7 +1193,6 @@ let g_PanelsOrder = [
// UNIQUE PANES (importance doesn't matter) // UNIQUE PANES (importance doesn't matter)
"Command", "Command",
"AllyCommand",
"Queue", "Queue",
"Selection", "Selection",
]; ];
@@ -302,30 +302,10 @@ function performCommand(entStates, commandName)
if (!entStates.length) if (!entStates.length)
return; return;
// Don't check all entities, because we assume a player cannot if (getCommandInfo(commandName, entStates))
// select entities from more than one player
if (!controlsPlayer(entStates[0].player) &&
!(g_IsObserver && commandName == "focus-rally"))
return;
if (g_EntityCommands[commandName])
g_EntityCommands[commandName].execute(entStates); g_EntityCommands[commandName].execute(entStates);
} }
function performAllyCommand(entity, commandName)
{
if (!entity)
return;
let entState = GetEntityState(entity);
let playerState = GetSimState().players[Engine.GetPlayerID()];
if (!playerState.isMutualAlly[entState.player] || g_IsObserver)
return;
if (g_AllyEntityCommands[commandName])
g_AllyEntityCommands[commandName].execute(entState);
}
function performFormation(entities, formationTemplate) function performFormation(entities, formationTemplate)
{ {
if (!entities) if (!entities)
@@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Unit Commands -->
<object name="unitAllyCommandPanel"
size="0 100%-40 100% 100%-4"
type="image"
z="30"
>
<object size="0 0 100% 100%">
<repeat count="2">
<object name="unitAllyCommandButton[n]" hidden="true" style="iconButton" type="button" size="0 0 32 32" tooltip_style="sessionToolTipBottomBold">
<object name="unitAllyCommandIcon[n]" ghost="true" type="image" style="commandIcon"/>
<object name="unitAllyCommandCount[n]" ghost="true" style="groupIconsText" type="text"/>
</object>
</repeat>
</object>
</object>
@@ -1132,8 +1132,17 @@ var g_EntityCommands =
{ {
let count = 0; let count = 0;
for (let entState of entStates) for (let entState of entStates)
if (entState.garrisonHolder) {
if (!entState.garrisonHolder)
continue;
if (allowedPlayersCheck([entState], ["Player"]))
count += entState.garrisonHolder.entities.length; count += entState.garrisonHolder.entities.length;
else
for (let entity of entState.garrisonHolder.entities)
if (allowedPlayersCheck([GetEntityState(entity)], ["Player"]))
++count;
}
if (!count) if (!count)
return false; return false;
@@ -1143,12 +1152,14 @@ var g_EntityCommands =
translate("Unload All."), translate("Unload All."),
"icon": "garrison-out.png", "icon": "garrison-out.png",
"count": count, "count": count,
"enabled": true
}; };
}, },
"execute": function() "execute": function()
{ {
unloadAll(); unloadAll();
}, },
"allowedPlayers": ["Player", "Ally"]
}, },
"delete": { "delete": {
@@ -1163,7 +1174,8 @@ var g_EntityCommands =
translate("Use %(hotkey)s to avoid the confirmation dialog."), translate("Use %(hotkey)s to avoid the confirmation dialog."),
"session.noconfirmation" "session.noconfirmation"
), ),
"icon": "kill_small.png" "icon": "kill_small.png",
"enabled": true
} : } :
{ {
// Get all delete reasons and remove duplications // Get all delete reasons and remove duplications
@@ -1171,7 +1183,8 @@ var g_EntityCommands =
.filter((reason, pos, self) => .filter((reason, pos, self) =>
self.indexOf(reason) == pos && reason self.indexOf(reason) == pos && reason
).join("\n"), ).join("\n"),
"icon": "kill_small_disabled.png" "icon": "kill_small_disabled.png",
"enabled": false
}; };
}, },
"execute": function(entStates) "execute": function(entStates)
@@ -1197,6 +1210,7 @@ var g_EntityCommands =
else else
(new DeleteSelectionConfirmation(deleteSelection)).display(); (new DeleteSelectionConfirmation(deleteSelection)).display();
}, },
"allowedPlayers": ["Player"]
}, },
"stop": { "stop": {
@@ -1208,7 +1222,8 @@ var g_EntityCommands =
return { return {
"tooltip": colorizeHotkey("%(hotkey)s" + " ", "session.stop") + "tooltip": colorizeHotkey("%(hotkey)s" + " ", "session.stop") +
translate("Abort the current order."), translate("Abort the current order."),
"icon": "stop.png" "icon": "stop.png",
"enabled": true
}; };
}, },
"execute": function(entStates) "execute": function(entStates)
@@ -1216,6 +1231,7 @@ var g_EntityCommands =
if (entStates.length) if (entStates.length)
stopUnits(entStates.map(entState => entState.id)); stopUnits(entStates.map(entState => entState.id));
}, },
"allowedPlayers": ["Player"]
}, },
"garrison": { "garrison": {
@@ -1227,7 +1243,8 @@ var g_EntityCommands =
return { return {
"tooltip": colorizeHotkey("%(hotkey)s" + " ", "session.garrison") + "tooltip": colorizeHotkey("%(hotkey)s" + " ", "session.garrison") +
translate("Order the selected units to garrison in a structure or unit."), translate("Order the selected units to garrison in a structure or unit."),
"icon": "garrison.png" "icon": "garrison.png",
"enabled": true
}; };
}, },
"execute": function() "execute": function()
@@ -1235,6 +1252,7 @@ var g_EntityCommands =
inputState = INPUT_PRESELECTEDACTION; inputState = INPUT_PRESELECTEDACTION;
preSelectedAction = ACTION_GARRISON; preSelectedAction = ACTION_GARRISON;
}, },
"allowedPlayers": ["Player"]
}, },
"unload": { "unload": {
@@ -1250,13 +1268,15 @@ var g_EntityCommands =
return { return {
"tooltip": translate("Unload"), "tooltip": translate("Unload"),
"icon": "garrison-out.png" "icon": "garrison-out.png",
"enabled": true
}; };
}, },
"execute": function() "execute": function()
{ {
unloadSelection(); unloadSelection();
}, },
"allowedPlayers": ["Player"]
}, },
"repair": { "repair": {
@@ -1268,7 +1288,8 @@ var g_EntityCommands =
return { return {
"tooltip": colorizeHotkey("%(hotkey)s" + " ", "session.repair") + "tooltip": colorizeHotkey("%(hotkey)s" + " ", "session.repair") +
translate("Order the selected units to repair a structure, ship, or siege engine."), translate("Order the selected units to repair a structure, ship, or siege engine."),
"icon": "repair.png" "icon": "repair.png",
"enabled": true
}; };
}, },
"execute": function() "execute": function()
@@ -1276,6 +1297,7 @@ var g_EntityCommands =
inputState = INPUT_PRESELECTEDACTION; inputState = INPUT_PRESELECTEDACTION;
preSelectedAction = ACTION_REPAIR; preSelectedAction = ACTION_REPAIR;
}, },
"allowedPlayers": ["Player"]
}, },
"focus-rally": { "focus-rally": {
@@ -1287,7 +1309,8 @@ var g_EntityCommands =
return { return {
"tooltip": colorizeHotkey("%(hotkey)s" + " ", "camera.rallypointfocus") + "tooltip": colorizeHotkey("%(hotkey)s" + " ", "camera.rallypointfocus") +
translate("Focus on Rally Point."), translate("Focus on Rally Point."),
"icon": "focus-rally.png" "icon": "focus-rally.png",
"enabled": true
}; };
}, },
"execute": function(entStates) "execute": function(entStates)
@@ -1311,6 +1334,7 @@ var g_EntityCommands =
if (focusTarget) if (focusTarget)
Engine.CameraMoveTo(focusTarget.x, focusTarget.z); Engine.CameraMoveTo(focusTarget.x, focusTarget.z);
}, },
"allowedPlayers": ["Player", "Observer"]
}, },
"back-to-work": { "back-to-work": {
@@ -1322,13 +1346,15 @@ var g_EntityCommands =
return { return {
"tooltip": colorizeHotkey("%(hotkey)s" + " ", "session.backtowork") + "tooltip": colorizeHotkey("%(hotkey)s" + " ", "session.backtowork") +
translate("Back to Work"), translate("Back to Work"),
"icon": "back-to-work.png" "icon": "back-to-work.png",
"enabled": true
}; };
}, },
"execute": function() "execute": function()
{ {
backToWork(); backToWork();
}, },
"allowedPlayers": ["Player"]
}, },
"add-guard": { "add-guard": {
@@ -1341,7 +1367,8 @@ var g_EntityCommands =
return { return {
"tooltip": colorizeHotkey("%(hotkey)s" + " ", "session.guard") + "tooltip": colorizeHotkey("%(hotkey)s" + " ", "session.guard") +
translate("Order the selected units to guard a structure or unit."), translate("Order the selected units to guard a structure or unit."),
"icon": "add-guard.png" "icon": "add-guard.png",
"enabled": true
}; };
}, },
"execute": function() "execute": function()
@@ -1349,6 +1376,7 @@ var g_EntityCommands =
inputState = INPUT_PRESELECTEDACTION; inputState = INPUT_PRESELECTEDACTION;
preSelectedAction = ACTION_GUARD; preSelectedAction = ACTION_GUARD;
}, },
"allowedPlayers": ["Player"]
}, },
"remove-guard": { "remove-guard": {
@@ -1359,13 +1387,15 @@ var g_EntityCommands =
return { return {
"tooltip": translate("Remove guard"), "tooltip": translate("Remove guard"),
"icon": "remove-guard.png" "icon": "remove-guard.png",
"enabled": true
}; };
}, },
"execute": function() "execute": function()
{ {
removeGuard(); removeGuard();
}, },
"allowedPlayers": ["Player"]
}, },
"select-trading-goods": { "select-trading-goods": {
@@ -1376,13 +1406,15 @@ var g_EntityCommands =
return { return {
"tooltip": translate("Barter & Trade"), "tooltip": translate("Barter & Trade"),
"icon": "economics.png" "icon": "economics.png",
"enabled": true
}; };
}, },
"execute": function() "execute": function()
{ {
g_TradeDialog.toggle(); g_TradeDialog.toggle();
}, },
"allowedPlayers": ["Player"]
}, },
"patrol": { "patrol": {
@@ -1395,7 +1427,8 @@ var g_EntityCommands =
"tooltip": colorizeHotkey("%(hotkey)s" + " ", "session.patrol") + "tooltip": colorizeHotkey("%(hotkey)s" + " ", "session.patrol") +
translate("Patrol") + "\n" + translate("Patrol") + "\n" +
translate("Attack all encountered enemy units while avoiding structures."), translate("Attack all encountered enemy units while avoiding structures."),
"icon": "patrol.png" "icon": "patrol.png",
"enabled": true
}; };
}, },
"execute": function() "execute": function()
@@ -1403,6 +1436,7 @@ var g_EntityCommands =
inputState = INPUT_PRESELECTEDACTION; inputState = INPUT_PRESELECTEDACTION;
preSelectedAction = ACTION_PATROL; preSelectedAction = ACTION_PATROL;
}, },
"allowedPlayers": ["Player"]
}, },
"share-dropsite": { "share-dropsite": {
@@ -1413,7 +1447,7 @@ var g_EntityCommands =
if (!sharableEntities.length) if (!sharableEntities.length)
return false; return false;
// Returns if none of the entities belong to a player with a mutual ally // Returns if none of the entities belong to a player with a mutual ally.
if (entStates.every(entState => !GetSimState().players[entState.player].isMutualAlly.some( if (entStates.every(entState => !GetSimState().players[entState.player].isMutualAlly.some(
(isAlly, playerId) => isAlly && playerId != entState.player))) (isAlly, playerId) => isAlly && playerId != entState.player)))
return false; return false;
@@ -1421,87 +1455,62 @@ var g_EntityCommands =
return sharableEntities.some(entState => !entState.resourceDropsite.shared) ? return sharableEntities.some(entState => !entState.resourceDropsite.shared) ?
{ {
"tooltip": translate("Press to allow allies to use this dropsite"), "tooltip": translate("Press to allow allies to use this dropsite"),
"icon": "locked_small.png" "icon": "locked_small.png",
"enabled": true
} : } :
{ {
"tooltip": translate("Press to prevent allies from using this dropsite"), "tooltip": translate("Press to prevent allies from using this dropsite"),
"icon": "unlocked_small.png" "icon": "unlocked_small.png",
"enabled": true
}; };
}, },
"execute": function(entStates) "execute": function(entStates)
{ {
let sharableEntities = entStates.filter( let sharableEntities = entStates.filter(
entState => entState.resourceDropsite && entState.resourceDropsite.sharable); entState => entState.resourceDropsite && entState.resourceDropsite.sharable);
Engine.PostNetworkCommand({ if (sharableEntities)
"type": "set-dropsite-sharing", Engine.PostNetworkCommand({
"entities": sharableEntities.map(entState => entState.id), "type": "set-dropsite-sharing",
"shared": sharableEntities.some(entState => !entState.resourceDropsite.shared) "entities": sharableEntities.map(entState => entState.id),
}); "shared": sharableEntities.some(entState => !entState.resourceDropsite.shared)
});
}, },
} "allowedPlayers": ["Player"]
}; },
var g_AllyEntityCommands = "is-dropsite-shared": {
{ "getInfo": function(entStates)
"unload-all": {
"getInfo": function(entState)
{ {
if (!entState.garrisonHolder) let sharableEntities = entStates.filter(
entState => entState.resourceDropsite && entState.resourceDropsite.sharable);
if (!sharableEntities.length)
return false; return false;
let player = Engine.GetPlayerID(); let player = Engine.GetPlayerID();
let simState = GetSimState();
let count = 0; if (!g_IsObserver && !simState.players[player].hasSharedDropsites ||
for (let ent in g_Selection.selected) entStates.every(entState => controlsPlayer(entState.player)))
{
let selectedEntState = GetEntityState(+ent);
if (!selectedEntState.garrisonHolder)
continue;
for (let entity of selectedEntState.garrisonHolder.entities)
{
let state = GetEntityState(entity);
if (state.player == player)
++count;
}
}
return {
"tooltip": colorizeHotkey("%(hotkey)s" + " ", "session.unload") +
translate("Unload All."),
"icon": "garrison-out.png",
"count": count,
};
},
"execute": function(entState)
{
unloadAll();
},
},
"share-dropsite": {
"getInfo": function(entState)
{
if (Engine.GetPlayerID() == -1 ||
!GetSimState().players[Engine.GetPlayerID()].hasSharedDropsites ||
!entState.resourceDropsite || !entState.resourceDropsite.sharable)
return false; return false;
if (entState.resourceDropsite.shared) if (!entStates.every(entState => entState.resourceDropsite.shared))
return { return {
"tooltip": translate("You are allowed to use this dropsite"), "tooltip": translate("The use of this dropsite is prohibited"),
"icon": "unlocked_small.png" "icon": "locked_small.png",
"enabled": false
}; };
return { return {
"tooltip": translate("The use of this dropsite is prohibited"), "tooltip": g_IsObserver ? translate("Allies are allowed to use this dropsite.") :
"icon": "locked_small.png" translate("You are allowed to use this dropsite"),
"icon": "unlocked_small.png",
"enabled": false
}; };
}, },
"execute": function(entState) "execute": function(entState)
{ {
// This command button is always disabled // This command button is always disabled.
}, },
"allowedPlayers": ["Ally", "Observer"]
} }
}; };
@@ -1517,6 +1526,29 @@ function playerCheck(entState, targetState, validPlayers)
return false; return false;
} }
/**
* Checks whether the entities have the right diplomatic status
* with respect to the currently active player.
* Also "Observer" can be used.
*
* @param {Object[]} entStates - An array containing the entity states to check.
* @param {string[]} validPlayers - An array containing the diplomatic statuses.
*
* @return {boolean} - Whether the currently active player is allowed.
*/
function allowedPlayersCheck(entStates, validPlayers)
{
// Assume we can only select entities from one player,
// or it does not matter (e.g. observer).
let targetState = entStates[0];
let playerState = GetSimState().players[Engine.GetPlayerID()];
return validPlayers.some(player =>
player == "Observer" && g_IsObserver ||
player == "Player" && controlsPlayer(targetState.player) ||
playerState && playerState["is" + player] && playerState["is" + player][targetState.player]);
}
function hasClass(entState, className) function hasClass(entState, className)
{ {
// note: use the functions in globalscripts/Templates.js for more versatile matching // note: use the functions in globalscripts/Templates.js for more versatile matching
@@ -1553,6 +1585,13 @@ function DrawTargetMarker(target)
}); });
} }
function getCommandInfo(command, entStates)
{
return entStates && g_EntityCommands[command] &&
allowedPlayersCheck(entStates, g_EntityCommands[command].allowedPlayers) &&
g_EntityCommands[command].getInfo(entStates);
}
function getActionInfo(action, target, selection) function getActionInfo(action, target, selection)
{ {
if (!selection || !selection.length || !GetEntityState(selection[0])) if (!selection || !selection.length || !GetEntityState(selection[0]))
@@ -10,7 +10,6 @@ var g_unitPanelButtons = {
"Barter": 0, "Barter": 0,
"Construction": 0, "Construction": 0,
"Command": 0, "Command": 0,
"AllyCommand": 0,
"Stance": 0, "Stance": 0,
"Gate": 0, "Gate": 0,
"Pack": 0, "Pack": 0,
@@ -128,16 +127,17 @@ function updateUnitCommands(entStates, supplementalDetailsPanel, commandsPanel)
for (let panel in g_SelectionPanels) for (let panel in g_SelectionPanels)
g_SelectionPanels[panel].used = false; g_SelectionPanels[panel].used = false;
// If the selection is friendly units, add the command panels
// Get player state to check some constraints // Get player state to check some constraints
// e.g. presence of a hero or build limits // e.g. presence of a hero or build limits.
let playerStates = GetSimState().players; let playerStates = GetSimState().players;
let playerState = playerStates[Engine.GetPlayerID()]; let playerState = playerStates[Engine.GetPlayerID()];
// Always show selection.
setupUnitPanel("Selection", entStates, playerStates[entStates[0].player]); setupUnitPanel("Selection", entStates, playerStates[entStates[0].player]);
// Command panel always shown for it can contain commands
// for which the entity does not need to be owned.
setupUnitPanel("Command", entStates, playerState);
if (g_IsObserver || entStates.every(entState => if (g_IsObserver || entStates.every(entState =>
controlsPlayer(entState.player) && controlsPlayer(entState.player) &&
(!entState.identity || entState.identity.controllable)) || (!entState.identity || entState.identity.controllable)) ||
@@ -145,7 +145,6 @@ function updateUnitCommands(entStates, supplementalDetailsPanel, commandsPanel)
{ {
for (let guiName of g_PanelsOrder) for (let guiName of g_PanelsOrder)
{ {
if (g_SelectionPanels[guiName].conflictsWith && if (g_SelectionPanels[guiName].conflictsWith &&
g_SelectionPanels[guiName].conflictsWith.some(p => g_SelectionPanels[p].used)) g_SelectionPanels[guiName].conflictsWith.some(p => g_SelectionPanels[p].used))
continue; continue;
@@ -156,18 +155,17 @@ function updateUnitCommands(entStates, supplementalDetailsPanel, commandsPanel)
supplementalDetailsPanel.hidden = false; supplementalDetailsPanel.hidden = false;
commandsPanel.hidden = false; commandsPanel.hidden = false;
} }
else if (playerState.isMutualAlly[entStates[0].player]) // owned by allied player else if (playerState.isMutualAlly[entStates[0].player])
{ {
// TODO if there's a second panel needed for a different player // TODO if there's a second panel needed for a different player
// we should consider adding the players list to g_SelectionPanels // we should consider adding the players list to g_SelectionPanels
setupUnitPanel("Garrison", entStates, playerState); setupUnitPanel("Garrison", entStates, playerState);
setupUnitPanel("AllyCommand", entStates, playerState);
supplementalDetailsPanel.hidden = !g_SelectionPanels.Garrison.used; supplementalDetailsPanel.hidden = !g_SelectionPanels.Garrison.used;
commandsPanel.hidden = true; commandsPanel.hidden = true;
} }
else // owned by another player else
{ {
supplementalDetailsPanel.hidden = true; supplementalDetailsPanel.hidden = true;
commandsPanel.hidden = true; commandsPanel.hidden = true;