Patrol units. Patch by Imarok, based on patch by svott, reviewed by fatherbushido and bb.
This was SVN commit r18779.
This commit is contained in:
parent
51b7b80de2
commit
a85c6c6967
@ -287,6 +287,7 @@ attackmoveUnit = "Ctrl+Q" ; Modifier to attackmove targeting only units when
|
||||
garrison = Ctrl ; Modifier to garrison when clicking on building
|
||||
autorallypoint = Ctrl ; Modifier to set the rally point on the building itself
|
||||
guard = "G" ; Modifier to escort/guard when clicking on unit/building
|
||||
patrol = "P" ; Modifier to patrol a unit
|
||||
repair = "J" ; Modifier to repair when clicking on building/mechanical unit
|
||||
queue = Shift ; Modifier to queue unit orders instead of replacing
|
||||
batchtrain = Shift ; Modifier to train units in batches
|
||||
|
@ -85,6 +85,7 @@ Tab: See all status bars (which would also show the building progress)
|
||||
[font="sans-bold-14"]Modify mouse action
|
||||
[font="sans-14"]Ctrl + Right Click on building: Garrison
|
||||
J + Right Click on building: Repair
|
||||
P + Right Click: Patrol
|
||||
Shift + Right Click: Queue the move/build/gather/etc order
|
||||
Shift + Left click when training unit/s: Add units in batches of five
|
||||
Shift + Left Click or Left Drag over unit on map: Add unit to selection
|
||||
|
@ -16,6 +16,7 @@ const ACTION_NONE = 0;
|
||||
const ACTION_GARRISON = 1;
|
||||
const ACTION_REPAIR = 2;
|
||||
const ACTION_GUARD = 3;
|
||||
const ACTION_PATROL = 4;
|
||||
var preSelectedAction = ACTION_NONE;
|
||||
|
||||
const INPUT_NORMAL = 0;
|
||||
@ -205,10 +206,16 @@ function getActionInfo(action, target)
|
||||
data.targetClasses = Engine.HotkeyIsPressed("session.attackmoveUnit") ? { "attack": ["Unit"] } : { "attack": ["Unit", "Structure"] };
|
||||
cursor = "action-attack-move";
|
||||
}
|
||||
else if (Engine.HotkeyIsPressed("session.patrol"))
|
||||
{
|
||||
data.command = "patrol";
|
||||
data.targetClasses = { "attack": ["Unit"] };
|
||||
cursor = "action-patrol";
|
||||
}
|
||||
return { "possible": true, "data": data, "cursor": cursor };
|
||||
}
|
||||
|
||||
return { "possible": (action == "move" || action == "attack-move" || action == "remove-guard") };
|
||||
return { "possible": ["move", "attack-move", "remove-guard", "patrol"].indexOf(action) > -1 };
|
||||
}
|
||||
|
||||
// Look at the first targeted entity
|
||||
|
@ -208,6 +208,52 @@ var unitActions =
|
||||
"specificness": 10,
|
||||
},
|
||||
|
||||
"patrol":
|
||||
{
|
||||
"execute": function(target, action, selection, queued)
|
||||
{
|
||||
Engine.PostNetworkCommand({
|
||||
"type": "patrol",
|
||||
"entities": selection,
|
||||
"x": target.x,
|
||||
"z": target.z,
|
||||
"target": action.target,
|
||||
"targetClasses": { "attack": ["Unit"] }, // patrol should only attack units
|
||||
"queued": queued,
|
||||
"allowCapture": false
|
||||
});
|
||||
Engine.GuiInterfaceCall("PlaySound", { "name": "order_patrol", "entity": selection[0] });
|
||||
return true;
|
||||
},
|
||||
"getActionInfo": function(entState, targetState)
|
||||
{
|
||||
return { "possible": true };
|
||||
},
|
||||
"hotkeyActionCheck": function(target, selection)
|
||||
{
|
||||
if (!someUnitAI(selection) ||
|
||||
!Engine.HotkeyIsPressed("session.patrol") ||
|
||||
!getActionInfo("patrol", target).possible)
|
||||
return false;
|
||||
return {
|
||||
"type": "patrol",
|
||||
"cursor": "action-patrol",
|
||||
"target": target
|
||||
};
|
||||
},
|
||||
"preSelectedActionCheck" : function(target)
|
||||
{
|
||||
if (preSelectedAction != ACTION_PATROL || !getActionInfo("patrol", target).possible)
|
||||
return false;
|
||||
return {
|
||||
"type": "patrol",
|
||||
"cursor": "action-patrol",
|
||||
"target": target
|
||||
};
|
||||
},
|
||||
"specificness": 37,
|
||||
},
|
||||
|
||||
"heal":
|
||||
{
|
||||
"execute": function(target, action, selection, queued)
|
||||
@ -1219,6 +1265,25 @@ var g_EntityCommands =
|
||||
},
|
||||
},
|
||||
|
||||
"patrol": {
|
||||
"getInfo": function(entState)
|
||||
{
|
||||
if (g_Selection.toList().every(ent => !GetEntityState(ent).unitAI))
|
||||
return false;
|
||||
return {
|
||||
"tooltip": colorizeHotkey("%(hotkey)s" + " ", "session.patrol") +
|
||||
translate("Patrol") + "\n" +
|
||||
translate("Attack encountered encountered units while avoiding buildings."),
|
||||
"icon": "patrol.png"
|
||||
};
|
||||
},
|
||||
"execute": function(entState)
|
||||
{
|
||||
inputState = INPUT_PRESELECTEDACTION;
|
||||
preSelectedAction = ACTION_PATROL;
|
||||
},
|
||||
},
|
||||
|
||||
"share-dropsite": {
|
||||
"getInfo": function(entState)
|
||||
{
|
||||
|
@ -514,6 +514,24 @@ UnitAI.prototype.UnitFsmSpec = {
|
||||
this.FinishOrder();
|
||||
},
|
||||
|
||||
"Order.Patrol": function(msg) {
|
||||
// Let players move captured domestic animals around
|
||||
if (this.IsAnimal() || this.IsTurret())
|
||||
{
|
||||
this.FinishOrder();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.CanPack())
|
||||
{
|
||||
this.PushOrderFront("Pack", { "force": true });
|
||||
return;
|
||||
}
|
||||
|
||||
this.MoveToPoint(this.order.data.x, this.order.data.z);
|
||||
this.SetNextState("INDIVIDUAL.PATROL");
|
||||
},
|
||||
|
||||
"Order.Heal": function(msg) {
|
||||
// Check the target is alive
|
||||
if (!this.TargetIsAlive(this.order.data.target))
|
||||
@ -829,6 +847,13 @@ UnitAI.prototype.UnitFsmSpec = {
|
||||
this.FinishOrder();
|
||||
},
|
||||
|
||||
"Order.Patrol": function(msg) {
|
||||
this.CallMemberFunction("SetHeldPosition", [msg.data.x, msg.data.z]);
|
||||
|
||||
this.MoveToPoint(this.order.data.x, this.order.data.z);
|
||||
this.SetNextState("PATROL");
|
||||
},
|
||||
|
||||
"Order.Guard": function(msg) {
|
||||
this.CallMemberFunction("Guard", [msg.data.target, false]);
|
||||
var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation);
|
||||
@ -1078,6 +1103,59 @@ UnitAI.prototype.UnitFsmSpec = {
|
||||
},
|
||||
},
|
||||
|
||||
"PATROL": {
|
||||
"enter": function(msg) {
|
||||
// Memorize the origin position in case that we want to go back
|
||||
let cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
|
||||
if (!cmpPosition || !cmpPosition.IsInWorld())
|
||||
{
|
||||
this.FinishOrder();
|
||||
return;
|
||||
}
|
||||
if (!this.patrolStartPosOrder)
|
||||
{
|
||||
this.patrolStartPosOrder = cmpPosition.GetPosition();
|
||||
this.patrolStartPosOrder.targetClasses = { "attack": ["Unit"] };
|
||||
}
|
||||
|
||||
this.StartTimer(0, 1000);
|
||||
},
|
||||
|
||||
"Timer": function(msg) {
|
||||
// Check if there are no enemies to attack
|
||||
this.FindWalkAndFightTargets();
|
||||
},
|
||||
|
||||
"leave": function(msg) {
|
||||
this.StopTimer();
|
||||
delete this.patrolStartPosOrder;
|
||||
},
|
||||
|
||||
"MoveStarted": function(msg) {
|
||||
let cmpFormation = Engine.QueryInterface(this.entity, IID_Formation);
|
||||
cmpFormation.SetRearrange(true);
|
||||
cmpFormation.MoveMembersIntoFormation(true, true);
|
||||
},
|
||||
|
||||
"MoveCompleted": function() {
|
||||
/**
|
||||
* A-B-A-B-..:
|
||||
* if the user only commands one patrol order, the patrol will be between
|
||||
* the last position and the defined waypoint
|
||||
* A-B-C-..-A-B-..:
|
||||
* otherwise, the patrol is only between the given patrol commands and the
|
||||
* last position is not included (last position = the position where the unit
|
||||
* is located at the time of the first patrol order)
|
||||
*/
|
||||
|
||||
if (this.orderQueue.length == 1)
|
||||
this.PushOrder("Patrol", this.patrolStartPosOrder);
|
||||
|
||||
this.PushOrder(this.order.type, this.order.data);
|
||||
this.FinishOrder();
|
||||
},
|
||||
},
|
||||
|
||||
"GARRISON":{
|
||||
"enter": function() {
|
||||
// If the garrisonholder should pickup, warn it so it can take needed action
|
||||
@ -1555,6 +1633,43 @@ UnitAI.prototype.UnitFsmSpec = {
|
||||
},
|
||||
},
|
||||
|
||||
"PATROL": {
|
||||
"enter": function () {
|
||||
// Memorize the origin position in case that we want to go back
|
||||
let cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
|
||||
if (!cmpPosition || !cmpPosition.IsInWorld())
|
||||
{
|
||||
this.FinishOrder();
|
||||
return;
|
||||
}
|
||||
if (!this.patrolStartPosOrder)
|
||||
{
|
||||
this.patrolStartPosOrder = cmpPosition.GetPosition();
|
||||
this.patrolStartPosOrder.targetClasses = { "attack": ["Unit"] };
|
||||
}
|
||||
|
||||
this.StartTimer(0, 1000);
|
||||
this.SelectAnimation("move");
|
||||
},
|
||||
|
||||
"leave": function() {
|
||||
this.StopTimer();
|
||||
delete this.patrolStartPosOrder;
|
||||
},
|
||||
|
||||
"Timer": function(msg) {
|
||||
this.FindWalkAndFightTargets();
|
||||
},
|
||||
|
||||
"MoveCompleted": function() {
|
||||
if (this.orderQueue.length == 1)
|
||||
this.PushOrder("Patrol",this.patrolStartPosOrder);
|
||||
|
||||
this.PushOrder(this.order.type, this.order.data);
|
||||
this.FinishOrder();
|
||||
},
|
||||
},
|
||||
|
||||
"GUARD": {
|
||||
"RemoveGuard": function() {
|
||||
this.StopMoving();
|
||||
@ -4762,6 +4877,7 @@ UnitAI.prototype.GetTargetPositions = function()
|
||||
case "WalkToPointRange":
|
||||
case "MoveIntoFormation":
|
||||
case "GatherNearPosition":
|
||||
case "Patrol":
|
||||
targetPositions.push(new Vector2D(order.data.x, order.data.z));
|
||||
break; // and continue the loop
|
||||
|
||||
@ -4974,6 +5090,11 @@ UnitAI.prototype.WalkAndFight = function(x, z, targetClasses, queued)
|
||||
this.AddOrder("WalkAndFight", { "x": x, "z": z, "targetClasses": targetClasses, "force": true }, queued);
|
||||
};
|
||||
|
||||
UnitAI.prototype.Patrol = function(x, z, targetClasses, queued)
|
||||
{
|
||||
this.AddOrder("Patrol", { "x": x, "z": z, "targetClasses": targetClasses, "force": true }, queued);
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds leave foundation order to queue, treated as forced.
|
||||
*/
|
||||
|
@ -176,6 +176,13 @@ var g_Commands = {
|
||||
});
|
||||
},
|
||||
|
||||
"patrol": function(player, cmd, data)
|
||||
{
|
||||
GetFormationUnitAIs(data.entities, player).forEach(cmpUnitAI =>
|
||||
cmpUnitAI.Patrol(cmd.x, cmd.z, cmd.targetClasses, cmd.queued)
|
||||
);
|
||||
},
|
||||
|
||||
"heal": function(player, cmd, data)
|
||||
{
|
||||
if (g_DebugCommands && !(IsOwnedByPlayer(player, cmd.target) || IsOwnedByAllyOfPlayer(player, cmd.target)))
|
||||
|
@ -32,7 +32,7 @@ function GetRallyPointCommands(cmpRallyPoint, spawnedEnts)
|
||||
switch (command)
|
||||
{
|
||||
case "gather":
|
||||
ret.push( {
|
||||
ret.push({
|
||||
"type": "gather-near-position",
|
||||
"entities": spawnedEnts,
|
||||
"x": rallyPos[i].x,
|
||||
@ -70,6 +70,17 @@ function GetRallyPointCommands(cmpRallyPoint, spawnedEnts)
|
||||
"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",
|
||||
|
Loading…
Reference in New Issue
Block a user