Ticket #4098: 4098.2.diff
File 4098.2.diff, 21.1 KB (added by , 8 years ago) |
---|
-
binaries/data/mods/public/simulation/components/UnitAI.js
356 356 // Check if we need to move TODO implement a better way to know if we are on the shoreline 357 357 var needToMove = true; 358 358 var cmpPosition = Engine.QueryInterface(this.entity, IID_Position); 359 if (this.lastShorelinePosition && cmpPosition && (this.lastShorelinePosition.x == cmpPosition.GetPosition().x) 360 && (this.lastShorelinePosition.z == cmpPosition.GetPosition().z)) 359 if (this.lastShorelinePosition && cmpPosition && 360 this.lastShorelinePosition.x == cmpPosition.GetPosition().x && 361 this.lastShorelinePosition.z == cmpPosition.GetPosition().z) 361 362 { 362 363 // we were already on the shoreline, and have not moved since 363 364 if (DistanceBetweenEntities(this.entity, this.order.data.target) < 50) … … 1376 1377 1377 1378 "GuardedAttacked": function(msg) { 1378 1379 // do nothing if we have a forced order in queue before the guard order 1379 for ( vari = 0; i < this.orderQueue.length; ++i)1380 for (let i = 0; i < this.orderQueue.length; ++i) 1380 1381 { 1381 1382 if (this.orderQueue[i].type == "Guard") 1382 1383 break; … … 1831 1832 var animationName = "attack_" + this.order.data.attackType.toLowerCase(); 1832 1833 if (this.IsFormationMember()) 1833 1834 { 1834 varcmpFormation = Engine.QueryInterface(this.formationController, IID_Formation);1835 let cmpFormation = Engine.QueryInterface(this.formationController, IID_Formation); 1835 1836 if (cmpFormation) 1836 1837 animationName = cmpFormation.GetFormationAnimation(this.entity, animationName); 1837 1838 } … … 2054 2055 2055 2056 // Try to find another nearby target of the same specific type 2056 2057 // Also don't switch to a different type of huntable animal 2057 var nearby = this.FindNearbyResource(function (ent, type, template) { 2058 return ( 2059 ent != oldTarget 2060 && ((type.generic == "treasure" && oldType.generic == "treasure") 2061 || (type.specific == oldType.specific 2062 && (type.specific != "meat" || oldTemplate == template))) 2063 ); 2064 }, oldTarget); 2058 let nearby = this.FindNearbyResource((ent, type, template) => 2059 ent != oldTarget && 2060 (type.generic == "treasure" && oldType.generic == "treasure" || 2061 (type.specific == oldType.specific && 2062 (type.specific != "meat" || oldTemplate == template))), 2063 oldTarget); 2065 2064 if (nearby) 2066 2065 { 2067 2066 this.PerformGather(nearby, false, false); … … 2082 2081 else 2083 2082 { 2084 2083 // we're kind of stuck here. Return resource. 2085 varnearby = this.FindNearestDropsite(oldType.generic);2084 nearby = this.FindNearestDropsite(oldType.generic); 2086 2085 if (nearby) 2087 2086 { 2088 2087 this.PushOrderFront("ReturnResource", { "target": nearby, "force": false }); … … 2119 2118 2120 2119 // Try to find another nearby target of the same specific type 2121 2120 // Also don't switch to a different type of huntable animal 2122 var nearby = this.FindNearbyResource(function (ent, type, template) { 2123 return ( 2124 ent != oldTarget 2125 && ((type.generic == "treasure" && oldType.generic == "treasure") 2126 || (type.specific == oldType.specific 2127 && (type.specific != "meat" || oldTemplate == template))) 2128 ); 2129 }); 2121 let nearby = this.FindNearbyResource((ent, type, template) => 2122 ent != oldTarget && 2123 (type.generic == "treasure" && oldType.generic == "treasure" || 2124 (type.specific == oldType.specific && 2125 (type.specific != "meat" || oldTemplate == template)))); 2130 2126 if (nearby) 2131 2127 { 2132 2128 this.PerformGather(nearby, false, false); … … 2165 2161 2166 2162 // Try to find another nearby target of the same specific type 2167 2163 // Also don't switch to a different type of huntable animal 2168 var nearby = this.FindNearbyResource(function (ent, type, template) { 2169 return ( 2170 (type.generic == "treasure" && resourceType.generic == "treasure") 2171 || (type.specific == resourceType.specific 2172 && (type.specific != "meat" || resourceTemplate == template)) 2173 ); 2174 }); 2164 let nearby = this.FindNearbyResource((ent, type, template) => 2165 (type.generic == "treasure" && resourceType.generic == "treasure") || 2166 (type.specific == resourceType.specific && 2167 (type.specific != "meat" || resourceTemplate == template))); 2175 2168 2176 2169 // If there is a nearby resource start gathering 2177 2170 if (nearby) … … 2185 2178 return; 2186 2179 2187 2180 // Nothing better to do: go back to dropsite 2188 varnearby = this.FindNearestDropsite(resourceType.generic);2181 nearby = this.FindNearestDropsite(resourceType.generic); 2189 2182 if (nearby) 2190 2183 { 2191 2184 this.PushOrderFront("ReturnResource", { "target": nearby, "force": false }); … … 2288 2281 if (this.CheckTargetRange(this.gatheringTarget, IID_ResourceGatherer) && this.CanGather(this.gatheringTarget)) 2289 2282 { 2290 2283 // Gather the resources: 2284 let cmpResourceGatherer = Engine.QueryInterface(this.entity, IID_ResourceGatherer); 2291 2285 2292 var cmpResourceGatherer = Engine.QueryInterface(this.entity, IID_ResourceGatherer);2293 2294 2286 // Try to gather treasure 2295 2287 if (cmpResourceGatherer.TryInstantGather(this.gatheringTarget)) 2296 2288 return; … … 2307 2299 // return to the nearest dropsite 2308 2300 if (status.filled) 2309 2301 { 2310 varnearby = this.FindNearestDropsite(resourceType.generic);2302 let nearby = this.FindNearestDropsite(resourceType.generic); 2311 2303 if (nearby) 2312 2304 { 2313 2305 // (Keep this Gather order on the stack so we'll … … 2357 2349 2358 2350 // Give up on this order and try our next queued order 2359 2351 // but first check what is our next order and, if needed, insert a returnResource order 2360 varcmpResourceGatherer = Engine.QueryInterface(this.entity, IID_ResourceGatherer);2352 let cmpResourceGatherer = Engine.QueryInterface(this.entity, IID_ResourceGatherer); 2361 2353 if (cmpResourceGatherer.IsCarrying(resourceType.generic) && 2362 2354 this.orderQueue.length > 1 && this.orderQueue[1] !== "ReturnResource" && 2363 2355 (this.orderQueue[1].type !== "Gather" || this.orderQueue[1].data.type.generic !== resourceType.generic)) … … 2373 2365 2374 2366 // Try to find a new resource of the same specific type near our current position: 2375 2367 // Also don't switch to a different type of huntable animal 2376 var nearby = this.FindNearbyResource(function (ent, type, template) { 2377 return ( 2378 (type.generic == "treasure" && resourceType.generic == "treasure") 2379 || (type.specific == resourceType.specific 2380 && (type.specific != "meat" || resourceTemplate == template)) 2381 ); 2382 }); 2368 let nearby = this.FindNearbyResource((ent, type, template) => 2369 (type.generic == "treasure" && resourceType.generic == "treasure") || 2370 (type.specific == resourceType.specific && 2371 (type.specific != "meat" || resourceTemplate == template))); 2383 2372 if (nearby) 2384 2373 { 2385 2374 this.PerformGather(nearby, false, false); … … 2397 2386 // drop it off, and if not then we might as well head to the dropsite 2398 2387 // anyway because that's a nice enough place to congregate and idle 2399 2388 2400 varnearby = this.FindNearestDropsite(resourceType.generic);2389 nearby = this.FindNearestDropsite(resourceType.generic); 2401 2390 if (nearby) 2402 2391 { 2403 2392 this.PushOrderFront("ReturnResource", { "target": nearby, "force": false }); … … 2565 2554 // Dump any resources we can 2566 2555 var dropsiteTypes = cmpResourceDropsite.GetTypes(); 2567 2556 2568 varcmpResourceGatherer = Engine.QueryInterface(this.entity, IID_ResourceGatherer);2557 let cmpResourceGatherer = Engine.QueryInterface(this.entity, IID_ResourceGatherer); 2569 2558 cmpResourceGatherer.CommitResources(dropsiteTypes); 2570 2559 2571 2560 // Stop showing the carried resource animation. … … 2581 2570 // The dropsite was destroyed, or we couldn't reach it, or ownership changed 2582 2571 // Look for a new one. 2583 2572 2584 varcmpResourceGatherer = Engine.QueryInterface(this.entity, IID_ResourceGatherer);2573 let cmpResourceGatherer = Engine.QueryInterface(this.entity, IID_ResourceGatherer); 2585 2574 var genericType = cmpResourceGatherer.GetMainCarryingType(); 2586 2575 var nearby = this.FindNearestDropsite(genericType); 2587 2576 if (nearby) … … 2776 2765 // the build command should look for nearby resources to gather 2777 2766 if ((oldData.force || oldData.autoharvest) && this.CanReturnResource(msg.data.newentity, false)) 2778 2767 { 2779 varcmpResourceDropsite = Engine.QueryInterface(msg.data.newentity, IID_ResourceDropsite);2780 vartypes = cmpResourceDropsite.GetTypes();2768 cmpResourceDropsite = Engine.QueryInterface(msg.data.newentity, IID_ResourceDropsite); 2769 let types = cmpResourceDropsite.GetTypes(); 2781 2770 // TODO: Slightly undefined behavior here, we don't know what type of resource will be collected, 2782 2771 // may cause problems for AIs (especially hunting fast animals), but avoid ugly hacks to fix that! 2783 var nearby = this.FindNearbyResource(function (ent, type, template) { 2784 return (types.indexOf(type.generic) != -1); 2785 }); 2772 let nearby = this.FindNearbyResource((ent, type, template) => types.indexOf(type.generic) != -1); 2786 2773 if (nearby) 2787 2774 { 2788 2775 this.PerformGather(nearby, true, false); … … 2861 2848 "GARRISONED": { 2862 2849 "enter": function() { 2863 2850 // Target is not handled the same way with Alert and direct garrisoning 2864 if (this.order.data.target) 2865 var target = this.order.data.target; 2866 else 2851 let target = this.order.data.target; 2852 if (!target) 2867 2853 { 2868 2854 if (!this.alertGarrisoningTarget) 2869 2855 { … … 2871 2857 this.FinishOrder(); 2872 2858 return true; 2873 2859 } 2874 vartarget = this.alertGarrisoningTarget;2860 target = this.alertGarrisoningTarget; 2875 2861 } 2876 2862 2877 2863 // Check that we can garrison here … … 3243 3229 3244 3230 UnitAI.prototype.IsUnderAlert = function() 3245 3231 { 3246 return this.alertRaiser != undefined;3232 return this.alertRaiser !== undefined; 3247 3233 }; 3248 3234 3249 3235 UnitAI.prototype.ResetAlert = function() … … 3367 3353 { 3368 3354 // Switch to a virgin state to let states execute their leave handlers. 3369 3355 // except if garrisoned or cheering or (un)packing, in which case we only clear the order queue 3370 if (this.isGarrisoned || (this.orderQueue[0] && (this.orderQueue[0].type == "Cheering" 3371 ||this.orderQueue[0].type == "Pack" || this.orderQueue[0].type == "Unpack")))3356 if (this.isGarrisoned || (this.orderQueue[0] && (this.orderQueue[0].type == "Cheering" || 3357 this.orderQueue[0].type == "Pack" || this.orderQueue[0].type == "Unpack"))) 3372 3358 { 3373 3359 this.orderQueue.length = Math.min(this.orderQueue.length, 1); 3374 3360 Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); … … 3427 3413 { 3428 3414 if (this.orderQueue[i].type != "PickupUnit" || this.orderQueue[i].data.target != msg.entity) 3429 3415 continue; 3430 if (i == 0)3416 if (i === 0) 3431 3417 this.UnitFsm.ProcessMessage(this, {"type": "PickupCanceled", "data": msg}); 3432 3418 else 3433 3419 this.orderQueue.splice(i, 1); … … 3729 3715 // TODO: maybe a better way of doing this would be to use priority levels 3730 3716 if (this.order && this.order.type == "Cheering") 3731 3717 { 3732 varorder = { "type": type, "data": data };3718 let order = { "type": type, "data": data }; 3733 3719 var cheeringOrder = this.orderQueue.shift(); 3734 3720 this.orderQueue = [cheeringOrder, order]; 3735 3721 } 3736 3722 else if (this.IsPacking() && type != "CancelPack" && type != "CancelUnpack") 3737 3723 { 3738 varorder = { "type": type, "data": data };3724 let order = { "type": type, "data": data }; 3739 3725 var packingOrder = this.orderQueue.shift(); 3740 3726 this.orderQueue = [packingOrder, order]; 3741 3727 } … … 3792 3778 var cmpUnitAI = Engine.QueryInterface(this.formationController, IID_UnitAI); 3793 3779 if (cmpUnitAI) 3794 3780 { 3795 for ( vari = 0; i < cmpUnitAI.orderQueue.length; ++i)3781 for (let i = 0; i < cmpUnitAI.orderQueue.length; ++i) 3796 3782 { 3797 3783 if (isWorkType(cmpUnitAI.orderQueue[i].type)) 3798 3784 { … … 3804 3790 } 3805 3791 3806 3792 // If nothing found, take the unit orders 3807 for ( vari = 0; i < this.orderQueue.length; ++i)3793 for (let i = 0; i < this.orderQueue.length; ++i) 3808 3794 { 3809 3795 if (isWorkType(this.orderQueue[i].type)) 3810 3796 { … … 3816 3802 3817 3803 UnitAI.prototype.BackToWork = function() 3818 3804 { 3819 if ( this.workOrders.length == 0)3805 if (!this.workOrders.length) 3820 3806 return false; 3821 3807 3822 3808 // Clear the order queue considering special orders not to avoid … … 3998 3984 return true; 3999 3985 4000 3986 var cmpHealth = QueryMiragedInterface(ent, IID_Health); 4001 return cmpHealth && cmpHealth.GetHitpoints() != 0;3987 return cmpHealth && cmpHealth.GetHitpoints() !== 0; 4002 3988 }; 4003 3989 4004 3990 /** … … 4336 4322 var t = targetCmpPosition.GetPosition(); 4337 4323 // h is positive when I'm higher than the target 4338 4324 var h = s.y-t.y+range.elevationBonus; 4339 4325 let parabolicMaxRange = 0; 4340 4326 // No negative roots please 4341 if (h>-range.max/2) 4342 var parabolicMaxRange = Math.sqrt(range.max*range.max+2*range.max*h); 4343 else 4344 // return false? Or hope you come close enough? 4345 var parabolicMaxRange = 0; 4346 //return false; 4327 if (h > -range.max / 2) 4328 parabolicMaxRange = Math.sqrt(range.max * range.max + 2 * range.max * h); 4347 4329 4348 4330 // the parabole changes while walking, take something in the middle 4349 var guessedMaxRange = (range.max + parabolicMaxRange) /2;4331 var guessedMaxRange = (range.max + parabolicMaxRange) / 2; 4350 4332 4351 4333 var cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); 4352 4334 if (cmpUnitMotion.MoveToTargetRange(target, range.min, guessedMaxRange)) … … 4408 4390 if (this.IsFormationMember()) 4409 4391 { 4410 4392 var cmpFormationUnitAI = Engine.QueryInterface(this.formationController, IID_UnitAI); 4411 if (cmpFormationUnitAI && cmpFormationUnitAI.IsAttackingAsFormation() 4412 && cmpFormationUnitAI.order.data.target == target) 4393 if (cmpFormationUnitAI && cmpFormationUnitAI.IsAttackingAsFormation() && cmpFormationUnitAI.order.data.target == target) 4413 4394 return true; 4414 4395 } 4415 4396 … … 4588 4569 UnitAI.prototype.AttackEntityInZone = function(ents, forceResponse) 4589 4570 { 4590 4571 var target = ents.find(target => 4591 this.CanAttack(target, forceResponse) 4592 && this.CheckTargetDistanceFromHeldPosition(target, IID_Attack, this.GetBestAttackAgainst(target, true))4593 &&(this.GetStance().respondChaseBeyondVision || this.CheckTargetIsInVisionRange(target))4572 this.CanAttack(target, forceResponse) && 4573 this.CheckTargetDistanceFromHeldPosition(target, IID_Attack, this.GetBestAttackAgainst(target, true)) && 4574 (this.GetStance().respondChaseBeyondVision || this.CheckTargetIsInVisionRange(target)) 4594 4575 ); 4595 4576 if (!target) 4596 4577 return false; … … 5098 5079 5099 5080 // Remember the position of our target, if any, in case it disappears 5100 5081 // later and we want to head to its last known position 5101 var lastPos = undefined;5082 var lastPos; 5102 5083 var cmpPosition = Engine.QueryInterface(target, IID_Position); 5103 5084 if (cmpPosition && cmpPosition.IsInWorld()) 5104 5085 lastPos = cmpPosition.GetPosition(); … … 5225 5206 5226 5207 UnitAI.prototype.MoveToMarket = function(targetMarket) 5227 5208 { 5228 if (this.waypoints && this.waypoints.length > 1) 5229 { 5230 var point = this.waypoints.pop(); 5231 var ok = this.MoveToPoint(point.x, point.z); 5232 if (!ok) 5233 ok = this.MoveToMarket(targetMarket); 5234 } 5235 else 5236 { 5237 this.waypoints = undefined; 5238 var ok = this.MoveToTarget(targetMarket); 5239 } 5240 5241 return ok; 5209 if (this.waypoints && this.waypoints.length > 1) 5210 { 5211 var point = this.waypoints.pop(); 5212 return this.MoveToPoint(point.x, point.z) || this.MoveToMarket(targetMarket); 5213 } 5214 5215 this.waypoints = undefined; 5216 return this.MoveToTarget(targetMarket); 5242 5217 }; 5243 5218 5244 5219 UnitAI.prototype.PerformTradeAndMoveToNextMarket = function(currentMarket) … … 5427 5402 { 5428 5403 var cmpUnitAI; 5429 5404 var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); 5430 for each (var ent incmpFormation.members)5405 for (let ent of cmpFormation.members) 5431 5406 { 5432 5407 if (!(cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI))) 5433 5408 continue; 5434 vartargets = cmpUnitAI.GetTargetsFromUnit();5435 for ( var targof targets)5409 let targets = cmpUnitAI.GetTargetsFromUnit(); 5410 for (let target of targets) 5436 5411 { 5437 if (!cmpUnitAI.CanAttack(targ ))5412 if (!cmpUnitAI.CanAttack(target)) 5438 5413 continue; 5439 5414 if (this.order.data.targetClasses) 5440 5415 { 5441 var cmpIdentity = Engine.QueryInterface(targ, IID_Identity); 5442 var targetClasses = this.order.data.targetClasses; 5443 if (targetClasses.attack && cmpIdentity 5444 && !MatchesClassList(cmpIdentity.GetClassesList(), targetClasses.attack)) 5416 let cmpIdentity = Engine.QueryInterface(target, IID_Identity); 5417 let targetClasses = this.order.data.targetClasses; 5418 if (targetClasses.attack && cmpIdentity && !MatchesClassList(cmpIdentity.GetClassesList(), targetClasses.attack)) 5445 5419 continue; 5446 if (targetClasses.avoid && cmpIdentity 5447 && MatchesClassList(cmpIdentity.GetClassesList(), targetClasses.avoid)) 5420 if (targetClasses.avoid && cmpIdentity && MatchesClassList(cmpIdentity.GetClassesList(), targetClasses.avoid)) 5448 5421 continue; 5449 5422 // Only used by the AIs to prevent some choices of targets 5450 if (targetClasses.vetoEntities && targetClasses.vetoEntities[targ ])5423 if (targetClasses.vetoEntities && targetClasses.vetoEntities[target]) 5451 5424 continue; 5452 5425 } 5453 this.PushOrderFront("Attack", { "target": targ , "force": true, "allowCapture": true });5426 this.PushOrderFront("Attack", { "target": target, "force": true, "allowCapture": true }); 5454 5427 return true; 5455 5428 } 5456 5429 } … … 5458 5431 } 5459 5432 5460 5433 var targets = this.GetTargetsFromUnit(); 5461 for ( var targof targets)5434 for (let target of targets) 5462 5435 { 5463 if (!this.CanAttack(targ ))5436 if (!this.CanAttack(target)) 5464 5437 continue; 5465 5438 if (this.order.data.targetClasses) 5466 5439 { 5467 var cmpIdentity = Engine.QueryInterface(targ, IID_Identity); 5468 var targetClasses = this.order.data.targetClasses; 5469 if (cmpIdentity && targetClasses.attack 5470 && !MatchesClassList(cmpIdentity.GetClassesList(), targetClasses.attack)) 5440 let cmpIdentity = Engine.QueryInterface(target, IID_Identity); 5441 let targetClasses = this.order.data.targetClasses; 5442 if (cmpIdentity && targetClasses.attack && !MatchesClassList(cmpIdentity.GetClassesList(), targetClasses.attack)) 5471 5443 continue; 5472 if (cmpIdentity && targetClasses.avoid 5473 && MatchesClassList(cmpIdentity.GetClassesList(), targetClasses.avoid)) 5444 if (cmpIdentity && targetClasses.avoid && MatchesClassList(cmpIdentity.GetClassesList(), targetClasses.avoid)) 5474 5445 continue; 5475 5446 // Only used by the AIs to prevent some choices of targets 5476 if (targetClasses.vetoEntities && targetClasses.vetoEntities[targ ])5447 if (targetClasses.vetoEntities && targetClasses.vetoEntities[target]) 5477 5448 continue; 5478 5449 } 5479 this.PushOrderFront("Attack", { "target": targ , "force": true, "allowCapture": true });5450 this.PushOrderFront("Attack", { "target": target, "force": true, "allowCapture": true }); 5480 5451 return true; 5481 5452 } 5482 5453 … … 5533 5504 var ret = { "min": 0, "max": 0 }; 5534 5505 if (this.GetStance().respondStandGround) 5535 5506 { 5536 varcmpRanged = Engine.QueryInterface(this.entity, iid);5507 let cmpRanged = Engine.QueryInterface(this.entity, iid); 5537 5508 if (!cmpRanged) 5538 5509 return ret; 5539 varrange = iid !== IID_Attack ? cmpRanged.GetRange() : cmpRanged.GetFullAttackRange();5510 let range = iid !== IID_Attack ? cmpRanged.GetRange() : cmpRanged.GetFullAttackRange(); 5540 5511 ret.min = range.min; 5541 5512 ret.max = range.max; 5542 5513 } 5543 5514 else if (this.GetStance().respondChase) 5544 5515 { 5545 varcmpVision = Engine.QueryInterface(this.entity, IID_Vision);5516 let cmpVision = Engine.QueryInterface(this.entity, IID_Vision); 5546 5517 if (!cmpVision) 5547 5518 return ret; 5548 var range = cmpVision.GetRange(); 5549 ret.max = range; 5519 ret.max = cmpVision.GetRange(); 5550 5520 } 5551 5521 else if (this.GetStance().respondHoldGround) 5552 5522 { 5553 varcmpRanged = Engine.QueryInterface(this.entity, iid);5523 let cmpRanged = Engine.QueryInterface(this.entity, iid); 5554 5524 if (!cmpRanged) 5555 5525 return ret; 5556 varrange = iid !== IID_Attack ? cmpRanged.GetRange() : cmpRanged.GetFullAttackRange();5557 varcmpVision = Engine.QueryInterface(this.entity, IID_Vision);5526 let range = iid !== IID_Attack ? cmpRanged.GetRange() : cmpRanged.GetFullAttackRange(); 5527 let cmpVision = Engine.QueryInterface(this.entity, IID_Vision); 5558 5528 if (!cmpVision) 5559 5529 return ret; 5560 5530 var halfvision = cmpVision.GetRange() / 2; … … 5564 5534 // but as it is the default for healers we need to set it to something sane. 5565 5535 else if (iid === IID_Heal) 5566 5536 { 5567 varcmpVision = Engine.QueryInterface(this.entity, IID_Vision);5537 let cmpVision = Engine.QueryInterface(this.entity, IID_Vision); 5568 5538 if (!cmpVision) 5569 5539 return ret; 5570 var range = cmpVision.GetRange();5571 ret.max = range;5540 5541 ret.max = cmpVision.GetRange(); 5572 5542 } 5573 5543 return ret; 5574 5544 }; … … 5865 5835 UnitAI.prototype.IsAttackingAsFormation = function() 5866 5836 { 5867 5837 var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack); 5868 return cmpAttack && cmpAttack.CanAttackAsFormation() 5869 && this.GetCurrentState() == "FORMATIONCONTROLLER.COMBAT.ATTACKING"; 5838 return cmpAttack && cmpAttack.CanAttackAsFormation() && this.GetCurrentState() == "FORMATIONCONTROLLER.COMBAT.ATTACKING"; 5870 5839 }; 5871 5840 5872 5841 //// Animal specific functions ////