Ticket #2706: UpgradeComponent.2.patch

File UpgradeComponent.2.patch, 45.0 KB (added by wraitii, 4 years ago)

Updated.

  • binaries/data/mods/public/art/textures/ui/session/icons/upgrade.png

    Cannot display: file marked as a binary type.
    svn:mime-type = application/octet-stream
  • binaries/data/mods/public/gui/session/input.js

    Property changes on: binaries/data/mods/public/art/textures/ui/session/icons/upgrade.png
    ___________________________________________________________________
    Added: svn:mime-type
    ## -0,0 +1 ##
    +application/octet-stream
    \ No newline at end of property
     
    16141614    });
    16151615}
    16161616
    1617 // Transform a wall to a gate
    1618 function transformWallToGate(template)
     1617// Upgrade an entity to another
     1618function upgradeEntity(Template)
    16191619{
    16201620    var selection = g_Selection.toList();
    16211621    Engine.PostNetworkCommand({
    1622         "type": "wall-to-gate",
    1623         "entities": selection.filter( function(e) { return getWallGateTemplate(e) == template } ),
    1624         "template": template,
     1622        "type": "upgrade",
     1623        "entities": selection,
     1624        "template": Template,
     1625        "queued": false
    16251626    });
    16261627}
    16271628
    1628 // Gets the gate form (if any) of a given long wall piece
    1629 function getWallGateTemplate(entity)
     1629// Cancel upgrading entities
     1630function cancelUpgradeEntity()
    16301631{
    1631     // TODO: find the gate template name in a better way
    1632     var entState = GetEntityState(entity);
    1633     var index;
    1634 
    1635     if (entState && !entState.foundation && hasClass(entState, "LongWall") && (index = entState.template.indexOf("long")) >= 0)
    1636         return entState.template.substr(0, index) + "gate";
    1637     return undefined;
     1632    var selection = g_Selection.toList();
     1633    Engine.PostNetworkCommand({
     1634        "type": "cancel-upgrade",
     1635        "entities": selection,
     1636        "queued": false
     1637    });
    16381638}
    16391639
    16401640// Set the camera to follow the given unit
  • binaries/data/mods/public/gui/session/selection_panels.js

     
    372372        for (var i in selection)
    373373        {
    374374            var state = GetEntityState(selection[i]);
    375             if (hasClass(state, "LongWall") && !state.gate && !longWallTypes[state.template])
     375            if (state.gate && !gates.length)
    376376            {
    377                 var gateTemplate = getWallGateTemplate(state.id);
    378                 if (gateTemplate)
    379                 {
    380                     var tooltipString = GetTemplateDataWithoutLocalization(state.template).gateConversionTooltip;
    381                     if (!tooltipString)
    382                     {
    383                         warn(state.template + " is supposed to be convertable to a gate, but it's missing the GateConversionTooltip in the Identity template");
    384                         tooltipString = "";
    385                     }
    386                     walls.push({
    387                         "tooltip": translate(tooltipString),
    388                         "template": gateTemplate,
    389                         "callback": function (item) { transformWallToGate(item.template); }
    390                     });
    391                 }
    392 
    393                 // We only need one entity per type.
    394                 longWallTypes[state.template] = true;
    395             }
    396             else if (state.gate && !gates.length)
    397             {
    398377                gates.push({
    399378                    "gate": state.gate,
    400379                    "tooltip": translate("Lock Gate"),
     
    424403    },
    425404    "setTooltip": function(data)
    426405    {
    427         var tooltip = data.item.tooltip;
    428         if (data.item.template)
    429         {
    430             data.template = GetTemplateData(data.item.template);
    431             data.wallCount = data.selection.reduce(function (count, ent) {
    432                     var state = GetEntityState(ent);
    433                     if (hasClass(state, "LongWall") && !state.gate)
    434                         count++;
    435                     return count;
    436                 }, 0);
    437 
    438             tooltip += "\n" + getEntityCostTooltip(data.template, data.wallCount);
    439 
    440 
    441             data.neededResources = Engine.GuiInterfaceCall("GetNeededResources", multiplyEntityCosts(data.template, data.wallCount));
    442             if (data.neededResources)
    443                 tooltip += getNeededResourcesTooltip(data.neededResources);
    444         }
    445         data.button.tooltip = tooltip;
     406        data.button.tooltip = data.item.tooltip;
    446407    },
    447408    "setGraphics": function(data)
    448409    {
    449         data.affordableMask.hidden == data.neededResources ? true : false;
    450410        var gateIcon;
    451411        if (data.item.gate)
    452412        {
    453             // If already a gate, show locking actions
     413            // Show locking actions
    454414            gateIcon = "icons/lock_" + GATE_ACTIONS[data.item.locked ? 0 : 1] + "ed.png";
    455415            if (data.item.gate.locked === undefined)
    456416                data.guiSelection.hidden = false
     
    457417            else
    458418                data.guiSelection.hidden = data.item.gate.locked != data.item.locked;
    459419        }
    460         else
    461         {
    462             // otherwise show gate upgrade icon
    463             var template = GetTemplateData(data.item.template);
    464             if (!template)
    465                 return;
    466             gateIcon = data.template.icon ? "portraits/" + data.template.icon : "icons/gate_closed.png";
    467             data.guiSelection.hidden = true;
    468         }
    469 
    470420        data.icon.sprite = "stretched:session/" + gateIcon;
    471421    },
    472422    "setPosition": function(data)
     
    541491    },
    542492};
    543493
     494// UPGRADE
     495g_SelectionPanels.Upgrade = {
     496    "getMaxNumberOfItems": function()
     497    {
     498        return 24 - getNumberOfRightPanelButtons();
     499    },
     500    "getItems": function(unitEntState, selection)
     501    {
     502        // Interface becomes complicated with multiple units and this is meant per-entity, so prevent it if the selection has multiple units.
     503        if (selection.length > 1)
     504            return false;
     505        var items = [];
     506
     507        if (!unitEntState.upgrade)
     508            return false;
     509       
     510        for each (var upgrade in unitEntState.upgrade.upgrades)
     511        {
     512            var item = {};
     513            item.entType = upgrade.entity;
     514            item.template = GetTemplateData(upgrade.entity);
     515            if (!item.template) // abort if no template
     516                return false;
     517
     518            item.icon = upgrade.icon;
     519            if (!item.icon)
     520                item.icon = "portraits/" + item.template.icon;
     521
     522            if (upgrade.requiredTechnology !== null)
     523            {
     524                item.requiredTechnology = upgrade.requiredTechnology;
     525                if (!item.requiredTechnology && item.template.requiredTechnology)
     526                    item.requiredTechnology = item.template.requiredTechnology
     527            }
     528            item.cost = upgrade.cost;
     529            item.time = upgrade.time;
     530
     531            if (unitEntState.upgrade.progress === undefined)
     532            {
     533                item.upgrading = UPGRADING_NOT_STARTED;
     534                item.tooltip = translate("Upgrade into a " + item.template.name.generic + (upgrade.tooltip? ".\n" + upgrade.tooltip : "."));
     535                item.callback = function(data) { upgradeEntity(data.entType); };
     536            }
     537            else if (unitEntState.upgrade.template !== upgrade.entity)
     538            {
     539                item.upgrading = UPGRADING_CHOSEN_OTHER;
     540                item.tooltip = translate("Cannot upgrade when the entity is already upgrading.");
     541                item.callback = function(data) { };
     542            }
     543            else
     544            {
     545                item.upgrading = unitEntState.upgrade.progress;
     546                item.tooltip = translate("Cancel Upgrading");
     547                item.callback = function(data) { cancelUpgradeEntity(); };
     548            }
     549            items.push(item);
     550        }
     551        return items;
     552    },
     553    "addData" : function(data)
     554    {
     555        data.item.technologyEnabled = true;
     556        if (data.item.requiredTechnology)
     557            data.item.technologyEnabled = Engine.GuiInterfaceCall("IsTechnologyResearched", data.item.requiredTechnology);
     558        if (data.item.cost)
     559        {
     560            var totalCost = {};
     561            for (var i in data.item.cost)
     562                totalCost[i] = data.item.cost[i];
     563            data.item.neededResources = Engine.GuiInterfaceCall("GetNeededResources", totalCost);
     564        }
     565        data.item.limits = getEntityLimitAndCount(data.playerState, data.item.entType);
     566        return true;
     567    },
     568    "setAction": function(data)
     569    {
     570        data.button.onPress = function() { data.item.callback(data.item); };
     571    },
     572    "setTooltip": function(data)
     573    {
     574        var tooltip = data.item.tooltip;
     575
     576        if (data.item.upgrading !== UPGRADING_NOT_STARTED)
     577        {
     578            data.button.tooltip = tooltip;
     579            return;
     580        }
     581
     582        if (data.item.cost)
     583            tooltip += "\n" + getEntityCostTooltip(data.item);
     584       
     585        tooltip += formatLimitString(data.item.limits.entLimit, data.item.limits.entCount, data.item.limits.entLimitChangers);
     586        if (!data.item.technologyEnabled)
     587        {
     588            var techName = getEntityNames(GetTechnologyData(data.item.requiredTechnology));
     589            tooltip += "\n" + sprintf(translate("Requires %(technology)s"), { technology: techName });
     590        }
     591        if (data.item.neededResources)
     592            tooltip += getNeededResourcesTooltip(data.item.neededResources);
     593
     594        data.button.tooltip = tooltip;
     595    },
     596    "setGraphics": function(data)
     597    {
     598        var grayscale = "";
     599        if (data.item.upgrading == UPGRADING_CHOSEN_OTHER || !data.item.technologyEnabled || (data.item.limits.canBeAddedCount == 0 && data.item.upgrading == UPGRADING_NOT_STARTED))
     600        {
     601            data.button.enabled = false;
     602            grayscale = "grayscale:";
     603            data.affordableMask.hidden = false;
     604            data.affordableMask.sprite = "colour: 0 0 0 127";
     605        }
     606        else if (data.item.upgrading == UPGRADING_NOT_STARTED && data.item.neededResources)
     607        {
     608            data.button.enabled = false;
     609            data.affordableMask.hidden = false;
     610            data.affordableMask.sprite = resourcesToAlphaMask(data.item.neededResources);
     611        }
     612       
     613        data.icon.sprite = "stretched:" + grayscale + "session/" + data.item.icon;
     614
     615        var guiObject = Engine.GetGUIObjectByName("unitUpgradeProgressSlider["+data.i+"]");
     616        var size = guiObject.size;
     617        if (data.item.upgrading < 0)
     618            size.top = size.right;
     619        else
     620            size.top = size.left + Math.round(Math.max(0,data.item.upgrading) * (size.right - size.left));
     621        guiObject.size = size;
     622    },
     623    "setPosition": function(data)
     624    {
     625        var index = data.i + getNumberOfRightPanelButtons();
     626        setPanelObjectPosition(data.button, index, data.rowLength);
     627    },
     628};
     629
    544630// QUEUE
    545631g_SelectionPanels.Queue = {
    546632    "getMaxNumberOfItems": function()
     
    10151101    // RIGHT PANE
    10161102    "Gate", // must always be shown on gates
    10171103    "Pack", // must always be shown on packable entities
     1104    "Upgrade", // must always be shown on upgradable entities
    10181105    "Training",
    10191106    "Construction",
    10201107    "Research", // normal together with training
  • binaries/data/mods/public/gui/session/selection_panels_helpers.js

     
    88// Gate constants
    99const GATE_ACTIONS = ["lock", "unlock"];
    1010
     11// upgrade constants
     12const UPGRADING_NOT_STARTED = -2;
     13const UPGRADING_CHOSEN_OTHER = -1;
     14
    1115// ==============================================
    1216// BARTER HELPERS
    1317// Resources to sell on barter panel
  • binaries/data/mods/public/gui/session/unit_commands.js

     
    11// The number of currently visible buttons (used to optimise showing/hiding)
    2 var g_unitPanelButtons = {"Selection": 0, "Queue": 0, "Formation": 0, "Garrison": 0, "Training": 0, "Research": 0, "Barter": 0, "Construction": 0, "Command": 0, "Stance": 0, "Gate": 0, "Pack": 0};
     2var g_unitPanelButtons = {"Selection": 0, "Queue": 0, "Formation": 0, "Garrison": 0, "Training": 0, "Research": 0, "Barter": 0, "Construction": 0, "Command": 0, "Stance": 0, "Gate": 0, "Pack": 0, "Upgrade": 0};
    33
    44/**
    55 * Set the position of a panel object according to the index,
     
    289289        sum += g_unitPanelButtons["Pack"];
    290290    if (g_SelectionPanels["Gate"].used)
    291291        sum += g_unitPanelButtons["Gate"];
     292    if (g_SelectionPanels["Upgrade"].used)
     293        sum += g_unitPanelButtons["Upgrade"];
    292294    return sum;
    293295}
  • binaries/data/mods/public/gui/session/selection_panels_right/gate_panel.xml

     
    77        <object name="unitGateButton[n]" hidden="true" style="iconButton" type="button" size="0 0 46 46" tooltip_style="sessionToolTipBottom">
    88        <object name="unitGateIcon[n]" type="image" ghost="true" size="3 3 43 43"/>
    99        <object name="unitGateSelection[n]" hidden="true" type="image" ghost="true" size="3 3 43 43" sprite="stretched:session/icons/corners.png"/>
    10         <object name="unitGateUnaffordable[n]" hidden="true" type="image" ghost="true" size="3 3 43 43" sprite="colour: 255 0 0 127"/>
    1110        </object>
    1211    </repeat>
    1312    </object>
  • binaries/data/mods/public/gui/session/selection_panels_right/upgrade_panel.xml

     
     1<?xml version="1.0" encoding="utf-8"?>
     2<object name="unitUpgradePanel"
     3    size="10 12 100% 100%"
     4>
     5    <object size="0 0 100% 100%">
     6    <repeat count="8">
     7        <object name="unitUpgradeButton[n]" hidden="true" style="iconButton" type="button" size="0 0 46 46" tooltip_style="sessionToolTipBottom">
     8        <object name="unitUpgradeIcon[n]" type="image" ghost="true" size="3 3 43 43"/>
     9        <object name="unitUpgradeUpgradeIcon[n]" type="image" ghost="true" size="3 3 43 43" sprite="stretched:session/icons/upgrade.png"/>
     10        <object name="unitUpgradeProgressSlider[n]" type="image" sprite="queueProgressSlider" ghost="true" size="3 3 43 43" z="20"/>
     11        <object name="unitUpgradeSelection[n]" hidden="true" type="image" ghost="true" size="3 3 43 43" sprite="stretched:session/icons/corners.png"/>
     12        <object name="unitUpgradeUnaffordable[n]" hidden="true" type="image" ghost="true" size="3 3 43 43" sprite="colour: 255 0 0 127"/>
     13        </object>
     14    </repeat>
     15    </object>
     16</object>
  • binaries/data/mods/public/simulation/components/GuiInterface.js

    Property changes on: binaries/data/mods/public/gui/session/selection_panels_right/upgrade_panel.xml
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
     
    180180        "gate": null,
    181181        "guard": null,
    182182        "pack": null,
     183        "upgrade" : null,
    183184        "player": -1,
    184185        "position": null,
    185186        "production": null,
     
    232233        };
    233234    }
    234235
     236    var cmpUpgrade = Engine.QueryInterface(ent, IID_Upgrade);
     237    if (cmpUpgrade)
     238    {
     239        ret.upgrade = {
     240            "upgrades" : cmpUpgrade.GetUpgrades(),
     241            "progress": cmpUpgrade.GetProgress(),
     242            "template": cmpUpgrade.GetUpgradingTo()
     243        };
     244    }
     245
    235246    var cmpProductionQueue = Engine.QueryInterface(ent, IID_ProductionQueue);
    236247    if (cmpProductionQueue)
    237248    {
     
    653664        };
    654665        ret.icon = template.Identity.Icon;
    655666        ret.tooltip =  template.Identity.Tooltip;
    656         ret.gateConversionTooltip =  template.Identity.GateConversionTooltip;
    657667        ret.requiredTechnology = template.Identity.RequiredTechnology;
    658668        ret.visibleIdentityClasses = GetVisibleIdentityClasses(template.Identity);
    659669    }
  • binaries/data/mods/public/simulation/components/Identity.js

     
    3030        "</element>" +
    3131    "</optional>" +
    3232    "<optional>" +
    33         "<element name='GateConversionTooltip'>" +
    34             "<text/>" +
    35         "</element>" +
    36     "</optional>" +
    37     "<optional>" +
    3833        "<element name='Rollover'>" +
    3934            "<text/>" +
    4035        "</element>" +
  • binaries/data/mods/public/simulation/components/Pack.js

     
    116116
    117117Pack.prototype.PackProgress = function(data, lateness)
    118118{
    119     if (this.elapsedTime >= this.GetPackTime())
     119    if (this.elapsedTime < this.GetPackTime())
    120120    {
    121         this.CancelTimer();
     121        this.SetElapsedTime(this.GetElapsedTime() + PACKING_INTERVAL + lateness);
     122        return;
     123    }
    122124
    123         this.packed = !this.packed;
    124         Engine.PostMessage(this.entity, MT_PackFinished, { packed: this.packed });
     125    this.CancelTimer();
    125126
    126         // Done un/packing, copy our parameters to the final entity
    127         var newEntity = Engine.AddEntity(this.template.Entity);
    128         if (newEntity == INVALID_ENTITY)
    129         {
    130             // Error (e.g. invalid template names)
    131             error("PackProgress: Error creating entity for '" + this.template.Entity + "'");
    132             return;
    133         }
     127    this.packed = !this.packed;
     128    Engine.PostMessage(this.entity, MT_PackFinished, { packed: this.packed });
    134129
    135         var cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
    136         var cmpNewPosition = Engine.QueryInterface(newEntity, IID_Position);
    137         if (cmpPosition.IsInWorld())
    138         {
    139             var pos = cmpPosition.GetPosition2D();
    140             cmpNewPosition.JumpTo(pos.x, pos.y);
    141         }
    142         var rot = cmpPosition.GetRotation();
    143         cmpNewPosition.SetYRotation(rot.y);
    144         cmpNewPosition.SetXZRotation(rot.x, rot.z);
    145         cmpNewPosition.SetHeightOffset(cmpPosition.GetHeightOffset());
     130    var newEntity = ChangeEntityTemplate(this.entity, this.template.Entity);
    146131
    147         var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
    148         var cmpNewOwnership = Engine.QueryInterface(newEntity, IID_Ownership);
    149         cmpNewOwnership.SetOwner(cmpOwnership.GetOwner());
    150 
    151         // Maintain current health level
    152         var cmpHealth = Engine.QueryInterface(this.entity, IID_Health);
    153         var cmpNewHealth = Engine.QueryInterface(newEntity, IID_Health);
    154         var healthLevel = Math.max(0, Math.min(1, cmpHealth.GetHitpoints() / cmpHealth.GetMaxHitpoints()));
    155         cmpNewHealth.SetHitpoints(Math.round(cmpNewHealth.GetMaxHitpoints() * healthLevel));
    156 
    157         var cmpUnitAI = Engine.QueryInterface(this.entity, IID_UnitAI);
    158         var cmpNewUnitAI = Engine.QueryInterface(newEntity, IID_UnitAI);
    159         if (cmpUnitAI && cmpNewUnitAI)
    160         {
    161             var pos = cmpUnitAI.GetHeldPosition();
    162             if (pos)
    163                 cmpNewUnitAI.SetHeldPosition(pos.x, pos.z);
    164             if (cmpUnitAI.GetStanceName())
    165                 cmpNewUnitAI.SwitchToStance(cmpUnitAI.GetStanceName());
    166             cmpNewUnitAI.AddOrders(cmpUnitAI.GetOrders());
    167             cmpNewUnitAI.SetGuardOf(cmpUnitAI.IsGuardOf());
    168         }
    169 
    170         // Maintain the list of guards
    171         var cmpGuard = Engine.QueryInterface(this.entity, IID_Guard);
    172         var cmpNewGuard = Engine.QueryInterface(newEntity, IID_Guard);
    173         if (cmpGuard && cmpNewGuard)
    174             cmpNewGuard.SetEntities(cmpGuard.GetEntities());
    175 
    176         Engine.BroadcastMessage(MT_EntityRenamed, { entity: this.entity, newentity: newEntity });
    177 
    178         // Play notification sound
     132    // Play notification sound
     133    if (newEntity)
     134    {
    179135        var sound = this.packed ? "packed" : "unpacked";
    180136        PlaySound(sound, newEntity);
    181 
    182         // Destroy current entity
    183         Engine.DestroyEntity(this.entity);
    184137    }
    185     else
    186     {
    187         this.SetElapsedTime(this.GetElapsedTime() + PACKING_INTERVAL + lateness);
    188     }
    189138};
    190139
    191140Engine.RegisterComponentType(IID_Pack, "Pack", Pack);
  • binaries/data/mods/public/simulation/components/Upgrade.js

     
     1function Upgrade() {}
     2
     3const UPGRADING_PROGRESS_INTERVAL = 250;
     4
     5Upgrade.prototype.Schema =
     6    "<oneOrMore>" +
     7        "<element>" +
     8            "<anyName />" +
     9            "<interleave>" +
     10                "<element name='Entity' a:help='Entity to upgrade to'>" +
     11                    "<text/>" +
     12                "</element>" +
     13                "<optional>" +
     14                    "<element name='Icon' a:help='Icon to show in the GUI'>" +
     15                        "<text/>" +
     16                    "</element>" +
     17                "</optional>" +
     18                "<optional>" +
     19                    "<element name='Tooltip' a:help='This will be added to the tooltip to help the player choose why to upgrade.'>" +
     20                        "<text/>" +
     21                    "</element>" +
     22                "</optional>" +
     23                "<optional>" +
     24                    "<element name='Time' a:help='Time required to upgrade this entity, in milliseconds'>" +
     25                        "<data type='nonNegativeInteger'/>" +
     26                    "</element>" +
     27                "</optional>" +
     28                "<optional>" +
     29                    "<element name='Cost' a:help='Resource cost to upgrade this unit'>" +
     30                        "<oneOrMore>" +
     31                            "<choice>" +
     32                                "<element name='food'><data type='nonNegativeInteger'/></element>" +
     33                                "<element name='wood'><data type='nonNegativeInteger'/></element>" +
     34                                "<element name='stone'><data type='nonNegativeInteger'/></element>" +
     35                                "<element name='metal'><data type='nonNegativeInteger'/></element>" +
     36                            "</choice>" +
     37                        "</oneOrMore>" +
     38                    "</element>" +
     39                "</optional>" +
     40                "<optional>" +
     41                    "<element name='RequiredTechnology' a:help='Define what technology is required for this upgrade'>" +
     42                        "<choice>" +
     43                            "<text/>" +
     44                            "<empty/>" +
     45                        "</choice>" +
     46                    "</element>" +
     47                "</optional>" +
     48                "<optional>" +
     49                    "<element name='CheckPlacementRestrictions' a:help='Upgrading will check for placement restrictions'><empty/></element>" +
     50                "</optional>" +
     51            "</interleave>" +
     52        "</element>" +
     53    "</oneOrMore>";
     54
     55Upgrade.prototype.Init = function()
     56{
     57    this.upgrading = false;
     58    this.elapsedTime = 0;
     59    this.timer = undefined;
     60
     61    this.upgradeTemplates = {};
     62
     63    for (var choice in this.template)
     64    {
     65        var cmpIdentity = Engine.QueryInterface(this.entity, IID_Identity);
     66        var name = this.template[choice].Entity;
     67        if (cmpIdentity)
     68            name = name.replace(/\{civ\}/g, cmpIdentity.GetCiv());
     69        this.upgradeTemplates[name] = choice;
     70    }
     71};
     72
     73// On owner change, abort the upgrade
     74// This will also deal with the "OnDestroy" case.
     75Upgrade.prototype.OnOwnershipChanged = function(msg)
     76{
     77    this.CancelUpgrade();
     78
     79    if (msg.to !== -1)
     80        this.owner = msg.to;
     81};
     82
     83Upgrade.prototype.ChangeUpgradedEntityCount = function(amount)
     84{
     85    if (!this.IsUpgrading())
     86        return;
     87    var cmpTempMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
     88    var template = cmpTempMan.GetTemplate(this.upgrading);
     89    var category = null;
     90    if (template.TrainingRestrictions)
     91        category = template.TrainingRestrictions.Category;
     92    else if (template.BuildRestrictions)
     93        category = template.BuildRestrictions.Category;
     94
     95    var cmpEntityLimits = QueryPlayerIDInterface(this.owner, IID_EntityLimits);
     96    cmpEntityLimits.ChangeCount(category,amount);
     97};
     98
     99Upgrade.prototype.CanUpgradeTo = function(Template)
     100{
     101    return this.upgradeTemplates[Template] !== undefined;
     102};
     103
     104Upgrade.prototype.GetUpgrades = function()
     105{
     106    var ret = [];
     107
     108    var cmpIdentity = Engine.QueryInterface(this.entity, IID_Identity);
     109
     110    for each (var choice in this.template)
     111    {
     112        var entType = choice.Entity;
     113        if (cmpIdentity)
     114            entType = entType.replace(/\{civ\}/g, cmpIdentity.GetCiv());
     115
     116        var hasCosts = false;
     117        var cost = {};
     118        if (choice.Cost)
     119        {
     120            hasCosts = true;
     121            for (var type in choice.Cost)
     122                cost[type] = ApplyValueModificationsToTemplate("Upgrade/Cost/"+type, +choice.Cost[type], this.owner, entType);
     123        }
     124        if (choice.Time)
     125        {
     126            hasCosts = true;
     127            cost["time"] = ApplyValueModificationsToTemplate("Upgrade/Time", +choice.Time/1000.0, this.owner, entType);
     128        }
     129        ret.push(
     130        {
     131            "entity": entType,
     132            "icon": choice.Icon || undefined,
     133            "cost": hasCosts ? cost : undefined,
     134            "tooltip": choice.Tooltip || undefined,
     135            "requiredTechnology": "RequiredTechnology" in choice ? choice.RequiredTechnology : null,
     136        });
     137    }
     138
     139    return ret;
     140};
     141
     142Upgrade.prototype.CancelTimer = function()
     143{
     144    if (this.timer)
     145    {
     146        var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
     147        cmpTimer.CancelTimer(this.timer);
     148        this.timer = undefined;
     149    }
     150};
     151
     152Upgrade.prototype.IsUpgrading = function()
     153{
     154    return this.upgrading !== false;
     155};
     156
     157Upgrade.prototype.GetUpgradingTo = function()
     158{
     159    return this.upgrading;
     160};
     161
     162Upgrade.prototype.CheckPlacementRestrictions = function(Template)
     163{
     164    if (!this.upgradeTemplates[Template])
     165        return undefined;
     166
     167    return ("CheckPlacementRestrictions" in this.template[this.upgradeTemplates[Template]]);
     168};
     169
     170Upgrade.prototype.GetRequiredTechnology = function(Template)
     171{
     172    if (!this.upgradeTemplates[Template])
     173        return undefined;
     174
     175    var choice = this.upgradeTemplates[Template];
     176
     177    if ("RequiredTechnology" in this.template[choice] && this.template[choice].RequiredTechnology === undefined)
     178    {
     179        var cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
     180        var template = cmpTemplateManager.GetTemplate(this.template[choice].Entity);
     181        if (template.Identity.RequiredTechnology)
     182            return template.Identity.RequiredTechnology;
     183    }
     184    else if ("RequiredTechnology" in this.template[choice])
     185        return this.template[choice].RequiredTechnology;
     186    return null;
     187};
     188
     189Upgrade.prototype.GetResourceCosts = function(Template)
     190{
     191    if (!this.upgradeTemplates[Template])
     192        return undefined;
     193
     194    var choice = this.upgradeTemplates[Template];
     195    if (!this.template[choice].Cost)
     196        return {};
     197
     198    var costs = {};
     199    for (var r in this.template[choice].Cost)
     200    {
     201        costs[r] = +this.template[choice].Cost[r];
     202        costs[r] = ApplyValueModificationsToEntity("Upgrade/Cost/"+r, costs[r], this.entity);
     203    }
     204    return costs;
     205};
     206
     207Upgrade.prototype.Upgrade = function(Template)
     208{
     209    if (this.IsUpgrading())
     210        return false;
     211
     212    if (!this.upgradeTemplates[Template])
     213        return false;
     214
     215    var cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
     216    var cmpPlayer = Engine.QueryInterface(cmpPlayerManager.GetPlayerByID(this.owner), IID_Player);
     217
     218    if (!cmpPlayer.TrySubtractResources(this.GetResourceCosts(Template)))
     219        return false;
     220
     221    this.upgrading = Template;
     222
     223    // prevent cheating
     224    this.ChangeUpgradedEntityCount(1);
     225
     226    if (this.GetUpgradeTime(Template) !== 0)
     227    {
     228        var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
     229        this.timer = cmpTimer.SetInterval(this.entity, IID_Upgrade, "UpgradeProgress", 0, UPGRADING_PROGRESS_INTERVAL, {"upgrading": Template});
     230    }
     231    else
     232        this.UpgradeProgress();
     233
     234    return true;
     235};
     236
     237Upgrade.prototype.CancelUpgrade = function()
     238{
     239    if (this.IsUpgrading() === false)
     240        return;
     241
     242    var cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
     243    var cmpPlayer = Engine.QueryInterface(cmpPlayerManager.GetPlayerByID(this.owner), IID_Player);
     244    if (cmpPlayer)
     245    {
     246        var costs = this.GetResourceCosts(this.upgrading);
     247        cmpPlayer.AddResources(costs);
     248    }
     249
     250    this.ChangeUpgradedEntityCount(-1);
     251
     252    this.upgrading = false;
     253    this.CancelTimer();
     254    this.SetElapsedTime(0);
     255};
     256
     257Upgrade.prototype.GetUpgradeTime = function(Template)
     258{
     259    var template = this.upgrading || Template;
     260    var choice = this.upgradeTemplates[template];
     261    if (!choice)
     262        return undefined;
     263    return this.template[choice].Time ? ApplyValueModificationsToEntity("Upgrade/Time", +this.template[choice].Time, this.entity) : 0;
     264};
     265
     266Upgrade.prototype.GetElapsedTime = function()
     267{
     268    return this.elapsedTime;
     269};
     270
     271Upgrade.prototype.GetProgress = function()
     272{
     273    // Hopefully undefined and 0 are the only thing that would trigger that.
     274    if (!this.IsUpgrading())
     275        return undefined;
     276    return this.GetUpgradeTime() == 0 ? 1 : this.elapsedTime / this.GetUpgradeTime();
     277};
     278
     279Upgrade.prototype.SetElapsedTime = function(time)
     280{
     281    this.elapsedTime = time;
     282};
     283
     284Upgrade.prototype.UpgradeProgress = function(data, lateness)
     285{
     286    if (this.elapsedTime < this.GetUpgradeTime())
     287    {
     288        this.SetElapsedTime(this.GetElapsedTime() + UPGRADING_PROGRESS_INTERVAL + lateness);
     289        return;
     290    }
     291
     292    this.CancelTimer();
     293
     294    var newEntity = ChangeEntityTemplate(this.entity, this.upgrading);
     295
     296    // Play notification sound
     297    if (newEntity)
     298        PlaySound("upgraded", newEntity);
     299};
     300
     301Engine.RegisterComponentType(IID_Upgrade, "Upgrade", Upgrade);
  • binaries/data/mods/public/simulation/components/interfaces/Upgrade.js

    Property changes on: binaries/data/mods/public/simulation/components/Upgrade.js
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
     
     1Engine.RegisterInterface("Upgrade");
  • binaries/data/mods/public/simulation/helpers/Commands.js

    Property changes on: binaries/data/mods/public/simulation/components/interfaces/Upgrade.js
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
     
    551551        }
    552552    },
    553553
    554     "wall-to-gate": function(player, cmd, data)
    555     {
    556         for each (var ent in data.entities)
    557         {
    558             TryTransformWallToGate(ent, data.cmpPlayer, cmd.template);
    559         }
    560     },
    561 
    562554    "lock-gate": function(player, cmd, data)
    563555    {
    564556        for each (var ent in data.entities)
     
    642634            }
    643635        }
    644636    },
     637
     638    "upgrade": function(player, cmd, data)
     639    {
     640        for each (var ent in data.entities)
     641        {
     642            var cmpUpgrade = Engine.QueryInterface(ent, IID_Upgrade);
     643
     644            var templateName = cmd.template;
     645
     646            if (!cmpUpgrade || !cmpUpgrade.CanUpgradeTo(templateName))
     647                continue;
     648
     649            if (cmpUpgrade.CheckPlacementRestrictions(templateName) && !CheckObstructionsForTemplateChange(ent, templateName))
     650            {
     651                var notification = {"players": [data.cmpPlayer.GetPlayerID()], "message": "Cannot upgrade as distance requirements are not verified or terrain is obstructed." };
     652                var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
     653                cmpGUIInterface.PushNotification(notification);
     654                continue;
     655            }
     656
     657            if (!CheckGarrisonedCanChangeTemplate(ent, templateName))
     658            {
     659                var notification = {"players": [data.cmpPlayer.GetPlayerID()], "message": "Cannot upgrade a garrisoned entity." };
     660                var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
     661                cmpGUIInterface.PushNotification(notification);
     662                continue;
     663            }
     664
     665            // Check entity limits
     666            var cmpTempMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
     667            var template = cmpTempMan.GetTemplate(templateName);
     668            var cmpEntityLimits = QueryPlayerIDInterface(player, IID_EntityLimits);
     669            if ((template.TrainingRestrictions && !cmpEntityLimits.AllowedToTrain(template.TrainingRestrictions.Category,1))
     670                || (template.BuildRestrictions && !cmpEntityLimits.AllowedToBuild(template.BuildRestrictions.Category)))
     671            {
     672                if (g_DebugCommands)
     673                    warn("Invalid command: build limits check failed for player "+player+": "+uneval(cmd));
     674                continue;
     675            }
     676
     677            var cmpTechnologyManager = QueryOwnerInterface(ent, IID_TechnologyManager);
     678            if (cmpUpgrade.GetRequiredTechnology() && !cmpTechnologyManager.IsTechnologyResearched(cmpUpgrade.GetRequiredTechnology()))
     679            {
     680                if (g_DebugCommands)
     681                    warn("Invalid command: upgrading requires unresearched technology: " + uneval(cmd));
     682                continue;
     683            }
     684
     685            cmpUpgrade.Upgrade(templateName, data.cmpPlayer);
     686        }
     687    },
     688
     689    "cancel-upgrade": function(player, cmd, data)
     690    {
     691        for each (var ent in data.entities)
     692        {
     693            var cmpUpgrade = Engine.QueryInterface(ent, IID_Upgrade);
     694
     695            if (!cmpUpgrade)
     696                continue
     697
     698            cmpUpgrade.CancelUpgrade(data.cmpPlayer);
     699        }
     700    },
     701
    645702    "dialog-answer": function(player, cmd, data)
    646703    {
    647704        // Currently nothing. Triggers can read it anyway, and send this
     
    15121569    return entities.filter(function(ent) { return CanControlUnitOrIsAlly(ent, player, controlAll);} );
    15131570}
    15141571
    1515 /**
    1516  * Try to transform a wall to a gate
    1517  */
    1518 function TryTransformWallToGate(ent, cmpPlayer, template)
    1519 {
    1520     var cmpIdentity = Engine.QueryInterface(ent, IID_Identity);
    1521     if (!cmpIdentity)
    1522         return;
    1523 
    1524     // Check if this is a valid long wall segment
    1525     if (!cmpIdentity.HasClass("LongWall"))
    1526     {
    1527         if (g_DebugCommands)
    1528             warn("Invalid command: invalid wall conversion to gate for player "+player+": "+uneval(cmd));
    1529         return;
    1530     }
    1531 
    1532     var civ = cmpIdentity.GetCiv();
    1533     var gate = Engine.AddEntity(template);
    1534 
    1535     var cmpCost = Engine.QueryInterface(gate, IID_Cost);
    1536     if (!cmpPlayer.TrySubtractResources(cmpCost.GetResourceCosts()))
    1537     {
    1538         if (g_DebugCommands)
    1539             warn("Invalid command: convert gate cost check failed for player "+player+": "+uneval(cmd));
    1540 
    1541         Engine.DestroyEntity(gate);
    1542         return;
    1543     }
    1544 
    1545     ReplaceBuildingWith(ent, gate);
    1546 }
    1547 
    1548 /**
    1549  * Unconditionally replace a building with another one
    1550  */
    1551 function ReplaceBuildingWith(ent, building)
    1552 {
    1553     // Move the building to the right place
    1554     var cmpPosition = Engine.QueryInterface(ent, IID_Position);
    1555     var cmpBuildingPosition = Engine.QueryInterface(building, IID_Position);
    1556     var pos = cmpPosition.GetPosition2D();
    1557     cmpBuildingPosition.JumpTo(pos.x, pos.y);
    1558     var rot = cmpPosition.GetRotation();
    1559     cmpBuildingPosition.SetYRotation(rot.y);
    1560     cmpBuildingPosition.SetXZRotation(rot.x, rot.z);
    1561 
    1562     // Copy ownership
    1563     var cmpOwnership = Engine.QueryInterface(ent, IID_Ownership);
    1564     var cmpBuildingOwnership = Engine.QueryInterface(building, IID_Ownership);
    1565     cmpBuildingOwnership.SetOwner(cmpOwnership.GetOwner());
    1566 
    1567     // Copy control groups
    1568     var cmpObstruction = Engine.QueryInterface(ent, IID_Obstruction);
    1569     var cmpBuildingObstruction = Engine.QueryInterface(building, IID_Obstruction);
    1570     cmpBuildingObstruction.SetControlGroup(cmpObstruction.GetControlGroup());
    1571     cmpBuildingObstruction.SetControlGroup2(cmpObstruction.GetControlGroup2());
    1572 
    1573     // Copy health level from the old entity to the new
    1574     var cmpHealth = Engine.QueryInterface(ent, IID_Health);
    1575     var cmpBuildingHealth = Engine.QueryInterface(building, IID_Health);
    1576     var healthFraction = Math.max(0, Math.min(1, cmpHealth.GetHitpoints() / cmpHealth.GetMaxHitpoints()));
    1577     var buildingHitpoints = Math.round(cmpBuildingHealth.GetMaxHitpoints() * healthFraction);
    1578     cmpBuildingHealth.SetHitpoints(buildingHitpoints);
    1579 
    1580     PlaySound("constructed", building);
    1581 
    1582     Engine.PostMessage(ent, MT_ConstructionFinished,
    1583         { "entity": ent, "newentity": building });
    1584     Engine.BroadcastMessage(MT_EntityRenamed, { entity: ent, newentity: building });
    1585 
    1586     Engine.DestroyEntity(ent);
    1587 }
    1588 
    15891572Engine.RegisterGlobal("GetFormationRequirements", GetFormationRequirements);
    15901573Engine.RegisterGlobal("CanMoveEntsIntoFormation", CanMoveEntsIntoFormation);
    15911574Engine.RegisterGlobal("GetDockAngle", GetDockAngle);
  • binaries/data/mods/public/simulation/helpers/Transform.js

     
     1// Helper functions to change an entity's template and check if the transformation is possible
     2
     3// returns the ID of the new entity or false.
     4var ChangeEntityTemplate = function(oldEntityID, newTemplate)
     5{
     6    // Done un/packing, copy our parameters to the final entity
     7    var newEntity = Engine.AddEntity(newTemplate);
     8    if (newEntity == INVALID_ENTITY)
     9    {
     10        // Error (e.g. invalid template names)
     11        error("Transform.js: Error replacing entity " + oldEntity + " for a '" + newTemplate + "'");
     12        return false;
     13    }
     14
     15    var cmpPosition = Engine.QueryInterface(oldEntityID, IID_Position);
     16    var cmpNewPosition = Engine.QueryInterface(newEntity, IID_Position);
     17    if (cmpPosition && cmpNewPosition)
     18    {
     19        if (cmpPosition.IsInWorld())
     20        {
     21            var pos = cmpPosition.GetPosition2D();
     22            cmpNewPosition.JumpTo(pos.x, pos.y);
     23        }
     24        var rot = cmpPosition.GetRotation();
     25        cmpNewPosition.SetYRotation(rot.y);
     26        cmpNewPosition.SetXZRotation(rot.x, rot.z);
     27        cmpNewPosition.SetHeightOffset(cmpPosition.GetHeightOffset());
     28    }
     29
     30    var cmpOwnership = Engine.QueryInterface(oldEntityID, IID_Ownership);
     31    var cmpNewOwnership = Engine.QueryInterface(newEntity, IID_Ownership);
     32    if (cmpOwnership && cmpNewOwnership)
     33        cmpNewOwnership.SetOwner(cmpOwnership.GetOwner());
     34
     35    // Copy control groups
     36    var cmpObstruction = Engine.QueryInterface(oldEntityID, IID_Obstruction);
     37    var cmpNewObstruction = Engine.QueryInterface(newEntity, IID_Obstruction);
     38    if (cmpObstruction && cmpNewObstruction)
     39    {
     40        cmpNewObstruction.SetControlGroup(cmpObstruction.GetControlGroup());
     41        cmpNewObstruction.SetControlGroup2(cmpObstruction.GetControlGroup2());
     42    }
     43
     44    // Maintain current health level
     45    var cmpHealth = Engine.QueryInterface(oldEntityID, IID_Health);
     46    var cmpNewHealth = Engine.QueryInterface(newEntity, IID_Health);
     47    if (cmpHealth && cmpNewHealth)
     48    {
     49        var healthLevel = Math.max(0, Math.min(1, cmpHealth.GetHitpoints() / cmpHealth.GetMaxHitpoints()));
     50        cmpNewHealth.SetHitpoints(Math.round(cmpNewHealth.GetMaxHitpoints() * healthLevel));
     51    }
     52
     53    var cmpUnitAI = Engine.QueryInterface(oldEntityID, IID_UnitAI);
     54    var cmpNewUnitAI = Engine.QueryInterface(newEntity, IID_UnitAI);
     55    if (cmpUnitAI && cmpNewUnitAI)
     56    {
     57        var pos = cmpUnitAI.GetHeldPosition();
     58        if (pos)
     59            cmpNewUnitAI.SetHeldPosition(pos.x, pos.z);
     60        if (cmpUnitAI.GetStanceName())
     61            cmpNewUnitAI.SwitchToStance(cmpUnitAI.GetStanceName());
     62        cmpNewUnitAI.AddOrders(cmpUnitAI.GetOrders());
     63        cmpNewUnitAI.SetGuardOf(cmpUnitAI.IsGuardOf());
     64    }
     65
     66    // Maintain the list of guards
     67    var cmpGuard = Engine.QueryInterface(oldEntityID, IID_Guard);
     68    var cmpNewGuard = Engine.QueryInterface(newEntity, IID_Guard);
     69    if (cmpGuard && cmpNewGuard)
     70        cmpNewGuard.SetEntities(cmpGuard.GetEntities());
     71
     72    TransferGarrisonedUnits(oldEntityID, newEntity);
     73
     74    Engine.BroadcastMessage(MT_EntityRenamed, { entity: oldEntityID, newentity: newEntity });
     75
     76    // Destroy current entity
     77    Engine.DestroyEntity(oldEntityID);
     78
     79    return newEntity;
     80};
     81
     82var CheckGarrisonedCanChangeTemplate = function(entityID, Template)
     83{
     84    var cmpPosition = Engine.QueryInterface(entityID, IID_Position);
     85    var unitAI = Engine.QueryInterface(entityID, IID_UnitAI);
     86    if (cmpPosition && !cmpPosition.IsInWorld() && unitAI && unitAI.IsGarrisoned())
     87    {
     88        // We're a garrisoned unit, assume impossibility as I've been unable to find a way to get the holder ID.
     89        return false;
     90    }
     91    return true;
     92}
     93
     94var CheckObstructionsForTemplateChange = function(entityID, Template)
     95{
     96    var previewEntity = Engine.AddEntity("preview|"+Template);
     97
     98    if (previewEntity == INVALID_ENTITY)
     99        return false;   // no need to destroy since it was invalid in the first place.
     100
     101    var cmpBuildRestrictions = Engine.QueryInterface(previewEntity, IID_BuildRestrictions);
     102    var cmpPosition = Engine.QueryInterface(entityID, IID_Position);
     103    var cmpOwnership = Engine.QueryInterface(entityID, IID_Ownership);
     104
     105    if (!cmpBuildRestrictions || !cmpPosition || !cmpOwnership)
     106    {
     107        Engine.DestroyEntity(previewEntity);
     108        return true;
     109    }
     110
     111    var canTransform = true;
     112
     113    var pos = cmpPosition.GetPosition2D();
     114    var angle = cmpPosition.GetRotation();
     115    // move us away to avoid our obstruction blocking the upgrade.
     116    cmpPosition.MoveOutOfWorld();
     117
     118    var cmpNewPosition = Engine.QueryInterface(previewEntity, IID_Position);
     119    cmpNewPosition.JumpTo(pos.x, pos.y);
     120    cmpNewPosition.SetYRotation(angle.y);
     121
     122    var cmpNewOwnership = Engine.QueryInterface(previewEntity, IID_Ownership);
     123    cmpNewOwnership.SetOwner(cmpOwnership.GetOwner());
     124
     125    var checkPlacement = cmpBuildRestrictions.CheckPlacement();
     126    if (checkPlacement && !checkPlacement.success)
     127        canTransform = false;
     128
     129    var cmpTempMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
     130    var template = cmpTempMan.GetTemplate(cmpTempMan.GetCurrentTemplateName());
     131    var newTemplate = cmpTempMan.GetTemplate(Template);
     132
     133    var obstruction = template.Obstruction;
     134
     135    // Check if units are blocking our template change
     136    if (canTransform && template.Obstruction && newTemplate.Obstruction)
     137    {
     138        // This only needs to be done if the new template is strictly bigger than the old one
     139        // "Obstructions" are annoying to test so just check.
     140        if (newTemplate.Obstruction.Obstructions
     141            || (template.Obstruction.Static && template.Obstruction.Static.width > newTemplate.Obstruction.Static.width
     142                                            && template.Obstruction.Static.depth > newTemplate.Obstruction.Static.depth)
     143            || (template.Obstruction.Unit && template.Obstruction.Unit.radius > newTemplate.Obstruction.Unit.radius))
     144        {
     145            var cmpNewObstruction = Engine.QueryInterface(previewEntity, IID_Obstruction); 
     146            if (cmpNewObstruction && cmpNewObstruction.GetBlockMovementFlag())
     147            {
     148                // Check for units
     149                var collisions = cmpNewObstruction.GetEntityCollisions(false, true);
     150                if (collisions.length !== 0)
     151                    canTransform = false;
     152            }
     153        }
     154    }
     155
     156    // Move preview entity out of world so it won't interfere with additional calls
     157    //    to this function for entityID on the same sim update.
     158    // Specifically, CheckPlacement() would incorrectly spot and fail on earlier preview entities
     159    //    if those are left in the world.
     160    cmpNewPosition.MoveOutOfWorld();
     161    cmpPosition.JumpTo(pos.x, pos.y);
     162    cmpPosition.SetYRotation(angle.y);
     163
     164    Engine.DestroyEntity(previewEntity);
     165    return canTransform;
     166};
     167
     168var TransferGarrisonedUnits = function(oldEntityID, newEntityID)
     169{
     170    // Transfer garrisoned units if possible, or unload them
     171    var cmpGarrison = Engine.QueryInterface(oldEntityID, IID_GarrisonHolder);
     172    var cmpNewGarrison = Engine.QueryInterface(newEntityID, IID_GarrisonHolder);
     173    if (!cmpNewGarrison)
     174        return; // nothing to do as the code will by default unload all.
     175
     176    if (cmpGarrison && cmpGarrison.GetEntities().length > 0)
     177    {
     178        var garrisonedEntities = cmpGarrison.GetEntities().slice();
     179        cmpGarrison.UnloadAll(true);
     180        for (var j = 0; j < garrisonedEntities.length; ++j)
     181        {
     182            var cmpUnitAI = Engine.QueryInterface(garrisonedEntities[j], IID_UnitAI);
     183            cmpUnitAI.Autogarrison(newEntityID);
     184            cmpNewGarrison.Garrison(garrisonedEntities[j]);
     185        }
     186    }
     187}
     188
     189Engine.RegisterGlobal("ChangeEntityTemplate", ChangeEntityTemplate);
     190Engine.RegisterGlobal("CheckGarrisonedCanChangeTemplate", CheckGarrisonedCanChangeTemplate);
     191Engine.RegisterGlobal("CheckObstructionsForTemplateChange", CheckObstructionsForTemplateChange);
     192 No newline at end of file
  • binaries/data/mods/public/simulation/templates/template_structure_defense_wall_long.xml

    Property changes on: binaries/data/mods/public/simulation/helpers/Transform.js
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
     
    5151  <Identity>
    5252    <Classes datatype="tokens">LongWall</Classes>
    5353    <Tooltip>Long wall segments can be converted to gates.</Tooltip>
    54     <GateConversionTooltip>Convert Stone Wall into City Gate</GateConversionTooltip>
    5554  </Identity>
     55  <Upgrade>
     56    <Gate>
     57      <Entity>structures/{civ}_wall_gate</Entity>
     58      <Tooltip>This will allow you to let units circulate through your fortifications.</Tooltip>
     59      <Cost>
     60        <stone>60</stone>
     61      </Cost>
     62      <Time>10000</Time>
     63    </Gate>
     64  </Upgrade>
    5665</Entity>
  • binaries/data/mods/public/simulation/templates/other/palisades_rocks_long.xml

     
    2121    <SelectionGroupName>other/wallset_palisade</SelectionGroupName>
    2222    <SpecificName>Palisade</SpecificName>
    2323    <GenericName>Wooden Wall</GenericName>
    24     <GateConversionTooltip>Convert Wooden Wall into Wooden Gate</GateConversionTooltip>
    2524    <Classes datatype="tokens">-StoneWall Palisade</Classes>
    2625    <History>A cheap, quick defensive structure constructed with sharpened tree trunks</History>
    2726    <Icon>gaia/special_palisade.png</Icon>
     
    4140  <WallPiece>
    4241    <Length>11.0</Length>
    4342  </WallPiece>
     43  <Upgrade>
     44    <Gate>
     45      <Entity>other/palisades_rocks_gate</Entity>
     46      <Cost>
     47        <stone>0</stone>
     48        <wood>20</wood>
     49      </Cost>
     50      <Time>5000</Time>
     51    </Gate>
     52  </Upgrade>
    4453</Entity>
  • binaries/data/mods/public/simulation/templates/structures/rome_siege_wall_long.xml

     
    5555    </Classes>
    5656    <Icon>structures/palisade.png</Icon>
    5757    <Tooltip>A wooden and turf palisade buildable in enemy and neutral territories.</Tooltip>
    58     <GateConversionTooltip>Convert Siege Wall into Siege Wall Gate</GateConversionTooltip>
    5958    <History>Quick building, but expensive wooden and earthen walls used to surround and siege an enemy town or fortified position. The most famous examples are the Roman sieges of the Iberian stronghold of Numantia and the Gallic stronghold of Alesia.</History>
    6059  </Identity>
    6160  <Obstruction>