0ad/binaries/data/mods/public/simulation/helpers/RallyPointCommands.js
mehmed-faheim-arslan 39b1311fac Allow players to set rally points on allied buildings
Instead of storing a single flat list of positions and data per
building, RallyPoint now stores them keyed by player ID. This lets
mutual allies independently set and display rally points on each
other's structures.

The GUI now allows selecting allied buildings with a rally point
and only shows the viewing player's own rally point data.
GuiInterface gets an OnUpdate handler to keep displayed positions
in sync when rally point targets move.

GetRallyPointCommands now takes raw position and data arrays instead
of a component reference. The network command field is also renamed
from "entities" to "structures".

Fixes #3115
2026-06-10 00:09:48 +02:00

172 lines
3.9 KiB
JavaScript

// Returns an array of commands suitable for ProcessCommand() based on the rally point data.
// This assumes that the rally point has a valid position.
function GetRallyPointCommands(rallyPos, data, spawnedEnts)
{
const ret = [];
for (let i = 0; i < rallyPos.length; ++i)
{
// Look and see if there is a command in the rally point data, otherwise just walk there.
let command = data[i]?.command ?? "walk";
// If a target was set and the target no longer exists, or no longer
// has a valid position, then just walk to the rally point.
if (data[i]?.target)
{
const cmpPosition = Engine.QueryInterface(data[i].target, IID_Position);
if (!cmpPosition || !cmpPosition.IsInWorld())
{
if (command == "gather")
command = "gather-near-position";
else if (command == "collect-treasure")
command = "collect-treasure-near-position";
else if (command == "attack")
command = "attack-walk";
else
command = "walk";
}
}
switch (command)
{
case "gather":
ret.push({
"type": "gather",
"entities": spawnedEnts,
"target": data[i].target,
"queued": true
});
break;
case "gather-near-position":
ret.push({
"type": "gather-near-position",
"entities": spawnedEnts,
"x": rallyPos[i].x,
"z": rallyPos[i].z,
"resourceType": data[i].resourceType,
"resourceTemplate": data[i].resourceTemplate,
"queued": true
});
break;
case "repair":
case "build":
ret.push({
"type": "repair",
"entities": spawnedEnts,
"target": data[i].target,
"queued": true,
"autocontinue": i == rallyPos.length - 1
});
break;
case "occupy-turret":
ret.push({
"type": "occupy-turret",
"entities": spawnedEnts,
"target": data[i].target,
"queued": true
});
break;
case "garrison":
ret.push({
"type": "garrison",
"entities": spawnedEnts,
"target": data[i].target,
"queued": true
});
break;
case "attack-walk":
ret.push({
"type": "attack-walk",
"entities": spawnedEnts,
"x": rallyPos[i].x,
"z": rallyPos[i].z,
"targetClasses": data[i].targetClasses,
"queued": true
});
break;
case "patrol":
ret.push({
"type": "patrol",
"entities": spawnedEnts,
"x": rallyPos[i].x,
"z": rallyPos[i].z,
"target": data[i].target,
"targetClasses": data[i].targetClasses,
"queued": true
});
break;
case "attack":
ret.push({
"type": "attack",
"entities": spawnedEnts,
"target": data[i].target,
"allowCapture": data[i].allowCapture,
"queued": true,
});
break;
case "trade":
ret.push({
"type": "setup-trade-route",
"entities": spawnedEnts,
"source": data[i].source,
"target": data[i].target,
"route": undefined,
"queued": true
});
break;
case "collect-treasure":
ret.push({
"type": "collect-treasure",
"entities": spawnedEnts,
"target": data[i].target,
"queued": true
});
break;
case "collect-treasure-near-position":
ret.push({
"type": "collect-treasure-near-position",
"entities": spawnedEnts,
"x": rallyPos[i].x,
"z": rallyPos[i].z,
"queued": true
});
break;
default:
ret.push({
"type": "walk",
"entities": spawnedEnts,
"x": rallyPos[i].x,
"z": rallyPos[i].z,
"queued": true
});
break;
}
}
// special case: trade route with waypoints
// (we do not modify the RallyPoint before, as we want it to be displayed with all way-points)
if (ret.length > 1 && ret[ret.length-1].type == "setup-trade-route")
{
let route = [];
const waypoints = ret.length - 1;
for (let i = 0; i < waypoints; ++i)
{
if (ret[i].type != "walk")
{
route = undefined;
break;
}
route.push({ "x": ret[i].x, "z": ret[i].z });
}
if (route && route.length > 0)
{
ret.splice(0, waypoints);
ret[0].route = route;
}
}
return ret;
}
Engine.RegisterGlobal("GetRallyPointCommands", GetRallyPointCommands);