Ticket #1847: attack-move-v4.diff

File attack-move-v4.diff, 8.2 KB (added by mimo, 11 years ago)
  • binaries/data/mods/public/simulation/components/UnitAI.js

     
    288288            return;
    289289        }
    290290
    291         this.SetHeldPosition(this.order.data.x, this.order.data.z);
     291        this.ResetHeldPosition();
    292292        this.MoveToPoint(this.order.data.x, this.order.data.z);
    293293        if (this.IsAnimal())
    294294            this.SetNextState("ANIMAL.WALKING");   // WalkAndFight not applicable for animals
     
    660660
    661661        "Order.WalkAndFight": function(msg) {
    662662            var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation);
    663             cmpFormation.CallMemberFunction("SetHeldPosition", [msg.data.x, msg.data.z]);
     663            cmpFormation.CallMemberFunction("ResetHeldPosition", []);
    664664
    665665            this.MoveToPoint(this.order.data.x, this.order.data.z);
    666666            this.SetNextState("WALKINGANDFIGHTING");
     
    924924
    925925        "WALKINGANDFIGHTING": {
    926926            "enter": function(msg) {
    927                 this.StartTimer(0, 1000);
     927                this.StartTimer(1000, 1000);
     928                this.FormationFindNewTargets();
    928929            },
    929930
    930931            "Timer": function(msg) {
    931                 // check if there are no enemies to attack
    932                 var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation);
    933                 for each (var ent in cmpFormation.members)
    934                 {
    935                     var cmpUnitAI =  Engine.QueryInterface(ent, IID_UnitAI);
    936                         if (cmpUnitAI.FindNewTargets())
    937                     {
    938                         if (cmpUnitAI.orderQueue[0] && cmpUnitAI.orderQueue[0].type == "Attack")
    939                         {
    940                             var data = cmpUnitAI.orderQueue[0].data;
    941                             cmpUnitAI.FinishOrder();
    942                             this.PushOrderFront("Attack", { "target": data.target, "force": false, "forceResponse": data.forceResponse });
    943                             break;
    944                         }
    945                     }
    946                 }
     932                // check if there are no ennemies to attack
     933                this.FormationFindNewTargets();
    947934            },
    948935
    949936            "leave": function(msg) {
     
    10171004
    10181005                // Have all members finished the task?
    10191006                if (!cmpFormation.TestAllMemberFunction("HasFinishedOrder", []))
     1007                {
     1008                    // If in WalkAndFight and some units are not fighting, send them back to fight
     1009                    if (this.IsInWalkAndFight())
     1010                        cmpFormation.CallMemberFunction("SendBackToFight", []);
    10201011                    return;
     1012                }
    10211013
    10221014                cmpFormation.CallMemberFunction("ResetFinishOrder", []);
    10231015
     1016                // If in WalkAndFight, no more units fighting, will resume the walk
     1017                // but we must first duplicate the order, because FinishOrder will remove it
     1018                if (this.IsInWalkAndFight())
     1019                    this.PushOrderFront(this.orderQueue[0].type, this.orderQueue[0].data);
     1020
    10241021                // Execute the next order
    10251022                if (this.FinishOrder())
    1026                 {
    1027                     // if WalkAndFight order, look for new target before moving again
    1028                     if (this.orderQueue.length > 0 && this.orderQueue[0].type == "WalkAndFight")
    1029                     {
    1030                         for each (var ent in cmpFormation.members)
    1031                         {
    1032                             var cmpUnitAI =  Engine.QueryInterface(ent, IID_UnitAI);
    1033                                 if (cmpUnitAI.FindNewTargets())
    1034                             {
    1035                                 if (cmpUnitAI.orderQueue[0] && cmpUnitAI.orderQueue[0].type == "Attack")
    1036                                 {
    1037                                     var data = cmpUnitAI.orderQueue[0].data;
    1038                                     cmpUnitAI.FinishOrder();
    1039                                     this.PushOrderFront("Attack", { "target": data.target, "force": false, "forceResponse": data.forceResponse });
    1040                                     break;
    1041                                 }
    1042                             }
    1043                         }
    1044                     }
    10451023                    return;
    1046                 }
    10471024
    10481025                // No more order left.
    10491026                cmpFormation.Disband();
     
    12531230
    12541231        "WALKINGANDFIGHTING": {
    12551232            "enter": function () {
    1256                 this.StartTimer(0, 1000);
     1233                this.StartTimer(1000, 1000);
    12571234                this.SelectAnimation("move");
     1235                this.FindNewTargets();
    12581236            },
    12591237
    12601238            "Timer": function(msg) {
     
    14591437                    }
    14601438
    14611439                    // Can't reach it, no longer owned by enemy, or it doesn't exist any more - give up
     1440
    14621441                    // Except if in WalkAndFight mode where we look for more ennemies around before moving again
    1463                     if (this.FinishOrder())
     1442                    // but we should take care that the new target is in order 0 while the old target was order 1
     1443                    // so we must exchange them before FinishOrder
     1444
     1445                    if (this.IsInWalkAndFight())
    14641446                    {
    1465                         if (this.orderQueue.length > 0 && this.orderQueue[0].type == "WalkAndFight")
    1466                                 this.FindNewTargets();
    1467                         return;
     1447                        if (this.FindNewTargets())
     1448                            this.orderQueue[1].data = this.orderQueue[0].data;
     1449                        else if(this.GetTargetFromFormation())
     1450                            this.orderQueue[1].data = this.orderQueue[0].data;     
    14681451                    }
    14691452
     1453                    if (this.FinishOrder())
     1454                        return;
     1455
    14701456                    // See if we can switch to a new nearby enemy
    14711457                    if (this.FindNewTargets())
    14721458                    {
     
    27122698                // if there are still queued formation orders left
    27132699                if (cmpUnitAI.GetOrders().length > 1)
    27142700                    return true;
     2701                // length = 1 for WalkAndFight, but we still want to return true
     2702                if (cmpUnitAI.IsInWalkAndFight())
     2703                    return true;
    27152704            }
    27162705        }
    27172706
     
    34853474    return false;
    34863475};
    34873476
     3477/**
     3478 * Returns true if we are in WalkAndFight mode (which induces some change in Attack orders).
     3479 */
     3480UnitAI.prototype.IsInWalkAndFight = function()
     3481{
     3482    if (this.IsFormationMember())
     3483    {
     3484        var cmpUnitAI = Engine.QueryInterface(this.formationController, IID_UnitAI);
     3485        if (cmpUnitAI && cmpUnitAI.orderQueue[0] && cmpUnitAI.orderQueue[0].type == "WalkAndFight")
     3486            return true;
     3487    }
     3488    else
     3489    {
     3490        if (this.orderQueue[0] && this.orderQueue[0].type == "WalkAndFight")
     3491            return true;
     3492        if (this.orderQueue[1] && this.orderQueue[1].type == "WalkAndFight" && this.orderQueue[0].type == "Attack")
     3493            return true;
     3494    }
     3495    return false;
     3496};
     3497
    34883498//// External interface functions ////
    34893499
    34903500UnitAI.prototype.SetFormationController = function(ent)
     
    40784088    this.heldPosition = {"x": x, "z": z};
    40794089};
    40804090
     4091UnitAI.prototype.ResetHeldPosition = function(x, z)
     4092{
     4093    this.heldPosition = undefined;
     4094};
     4095
    40814096UnitAI.prototype.GetHeldPosition = function(pos)
    40824097{
    40834098    return this.heldPosition;
     
    43234338    return (cmpPack && cmpPack.IsPacking());
    43244339};
    43254340
     4341UnitAI.prototype.GetTargetFromFormation = function()
     4342{
     4343    if (!this.IsFormationMember())
     4344        return false;
     4345    var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
     4346    if (!cmpAttack)
     4347        return false;
     4348    var targetlist = [];
     4349    var cmpUnitAI = Engine.QueryInterface(this.formationController, IID_UnitAI);
     4350    var cmpFormation = Engine.QueryInterface(cmpUnitAI.entity, IID_Formation);
     4351    for each (var ent in cmpFormation.members)
     4352    {
     4353        var cmpUnitAI =  Engine.QueryInterface(ent, IID_UnitAI);
     4354        var targetfound = undefined;
     4355        var order = cmpUnitAI.orderQueue[0];
     4356        if(order && order.type == "Attack")
     4357            targetfound = order.data.target;
     4358        if (targetfound && this.TargetIsAlive(targetfound) && targetlist.indexOf(targetfound) == -1)
     4359            targetlist.push(targetfound);
     4360    }
     4361    if (targetlist.length == 0)
     4362        return false;
     4363    var ents = targetlist.filter(function (v, i, a) { return cmpAttack.CanAttack(v); })
     4364        .sort(function (a, b) { return cmpAttack.CompareEntitiesByPreference(a, b); })
     4365    if (this.AttackVisibleEntity(ents, true))
     4366        return true;
     4367    return false;
     4368};
     4369
     4370UnitAI.prototype.SendBackToFight = function()
     4371{
     4372    if (!this.HasFinishedOrder())
     4373        return;
     4374    if (this.GetTargetFromFormation())
     4375        this.finishedOrder = false;
     4376};
     4377
     4378UnitAI.prototype.FormationFindNewTargets = function()
     4379{
     4380    var targetlist = [];
     4381    var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation);
     4382    for each (var ent in cmpFormation.members)
     4383    {
     4384        var cmpUnitAI =  Engine.QueryInterface(ent, IID_UnitAI);
     4385        var targetfound = undefined;
     4386        if (cmpUnitAI.FindNewTargets())
     4387            targetfound = cmpUnitAI.orderQueue[0].data.target;
     4388        if (targetfound && targetlist.indexOf(targetfound) == -1)
     4389            targetlist.push(targetfound);
     4390    }
     4391    if (targetlist.length > 0)
     4392    {
     4393        // Reaffect units which have not already found a target
     4394        for each (var ent in cmpFormation.members)
     4395        {
     4396            var cmpUnitAI =  Engine.QueryInterface(ent, IID_UnitAI);
     4397            if (!cmpUnitAI.orderQueue[0] || cmpUnitAI.orderQueue[0].type != "Attack")
     4398                cmpUnitAI.AttackVisibleEntity(targetlist, true);
     4399        }
     4400        // We don't want to rearrange the formation if the individual units are attacking
     4401        cmpFormation.SetRearrange(false);
     4402        this.SetNextStateAlwaysEntering("MEMBER");
     4403    }
     4404    return (targetlist.length > 0);
     4405};
     4406
    43264407//// Animal specific functions ////
    43274408
    43284409UnitAI.prototype.MoveRandomly = function(distance)