Ticket #1391: shipgarrison-v5.diff

File shipgarrison-v5.diff, 17.4 KB (added by mimo, 11 years ago)
  • binaries/data/mods/public/simulation/components/UnitAI.js

     
    160160        // ignore
    161161    },
    162162
     163    "PickupCanceled": function(msg) {
     164        // ignore
     165    },
     166
    163167    // Formation handlers:
    164168
    165169    "FormationLeave": function(msg) {
     
    328332        }
    329333    },
    330334
     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        if (this.MoveToTarget(this.order.data.target))
     344        {
     345            this.SetNextState("INDIVIDUAL.PICKUP.APPROACHING");
     346        }
     347        else
     348        {
     349        // We are already at the target, or can't move at all
     350            this.StopMoving();
     351            this.SetNextState("INDIVIDUAL.PICKUP.LOADING");
     352        }
     353    },
     354
    331355    "Order.Flee": function(msg) {
    332356        // We use the distance between the enities to account for ranged attacks
    333357        var distance = DistanceBetweenEntities(this.entity, this.order.data.target) + (+this.template.FleeDistance);
     
    597621            return;
    598622        }
    599623
    600         if (this.MoveToTarget(this.order.data.target))
     624        if (this.MoveToGarrisonRange(this.order.data.target))
    601625        {
    602626            this.SetNextState("INDIVIDUAL.GARRISON.APPROACHING");
    603627        }
     
    716740        },
    717741
    718742        "Order.Garrison": function(msg) {
    719             // TODO: on what should we base this range?
     743            if (!Engine.QueryInterface(msg.data.target, IID_GarrisonHolder))
     744            {
     745                this.FinishOrder();
     746                return;
     747            }
    720748            // Check if we are already in range, otherwise walk there
    721             if (!this.CheckTargetRangeExplicit(msg.data.target, 0, 10))
     749            if (!this.CheckGarrisonRange(msg.data.target))
    722750            {
    723                 if (!this.TargetIsAlive(msg.data.target) || !this.CheckTargetVisible(msg.data.target))
    724                     // The target was destroyed
     751                if (!this.CheckTargetVisible(msg.data.target))
     752                {
    725753                    this.FinishOrder();
     754                    return;
     755                }
    726756                else
     757                {
    727758                    // Out of range; move there in formation
    728                     this.PushOrderFront("WalkToTargetRange", { "target": msg.data.target, "min": 0, "max": 10 });
    729                 return;
     759                    if (this.MoveToGarrisonRange(msg.data.target))
     760                    {
     761                        this.SetNextState("GARRISON.APPROACHING");
     762                        return;
     763                    }
     764                }
    730765            }
    731766
    732             var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation);
    733             // We don't want to rearrange the formation if the individual units are carrying
    734             // out a task and one of the members dies/leaves the formation.
    735             cmpFormation.SetRearrange(false);
    736             cmpFormation.CallMemberFunction("Garrison", [msg.data.target, false]);
    737 
    738             this.SetNextStateAlwaysEntering("MEMBER");
     767            this.SetNextState("GARRISON.GARRISONING");
    739768        },
    740769
    741770        "Order.Gather": function(msg) {
     
    966995            },
    967996        },
    968997
     998        "GARRISON":{
     999            "enter": function() {
     1000                // If the garrisonholder should pickup, warn it so it can take needed action
     1001                var cmpGarrisonHolder = Engine.QueryInterface(this.order.data.target, IID_GarrisonHolder);
     1002                if (cmpGarrisonHolder && cmpGarrisonHolder.ShouldPickup())
     1003                {
     1004                    this.pickup = this.order.data.target;       // temporary, deleted in "leave"
     1005                    Engine.PostMessage(this.pickup, MT_PickupRequested, { "entity": this.entity });
     1006                }
     1007            },
     1008
     1009            "leave": function() {
     1010                // If a pickup has been requested and not yet canceled, cancel it
     1011                if (this.pickup)
     1012                {
     1013                    Engine.PostMessage(this.pickup, MT_PickupCanceled, { "entity": this.entity });
     1014                    delete this.pickup;
     1015                }
     1016            },
     1017
     1018
     1019            "APPROACHING": {
     1020                "MoveStarted": function(msg) {
     1021                    var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation);
     1022                    cmpFormation.SetRearrange(true);
     1023                    cmpFormation.MoveMembersIntoFormation(true, true);
     1024                },
     1025
     1026                "MoveCompleted": function(msg) {
     1027                    this.SetNextState("GARRISONING");
     1028                },
     1029            },
     1030
     1031            "GARRISONING": {
     1032                "enter": function() {
     1033                    // If a pickup has been requested, cancel it as it will be requested by members
     1034                    if (this.pickup)
     1035                    {
     1036                        Engine.PostMessage(this.pickup, MT_PickupCanceled, { "entity": this.entity });
     1037                        delete this.pickup;
     1038                    }
     1039                    var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation);
     1040                    // We don't want to rearrange the formation if the individual units are carrying
     1041                    // out a task and one of the members dies/leaves the formation.
     1042                    cmpFormation.SetRearrange(false);
     1043                    cmpFormation.CallMemberFunction("Garrison", [this.order.data.target, false]);
     1044                    this.SetNextStateAlwaysEntering("MEMBER");
     1045                },
     1046            },
     1047        },
     1048
    9691049        "FORMING": {
    9701050            "MoveStarted": function(msg) {
    9711051                var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation);
     
    21862266        },
    21872267
    21882268        "GARRISON": {
     2269            "enter": function() {
     2270                // If the garrisonholder should pickup, warn it so it can take needed action
     2271                var cmpGarrisonHolder = Engine.QueryInterface(this.order.data.target, IID_GarrisonHolder);
     2272                if (cmpGarrisonHolder && cmpGarrisonHolder.ShouldPickup())
     2273                {
     2274                    this.pickup = this.order.data.target;       // temporary, deleted in "leave"
     2275                    Engine.PostMessage(this.pickup, MT_PickupRequested, { "entity": this.entity });
     2276                }
     2277            },
     2278
     2279            "leave": function() {
     2280                // If a pickup has been requested and not yet canceled, cancel it
     2281                if (this.pickup)
     2282                {
     2283                    Engine.PostMessage(this.pickup, MT_PickupCanceled, { "entity": this.entity });
     2284                    delete this.pickup;
     2285                }
     2286
     2287                if (this.stationary)
     2288                    delete this.stationary;
     2289            },
     2290
    21892291            "APPROACHING": {
    21902292                "enter": function() {
    21912293                    this.SelectAnimation("move");
     
    21942296                "MoveCompleted": function() {
    21952297                    this.SetNextState("GARRISONED");
    21962298                },
    2197                
    2198                 "leave": function() {
    2199                     this.StopTimer();
    2200                 }
    22012299            },
    22022300
    22032301            "GARRISONED": {
     
    22292327                                        this.SetGathererAnimationOverride();
    22302328                                    }
    22312329                                }
     2330
     2331                                // If a pickup has been requested, remove it
     2332                                if (this.pickup)
     2333                                {
     2334                                    Engine.PostMessage(this.pickup, MT_PickupCanceled, { "entity": this.entity });
     2335                                    delete this.pickup;
     2336                                }
    22322337                               
    22332338                                return false;
    22342339                            }
    22352340                        }
    22362341                        else
    22372342                        {
    2238                             // Unable to reach the target, try again
    2239                             // (or follow if it's a moving target)
    2240                             if (this.MoveToTarget(target))
     2343                            // Unable to reach the target, we try again or follow it if it's a moving target
     2344 
     2345                            if (this.stationary && this.stationary.n > 10)
    22412346                            {
    2242                                 this.SetNextState("APPROACHING");
    2243                                 return false;
     2347                                // If we've been stationary in the last trials, we delay the following trials
     2348                                // and eventually stop trying (more trials if target can pickup and not full to leave it time to come))
     2349                                if (!cmpGarrisonHolder.ShouldPickup() || cmpGarrisonHolder.IsFull() || this.stationary.n > 100)
     2350                                {
     2351                                    this.FinishOrder();
     2352                                    return true;
     2353                                }
    22442354                            }
     2355
     2356                            var pos = Engine.QueryInterface(this.entity, IID_Position).GetPosition();
     2357                            if (!this.stationary || Math.abs(this.stationary.x-pos.x) > 0.00001 || Math.abs(this.stationary.z-pos.z) > 0.00001)
     2358                                this.stationary = { "x": pos.x, "z": pos.z, "n": 0};
     2359                            else
     2360                                this.stationary.n += 1;
     2361
     2362                            if (this.stationary.n < 5)
     2363                                this.StartTimer(0);
     2364                            else if (this.stationary.n < 10)
     2365                                this.StartTimer(200);
     2366                            else
     2367                                this.StartTimer(1000);
     2368
     2369                            return false;
    22452370                        }
    22462371                    }
    22472372                    // Garrisoning failed for some reason, so finish the order
    22482373                    this.FinishOrder();
    22492374                    return true;
    22502375                },
     2376
     2377                "Timer": function(msg) {
     2378                    if (this.MoveToGarrisonRange(this.order.data.target))
     2379                    {
     2380                        // If the target should pickup, warn it again from time to time (in case its orders were changed)
     2381                        if (this.pickup && this.stationary.n%5 == 0)
     2382                            Engine.PostMessage(this.pickup, MT_PickupRequested, { "entity": this.entity });
     2383                        this.SetNextState("APPROACHING");
     2384                    }
     2385                    else
     2386                    {
     2387                        this.FinishOrder();
     2388                    }
     2389                },
    22512390               
    22522391                "Order.Ungarrison": function() {
    22532392                    if (this.FinishOrder())
     
    22562395
    22572396                "leave": function() {
    22582397                    this.isGarrisoned = false;
    2259                 }
     2398                },
    22602399            },
    22612400        },
    22622401
     
    23162455                // Ignore attacks while unpacking
    23172456            },
    23182457        },
     2458
     2459        "PICKUP": {
     2460            "APPROACHING": {
     2461                "enter": function() {
     2462                    this.SelectAnimation("move");
     2463                },
     2464
     2465                "MoveCompleted": function() {
     2466                    this.SetNextState("LOADING");
     2467                },
     2468
     2469                "PickupCanceled": function() {
     2470                    this.StopMoving();
     2471                    this.FinishOrder();
     2472                },
     2473            },
     2474
     2475            "LOADING": {
     2476                "enter": function() {
     2477                    this.SelectAnimation("idle");
     2478                    var cmpGarrisonHolder = Engine.QueryInterface(this.entity, IID_GarrisonHolder);
     2479                    if (!cmpGarrisonHolder || cmpGarrisonHolder.IsFull())
     2480                    {
     2481                        this.FinishOrder();
     2482                        return true;
     2483                    }
     2484                    return false;
     2485                },
     2486
     2487                "PickupCanceled": function() {
     2488                    this.FinishOrder();
     2489                },
     2490            },
     2491        },
    23192492    },
    23202493
    23212494    "ANIMAL": {
     
    25852758        this.SetupRangeQueries();
    25862759};
    25872760
     2761UnitAI.prototype.OnPickupRequested = function(msg)
     2762{
     2763    var cmpGarrisonHolder = Engine.QueryInterface(this.entity, IID_GarrisonHolder);
     2764    if (cmpGarrisonHolder && !cmpGarrisonHolder.IsFull())
     2765    {
     2766        // First check if we already have such a requirement
     2767        for each (var order in this.orderQueue)
     2768        {
     2769            if (order.type == "PickupUnit" && order.data.target == msg.entity)
     2770                return;
     2771        }
     2772        // Insert the PickUp order after the last forced order
     2773        this.PushOrderAfterForced("PickupUnit", { "target": msg.entity });
     2774    }
     2775};
     2776
     2777UnitAI.prototype.OnPickupCanceled = function(msg)
     2778{
     2779    var cmpUnitAI = Engine.QueryInterface(msg.entity, IID_UnitAI);
     2780    for (var i = 0; i < this.orderQueue.length; ++i)
     2781    {
     2782        if (this.orderQueue[i].type == "PickupUnit" && this.orderQueue[i].data.target == msg.entity)
     2783        {
     2784            if (i == 0)
     2785                UnitFsm.ProcessMessage(this, {"type": "PickupCanceled", "data": msg});
     2786            else
     2787                this.orderQueue.splice(i, 1);
     2788            break;
     2789        }
     2790    }
     2791};
     2792
    25882793// Wrapper function that sets up the normal, healer, and Gaia range queries.
    25892794UnitAI.prototype.SetupRangeQueries = function()
    25902795{
     
    28503055    }
    28513056};
    28523057
     3058/**
     3059 * Insert an order after the last forced order onto the queue
     3060 * and after the other orders of the same type
     3061 */
     3062UnitAI.prototype.PushOrderAfterForced = function(type, data)
     3063{
     3064    if (!this.order || ((!this.order.data || !this.order.data.force) && this.order.type != type))
     3065    {
     3066        this.PushOrderFront(type, data);
     3067    }
     3068    else
     3069    {
     3070        for (var i = 1; i < this.orderQueue.length; ++i)
     3071        {
     3072            if (this.orderQueue[i].data && this.orderQueue[i].data.force)
     3073                continue;
     3074            if (this.orderQueue[i].type == type)
     3075                continue;
     3076            this.orderQueue.splice(i, 0, {"type": type, "data": data});
     3077            return;
     3078        }
     3079        this.PushOrder(type, data);
     3080    }
     3081};
     3082
    28533083UnitAI.prototype.ReplaceOrder = function(type, data)
    28543084{
    28553085    // Special cases of orders that shouldn't be replaced:
     
    32883518    return cmpUnitMotion.MoveToTargetRange(target, min, max);
    32893519};
    32903520
     3521UnitAI.prototype.MoveToGarrisonRange = function(target)
     3522{
     3523    if (!this.CheckTargetVisible(target))
     3524        return false;
     3525
     3526    var cmpGarrisonHolder = Engine.QueryInterface(target, IID_GarrisonHolder);
     3527    if (!cmpGarrisonHolder)
     3528        return false;
     3529    var range = cmpGarrisonHolder.GetLoadingRange();
     3530
     3531    var cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
     3532    return cmpUnitMotion.MoveToTargetRange(target, range.min, range.max);
     3533};
     3534
    32913535UnitAI.prototype.CheckPointRangeExplicit = function(x, z, min, max)
    32923536{
    32933537    var cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
     
    33123556UnitAI.prototype.CheckGarrisonRange = function(target)
    33133557{
    33143558    var cmpGarrisonHolder = Engine.QueryInterface(target, IID_GarrisonHolder);
     3559    if (!cmpGarrisonHolder)
     3560        return false;
    33153561    var range = cmpGarrisonHolder.GetLoadingRange();
    33163562
    33173563    var cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
  • binaries/data/mods/public/simulation/components/interfaces/UnitAI.js

     
    1111// Message of the form { "to": orderData }.
    1212// sent whenever the unit changes state
    1313Engine.RegisterMessageType("UnitAIOrderDataChanged");
     14
     15// Message of the form { "entity": entity },
     16// sent whenever a pickup is requested
     17Engine.RegisterMessageType("PickupRequested");
     18
     19// Message of the form { "entity": entity },
     20// sent whenever a pickup is no more needed
     21Engine.RegisterMessageType("PickupCanceled");
  • binaries/data/mods/public/simulation/components/GarrisonHolder.js

     
    1818    "</element>" +
    1919    "<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'>" +
    2020        "<ref name='nonNegativeDecimal'/>" +
    21     "</element>";
     21    "</element>" +
     22    "<optional>" +
     23        "<element name='Pickup' a:help='This garrisonHolder will move to pick up units to be garrisoned'>" +
     24            "<data type='boolean'/>" +
     25        "</element>" +
     26    "</optional>";
    2227
    2328/**
    2429 * Initialize GarrisonHolder Component
     
    4146};
    4247
    4348/**
     49 * Return true if this garrisonHolder should pickup units
     50 */
     51GarrisonHolder.prototype.ShouldPickup = function()
     52{
     53    return (this.template.Pickup || false);
     54};
     55
     56
     57/**
    4458 * Return the list of entities garrisoned inside
    4559 */
    4660GarrisonHolder.prototype.GetEntities = function()
     
    6781};
    6882
    6983/**
     84 * Return true if this garrisonHolder is full
     85 */
     86GarrisonHolder.prototype.IsFull = function()
     87{
     88    return this.entities.length >= this.GetCapacity();
     89};
     90
     91/**
    7092 * Get the heal rate with which garrisoned units will be healed
    7193 */
    7294GarrisonHolder.prototype.GetHealRate = function()
  • binaries/data/mods/public/simulation/templates/template_unit_mechanical_ship_fishing.xml

     
    2525    <List datatype="tokens">Support Infantry</List>
    2626    <BuffHeal>1</BuffHeal>
    2727    <LoadingRange>10</LoadingRange>
     28    <Pickup>true</Pickup>
    2829  </GarrisonHolder>
    2930  <Identity>
    3031    <GenericName>Fishing Boat</GenericName>
     
    4243      <treasure disable=""/>
    4344    </Rates>
    4445  </ResourceGatherer>
    45   <Sound>
    46     <SoundGroups>
    47       <order_walk>actor/ship/boat_move.xml</order_walk>
    48       <order_attack>actor/ship/boat_move.xml</order_attack>
    49     </SoundGroups>
    50   </Sound>
    5146  <UnitMotion>
    5247    <WalkSpeed>8.5</WalkSpeed>
    5348  </UnitMotion>
  • binaries/data/mods/public/simulation/templates/template_unit_mechanical_ship_bireme.xml

     
    3535    <List datatype="tokens">Support Infantry Cavalry</List>
    3636    <BuffHeal>1</BuffHeal>
    3737    <LoadingRange>10</LoadingRange>
     38    <Pickup>true</Pickup>
    3839  </GarrisonHolder>
    3940  <Health>
    4041    <Max>800</Max>
  • binaries/data/mods/public/simulation/templates/template_unit_mechanical_ship_quinquereme.xml

     
    3131    <List datatype="tokens">Support Infantry Cavalry Siege</List>
    3232    <BuffHeal>1</BuffHeal>
    3333    <LoadingRange>10</LoadingRange>
     34    <Pickup>true</Pickup>
    3435  </GarrisonHolder>
    3536  <Health>
    3637    <Max>2000</Max>
  • binaries/data/mods/public/simulation/templates/template_unit_mechanical_ship_merchant.xml

     
    1717    <List datatype="tokens">Support Infantry Cavalry</List>
    1818    <BuffHeal>1</BuffHeal>
    1919    <LoadingRange>10</LoadingRange>
     20    <Pickup>true</Pickup>
    2021  </GarrisonHolder>
    2122  <Health>
    2223    <Max>400</Max>
  • binaries/data/mods/public/simulation/templates/template_unit_mechanical_ship_trireme.xml

     
    3535    <List datatype="tokens">Support Infantry Cavalry Siege</List>
    3636    <BuffHeal>1</BuffHeal>
    3737    <LoadingRange>10</LoadingRange>
     38    <Pickup>true</Pickup>
    3839  </GarrisonHolder>
    3940  <Health>
    4041    <Max>1400</Max>