forked from 0ad/0ad
294 lines
8.8 KiB
JavaScript
294 lines
8.8 KiB
JavaScript
// 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};
|
|
|
|
/**
|
|
* 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;
|
|
// horizontal position
|
|
var oWidth = size.right - size.left;
|
|
var hIndex = index % rowLength;
|
|
size.left = hIndex * (oWidth + vMargin);
|
|
size.right = size.left + oWidth;
|
|
// vertical position
|
|
var oHeight = size.bottom - size.top;
|
|
var vIndex = Math.floor(index / rowLength);
|
|
size.top = vIndex * (oHeight + hMargin);
|
|
size.bottom = size.top + oHeight;
|
|
object.size = size;
|
|
}
|
|
|
|
/**
|
|
* Helper function for updateUnitCommands; sets up "unit panels"
|
|
* (i.e. panels with rows of icons) for the currently selected unit.
|
|
*
|
|
* @param guiName Short identifier string of this panel. See g_SelectionPanels.
|
|
* @param unitEntState Entity state of the (first) selected unit.
|
|
* @param payerState Player state
|
|
*/
|
|
function setupUnitPanel(guiName, unitEntState, playerState)
|
|
{
|
|
if (!g_SelectionPanels[guiName])
|
|
{
|
|
error("unknown guiName used '" + guiName + "'");
|
|
return;
|
|
}
|
|
var selection = g_Selection.toList();
|
|
|
|
var items = g_SelectionPanels[guiName].getItems(unitEntState, selection);
|
|
|
|
if (!items || !items.length)
|
|
return;
|
|
|
|
var numberOfItems = items.length;
|
|
var garrisonGroups = new EntityGroups();
|
|
|
|
// Determine how many buttons there should be
|
|
var maxNumberOfItems = g_SelectionPanels[guiName].getMaxNumberOfItems()
|
|
if (maxNumberOfItems < numberOfItems)
|
|
numberOfItems = maxNumberOfItems;
|
|
|
|
if (g_SelectionPanels[guiName].rowLength)
|
|
var rowLength = g_SelectionPanels[guiName].rowLength;
|
|
else
|
|
var rowLength = 8;
|
|
|
|
if (g_SelectionPanels[guiName].resizePanel)
|
|
g_SelectionPanels[guiName].resizePanel(numberOfItems, rowLength);
|
|
|
|
// Make buttons
|
|
for (var i = 0; i < numberOfItems; i++)
|
|
{
|
|
var item = items[i];
|
|
|
|
// If a tech has been researched it leaves an empty slot
|
|
if (!item)
|
|
{
|
|
if (g_SelectionPanels[guiName].hideItem)
|
|
g_SelectionPanels[guiName].hideItem(i, rowLength);
|
|
continue;
|
|
}
|
|
|
|
// STANDARD DATA
|
|
// add standard data
|
|
var data = {
|
|
"i": i,
|
|
"item": item,
|
|
"selection": selection,
|
|
"playerState": playerState,
|
|
"unitEntState": unitEntState,
|
|
"rowLength": rowLength,
|
|
"numberOfItems": numberOfItems,
|
|
};
|
|
|
|
// 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+"]");
|
|
data.affordableMask = Engine.GetGUIObjectByName("unit"+guiName+"Unaffordable["+i+"]");
|
|
data.icon = Engine.GetGUIObjectByName("unit"+guiName+"Icon["+i+"]");
|
|
data.guiSelection = Engine.GetGUIObjectByName("unit"+guiName+"Selection["+i+"]");
|
|
data.countDisplay = Engine.GetGUIObjectByName("unit"+guiName+"Count["+i+"]");
|
|
|
|
|
|
// DEFAULTS
|
|
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.
|
|
|
|
// GENERAL DATA
|
|
// add general data, and a chance to abort on faulty data
|
|
if (g_SelectionPanels[guiName].addData)
|
|
{
|
|
var success = g_SelectionPanels[guiName].addData(data);
|
|
if (!success)
|
|
continue; // ignore faulty data
|
|
}
|
|
|
|
// SET CONTENT
|
|
// run all content setters
|
|
for (var f in g_SelectionPanels[guiName])
|
|
{
|
|
if (f.match(/^set/))
|
|
g_SelectionPanels[guiName][f](data);
|
|
}
|
|
|
|
// Special case: position
|
|
if (!g_SelectionPanels[guiName].setPosition)
|
|
setPanelObjectPosition(data.button, i, rowLength);
|
|
|
|
// TODO: we should require all entities to have icons, so this case never occurs
|
|
if (data.icon && !data.icon.sprite)
|
|
data.icon.sprite = "bkFillBlack";
|
|
|
|
}
|
|
|
|
// Hide any buttons we're no longer using
|
|
for (var i = numberOfItems; i < g_unitPanelButtons[guiName]; ++i)
|
|
if (g_SelectionPanels[guiName].hideItem)
|
|
g_SelectionPanels[guiName].hideItem(i, rowLength);
|
|
else
|
|
Engine.GetGUIObjectByName("unit"+guiName+"Button["+i+"]").hidden = true;
|
|
|
|
// remember the number of items
|
|
g_unitPanelButtons[guiName] = numberOfItems;
|
|
g_SelectionPanels[guiName].used = true;
|
|
}
|
|
|
|
function resourcesToAlphaMask(neededResources)
|
|
{
|
|
var totalCost = 0;
|
|
for each (var resource in neededResources)
|
|
totalCost += resource;
|
|
var alpha = 50 + Math.round(totalCost/10);
|
|
alpha = alpha > 125 ? 125 : alpha;
|
|
return "colour: 255 0 0 " + (alpha);
|
|
}
|
|
|
|
/**
|
|
* Updates the selection panels where buttons are supposed to
|
|
* depend on the context.
|
|
* Runs in the main session loop via updateSelectionDetails().
|
|
* Delegates to setupUnitPanel to set up individual subpanels,
|
|
* appropriately activated depending on the selected unit's state.
|
|
*
|
|
* @param entState Entity state of the (first) selected unit.
|
|
* @param supplementalDetailsPanel Reference to the
|
|
* "supplementalSelectionDetails" GUI Object
|
|
* @param commandsPanel Reference to the "commandsPanel" GUI Object
|
|
* @param selection Array of currently selected entity IDs.
|
|
*/
|
|
function updateUnitCommands(entState, supplementalDetailsPanel, commandsPanel, selection)
|
|
{
|
|
for each (var panel in g_SelectionPanels)
|
|
panel.used = false;
|
|
|
|
// If the selection is friendly units, add the command panels
|
|
var player = Engine.GetPlayerID();
|
|
|
|
// Get player state to check some constraints
|
|
// e.g. presence of a hero or build limits
|
|
var simState = GetSimState();
|
|
var playerState = simState.players[player];
|
|
|
|
if (entState.player == player || g_DevSettings.controlAll)
|
|
{
|
|
for (var guiName of g_PanelsOrder)
|
|
{
|
|
if (
|
|
g_SelectionPanels[guiName].conflictsWith &&
|
|
g_SelectionPanels[guiName].conflictsWith.some(function (p) { return g_SelectionPanels[p].used; })
|
|
)
|
|
continue;
|
|
|
|
setupUnitPanel(guiName, entState, playerState);
|
|
}
|
|
|
|
supplementalDetailsPanel.hidden = false;
|
|
commandsPanel.hidden = false;
|
|
}
|
|
else if (playerState.isMutualAlly[entState.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);
|
|
if (g_SelectionPanels["Garrison"].used)
|
|
supplementalDetailsPanel.hidden = false;
|
|
else
|
|
supplementalDetailsPanel.hidden = true;
|
|
|
|
commandsPanel.hidden = true;
|
|
}
|
|
else // owned by another player
|
|
{
|
|
supplementalDetailsPanel.hidden = true;
|
|
commandsPanel.hidden = true;
|
|
}
|
|
|
|
// Hides / unhides Unit Panels (panels should be grouped by type, not by order, but we will leave that for another time)
|
|
for (var panelName in g_SelectionPanels)
|
|
Engine.GetGUIObjectByName("unit" + panelName + "Panel").hidden = !g_SelectionPanels[panelName].used;
|
|
}
|
|
|
|
// Force hide commands panels
|
|
function hideUnitCommands()
|
|
{
|
|
for (var panelName in g_SelectionPanels)
|
|
Engine.GetGUIObjectByName("unit" + panelName + "Panel").hidden = true;
|
|
}
|
|
|
|
// Get all of the available entities which can be trained by the selected entities
|
|
function getAllTrainableEntities(selection)
|
|
{
|
|
var trainableEnts = [];
|
|
var state;
|
|
// Get all buildable and trainable entities
|
|
for (var i in selection)
|
|
{
|
|
if ((state = GetEntityState(selection[i])) && state.production && state.production.entities.length)
|
|
trainableEnts = trainableEnts.concat(state.production.entities);
|
|
}
|
|
|
|
// Remove duplicates
|
|
removeDupes(trainableEnts);
|
|
return trainableEnts;
|
|
}
|
|
|
|
function getAllTrainableEntitiesFromSelection()
|
|
{
|
|
if (!g_allTrainableEntities)
|
|
g_allTrainableEntities = getAllTrainableEntities(g_Selection.toList());
|
|
|
|
return g_allTrainableEntities;
|
|
}
|
|
|
|
// Get all of the available entities which can be built by the selected entities
|
|
function getAllBuildableEntities(selection)
|
|
{
|
|
var buildableEnts = [];
|
|
var state;
|
|
// Get all buildable entities
|
|
for (var i in selection)
|
|
{
|
|
if ((state = GetEntityState(selection[i])) && state.buildEntities && state.buildEntities.length)
|
|
buildableEnts = buildableEnts.concat(state.buildEntities);
|
|
}
|
|
|
|
// Remove duplicates
|
|
removeDupes(buildableEnts);
|
|
return buildableEnts;
|
|
}
|
|
|
|
function getAllBuildableEntitiesFromSelection()
|
|
{
|
|
if (!g_allBuildableEntities)
|
|
g_allBuildableEntities = getAllBuildableEntities(g_Selection.toList());
|
|
|
|
return g_allBuildableEntities;
|
|
}
|
|
|
|
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;
|
|
}
|