forked from mirrors/0ad
Implement "Call to the Arms"-button.
This allows a player to task entities to drop off their resources and subsequently attack-move to a specified location with one button. Patch by: @JCWasmx86 Icon by: @Stan Differential revision: https://code.wildfiregames.com/D4149 Fixes: #1364 Comments by: @Langbart Based on a patch by: @Freagarach (https://code.wildfiregames.com/D1868) This was SVN commit r25868.
This commit is contained in:
@@ -353,6 +353,7 @@ snaptoedges = Ctrl ; Modifier to align new structures with nearby exis
|
||||
toggledefaultformation = "" ; Switch between null default formation and the last default formation used (defaults to "box")
|
||||
flare = K ; Modifier to send a flare to your allies
|
||||
flareactivate = "" ; Modifier to activate the mode to send a flare to your allies
|
||||
calltoarms = "" ; Modifier to call the selected units to the arms.
|
||||
; Overlays
|
||||
showstatusbars = Tab ; Toggle display of status bars
|
||||
devcommands.toggle = "Alt+D" ; Toggle developer commands panel
|
||||
|
||||
Binary file not shown.
@@ -174,6 +174,10 @@
|
||||
"session.flareactivate": {
|
||||
"name": "Flare (toggle)",
|
||||
"desc": "Set the cursor to Flare. The hotkey can be released."
|
||||
},
|
||||
"session.calltoarms": {
|
||||
"name": "Call to arms",
|
||||
"desc": "Send the selected units on attack move to the specified location after dropping resources."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ const ACTION_REPAIR = 2;
|
||||
const ACTION_GUARD = 3;
|
||||
const ACTION_PATROL = 4;
|
||||
const ACTION_OCCUPY_TURRET = 5;
|
||||
const ACTION_CALLTOARMS = 6;
|
||||
var preSelectedAction = ACTION_NONE;
|
||||
|
||||
const INPUT_NORMAL = 0;
|
||||
|
||||
@@ -246,6 +246,48 @@ var g_UnitActions =
|
||||
"specificness": 10,
|
||||
},
|
||||
|
||||
"call-to-arms": {
|
||||
"execute": function(target, action, selection, queued, pushFront)
|
||||
{
|
||||
let targetClasses;
|
||||
if (Engine.HotkeyIsPressed("session.attackmoveUnit"))
|
||||
targetClasses = { "attack": ["Unit"] };
|
||||
else
|
||||
targetClasses = { "attack": ["Unit", "Structure"] };
|
||||
Engine.PostNetworkCommand({
|
||||
"type": "call-to-arms",
|
||||
"entities": selection,
|
||||
"target": target,
|
||||
"targetClasses": targetClasses,
|
||||
"queued": queued,
|
||||
"pushFront": pushFront,
|
||||
"allowCapture": true,
|
||||
"formation": g_AutoFormation.getNull()
|
||||
});
|
||||
return true;
|
||||
},
|
||||
"getActionInfo": function(entState, targetState)
|
||||
{
|
||||
return { "possible": !!entState.unitAI };
|
||||
},
|
||||
"actionCheck": function(target, selection)
|
||||
{
|
||||
const actionInfo = getActionInfo("call-to-arms", target, selection);
|
||||
return actionInfo.possible && {
|
||||
"type": "call-to-arms",
|
||||
"cursor": "action-attack",
|
||||
"target": target,
|
||||
"firstAbleEntity": actionInfo.entity
|
||||
};
|
||||
},
|
||||
"preSelectedActionCheck": function(target, selection)
|
||||
{
|
||||
return preSelectedAction == ACTION_CALLTOARMS &&
|
||||
this.actionCheck(target, selection);
|
||||
},
|
||||
"specificness": 50,
|
||||
},
|
||||
|
||||
"patrol":
|
||||
{
|
||||
"execute": function(target, action, selection, queued, pushFront)
|
||||
@@ -1423,6 +1465,27 @@ var g_EntityCommands =
|
||||
"allowedPlayers": ["Player"]
|
||||
},
|
||||
|
||||
"call-to-arms": {
|
||||
"getInfo": function(entStates)
|
||||
{
|
||||
const classes = ["Soldier", "Warship", "Siege", "Healer"];
|
||||
if (entStates.every(entState => !MatchesClassList(entState.identity.classes, classes)))
|
||||
return false;
|
||||
return {
|
||||
"tooltip": colorizeHotkey("%(hotkey)s" + " ", "session.calltoarms") +
|
||||
translate("Send the selected units on attack move to the specified location after dropping resources."),
|
||||
"icon": "call-to-arms.png",
|
||||
"enabled": true
|
||||
};
|
||||
},
|
||||
"execute": function(entStates)
|
||||
{
|
||||
inputState = INPUT_PRESELECTEDACTION;
|
||||
preSelectedAction = ACTION_CALLTOARMS;
|
||||
},
|
||||
"allowedPlayers": ["Player"]
|
||||
},
|
||||
|
||||
"garrison": {
|
||||
"getInfo": function(entStates)
|
||||
{
|
||||
|
||||
@@ -556,6 +556,17 @@ UnitAI.prototype.UnitFsmSpec = {
|
||||
return ACCEPT_ORDER;
|
||||
},
|
||||
|
||||
"Order.DropAtNearestDropSite": function(msg) {
|
||||
const cmpResourceGatherer = Engine.QueryInterface(this.entity, IID_ResourceGatherer);
|
||||
if (!cmpResourceGatherer)
|
||||
return this.FinishOrder();
|
||||
const nearby = this.FindNearestDropsite(cmpResourceGatherer.GetMainCarryingType());
|
||||
if (!nearby)
|
||||
return this.FinishOrder();
|
||||
this.ReturnResource(nearby, false, true);
|
||||
return ACCEPT_ORDER;
|
||||
},
|
||||
|
||||
"Order.ReturnResource": function(msg) {
|
||||
if (this.CheckTargetRange(msg.data.target, IID_ResourceGatherer))
|
||||
this.SetNextState("INDIVIDUAL.RETURNRESOURCE.DROPPINGRESOURCES");
|
||||
@@ -960,6 +971,13 @@ UnitAI.prototype.UnitFsmSpec = {
|
||||
return ACCEPT_ORDER;
|
||||
},
|
||||
|
||||
"Order.DropAtNearestDropSite": function(msg) {
|
||||
this.CallMemberFunction("DropAtNearestDropSite", [false, false]);
|
||||
|
||||
this.SetNextState("MEMBER");
|
||||
return ACCEPT_ORDER;
|
||||
},
|
||||
|
||||
"IDLE": {
|
||||
"enter": function(msg) {
|
||||
// Turn rearrange off. Otherwise, if the formation is idle
|
||||
@@ -5233,6 +5251,9 @@ UnitAI.prototype.GetTargetPositions = function()
|
||||
case "Stop":
|
||||
return [];
|
||||
|
||||
case "DropAtNearestDropSite":
|
||||
break;
|
||||
|
||||
default:
|
||||
error("GetTargetPositions: Unrecognised order type '"+order.type+"'");
|
||||
return [];
|
||||
@@ -5408,6 +5429,15 @@ UnitAI.prototype.Stop = function(queued, pushFront)
|
||||
this.AddOrder("Stop", { "force": true }, queued, pushFront);
|
||||
};
|
||||
|
||||
/**
|
||||
* The unit will drop all resources at the closest dropsite. If this unit is no gatherer or
|
||||
* no dropsite is available, it will do nothing.
|
||||
*/
|
||||
UnitAI.prototype.DropAtNearestDropSite = function(queued, pushFront)
|
||||
{
|
||||
this.AddOrder("DropAtNearestDropSite", { "force": true }, queued, pushFront);
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds walk-to-target order to queue, this only occurs in response
|
||||
* to a player order, and so is forced.
|
||||
|
||||
@@ -279,6 +279,27 @@ var g_Commands = {
|
||||
}
|
||||
},
|
||||
|
||||
"call-to-arms": function(player, cmd, data)
|
||||
{
|
||||
const unitsToMove = data.entities.filter(ent =>
|
||||
MatchesClassList(Engine.QueryInterface(ent, IID_Identity).GetClassesList(),
|
||||
["Soldier", "Warship", "Siege", "Healer"])
|
||||
);
|
||||
GetFormationUnitAIs(unitsToMove, player, cmd, data.formation).forEach(cmpUnitAI => {
|
||||
const target = cmd.target;
|
||||
if (cmd.pushFront)
|
||||
{
|
||||
cmpUnitAI.WalkAndFight(target.x, target.z, cmd.targetClasses, cmd.allowCapture, false, cmd.pushFront);
|
||||
cmpUnitAI.DropAtNearestDropSite(false, cmd.pushFront);
|
||||
}
|
||||
else
|
||||
{
|
||||
cmpUnitAI.DropAtNearestDropSite(cmd.queued, false)
|
||||
cmpUnitAI.WalkAndFight(target.x, target.z, cmd.targetClasses, cmd.allowCapture, true, false);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
"remove-guard": function(player, cmd, data)
|
||||
{
|
||||
for (let ent of data.entities)
|
||||
|
||||
Reference in New Issue
Block a user