1
0
forked from mirrors/0ad

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)
{
let info = g_EntityCommands[command].getInfo(unitEntStates);
let info = getCommandInfo(command, unitEntStates);
if (info)
{
info.name = command;
@@ -134,10 +134,7 @@ g_SelectionPanels.Command = {
data.countDisplay.caption = data.item.count || "";
data.button.enabled =
g_IsObserver && data.item.name == "focus-rally" ||
controlsPlayer(data.player) && (data.item.name != "delete" ||
data.unitEntStates.some(state => !isUndeletable(state)));
data.button.enabled = data.item.enabled == true;
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 = {
"getMaxNumberOfItems": function()
{
@@ -1249,7 +1193,6 @@ let g_PanelsOrder = [
// UNIQUE PANES (importance doesn't matter)
"Command",
"AllyCommand",
"Queue",
"Selection",
];
@@ -302,30 +302,10 @@ function performCommand(entStates, commandName)
if (!entStates.length)
return;
// Don't check all entities, because we assume a player cannot
// select entities from more than one player
if (!controlsPlayer(entStates[0].player) &&
!(g_IsObserver && commandName == "focus-rally"))
return;
if (g_EntityCommands[commandName])
if (getCommandInfo(commandName, 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)
{
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;
for (let entState of entStates)
if (entState.garrisonHolder)
{
if (!entState.garrisonHolder)
continue;
if (allowedPlayersCheck([entState], ["Player"]))
count += entState.garrisonHolder.entities.length;
else
for (let entity of entState.garrisonHolder.entities)
if (allowedPlayersCheck([GetEntityState(entity)], ["Player"]))
++count;
}
if (!count)
return false;
@@ -1143,12 +1152,14 @@ var g_EntityCommands =
translate("Unload All."),
"icon": "garrison-out.png",
"count": count,
"enabled": true
};
},
"execute": function()
{
unloadAll();
},
"allowedPlayers": ["Player", "Ally"]
},
"delete": {
@@ -1163,7 +1174,8 @@ var g_EntityCommands =
translate("Use %(hotkey)s to avoid the confirmation dialog."),
"session.noconfirmation"
),
"icon": "kill_small.png"
"icon": "kill_small.png",
"enabled": true
} :
{
// Get all delete reasons and remove duplications
@@ -1171,7 +1183,8 @@ var g_EntityCommands =
.filter((reason, pos, self) =>
self.indexOf(reason) == pos && reason
).join("\n"),
"icon": "kill_small_disabled.png"
"icon": "kill_small_disabled.png",
"enabled": false
};
},
"execute": function(entStates)
@@ -1197,6 +1210,7 @@ var g_EntityCommands =
else
(new DeleteSelectionConfirmation(deleteSelection)).display();
},
"allowedPlayers": ["Player"]
},
"stop": {
@@ -1208,7 +1222,8 @@ var g_EntityCommands =
return {
"tooltip": colorizeHotkey("%(hotkey)s" + " ", "session.stop") +
translate("Abort the current order."),
"icon": "stop.png"
"icon": "stop.png",
"enabled": true
};
},
"execute": function(entStates)
@@ -1216,6 +1231,7 @@ var g_EntityCommands =
if (entStates.length)
stopUnits(entStates.map(entState => entState.id));
},
"allowedPlayers": ["Player"]
},
"garrison": {
@@ -1227,7 +1243,8 @@ var g_EntityCommands =
return {
"tooltip": colorizeHotkey("%(hotkey)s" + " ", "session.garrison") +
translate("Order the selected units to garrison in a structure or unit."),
"icon": "garrison.png"
"icon": "garrison.png",
"enabled": true
};
},
"execute": function()
@@ -1235,6 +1252,7 @@ var g_EntityCommands =
inputState = INPUT_PRESELECTEDACTION;
preSelectedAction = ACTION_GARRISON;
},
"allowedPlayers": ["Player"]
},
"unload": {
@@ -1250,13 +1268,15 @@ var g_EntityCommands =
return {
"tooltip": translate("Unload"),
"icon": "garrison-out.png"
"icon": "garrison-out.png",
"enabled": true
};
},
"execute": function()
{
unloadSelection();
},
"allowedPlayers": ["Player"]
},
"repair": {
@@ -1268,7 +1288,8 @@ var g_EntityCommands =
return {
"tooltip": colorizeHotkey("%(hotkey)s" + " ", "session.repair") +
translate("Order the selected units to repair a structure, ship, or siege engine."),
"icon": "repair.png"
"icon": "repair.png",
"enabled": true
};
},
"execute": function()
@@ -1276,6 +1297,7 @@ var g_EntityCommands =
inputState = INPUT_PRESELECTEDACTION;
preSelectedAction = ACTION_REPAIR;
},
"allowedPlayers": ["Player"]
},
"focus-rally": {
@@ -1287,7 +1309,8 @@ var g_EntityCommands =
return {
"tooltip": colorizeHotkey("%(hotkey)s" + " ", "camera.rallypointfocus") +
translate("Focus on Rally Point."),
"icon": "focus-rally.png"
"icon": "focus-rally.png",
"enabled": true
};
},
"execute": function(entStates)
@@ -1311,6 +1334,7 @@ var g_EntityCommands =
if (focusTarget)
Engine.CameraMoveTo(focusTarget.x, focusTarget.z);
},
"allowedPlayers": ["Player", "Observer"]
},
"back-to-work": {
@@ -1322,13 +1346,15 @@ var g_EntityCommands =
return {
"tooltip": colorizeHotkey("%(hotkey)s" + " ", "session.backtowork") +
translate("Back to Work"),
"icon": "back-to-work.png"
"icon": "back-to-work.png",
"enabled": true
};
},
"execute": function()
{
backToWork();
},
"allowedPlayers": ["Player"]
},
"add-guard": {
@@ -1341,7 +1367,8 @@ var g_EntityCommands =
return {
"tooltip": colorizeHotkey("%(hotkey)s" + " ", "session.guard") +
translate("Order the selected units to guard a structure or unit."),
"icon": "add-guard.png"
"icon": "add-guard.png",
"enabled": true
};
},
"execute": function()
@@ -1349,6 +1376,7 @@ var g_EntityCommands =
inputState = INPUT_PRESELECTEDACTION;
preSelectedAction = ACTION_GUARD;
},
"allowedPlayers": ["Player"]
},
"remove-guard": {
@@ -1359,13 +1387,15 @@ var g_EntityCommands =
return {
"tooltip": translate("Remove guard"),
"icon": "remove-guard.png"
"icon": "remove-guard.png",
"enabled": true
};
},
"execute": function()
{
removeGuard();
},
"allowedPlayers": ["Player"]
},
"select-trading-goods": {
@@ -1376,13 +1406,15 @@ var g_EntityCommands =
return {
"tooltip": translate("Barter & Trade"),
"icon": "economics.png"
"icon": "economics.png",
"enabled": true
};
},
"execute": function()
{
g_TradeDialog.toggle();
},
"allowedPlayers": ["Player"]
},
"patrol": {
@@ -1395,7 +1427,8 @@ var g_EntityCommands =
"tooltip": colorizeHotkey("%(hotkey)s" + " ", "session.patrol") +
translate("Patrol") + "\n" +
translate("Attack all encountered enemy units while avoiding structures."),
"icon": "patrol.png"
"icon": "patrol.png",
"enabled": true
};
},
"execute": function()
@@ -1403,6 +1436,7 @@ var g_EntityCommands =
inputState = INPUT_PRESELECTEDACTION;
preSelectedAction = ACTION_PATROL;
},
"allowedPlayers": ["Player"]
},
"share-dropsite": {
@@ -1413,7 +1447,7 @@ var g_EntityCommands =
if (!sharableEntities.length)
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(
(isAlly, playerId) => isAlly && playerId != entState.player)))
return false;
@@ -1421,87 +1455,62 @@ var g_EntityCommands =
return sharableEntities.some(entState => !entState.resourceDropsite.shared) ?
{
"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"),
"icon": "unlocked_small.png"
"icon": "unlocked_small.png",
"enabled": true
};
},
"execute": function(entStates)
{
let sharableEntities = entStates.filter(
entState => entState.resourceDropsite && entState.resourceDropsite.sharable);
Engine.PostNetworkCommand({
"type": "set-dropsite-sharing",
"entities": sharableEntities.map(entState => entState.id),
"shared": sharableEntities.some(entState => !entState.resourceDropsite.shared)
});
if (sharableEntities)
Engine.PostNetworkCommand({
"type": "set-dropsite-sharing",
"entities": sharableEntities.map(entState => entState.id),
"shared": sharableEntities.some(entState => !entState.resourceDropsite.shared)
});
},
}
};
"allowedPlayers": ["Player"]
},
var g_AllyEntityCommands =
{
"unload-all": {
"getInfo": function(entState)
"is-dropsite-shared": {
"getInfo": function(entStates)
{
if (!entState.garrisonHolder)
let sharableEntities = entStates.filter(
entState => entState.resourceDropsite && entState.resourceDropsite.sharable);
if (!sharableEntities.length)
return false;
let player = Engine.GetPlayerID();
let count = 0;
for (let ent in g_Selection.selected)
{
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)
let simState = GetSimState();
if (!g_IsObserver && !simState.players[player].hasSharedDropsites ||
entStates.every(entState => controlsPlayer(entState.player)))
return false;
if (entState.resourceDropsite.shared)
if (!entStates.every(entState => entState.resourceDropsite.shared))
return {
"tooltip": translate("You are allowed to use this dropsite"),
"icon": "unlocked_small.png"
"tooltip": translate("The use of this dropsite is prohibited"),
"icon": "locked_small.png",
"enabled": false
};
return {
"tooltip": translate("The use of this dropsite is prohibited"),
"icon": "locked_small.png"
"tooltip": g_IsObserver ? translate("Allies are allowed to use this dropsite.") :
translate("You are allowed to use this dropsite"),
"icon": "unlocked_small.png",
"enabled": false
};
},
"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;
}
/**
* 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)
{
// 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)
{
if (!selection || !selection.length || !GetEntityState(selection[0]))
@@ -10,7 +10,6 @@ var g_unitPanelButtons = {
"Barter": 0,
"Construction": 0,
"Command": 0,
"AllyCommand": 0,
"Stance": 0,
"Gate": 0,
"Pack": 0,
@@ -128,16 +127,17 @@ function updateUnitCommands(entStates, supplementalDetailsPanel, commandsPanel)
for (let panel in g_SelectionPanels)
g_SelectionPanels[panel].used = false;
// If the selection is friendly units, add the command panels
// 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 playerState = playerStates[Engine.GetPlayerID()];
// Always show selection.
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 =>
controlsPlayer(entState.player) &&
(!entState.identity || entState.identity.controllable)) ||
@@ -145,7 +145,6 @@ function updateUnitCommands(entStates, supplementalDetailsPanel, commandsPanel)
{
for (let guiName of g_PanelsOrder)
{
if (g_SelectionPanels[guiName].conflictsWith &&
g_SelectionPanels[guiName].conflictsWith.some(p => g_SelectionPanels[p].used))
continue;
@@ -156,18 +155,17 @@ function updateUnitCommands(entStates, supplementalDetailsPanel, commandsPanel)
supplementalDetailsPanel.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
// we should consider adding the players list to g_SelectionPanels
setupUnitPanel("Garrison", entStates, playerState);
setupUnitPanel("AllyCommand", entStates, playerState);
supplementalDetailsPanel.hidden = !g_SelectionPanels.Garrison.used;
commandsPanel.hidden = true;
}
else // owned by another player
else
{
supplementalDetailsPanel.hidden = true;
commandsPanel.hidden = true;