Ticket #1716: formation-order-queues.patch
File formation-order-queues.patch, 10.7 KB (added by , 12 years ago) |
---|
-
binaries/data/mods/public/simulation/components/Formation.js
174 174 }; 175 175 176 176 /** 177 * Call obj.functname(args) on UnitAI components of all members, 178 * and return true if all calls return true. 179 */ 180 Formation.prototype.TestAllMemberFunction = function(funcname, args) 181 { 182 for each (var ent in this.members) 183 { 184 var cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI); 185 if (!cmpUnitAI[funcname].apply(cmpUnitAI, args)) 186 return false; 187 } 188 return true; 189 }; 190 191 /** 177 192 * Set all members to form up into the formation shape. 178 193 * If moveCenter is true, the formation center will be reinitialised 179 194 * to the center of the units. -
binaries/data/mods/public/simulation/components/UnitAI.js
512 512 }, 513 513 514 514 "Order.Attack": function(msg) { 515 // TODO: we should move in formation towards the target, 516 // then break up into individuals when close enough to it 515 // TODO on what should we base this range? 516 // Check if we are already in range, otherwise walk there 517 if (!this.CheckTargetRangeExplicit(msg.data.target, 0, 20)) 518 { 519 if (!this.TargetIsAlive(msg.data.target)) 520 // The target was destroyed 521 this.FinishOrder(); 522 else 523 // Out of range; move there in formation 524 this.PushOrderFront("WalkToTargetRange", { "target": msg.data.target, "min": 0, "max": 20 }); 525 return; 526 } 517 527 518 528 var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); 529 // We don't want to rearrange the formation if the individual units are carrying 530 // out a task and one of the members dies/leaves the formation. 531 cmpFormation.SetRearrange(false); 519 532 cmpFormation.CallMemberFunction("Attack", [msg.data.target, false]); 520 533 521 // TODO: we should wait until the target is killed, then 522 // move on to the next queued order. 523 // Don't bother now, just disband the formation immediately. 524 cmpFormation.Disband(); 534 this.SetNextStateAlwaysEntering("MEMBER"); 525 535 }, 526 536 527 537 "Order.Heal": function(msg) { 528 // TODO: see notes in Order.Attack 538 // TODO on what should we base this range? 539 // Check if we are already in range, otherwise walk there 540 if (!this.CheckTargetRangeExplicit(msg.data.target, 0, 10)) 541 { 542 if (!this.TargetIsAlive(msg.data.target)) 543 // The target was destroyed 544 this.FinishOrder(); 545 else 546 // Out of range; move there in formation 547 this.PushOrderFront("WalkToTargetRange", { "target": msg.data.target, "min": 0, "max": 10 }); 548 return; 549 } 550 529 551 var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); 552 // We don't want to rearrange the formation if the individual units are carrying 553 // out a task and one of the members dies/leaves the formation. 554 cmpFormation.SetRearrange(false); 530 555 cmpFormation.CallMemberFunction("Heal", [msg.data.target, false]); 531 cmpFormation.Disband(); 556 557 this.SetNextStateAlwaysEntering("MEMBER"); 532 558 }, 533 559 534 560 "Order.Repair": function(msg) { … … 551 577 cmpFormation.SetRearrange(false); 552 578 cmpFormation.CallMemberFunction("Repair", [msg.data.target, msg.data.autocontinue, false]); 553 579 554 this.SetNextState ("REPAIR");580 this.SetNextStateAlwaysEntering("REPAIR"); 555 581 }, 556 582 557 583 "Order.Gather": function(msg) { 558 // TODO: see notes in Order.Attack 584 // TODO on what should we base this range? 585 // Check if we are already in range, otherwise walk there 586 if (!this.CheckTargetRangeExplicit(msg.data.target, 0, 10)) 587 { 588 if (!this.CanGather(msg.data.target)) 589 // The target isn't gatherable 590 this.FinishOrder(); 591 // TODO should be a GatherNearPosition order. 592 // else if (!this.TargetIsAlive(msg.data.target)) 593 // gather near position 594 //cmpFormation.CallMemberFunction("GatherNearPosition", [msg.data.lastPos.x, msg.data.lastPos.z, msg.data.type, msg.data.template, false]); 595 else 596 // Out of range; move there in formation 597 this.PushOrderFront("WalkToTargetRange", { "target": msg.data.target, "min": 0, "max": 10 }); 598 return; 599 } 559 600 560 // If the resource no longer exists, send a GatherNearPosition order561 601 var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); 562 if (this.CanGather(msg.data.target))563 cmpFormation.CallMemberFunction("Gather", [msg.data.target, false]);564 else565 cmpFormation.CallMemberFunction("GatherNearPosition", [msg.data.lastPos.x, msg.data.lastPos.z, msg.data.type, msg.data.template, false]);602 // We don't want to rearrange the formation if the individual units are carrying 603 // out a task and one of the members dies/leaves the formation. 604 cmpFormation.SetRearrange(false); 605 cmpFormation.CallMemberFunction("Gather", [msg.data.target, false]); 566 606 567 cmpFormation.Disband();607 this.SetNextStateAlwaysEntering("MEMBER"); 568 608 }, 569 609 570 610 "Order.GatherNearPosition": function(msg) { 571 // TODO: see notes in Order.Attack 611 // TODO on what should we base this range? 612 // Check if we are already in range, otherwise walk there 613 if (!this.CheckTargetRangeExplicit(msg.data.target, 0, 20)) 614 { 615 if (!this.TargetIsAlive(msg.data.target)) 616 // The target was destroyed 617 this.FinishOrder(); 618 else 619 // Out of range; move there in formation 620 this.PushOrderFront("WalkToTargetRange", { "target": msg.data.target, "min": 0, "max": 20 }); 621 return; 622 } 623 572 624 var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); 625 // We don't want to rearrange the formation if the individual units are carrying 626 // out a task and one of the members dies/leaves the formation. 627 cmpFormation.SetRearrange(false); 573 628 cmpFormation.CallMemberFunction("GatherNearPosition", [msg.data.x, msg.data.z, msg.data.type, msg.data.template, false]); 574 cmpFormation.Disband(); 629 630 this.SetNextStateAlwaysEntering("MEMBER"); 575 631 }, 576 632 577 633 "Order.ReturnResource": function(msg) { 578 // TODO: see notes in Order.Attack 634 // TODO on what should we base this range? 635 // Check if we are already in range, otherwise walk there 636 if (!this.CheckTargetRangeExplicit(msg.data.target, 0, 10)) 637 { 638 if (!this.TargetIsAlive(msg.data.target)) 639 // The target was destroyed 640 this.FinishOrder(); 641 else 642 // Out of range; move there in formation 643 this.PushOrderFront("WalkToTargetRange", { "target": msg.data.target, "min": 0, "max": 10 }); 644 return; 645 } 646 579 647 var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); 648 // We don't want to rearrange the formation if the individual units are carrying 649 // out a task and one of the members dies/leaves the formation. 650 cmpFormation.SetRearrange(false); 580 651 cmpFormation.CallMemberFunction("ReturnResource", [msg.data.target, false]); 581 cmpFormation.Disband(); 652 653 this.SetNextStateAlwaysEntering("MEMBER"); 582 654 }, 583 655 584 656 "Order.Garrison": function(msg) { 585 // TODO: see notes in Order.Attack 657 // TODO on what should we base this range? 658 // Check if we are already in range, otherwise walk there 659 if (!this.CheckTargetRangeExplicit(msg.data.target, 0, 10)) 660 { 661 if (!this.TargetIsAlive(msg.data.target)) 662 // The target was destroyed 663 this.FinishOrder(); 664 else 665 // Out of range; move there in formation 666 this.PushOrderFront("WalkToTargetRange", { "target": msg.data.target, "min": 0, "max": 10 }); 667 return; 668 } 669 586 670 var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); 671 // We don't want to rearrange the formation if the individual units are carrying 672 // out a task and one of the members dies/leaves the formation. 673 cmpFormation.SetRearrange(false); 587 674 cmpFormation.CallMemberFunction("Garrison", [msg.data.target, false]); 588 cmpFormation.Disband(); 675 676 this.SetNextStateAlwaysEntering("MEMBER"); 589 677 }, 590 678 591 679 "IDLE": { … … 601 689 "MoveCompleted": function(msg) { 602 690 if (this.FinishOrder()) 603 691 return; 604 692 605 693 // If this was the last order, attempt to disband the formation. 606 694 var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); 607 695 cmpFormation.FindInPosition(); … … 620 708 cmpFormation.Disband(); 621 709 }, 622 710 }, 711 712 "MEMBER": { 713 // Wait for individual members to finish 714 "enter": function(msg) { 715 this.StartTimer(1000, 1000); 716 }, 717 718 "Timer": function(msg) { 719 var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); 720 721 // Have all members finished the task? 722 if (!cmpFormation.TestAllMemberFunction("HasFinishedOrder", [])) 723 return; 724 725 // Execute the next order 726 if (this.FinishOrder()) 727 return; 728 729 // No more order left. 730 cmpFormation.Disband(); 731 }, 732 733 "leave": function(msg) { 734 this.StopTimer(); 735 var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); 736 cmpFormation.CallMemberFunction("ResetFinishOrder", []); 737 }, 738 }, 623 739 }, 624 740 625 741 626 742 // States for entities moving as part of a formation: 627 743 "FORMATIONMEMBER": { 628 744 "FormationLeave": function(msg) { 745 // We're not in a formation anymore, so no need to track this. 746 this.finishedOrder = false; 747 629 748 // Stop moving as soon as the formation disbands 630 749 this.StopMoving(); 631 750 … … 1849 1968 this.isGarrisoned = false; 1850 1969 this.isIdle = false; 1851 1970 this.lastFormationName = ""; 1971 this.finishedOrder = false; // used to find if all formation members finished the order 1852 1972 1853 1973 // For preventing increased action rate due to Stop orders or target death. 1854 1974 this.lastAttacked = undefined; … … 1862 1982 return (this.template.FormationController == "true"); 1863 1983 }; 1864 1984 1985 UnitAI.prototype.IsFormationMember = function() 1986 { 1987 return (this.formationController != INVALID_ENTITY); 1988 }; 1989 1990 UnitAI.prototype.HasFinishedOrder = function() 1991 { 1992 return this.finishedOrder; 1993 }; 1994 1995 UnitAI.prototype.ResetFinishOrder = function() 1996 { 1997 this.finishedOrder = false; 1998 }; 1999 1865 2000 UnitAI.prototype.IsAnimal = function() 1866 2001 { 1867 2002 return (this.template.NaturalBehaviour ? true : false); … … 2149 2284 else 2150 2285 { 2151 2286 this.SetNextState("IDLE"); 2287 2288 // Check if there are queued formation orders 2289 if (this.IsFormationMember()) 2290 { 2291 var cmpUnitAI = Engine.QueryInterface(this.formationController, IID_UnitAI); 2292 if (cmpUnitAI) 2293 { 2294 // Inform the formation controller that we finished this task 2295 this.finishedOrder = true; 2296 // We don't want to carry out the default order 2297 // if there are still queued formation orders left 2298 if (cmpUnitAI.GetOrders().length > 1) 2299 return true; 2300 } 2301 } 2302 2152 2303 return false; 2153 2304 } 2154 2305 };