Ticket #1391: shipgarrison-v6.diff

File shipgarrison-v6.diff, 16.3 KB (added by mimo, 11 years ago)
  • binaries/data/mods/public/simulation/templates/template_unit_mechanical_ship_quinquereme.xml

     
    4545    <List datatype="tokens">Support Infantry Cavalry Siege</List>
    4646    <BuffHeal>1</BuffHeal>
    4747    <LoadingRange>10</LoadingRange>
     48    <Pickup>true</Pickup>
    4849  </GarrisonHolder>
    4950  <Health>
    5051    <Max>2000</Max>
  • binaries/data/mods/public/simulation/templates/template_unit_mechanical_ship_bireme.xml

     
    3737    <List datatype="tokens">Support Infantry Cavalry</List>
    3838    <BuffHeal>1</BuffHeal>
    3939    <LoadingRange>10</LoadingRange>
     40    <Pickup>true</Pickup>
    4041  </GarrisonHolder>
    4142  <Health>
    4243    <Max>800</Max>
  • binaries/data/mods/public/simulation/templates/template_unit_mechanical_ship_trireme.xml

     
    3737    <List datatype="tokens">Support Infantry Cavalry Siege</List>
    3838    <BuffHeal>1</BuffHeal>
    3939    <LoadingRange>10</LoadingRange>
     40    <Pickup>true</Pickup>
    4041  </GarrisonHolder>
    4142  <Health>
    4243    <Max>1400</Max>
  • binaries/data/mods/public/simulation/templates/template_unit_mechanical_ship_fishing.xml

     
    2626    <List datatype="tokens">Support Infantry</List>
    2727    <BuffHeal>1</BuffHeal>
    2828    <LoadingRange>10</LoadingRange>
     29    <Pickup>true</Pickup>
    2930  </GarrisonHolder>
    3031  <Identity>
    3132    <GenericName>Fishing Boat</GenericName>
  • binaries/data/mods/public/simulation/templates/template_unit_mechanical_ship_merchant.xml

     
    1818    <List datatype="tokens">Support Infantry Cavalry</List>
    1919    <BuffHeal>1</BuffHeal>
    2020    <LoadingRange>10</LoadingRange>
     21    <Pickup>true</Pickup>
    2122  </GarrisonHolder>
    2223  <Health>
    2324    <Max>400</Max>
  • binaries/data/mods/public/simulation/components/GarrisonHolder.js

     
    2121    "</element>" +
    2222    "<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'>" +
    2323        "<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>";
    2530
    2631/**
    2732 * Initialize GarrisonHolder Component
     
    4550};
    4651
    4752/**
     53 * Return true if this garrisonHolder can pickup ent
     54 */
     55GarrisonHolder.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/**
    4868 * Return the list of entities garrisoned inside
    4969 */
    5070GarrisonHolder.prototype.GetEntities = function()
     
    7191};
    7292
    7393/**
     94 * Return true if this garrisonHolder is full
     95 */
     96GarrisonHolder.prototype.IsFull = function()
     97{
     98    return this.entities.length >= this.GetCapacity();
     99};
     100
     101/**
    74102 * Get the heal rate with which garrisoned units will be healed
    75103 */
    76104GarrisonHolder.prototype.GetHealRate = function()
  • 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/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        // 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
    331360    "Order.Flee": function(msg) {
    332361        // We use the distance between the enities to account for ranged attacks
    333362        var distance = DistanceBetweenEntities(this.entity, this.order.data.target) + (+this.template.FleeDistance);
     
    608637            return;
    609638        }
    610639
    611         if (this.MoveToTarget(this.order.data.target))
     640        if (this.MoveToGarrisonRange(this.order.data.target))
    612641        {
    613642            this.SetNextState("INDIVIDUAL.GARRISON.APPROACHING");
    614643        }
     
    727756        },
    728757
    729758        "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            }
    731764            // Check if we are already in range, otherwise walk there
    732             if (!this.CheckTargetRangeExplicit(msg.data.target, 0, 10))
     765            if (!this.CheckGarrisonRange(msg.data.target))
    733766            {
    734                 if (!this.TargetIsAlive(msg.data.target) || !this.CheckTargetVisible(msg.data.target))
    735                     // The target was destroyed
     767                if (!this.CheckTargetVisible(msg.data.target))
     768                {
    736769                    this.FinishOrder();
     770                    return;
     771                }
    737772                else
     773                {
    738774                    // 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                }
    741781            }
    742782
    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");
    750784        },
    751785
    752786        "Order.Gather": function(msg) {
     
    9771011            },
    9781012        },
    9791013
     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
    9801065        "FORMING": {
    9811066            "MoveStarted": function(msg) {
    9821067                var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation);
     
    22572342        },
    22582343
    22592344        "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
    22602365            "APPROACHING": {
    22612366                "enter": function() {
    22622367                    this.SelectAnimation("move");
     
    22652370                "MoveCompleted": function() {
    22662371                    this.SetNextState("GARRISONED");
    22672372                },
    2268                
    2269                 "leave": function() {
    2270                     this.StopTimer();
    2271                 }
    22722373            },
    22732374
    22742375            "GARRISONED": {
     
    23002401                                        this.SetGathererAnimationOverride();
    23012402                                    }
    23022403                                }
     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                                }
    23032411                               
    23042412                                return false;
    23052413                            }
    23062414                        }
    23072415                        else
    23082416                        {
    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                            }
    23112430                            if (this.MoveToTarget(target))
    23122431                            {
    23132432                                this.SetNextState("APPROACHING");
     
    23272446
    23282447                "leave": function() {
    23292448                    this.isGarrisoned = false;
    2330                 }
     2449                },
    23312450            },
    23322451        },
    23332452
     
    23872506                // Ignore attacks while unpacking
    23882507            },
    23892508        },
     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        },
    23902543    },
    23912544
    23922545    "ANIMAL": {
     
    26562809        this.SetupRangeQueries();
    26572810};
    26582811
     2812UnitAI.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
     2820UnitAI.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
     2829UnitAI.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
    26592845// Wrapper function that sets up the normal, healer, and Gaia range queries.
    26602846UnitAI.prototype.SetupRangeQueries = function()
    26612847{
     
    29213107    }
    29223108};
    29233109
     3110/**
     3111 * Insert an order after the last forced order onto the queue
     3112 * and after the other orders of the same type
     3113 */
     3114UnitAI.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
    29243135UnitAI.prototype.ReplaceOrder = function(type, data)
    29253136{
    29263137    // Special cases of orders that shouldn't be replaced:
     
    34063617    return cmpUnitMotion.MoveToTargetRange(target, min, max);
    34073618};
    34083619
     3620UnitAI.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
    34093634UnitAI.prototype.CheckPointRangeExplicit = function(x, z, min, max)
    34103635{
    34113636    var cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
     
    34673692UnitAI.prototype.CheckGarrisonRange = function(target)
    34683693{
    34693694    var cmpGarrisonHolder = Engine.QueryInterface(target, IID_GarrisonHolder);
     3695    if (!cmpGarrisonHolder)
     3696        return false;
    34703697    var range = cmpGarrisonHolder.GetLoadingRange();
    34713698
    34723699    var cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);