Ticket #1391: shipgarrison-v6.diff
File shipgarrison-v6.diff, 16.3 KB (added by , 11 years ago) |
---|
-
binaries/data/mods/public/simulation/templates/template_unit_mechanical_ship_quinquereme.xml
45 45 <List datatype="tokens">Support Infantry Cavalry Siege</List> 46 46 <BuffHeal>1</BuffHeal> 47 47 <LoadingRange>10</LoadingRange> 48 <Pickup>true</Pickup> 48 49 </GarrisonHolder> 49 50 <Health> 50 51 <Max>2000</Max> -
binaries/data/mods/public/simulation/templates/template_unit_mechanical_ship_bireme.xml
37 37 <List datatype="tokens">Support Infantry Cavalry</List> 38 38 <BuffHeal>1</BuffHeal> 39 39 <LoadingRange>10</LoadingRange> 40 <Pickup>true</Pickup> 40 41 </GarrisonHolder> 41 42 <Health> 42 43 <Max>800</Max> -
binaries/data/mods/public/simulation/templates/template_unit_mechanical_ship_trireme.xml
37 37 <List datatype="tokens">Support Infantry Cavalry Siege</List> 38 38 <BuffHeal>1</BuffHeal> 39 39 <LoadingRange>10</LoadingRange> 40 <Pickup>true</Pickup> 40 41 </GarrisonHolder> 41 42 <Health> 42 43 <Max>1400</Max> -
binaries/data/mods/public/simulation/templates/template_unit_mechanical_ship_fishing.xml
26 26 <List datatype="tokens">Support Infantry</List> 27 27 <BuffHeal>1</BuffHeal> 28 28 <LoadingRange>10</LoadingRange> 29 <Pickup>true</Pickup> 29 30 </GarrisonHolder> 30 31 <Identity> 31 32 <GenericName>Fishing Boat</GenericName> -
binaries/data/mods/public/simulation/templates/template_unit_mechanical_ship_merchant.xml
18 18 <List datatype="tokens">Support Infantry Cavalry</List> 19 19 <BuffHeal>1</BuffHeal> 20 20 <LoadingRange>10</LoadingRange> 21 <Pickup>true</Pickup> 21 22 </GarrisonHolder> 22 23 <Health> 23 24 <Max>400</Max> -
binaries/data/mods/public/simulation/components/GarrisonHolder.js
21 21 "</element>" + 22 22 "<element name='LoadingRange' a:help='The maximum distance from this holder at which entities are allowed to garrison. Should be about 2.0 for land entities and preferably greater for ships'>" + 23 23 "<ref name='nonNegativeDecimal'/>" + 24 "</element>"; 24 "</element>" + 25 "<optional>" + 26 "<element name='Pickup' a:help='This garrisonHolder will move to pick up units to be garrisoned'>" + 27 "<data type='boolean'/>" + 28 "</element>" + 29 "</optional>"; 25 30 26 31 /** 27 32 * Initialize GarrisonHolder Component … … 45 50 }; 46 51 47 52 /** 53 * Return true if this garrisonHolder can pickup ent 54 */ 55 GarrisonHolder.prototype.CanPickup = function(ent) 56 { 57 if (!this.template.Pickup || this.IsFull()) 58 return false; 59 var cmpOwner = Engine.QueryInterface(this.entity, IID_Ownership); 60 if (!cmpOwner) 61 return false; 62 var player = cmpOwner.GetOwner(); 63 return IsOwnedByPlayer(player, ent); 64 }; 65 66 67 /** 48 68 * Return the list of entities garrisoned inside 49 69 */ 50 70 GarrisonHolder.prototype.GetEntities = function() … … 71 91 }; 72 92 73 93 /** 94 * Return true if this garrisonHolder is full 95 */ 96 GarrisonHolder.prototype.IsFull = function() 97 { 98 return this.entities.length >= this.GetCapacity(); 99 }; 100 101 /** 74 102 * Get the heal rate with which garrisoned units will be healed 75 103 */ 76 104 GarrisonHolder.prototype.GetHealRate = function() -
binaries/data/mods/public/simulation/components/interfaces/UnitAI.js
11 11 // Message of the form { "to": orderData }. 12 12 // sent whenever the unit changes state 13 13 Engine.RegisterMessageType("UnitAIOrderDataChanged"); 14 15 // Message of the form { "entity": entity }, 16 // sent whenever a pickup is requested 17 Engine.RegisterMessageType("PickupRequested"); 18 19 // Message of the form { "entity": entity }, 20 // sent whenever a pickup is no more needed 21 Engine.RegisterMessageType("PickupCanceled"); -
binaries/data/mods/public/simulation/components/UnitAI.js
160 160 // ignore 161 161 }, 162 162 163 "PickupCanceled": function(msg) { 164 // ignore 165 }, 166 163 167 // Formation handlers: 164 168 165 169 "FormationLeave": function(msg) { … … 328 332 } 329 333 }, 330 334 335 "Order.PickupUnit": function(msg) { 336 var cmpGarrisonHolder = Engine.QueryInterface(this.entity, IID_GarrisonHolder); 337 if (!cmpGarrisonHolder || cmpGarrisonHolder.IsFull()) 338 { 339 this.FinishOrder(); 340 return; 341 } 342 343 // TODO improve these movements in case of ship : the MoveToTarget of the target brings 344 // it to the nearest point-on-land from the ship, while the MoveToTarget of the ship 345 // brings it to the nearest point-on-water from the target, and these can be quite 346 // different in some cases leading to weird movements. MoveToTarget should update its path 347 // according to the target movement more often. 348 if (this.MoveToTarget(this.order.data.target)) 349 { 350 this.SetNextState("INDIVIDUAL.PICKUP.APPROACHING"); 351 } 352 else 353 { 354 // We are already at the target, or can't move at all 355 this.StopMoving(); 356 this.SetNextState("INDIVIDUAL.PICKUP.LOADING"); 357 } 358 }, 359 331 360 "Order.Flee": function(msg) { 332 361 // We use the distance between the enities to account for ranged attacks 333 362 var distance = DistanceBetweenEntities(this.entity, this.order.data.target) + (+this.template.FleeDistance); … … 608 637 return; 609 638 } 610 639 611 if (this.MoveTo Target(this.order.data.target))640 if (this.MoveToGarrisonRange(this.order.data.target)) 612 641 { 613 642 this.SetNextState("INDIVIDUAL.GARRISON.APPROACHING"); 614 643 } … … 727 756 }, 728 757 729 758 "Order.Garrison": function(msg) { 730 // TODO: on what should we base this range? 759 if (!Engine.QueryInterface(msg.data.target, IID_GarrisonHolder)) 760 { 761 this.FinishOrder(); 762 return; 763 } 731 764 // Check if we are already in range, otherwise walk there 732 if (!this.Check TargetRangeExplicit(msg.data.target, 0, 10))765 if (!this.CheckGarrisonRange(msg.data.target)) 733 766 { 734 if (!this. TargetIsAlive(msg.data.target) || !this.CheckTargetVisible(msg.data.target))735 // The target was destroyed767 if (!this.CheckTargetVisible(msg.data.target)) 768 { 736 769 this.FinishOrder(); 770 return; 771 } 737 772 else 773 { 738 774 // Out of range; move there in formation 739 this.PushOrderFront("WalkToTargetRange", { "target": msg.data.target, "min": 0, "max": 10 }); 740 return; 775 if (this.MoveToGarrisonRange(msg.data.target)) 776 { 777 this.SetNextState("GARRISON.APPROACHING"); 778 return; 779 } 780 } 741 781 } 742 782 743 var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); 744 // We don't want to rearrange the formation if the individual units are carrying 745 // out a task and one of the members dies/leaves the formation. 746 cmpFormation.SetRearrange(false); 747 cmpFormation.CallMemberFunction("Garrison", [msg.data.target, false]); 748 749 this.SetNextStateAlwaysEntering("MEMBER"); 783 this.SetNextState("GARRISON.GARRISONING"); 750 784 }, 751 785 752 786 "Order.Gather": function(msg) { … … 977 1011 }, 978 1012 }, 979 1013 1014 "GARRISON":{ 1015 "enter": function() { 1016 // If the garrisonholder should pickup, warn it so it can take needed action 1017 var cmpGarrisonHolder = Engine.QueryInterface(this.order.data.target, IID_GarrisonHolder); 1018 if (cmpGarrisonHolder && cmpGarrisonHolder.CanPickup(this.entity)) 1019 { 1020 this.pickup = this.order.data.target; // temporary, deleted in "leave" 1021 Engine.PostMessage(this.pickup, MT_PickupRequested, { "entity": this.entity }); 1022 } 1023 }, 1024 1025 "leave": function() { 1026 // If a pickup has been requested and not yet canceled, cancel it 1027 if (this.pickup) 1028 { 1029 Engine.PostMessage(this.pickup, MT_PickupCanceled, { "entity": this.entity }); 1030 delete this.pickup; 1031 } 1032 }, 1033 1034 1035 "APPROACHING": { 1036 "MoveStarted": function(msg) { 1037 var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); 1038 cmpFormation.SetRearrange(true); 1039 cmpFormation.MoveMembersIntoFormation(true, true); 1040 }, 1041 1042 "MoveCompleted": function(msg) { 1043 this.SetNextState("GARRISONING"); 1044 }, 1045 }, 1046 1047 "GARRISONING": { 1048 "enter": function() { 1049 // If a pickup has been requested, cancel it as it will be requested by members 1050 if (this.pickup) 1051 { 1052 Engine.PostMessage(this.pickup, MT_PickupCanceled, { "entity": this.entity }); 1053 delete this.pickup; 1054 } 1055 var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); 1056 // We don't want to rearrange the formation if the individual units are carrying 1057 // out a task and one of the members dies/leaves the formation. 1058 cmpFormation.SetRearrange(false); 1059 cmpFormation.CallMemberFunction("Garrison", [this.order.data.target, false]); 1060 this.SetNextStateAlwaysEntering("MEMBER"); 1061 }, 1062 }, 1063 }, 1064 980 1065 "FORMING": { 981 1066 "MoveStarted": function(msg) { 982 1067 var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); … … 2257 2342 }, 2258 2343 2259 2344 "GARRISON": { 2345 "enter": function() { 2346 // If the garrisonholder should pickup, warn it so it can take needed action 2347 var cmpGarrisonHolder = Engine.QueryInterface(this.order.data.target, IID_GarrisonHolder); 2348 if (cmpGarrisonHolder && cmpGarrisonHolder.CanPickup(this.entity)) 2349 { 2350 this.pickup = this.order.data.target; // temporary, deleted in "leave" 2351 Engine.PostMessage(this.pickup, MT_PickupRequested, { "entity": this.entity }); 2352 } 2353 }, 2354 2355 "leave": function() { 2356 // If a pickup has been requested and not yet canceled, cancel it 2357 if (this.pickup) 2358 { 2359 Engine.PostMessage(this.pickup, MT_PickupCanceled, { "entity": this.entity }); 2360 delete this.pickup; 2361 } 2362 2363 }, 2364 2260 2365 "APPROACHING": { 2261 2366 "enter": function() { 2262 2367 this.SelectAnimation("move"); … … 2265 2370 "MoveCompleted": function() { 2266 2371 this.SetNextState("GARRISONED"); 2267 2372 }, 2268 2269 "leave": function() {2270 this.StopTimer();2271 }2272 2373 }, 2273 2374 2274 2375 "GARRISONED": { … … 2300 2401 this.SetGathererAnimationOverride(); 2301 2402 } 2302 2403 } 2404 2405 // If a pickup has been requested, remove it 2406 if (this.pickup) 2407 { 2408 Engine.PostMessage(this.pickup, MT_PickupCanceled, { "entity": this.entity }); 2409 delete this.pickup; 2410 } 2303 2411 2304 2412 return false; 2305 2413 } 2306 2414 } 2307 2415 else 2308 2416 { 2309 // Unable to reach the target, try again 2310 // (or follow if it's a moving target) 2417 // Unable to reach the target, try again (or follow if it is a moving target) 2418 // except if the garrisonholder should pickup does not exits anymore or its orders have changed 2419 if (this.pickup) 2420 { 2421 var cmpUnitAI = Engine.QueryInterface(this.pickup, IID_UnitAI); 2422 if (!cmpUnitAI || !cmpUnitAI.HasPickupOrder(this.entity)) 2423 { 2424 delete this.pickup; 2425 this.FinishOrder(); 2426 return true; 2427 } 2428 2429 } 2311 2430 if (this.MoveToTarget(target)) 2312 2431 { 2313 2432 this.SetNextState("APPROACHING"); … … 2327 2446 2328 2447 "leave": function() { 2329 2448 this.isGarrisoned = false; 2330 } 2449 }, 2331 2450 }, 2332 2451 }, 2333 2452 … … 2387 2506 // Ignore attacks while unpacking 2388 2507 }, 2389 2508 }, 2509 2510 "PICKUP": { 2511 "APPROACHING": { 2512 "enter": function() { 2513 this.SelectAnimation("move"); 2514 }, 2515 2516 "MoveCompleted": function() { 2517 this.SetNextState("LOADING"); 2518 }, 2519 2520 "PickupCanceled": function() { 2521 this.StopMoving(); 2522 this.FinishOrder(); 2523 }, 2524 }, 2525 2526 "LOADING": { 2527 "enter": function() { 2528 this.SelectAnimation("idle"); 2529 var cmpGarrisonHolder = Engine.QueryInterface(this.entity, IID_GarrisonHolder); 2530 if (!cmpGarrisonHolder || cmpGarrisonHolder.IsFull()) 2531 { 2532 this.FinishOrder(); 2533 return true; 2534 } 2535 return false; 2536 }, 2537 2538 "PickupCanceled": function() { 2539 this.FinishOrder(); 2540 }, 2541 }, 2542 }, 2390 2543 }, 2391 2544 2392 2545 "ANIMAL": { … … 2656 2809 this.SetupRangeQueries(); 2657 2810 }; 2658 2811 2812 UnitAI.prototype.HasPickupOrder = function(entity) 2813 { 2814 for each (var order in this.orderQueue) 2815 if (order.type == "PickupUnit" && order.data.target == entity) 2816 return true; 2817 return false; 2818 }; 2819 2820 UnitAI.prototype.OnPickupRequested = function(msg) 2821 { 2822 // First check if we already have such a request 2823 if (this.HasPickupOrder(msg.entity)) 2824 return; 2825 // Otherwise, insert the PickUp order after the last forced order 2826 this.PushOrderAfterForced("PickupUnit", { "target": msg.entity }); 2827 }; 2828 2829 UnitAI.prototype.OnPickupCanceled = function(msg) 2830 { 2831 var cmpUnitAI = Engine.QueryInterface(msg.entity, IID_UnitAI); 2832 for (var i = 0; i < this.orderQueue.length; ++i) 2833 { 2834 if (this.orderQueue[i].type == "PickupUnit" && this.orderQueue[i].data.target == msg.entity) 2835 { 2836 if (i == 0) 2837 UnitFsm.ProcessMessage(this, {"type": "PickupCanceled", "data": msg}); 2838 else 2839 this.orderQueue.splice(i, 1); 2840 break; 2841 } 2842 } 2843 }; 2844 2659 2845 // Wrapper function that sets up the normal, healer, and Gaia range queries. 2660 2846 UnitAI.prototype.SetupRangeQueries = function() 2661 2847 { … … 2921 3107 } 2922 3108 }; 2923 3109 3110 /** 3111 * Insert an order after the last forced order onto the queue 3112 * and after the other orders of the same type 3113 */ 3114 UnitAI.prototype.PushOrderAfterForced = function(type, data) 3115 { 3116 if (!this.order || ((!this.order.data || !this.order.data.force) && this.order.type != type)) 3117 { 3118 this.PushOrderFront(type, data); 3119 } 3120 else 3121 { 3122 for (var i = 1; i < this.orderQueue.length; ++i) 3123 { 3124 if (this.orderQueue[i].data && this.orderQueue[i].data.force) 3125 continue; 3126 if (this.orderQueue[i].type == type) 3127 continue; 3128 this.orderQueue.splice(i, 0, {"type": type, "data": data}); 3129 return; 3130 } 3131 this.PushOrder(type, data); 3132 } 3133 }; 3134 2924 3135 UnitAI.prototype.ReplaceOrder = function(type, data) 2925 3136 { 2926 3137 // Special cases of orders that shouldn't be replaced: … … 3406 3617 return cmpUnitMotion.MoveToTargetRange(target, min, max); 3407 3618 }; 3408 3619 3620 UnitAI.prototype.MoveToGarrisonRange = function(target) 3621 { 3622 if (!this.CheckTargetVisible(target)) 3623 return false; 3624 3625 var cmpGarrisonHolder = Engine.QueryInterface(target, IID_GarrisonHolder); 3626 if (!cmpGarrisonHolder) 3627 return false; 3628 var range = cmpGarrisonHolder.GetLoadingRange(); 3629 3630 var cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); 3631 return cmpUnitMotion.MoveToTargetRange(target, range.min, range.max); 3632 }; 3633 3409 3634 UnitAI.prototype.CheckPointRangeExplicit = function(x, z, min, max) 3410 3635 { 3411 3636 var cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); … … 3467 3692 UnitAI.prototype.CheckGarrisonRange = function(target) 3468 3693 { 3469 3694 var cmpGarrisonHolder = Engine.QueryInterface(target, IID_GarrisonHolder); 3695 if (!cmpGarrisonHolder) 3696 return false; 3470 3697 var range = cmpGarrisonHolder.GetLoadingRange(); 3471 3698 3472 3699 var cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);