Ticket #1720: patrol_V3.13.patch

File patrol_V3.13.patch, 10.5 KB (added by Imarok, 3 years ago)

Don't attack buildings when patrolling. Correctly continue patrolling after an attack

  • binaries/data/config/default.cfg

     
    286286garrison = Ctrl              ; Modifier to garrison when clicking on building
    287287autorallypoint = Ctrl        ; Modifier to set the rally point on the building itself
    288288guard = "G"                  ; Modifier to escort/guard when clicking on unit/building
     289patrol = "P"                 ; Modifier to patrol a unit
    289290repair = "J"                 ; Modifier to repair when clicking on building/mechanical unit
    290291queue = Shift                ; Modifier to queue unit orders instead of replacing
    291292batchtrain = Shift           ; Modifier to train units in batches
  • binaries/data/mods/public/gui/manual/intro.txt

     
    8484[font="sans-bold-14"]Modify mouse action
    8585[font="sans-14"]Ctrl + Right Click on building: Garrison
    8686J + Right Click on building: Repair
     87P + Right Click: Patrol
    8788Shift + Right Click: Queue the move/build/gather/etc order
    8889Shift + Left click when training unit/s: Add units in batches of five
    8990Shift + Left Click or Left Drag over unit on map: Add unit to selection
  • binaries/data/mods/public/gui/session/input.js

     
    1616const ACTION_GARRISON = 1;
    1717const ACTION_REPAIR = 2;
    1818const ACTION_GUARD = 3;
     19const ACTION_PATROL = 4;
    1920var preSelectedAction = ACTION_NONE;
    2021
    2122const INPUT_NORMAL = 0;
     
    205206                data.targetClasses = Engine.HotkeyIsPressed("session.attackmoveUnit") ? { "attack": ["Unit"] } : { "attack": ["Unit", "Structure"] };
    206207                cursor = "action-attack-move";
    207208            }
     209            else if (Engine.HotkeyIsPressed("session.patrol"))
     210            {
     211                data.command = "patrol";
     212                data.targetClasses = { "attack": ["Unit"] };
     213                cursor = "action-patrol";
     214            }
    208215            return { "possible": true, "data": data, "cursor": cursor };
    209216        }
    210217
    211         return { "possible": (action == "move" || action == "attack-move" || action == "remove-guard") };
     218        return { "possible": ["move", "attack-move", "remove-guard", "patrol"].indexOf(action) > -1 };
    212219    }
    213220
    214221    // Look at the first targeted entity
  • binaries/data/mods/public/gui/session/unit_actions.js

     
    208208        "specificness": 10,
    209209    },
    210210
     211    "patrol":
     212    {
     213        "execute": function(target, action, selection, queued)
     214        {
     215            Engine.PostNetworkCommand({
     216                "type": "patrol",
     217                "entities": selection,
     218                "x": target.x,
     219                "z": target.z,
     220                "target": action.target,
     221                "targetClasses": { "attack": ["Unit"] }, // patrol should only attack units
     222                "queued": queued,
     223                "allowCapture": false
     224            });
     225            Engine.GuiInterfaceCall("PlaySound", { "name": "order_patrol", "entity": selection[0] });
     226            return true;
     227        },
     228        "getActionInfo": function(entState, targetState)
     229        {
     230            return { "possible": true };
     231        },
     232        "hotkeyActionCheck": function(target, selection)
     233        {
     234            if (!someUnitAI(selection) ||
     235                !Engine.HotkeyIsPressed("session.patrol") ||
     236                !getActionInfo("patrol", target).possible)
     237                return false;
     238            return {
     239                "type": "patrol",
     240                "cursor": "action-patrol",
     241                "target": target
     242            };
     243        },
     244        "preSelectedActionCheck" : function(target)
     245        {
     246            if (preSelectedAction != ACTION_PATROL || !getActionInfo("patrol", target).possible)
     247                return false;
     248            return {
     249                "type": "patrol",
     250                "cursor": "action-patrol",
     251                "target": target
     252            };
     253        },
     254        "specificness": 37,
     255    },
     256
    211257    "heal":
    212258    {
    213259        "execute": function(target, action, selection, queued)
     
    12181264        },
    12191265    },
    12201266
     1267    "patrol": {
     1268        "getInfo": function(entState)
     1269        {
     1270            if (g_Selection.toList().every(ent => !GetExtendedEntityState(ent).unitAI))
     1271                return false;
     1272            return {
     1273                "tooltip": colorizeHotkey("%(hotkey)s" + " ", "session.patrol") + translate("Patrol"),
     1274                "icon": "patrol.png"
     1275            };
     1276        },
     1277        "execute": function(entState)
     1278        {
     1279            inputState = INPUT_PRESELECTEDACTION;
     1280            preSelectedAction = ACTION_PATROL;
     1281        },
     1282    },
     1283
    12211284    "share-dropsite": {
    12221285        "getInfo": function(entState)
    12231286        {
  • binaries/data/mods/public/simulation/components/UnitAI.js

     
    514514        this.FinishOrder();
    515515    },
    516516
     517    "Order.Patrol": function(msg) {
     518        // Let players move captured domestic animals around
     519        if (this.IsAnimal() || this.IsTurret())
     520        {
     521            this.FinishOrder();
     522            return;
     523        }
     524
     525        if (this.CanPack())
     526        {
     527            this.PushOrderFront("Pack", { "force": true });
     528            return;
     529        }
     530
     531        this.MoveToPoint(this.order.data.x, this.order.data.z);
     532        this.SetNextState("INDIVIDUAL.PATROL");
     533    },
     534
    517535    "Order.Heal": function(msg) {
    518536        // Check the target is alive
    519537        if (!this.TargetIsAlive(this.order.data.target))
     
    829847                this.FinishOrder();
    830848        },
    831849
     850        "Order.Patrol": function(msg) {
     851            this.CallMemberFunction("SetHeldPosition", [msg.data.x, msg.data.z]);
     852
     853            this.MoveToPoint(this.order.data.x, this.order.data.z);
     854            this.SetNextState("PATROL");
     855        },
     856
    832857        "Order.Guard": function(msg) {
    833858            this.CallMemberFunction("Guard", [msg.data.target, false]);
    834859            var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation);
     
    10781103            },
    10791104        },
    10801105
     1106        "PATROL": {
     1107            "enter": function(msg) {
     1108                // Memorize the origin position in case that we want to go back
     1109                let cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
     1110                if (!cmpPosition || !cmpPosition.IsInWorld())
     1111                {
     1112                    this.FinishOrder();
     1113                    return;
     1114                }
     1115                if (!this.patrolStartPosOrder){
     1116                    this.patrolStartPosOrder = cmpPosition.GetPosition();
     1117                    this.patrolStartPosOrder.targetClasses = { "attack": ["Unit"] };
     1118                }
     1119
     1120                this.StartTimer(0, 1000);
     1121            },
     1122
     1123            "Timer": function(msg) {
     1124                // Check if there are no enemies to attack
     1125                this.FindWalkAndFightTargets();
     1126            },
     1127
     1128            "leave": function(msg) {
     1129                this.StopTimer();
     1130                delete this.patrolStartPosOrder;
     1131            },
     1132
     1133            "MoveStarted": function(msg) {
     1134                let cmpFormation = Engine.QueryInterface(this.entity, IID_Formation);
     1135                cmpFormation.SetRearrange(true);
     1136                cmpFormation.MoveMembersIntoFormation(true, true);
     1137            },
     1138
     1139            "MoveCompleted": function() {
     1140                /**
     1141                 * A-B-A-B-..:
     1142                 * if the user only commands one patrol order, the patrol will be between
     1143                 * the last position and the defined waypoint
     1144                 * A-B-C-..-A-B-..:
     1145                 * otherwise, the patrol is only between the given patrol commands and the
     1146                 * last position is not included (last position = the position where the unit
     1147                 * is located at the time of the first patrol order)
     1148                 */
     1149
     1150                if (this.orderQueue.length == 1)
     1151                    this.PushOrder("Patrol", this.patrolStartPosOrder);
     1152
     1153                this.PushOrder(this.order.type, this.order.data);
     1154                this.FinishOrder();
     1155            },
     1156        },
     1157
    10811158        "GARRISON":{
    10821159            "enter": function() {
    10831160                // If the garrisonholder should pickup, warn it so it can take needed action
     
    15551632            },
    15561633        },
    15571634
     1635        "PATROL": {
     1636            "enter": function () {
     1637                // Memorize the origin position in case that we want to go back
     1638                let cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
     1639                if (!cmpPosition || !cmpPosition.IsInWorld())
     1640                {
     1641                    this.FinishOrder();
     1642                    return;
     1643                }
     1644                if (!this.patrolStartPosOrder){
     1645                    this.patrolStartPosOrder = cmpPosition.GetPosition();
     1646                    this.patrolStartPosOrder.targetClasses = { "attack": ["Unit"] };
     1647                }
     1648
     1649                this.StartTimer(0, 1000);
     1650                this.SelectAnimation("move");
     1651            },
     1652
     1653            "leave": function() {
     1654                this.StopTimer();
     1655                delete this.patrolStartPosOrder;
     1656            },
     1657
     1658            "Timer": function(msg) {
     1659                this.FindWalkAndFightTargets();
     1660            },
     1661
     1662            "MoveCompleted": function() {
     1663                if (this.orderQueue.length == 1)
     1664                    this.PushOrder("Patrol",this.patrolStartPosOrder);
     1665
     1666                this.PushOrder(this.order.type, this.order.data);
     1667                this.FinishOrder();
     1668            },
     1669        },
     1670
    15581671        "GUARD": {
    15591672            "RemoveGuard": function() {
    15601673                this.StopMoving();
     
    47574870        case "WalkToPointRange":
    47584871        case "MoveIntoFormation":
    47594872        case "GatherNearPosition":
     4873        case "Patrol":
    47604874            targetPositions.push(new Vector2D(order.data.x, order.data.z));
    47614875            break; // and continue the loop
    47624876
     
    49695083    this.AddOrder("WalkAndFight", { "x": x, "z": z, "targetClasses": targetClasses, "force": true }, queued);
    49705084};
    49715085
     5086UnitAI.prototype.Patrol = function(x, z, targetClasses, queued)
     5087{
     5088    this.AddOrder("Patrol", { "x": x, "z": z, "targetClasses": targetClasses, "force": true }, queued);
     5089};
     5090
    49725091/**
    49735092 * Adds leave foundation order to queue, treated as forced.
    49745093 */
  • binaries/data/mods/public/simulation/helpers/Commands.js

     
    176176        });
    177177    },
    178178
     179    "patrol": function(player, cmd, data)
     180    {
     181        GetFormationUnitAIs(data.entities, player).forEach(cmpUnitAI =>
     182            cmpUnitAI.Patrol(cmd.x, cmd.z, cmd.targetClasses, cmd.queued)
     183        );
     184    },
     185
    179186    "heal": function(player, cmd, data)
    180187    {
    181188        if (g_DebugCommands && !(IsOwnedByPlayer(player, cmd.target) || IsOwnedByAllyOfPlayer(player, cmd.target)))
  • binaries/data/mods/public/simulation/helpers/RallyPointCommands.js

     
    7070                "queued": true
    7171            });
    7272            break;
     73        case "patrol":
     74            ret.push( {
     75                "type": "patrol",
     76                "entities": spawnedEnts,
     77                "x": rallyPos[i].x,
     78                "z": rallyPos[i].z,
     79                "target": data[i].target,
     80                "targetClasses": data[i].targetClasses,
     81                "queued": true
     82            });
     83            break;
    7384        case "attack":
    7485            ret.push( {
    7586                "type": "attack",