Ticket #1907: corral-v2.diff

File corral-v2.diff, 21.0 KB (added by mimo, 11 years ago)
  • binaries/data/mods/public/gui/session/selection_details.js

     
    159159        getGUIObjectByName("resourceCarryingText").caption = entState.resourceSupply.gatherers.length + " / " + entState.resourceSupply.maxGatherers + "    ";
    160160        getGUIObjectByName("resourceCarryingIcon").tooltip = "Current/max gatherers";
    161161    }
     162    // And for number of corraled animals
     163    else if (entState.corral)
     164    {
     165        getGUIObjectByName("resourceCarryingIcon").hidden = false;
     166        getGUIObjectByName("resourceCarryingText").hidden = false;
     167        getGUIObjectByName("resourceCarryingIcon").sprite = "stretched:session/portraits/gaia/fauna_sheep.png";
     168        getGUIObjectByName("resourceCarryingText").caption = entState.corral.entities.length + " / " + entState.corral.capacity + "    ";
     169        getGUIObjectByName("resourceCarryingIcon").tooltip = "Current/max corraled animals";
     170    }
    162171    else
    163172    {
    164173        getGUIObjectByName("resourceCarryingIcon").hidden = true;
  • binaries/data/mods/public/gui/session/input.js

     
    232232            if (targetState.garrisonHolder.entities.length >= targetState.garrisonHolder.capacity)
    233233                tooltip = "[color=\"orange\"]" + tooltip + "[/color]";
    234234        }
     235        if (targetState.corral)
     236        {
     237            data.command = "corral";
     238            data.target = target;
     239            cursor = "action-gather-milk";
     240            tooltip = "Current corraled: " + targetState.corral.entities.length
     241                + "/" + targetState.corral.capacity;
     242            if (targetState.corral.entities.length >= targetState.corral.capacity)
     243                tooltip = "[color=\"orange\"]" + tooltip + "[/color]";
     244        }
    235245        else if (targetState.resourceSupply)
    236246        {
    237247            var resourceType = targetState.resourceSupply.type;
     
    333343                }
    334344            }
    335345            break;
     346        case "corral":
     347            if (hasClass(entState, "Unit") && targetState.corral)
     348            {
     349                var tooltip = "Current corraled: " + targetState.corral.entities.length
     350                    + "/" + targetState.corral.capacity;
     351                if (targetState.corral.entities.length >= targetState.corral.capacity)
     352                    tooltip = "[color=\"orange\"]" + tooltip + "[/color]";
     353                return {"possible": Engine.GuiInterfaceCall("CanBeCorraled", {"entity": entState.id, "corral": target}), "tooltip": tooltip};
     354            }
     355            break;
    336356        case "setup-trade-route":
    337357            // If ground or sea trade possible
    338358            if (!targetState.foundation && ((entState.trader && hasClass(entState, "Organic") && (playerOwned || allyOwned) && hasClass(targetState, "Market")) ||
     
    499519    {
    500520        return {"type": "garrison", "cursor": "action-garrison", "tooltip": actionInfo.tooltip, "target": target};
    501521    }
     522    else if (Engine.HotkeyIsPressed("session.corral") && (actionInfo = getActionInfo("corral", target)).possible)
     523    {
     524        return {"type": "corral", "cursor": "action-gather-milk", "tooltip": actionInfo.tooltip, "target": target};
     525    }
    502526    else if (Engine.HotkeyIsPressed("session.attackmove") && getActionInfo("attack-move", target).possible)
    503527    {
    504528            return {"type": "attack-move", "cursor": "action-attack-move"};
     
    653677    return preferredEnts;
    654678}
    655679
     680// Removes any units with special orders (i.e. escort)
     681function getNoOrderEntities(ents)
     682{
     683    var noOrderEnts = [];
     684    for each (var ent in ents)
     685    {
     686        var entState = GetEntityState(ent);
     687        if (entState.unitAI.special)
     688            continue;
     689        noOrderEnts.push(ent);
     690    }
     691    return noOrderEnts;
     692}
     693
    656694// Removes any support units from the passed list of entities
    657695function getMilitaryEntities(ents)
    658696{
     
    750788                    }
    751789                }
    752790
     791                // By default, we do not want to select units with special orders
     792                if (!Engine.HotkeyIsPressed("selection.includeorder"))
     793                    ents = getNoOrderEntities(ents);
     794
    753795                // Remove the bandbox hover highlighting
    754796                g_Selection.setHighlightList([]);
    755797
     
    12061248
    12071249                    // TODO: Should we handle "control all units" here as well?
    12081250                    ents = Engine.PickSimilarFriendlyEntities(templateToMatch, showOffscreen, matchRank, false);
     1251
     1252                    // By default, we do not want to select units with special orders
     1253                    if (!Engine.HotkeyIsPressed("selection.includeorder"))
     1254                        ents = getNoOrderEntities(ents);
    12091255                }
    12101256                else
    12111257                {
     
    13811427        Engine.GuiInterfaceCall("PlaySound", { "name": "order_garrison", "entity": selection[0] });
    13821428        return true;
    13831429
     1430    case "corral":
     1431        Engine.PostNetworkCommand({"type": "corral", "entities": selection, "target": action.target, "queued": queued});
     1432//      Engine.GuiInterfaceCall("PlaySound", { "name": "order_garrison", "entity": selection[0] });
     1433        return true;
     1434
    13841435    case "set-rallypoint":
    13851436        var pos = undefined;
    13861437        // if there is a position set in the action then use this so that when setting a
  • binaries/data/mods/public/gui/session/session.xml

     
    988988                <object size="90 -2 126 34" name="attackAndArmorStats" type="image" sprite="stretched:session/icons/stances/defensive.png" tooltip="Attack and Armor" tooltip_style="sessionToolTip"/>
    989989
    990990                <!-- Resource carrying icon/counter -->
    991                 <!-- Used also for number of gatherers/builders -->
     991                <!-- Used also for number of gatherers/builders/corraled -->
    992992                <object size="100%-78 -2 100%-28 34" type="text" name="resourceCarryingText" style="CarryingTextRight"/>
    993993                <object size="100%-36 -2 100% 34" type="image" name="resourceCarryingIcon" tooltip_style="sessionToolTip"/>
    994994            </object>
  • binaries/data/mods/public/simulation/templates/gaia/fauna_sheep.xml

     
    1212    <Classes datatype="tokens">Domestic</Classes>
    1313    <Icon>gaia/fauna_sheep.png</Icon>
    1414  </Identity>
     15  <UnitAI>
     16    <CorralType>food</CorralType>
     17    <CorralRate>0.4</CorralRate>
     18  </UnitAI>
    1519  <Sound>
    1620    <SoundGroups>
    1721      <select>actor/fauna/animal/sheep.xml</select>
  • binaries/data/mods/public/simulation/templates/gaia/fauna_pig.xml

     
    55    <SpecificName>Pig</SpecificName>
    66    <Icon>gaia/fauna_pig.png</Icon>
    77  </Identity>
     8  <UnitAI>
     9    <CorralType>food</CorralType>
     10    <CorralRate>0.4</CorralRate>
     11  </UnitAI>
    812  <StatusBars>
    913    <HeightOffset>5.0</HeightOffset>
    1014  </StatusBars>
  • binaries/data/mods/public/simulation/templates/template_structure_resource_corral.xml

     
    1010    <Square width="12.0" depth="22.0"/>
    1111    <Height>5.0</Height>
    1212  </Footprint>
    13   <GarrisonHolder>
    14     <Max>10</Max>
    15     <EjectHealth>0.1</EjectHealth>
    16     <List datatype="tokens">Animal</List>
    17     <BuffHeal>1</BuffHeal>
    18     <LoadingRange>2</LoadingRange>
    19   </GarrisonHolder>
     13  <Corral>
     14    <MaxCapacity>10</MaxCapacity>
     15    <Range>6</Range>
     16  </Corral>
    2017  <Health>
    2118    <Max>500</Max>
    2219    <SpawnEntityOnDeath>rubble/rubble_2x4</SpawnEntityOnDeath>
  • binaries/data/mods/public/simulation/helpers/Commands.js

     
    319319        }
    320320        break;
    321321
     322    case "corral":
     323        GetFormationUnitAIs(entities, player).forEach(function(cmpUnitAI) {
     324            cmpUnitAI.SetCorraled(cmd.target, cmd.queued);
     325        });
     326        break;
     327
    322328    case "stop":
    323329        GetFormationUnitAIs(entities, player).forEach(function(cmpUnitAI) {
    324330            cmpUnitAI.Stop(cmd.queued);
  • binaries/data/mods/public/simulation/components/GuiInterface.js

     
    272272        };
    273273    }
    274274
     275    var cmpCorral = Engine.QueryInterface(ent, IID_Corral);
     276    if (cmpCorral)
     277    {
     278        ret.corral = {
     279            "entities": cmpCorral.GetEntities(),
     280            "capacity": cmpCorral.GetCapacity()
     281        };
     282    }
     283
    275284    var cmpResourceGatherer = Engine.QueryInterface(ent, IID_ResourceGatherer);
    276285    if (cmpResourceGatherer)
    277286    {
     
    318327        ret.unitAI = {
    319328            "state": cmpUnitAI.GetCurrentState(),
    320329            "orders": cmpUnitAI.GetOrders(),
     330            "special": undefined
    321331        };
     332        if (cmpUnitAI.corral)
     333            ret.unitAI.special = "corraled";
    322334        // Add some information needed for ungarrisoning
    323335        if (cmpUnitAI.isGarrisoned && ret.player)
    324336            ret.template = "p" + ret.player + "&" + ret.template;
     
    16701682    return cmpAttack.CanAttack(data.target);
    16711683};
    16721684
     1685GuiInterface.prototype.CanBeCorraled = function(player, data)
     1686{
     1687    var cmpCorral = Engine.QueryInterface(data.corral, IID_Corral);
     1688    if (!cmpCorral)
     1689        return false;
     1690
     1691    return cmpCorral.CanBeCorraled(data.entity);
     1692};
     1693
    16731694/*
    16741695 * Returns batch build time.
    16751696 */
     
    17541775    "GetTradingRouteGain": 1,
    17551776    "GetTradingDetails": 1,
    17561777    "CanAttack": 1,
     1778    "CanBeCorraled": 1,
    17571779    "GetBatchTime": 1,
    17581780
    17591781    "SetPathfinderDebugOverlay": 1,
  • binaries/data/mods/public/simulation/components/UnitAI.js

     
    4646                "<ref name='positiveDecimal'/>" +
    4747            "</element>"+
    4848        "</interleave>" +
     49    "</optional>" +
     50    "<optional>" +
     51        "<interleave>" +
     52            "<element name='CorralType' a:help='Production type when corraled'>" +
     53                "<choice>" +
     54                    "<value>food</value>" +
     55                    "<value>metal</value>" +
     56                "</choice>" +
     57            "</element>" +
     58            "<element name='CorralRate' a:help='Production rate per sec when corraled'>" +
     59                "<ref name='positiveDecimal'/>" +
     60            "</element>" +
     61        "</interleave>" +
    4962    "</optional>";
    5063
    5164// Unit stances.
     
    609622        }
    610623    },
    611624
     625    "Order.Corral": function(msg) {
     626        var cmpCorral = Engine.QueryInterface(msg.data.target, IID_Corral);
     627        if (!cmpCorral)
     628        {
     629            this.FinishOrder();
     630            return;
     631        }
     632
     633        var range = cmpCorral.GetRange();
     634        if (this.MoveToTargetRangeExplicit(this.order.data.target, 0, range))
     635        {
     636            this.SetNextState("ANIMAL.CORRAL.APPROACHING");
     637        }
     638        else
     639        {
     640            this.StopMoving();
     641            this.SetNextState("ANIMAL.CORRAL.CORRALED");
     642        }
     643    },
     644
    612645    "Order.Cheering": function(msg) {
    613646        this.SetNextState("INDIVIDUAL.CHEERING");
    614647    },
     
    894927            this.SetNextStateAlwaysEntering("MEMBER");
    895928        },
    896929
     930        "Order.Corral": function(msg) {
     931            var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation);
     932            cmpFormation.SetRearrange(false);
     933            cmpFormation.CallMemberFunction("SetCorraled", [msg.data.target, false]);
     934
     935            this.SetNextStateAlwaysEntering("MEMBER");
     936        },
     937
    897938        "IDLE": {
    898939        },
    899940
     
    23462387            this.SetNextState("FLEEING");
    23472388        },
    23482389
     2390
     2391        "Order.Corral": function(msg) {
     2392            var cmpCorral = Engine.QueryInterface(msg.data.target, IID_Corral);
     2393            if (!cmpCorral)
     2394            {
     2395                this.FinishOrder();
     2396                return;
     2397            }
     2398
     2399            var range = cmpCorral.GetRange();
     2400            if (this.MoveToTargetRangeExplicit(this.order.data.target, 0, range))
     2401            {
     2402                this.SetNextState("ANIMAL.CORRAL.APPROACHING");
     2403            }
     2404            else
     2405            {
     2406                this.StopMoving();
     2407                this.SetNextState("ANIMAL.CORRAL.CORRALED");
     2408            }
     2409        },
     2410
    23492411        "IDLE": {
    23502412            // (We need an IDLE state so that FinishOrder works)
    23512413
     
    23562418            },
    23572419        },
    23582420
     2421        'CORRAL': {
     2422            'APPROACHING': {
     2423                "MoveCompleted": function() {
     2424                    var cmpCorral = Engine.QueryInterface(this.order.data.target, IID_Corral);
     2425                    if (cmpCorral)
     2426                    {
     2427                        var range = cmpCorral.GetRange();
     2428                        var cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
     2429                        if (cmpUnitMotion.IsInTargetRange(this.order.data.target, 0, range))
     2430                        {
     2431                            this.SetNextState("ANIMAL.CORRAL.CORRALED");
     2432                            return;
     2433                        }                       
     2434                    }
     2435                    this.FinishOrder();
     2436                },
     2437            },
     2438
     2439            'CORRALED': {
     2440                "enter": function() {
     2441                    this.corral = this.order.data.target;
     2442                    var cmpCorral = Engine.QueryInterface(this.corral, IID_Corral);
     2443                    if (!cmpCorral || !cmpCorral.AddCorraled(this.entity))
     2444                    {
     2445                        this.SetNextState("ROAMING");
     2446                        return true;
     2447                    }
     2448                    this.SelectAnimation("feeding");
     2449                    return false;
     2450                },
     2451
     2452                "Order.UnsetCorraled": function() {
     2453                    this.FinishOrder();
     2454                },
     2455
     2456                "leave": function() {
     2457                    if (this.corral)
     2458                    {
     2459                        var cmpCorral = Engine.QueryInterface(this.corral, IID_Corral);
     2460                        if (cmpCorral)
     2461                            cmpCorral.RemoveCorraled(this.entity);
     2462                        delete this.corral;
     2463                    }
     2464                },
     2465            },
     2466        },
     2467
    23592468        "ROAMING": {
    23602469            "enter": function() {
    23612470                // Walk in a random direction
     
    36613770        case "ReturnResource":
    36623771        case "Repair":
    36633772        case "Garrison":
     3773        case "Corral":
    36643774            // Find the target unit's position
    36653775            var cmpTargetPosition = Engine.QueryInterface(order.data.target, IID_Position);
    36663776            if (!cmpTargetPosition || !cmpTargetPosition.IsInWorld())
     
    44014511
    44024512//// Animal specific functions ////
    44034513
     4514/**
     4515 * Adds setcorraled order to the queue, forced by the player.
     4516 */
     4517UnitAI.prototype.SetCorraled = function(target, queued)
     4518{
     4519    var cmpCorral = Engine.QueryInterface(target, IID_Corral);
     4520    if (!cmpCorral || !cmpCorral.CanBeCorraled(this.entity))
     4521    {
     4522        this.WalkToTarget(target, queued);
     4523        return;
     4524    }
     4525    this.AddOrder("Corral", { "target": target, "force": true }, queued);
     4526};
     4527
     4528/**
     4529 * Adds unsetcorraled order to the queue.
     4530 */
     4531UnitAI.prototype.UnsetCorraled = function()
     4532{
     4533    if (this.corral)
     4534        this.AddOrder("UnsetCorraled", null, false);
     4535};
     4536
     4537UnitAI.prototype.GetCorralRate = function()
     4538{
     4539    return +(this.template.CorralRate || 0);
     4540};
     4541
     4542UnitAI.prototype.GetCorralType = function()
     4543{
     4544    return (this.template.CorralType || null);
     4545};
     4546
    44044547UnitAI.prototype.MoveRandomly = function(distance)
    44054548{
    44064549    // We want to walk in a random direction, but avoid getting stuck
  • binaries/data/mods/public/simulation/components/interfaces/Corral.js

     
     1Engine.RegisterInterface("Corral");
     2
     3// Message of the form { },
     4// sent to the current entity whenever the corraled units change.
     5Engine.RegisterMessageType("CorraledUnitsChanged");
  • binaries/data/mods/public/simulation/components/Corral.js

     
     1function Corral() {}
     2
     3Corral.prototype.Schema =
     4    "<element name='MaxCapacity' a:help='Maximum number of corraled units'>" +
     5        "<ref name='nonNegativeDecimal'/>" +
     6    "</element>" +
     7    "<element name='Range' a:help='Range distance of corraled units'>" +
     8        "<ref name='nonNegativeDecimal'/>" +
     9    "</element>";
     10
     11Corral.prototype.Init = function()
     12{
     13    this.entities = [];
     14    this.increment = 1;
     15    this.timer = undefined;
     16};
     17
     18Corral.prototype.GetCapacity = function()
     19{
     20    return +this.template.MaxCapacity;
     21};
     22
     23Corral.prototype.GetEntities = function()
     24{
     25    return this.entities;
     26};
     27
     28Corral.prototype.GetRange = function()
     29{
     30    return +this.template.Range;
     31};
     32
     33/**
     34 * Returns true if the entity ent can be corraled inside,
     35 */
     36Corral.prototype.CanBeCorraled = function(ent)
     37{
     38    var cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI);
     39    if (!cmpUnitAI)
     40        return false;
     41    // Formation controllers should always respond to commands
     42    if (cmpUnitAI.IsFormationController())
     43        return true;
     44
     45    // The entity must have a corral type not null
     46    var entType = cmpUnitAI.GetCorralType();
     47    if (entType == null)
     48        return false;
     49    // And if there is already a corraled unit, it must have the same type
     50    var type = this.GetType();
     51    if (type != null && type != entType)
     52        return false;
     53    return true;
     54};
     55
     56Corral.prototype.AddCorraled = function(ent)
     57{
     58    if (this.entities.indexOf(ent) != -1 || this.entities.length >= this.GetCapacity())
     59        return false;
     60    this.entities.push(ent);
     61    Engine.PostMessage(this.entity, MT_CorraledUnitsChanged, {});
     62    return true;
     63};
     64
     65Corral.prototype.RemoveCorraled = function(ent)
     66{
     67    if (this.entities.indexOf(ent) == -1)
     68        return;
     69    this.entities.splice(this.entities.indexOf(ent), 1);
     70    Engine.PostMessage(this.entity, MT_CorraledUnitsChanged, {});
     71};
     72
     73Corral.prototype.GetRate = function()
     74{
     75    var rate = 0;
     76    for each (var ent in this.entities)
     77    {
     78        var cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI);
     79        rate += cmpUnitAI.GetCorralRate();
     80    }
     81    rate = ApplyTechModificationsToEntity("Corral/Rate", rate, this.entity);
     82    return rate;
     83}
     84
     85Corral.prototype.GetType = function()
     86{
     87    var type = null;
     88    if (this.entities.length > 0)
     89    {
     90        var cmpUnitAI = Engine.QueryInterface(this.entities[0], IID_UnitAI);
     91        type= cmpUnitAI.GetCorralType();
     92    }
     93    return type;
     94}
     95
     96/**
     97 * Called every second. Produce food (in corrals)
     98 */
     99Corral.prototype.Timeout = function(data)
     100{
     101    var type = this.GetType();
     102    var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
     103    if (type != null)
     104    {
     105        var cmpPlayer = QueryOwnerInterface(this.entity, IID_Player);
     106        cmpPlayer.AddResource(type, this.increment);
     107        var cmpStatisticsTracker = QueryOwnerInterface(this.entity, IID_StatisticsTracker);
     108        if (cmpStatisticsTracker)
     109            cmpStatisticsTracker.IncreaseResourceGatheredCounter(type, this.increment);
     110
     111        var rate = this.GetRate();
     112        this.increment = this.entities.length;
     113        this.timer = cmpTimer.SetTimeout(this.entity, IID_Corral, "Timeout", this.increment*1000/rate, {});
     114    }
     115    else
     116    {
     117        cmpTimer.CancelTimer(this.timer);
     118        this.timer = undefined;
     119    }
     120};
     121
     122
     123Corral.prototype.OnCorraledUnitsChanged = function(msg)
     124{
     125    if (this.entities.length > 0 && !this.timer)
     126    {
     127        var rate = this.GetRate();
     128        this.increment = this.entities.length;
     129        var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
     130        this.timer = cmpTimer.SetTimeout(this.entity, IID_Corral, "Timeout", this.increment*1000/rate, {});
     131    }
     132    else if (this.entities.length == 0 && this.timer)
     133    {
     134        var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
     135        cmpTimer.CancelTimer(this.timer);
     136        this.timer = undefined;
     137    }
     138};
     139
     140Corral.prototype.OnDestroy = function()
     141{
     142    if (this.timer)
     143    {
     144        var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
     145        cmpTimer.CancelTimer(this.timer);
     146    }
     147
     148    for (var i = this.entities.length; i > 0; --i)
     149    {
     150        var cmpUnitAI = Engine.QueryInterface(this.entities[i-1], IID_UnitAI);
     151        if (cmpUnitAI)
     152            cmpUnitAI.UnsetCorraled();
     153    }
     154};
     155
     156
     157Engine.RegisterComponentType(IID_Corral, "Corral", Corral);
  • binaries/data/config/default.cfg

     
    270270hotkey.session.attack = "Ctrl+Alt"          ; Modifier to force attack instead of another action
    271271hotkey.session.garrison = Ctrl              ; Modifier to garrison when clicking on building
    272272hotkey.session.attackmove = Ctrl            ; Modifier to attackmove when clicking on a point
     273hotkey.session.corral = Ctrl                ; Modifier to corral an animal
    273274hotkey.session.queue = Shift                ; Modifier to queue unit orders instead of replacing
    274275hotkey.session.batchtrain = Shift           ; Modifier to train units in batches
    275276hotkey.session.massbarter = Shift           ; Modifier to barter bunch of resources
     
    278279hotkey.session.deselectgroup = Ctrl         ; Modifier to deselect units when clicking group icon, instead of selecting
    279280hotkey.session.rotate.cw = RightBracket     ; Rotate building placement preview clockwise
    280281hotkey.session.rotate.ccw = LeftBracket     ; Rotate building placement preview anticlockwise
     282hotkey.selection.includeorder = F1          ; Include in selection the units with special orders
    281283hotkey.timewarp.fastforward = Space         ; If timewarp mode enabled, speed up the game
    282284hotkey.timewarp.rewind = Backspace          ; If timewarp mode enabled, go back to earlier point in the game
    283285