Ticket #2706: UpgradeComponent.3.patch

File UpgradeComponent.3.patch, 44.8 KB (added by wraitii, 5 years ago)

RC

  • 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    if (newEntity)
     133    {
    179134        var sound = this.packed ? "packed" : "unpacked";
    180135        PlaySound(sound, newEntity);
    181 
    182         // Destroy current entity
    183         Engine.DestroyEntity(this.entity);
    184136    }
    185     else
    186     {
    187         this.SetElapsedTime(this.GetElapsedTime() + PACKING_INTERVAL + lateness);
    188     }
    189137};
    190138
    191139Engine.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(templateArg)
     171{
     172    if (!this.upgradeTemplates[templateArg])
     173        return undefined;
     174
     175    var choice = this.upgradeTemplates[templateArg];
     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
     187    return null;
     188};
     189
     190Upgrade.prototype.GetResourceCosts = function(template)
     191{
     192    if (!this.upgradeTemplates[template])
     193        return undefined;
     194
     195    var choice = this.upgradeTemplates[template];
     196    if (!this.template[choice].Cost)
     197        return {};
     198
     199    var costs = {};
     200    for (var r in this.template[choice].Cost)
     201    {
     202        costs[r] = +this.template[choice].Cost[r];
     203        costs[r] = ApplyValueModificationsToEntity("Upgrade/Cost/"+r, costs[r], this.entity);
     204    }
     205    return costs;
     206};
     207
     208Upgrade.prototype.Upgrade = function(template)
     209{
     210    if (this.IsUpgrading())
     211        return false;
     212
     213    if (!this.upgradeTemplates[template])
     214        return false;
     215
     216    var cmpPlayer = Engine.QueryOwnerInterface(this.entity, 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 cmpPlayer = Engine.QueryOwnerInterface(this.entity, IID_Player);
     243    if (cmpPlayer)
     244    {
     245        var costs = this.GetResourceCosts(this.upgrading);
     246        cmpPlayer.AddResources(costs);
     247    }
     248
     249    this.ChangeUpgradedEntityCount(-1);
     250
     251    this.upgrading = false;
     252    this.CancelTimer();
     253    this.SetElapsedTime(0);
     254};
     255
     256Upgrade.prototype.GetUpgradeTime = function(templateArg)
     257{
     258    var template = this.upgrading || templateArg;
     259    var choice = this.upgradeTemplates[template];
     260    if (!choice)
     261        return undefined;
     262    return this.template[choice].Time ? ApplyValueModificationsToEntity("Upgrade/Time", +this.template[choice].Time, this.entity) : 0;
     263};
     264
     265Upgrade.prototype.GetElapsedTime = function()
     266{
     267    return this.elapsedTime;
     268};
     269
     270Upgrade.prototype.GetProgress = function()
     271{
     272    if (!this.IsUpgrading())
     273        return undefined;
     274    return this.GetUpgradeTime() == 0 ? 1 : this.elapsedTime / this.GetUpgradeTime();
     275};
     276
     277Upgrade.prototype.SetElapsedTime = function(time)
     278{
     279    this.elapsedTime = time;
     280};
     281
     282Upgrade.prototype.UpgradeProgress = function(data, lateness)
     283{
     284    if (this.elapsedTime < this.GetUpgradeTime())
     285    {
     286        this.SetElapsedTime(this.GetElapsedTime() + UPGRADING_PROGRESS_INTERVAL + lateness);
     287        return;
     288    }
     289
     290    this.CancelTimer();
     291
     292    var newEntity = ChangeEntityTemplate(this.entity, this.upgrading);
     293
     294    if (newEntity)
     295        PlaySound("upgraded", newEntity);
     296};
     297
     298Engine.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            if (!cmpUpgrade || !cmpUpgrade.CanUpgradeTo(cmd.template))
     645                continue;
     646
     647            if (cmpUpgrade.CheckPlacementRestrictions(cmd.template) && ObstructionsBlockingTemplateChange(ent, cmd.template))
     648            {
     649                var notification = {"players": [data.cmpPlayer.GetPlayerID()], "message": "Cannot upgrade as distance requirements are not verified or terrain is obstructed." };
     650                var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
     651                cmpGUIInterface.PushNotification(notification);
     652                continue;
     653            }
     654
     655            if (!CanGarrisonedChangeTemplate(ent, cmd.template))
     656            {
     657                var notification = {"players": [data.cmpPlayer.GetPlayerID()], "message": "Cannot upgrade a garrisoned entity." };
     658                var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
     659                cmpGUIInterface.PushNotification(notification);
     660                continue;
     661            }
     662
     663            // Check entity limits
     664            var cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
     665            var template = cmpTemplateManager.GetTemplate(cmd.template);
     666            var cmpEntityLimits = QueryPlayerIDInterface(player, IID_EntityLimits);
     667            if ((template.TrainingRestrictions && !cmpEntityLimits.AllowedToTrain(template.TrainingRestrictions.Category, 1))
     668                || (template.BuildRestrictions && !cmpEntityLimits.AllowedToBuild(template.BuildRestrictions.Category)))
     669            {
     670                if (g_DebugCommands)
     671                    warn("Invalid command: build limits check failed for player " + player + ": " + uneval(cmd));
     672                continue;
     673            }
     674
     675            var cmpTechnologyManager = QueryOwnerInterface(ent, IID_TechnologyManager);
     676            if (cmpUpgrade.GetRequiredTechnology() && !cmpTechnologyManager.IsTechnologyResearched(cmpUpgrade.GetRequiredTechnology()))
     677            {
     678                if (g_DebugCommands)
     679                    warn("Invalid command: upgrading requires unresearched technology: " + uneval(cmd));
     680                continue;
     681            }
     682
     683            cmpUpgrade.Upgrade(cmd.template, data.cmpPlayer);
     684        }
     685    },
     686
     687    "cancel-upgrade": function(player, cmd, data)
     688    {
     689        for each (var ent in data.entities)
     690        {
     691            var cmpUpgrade = Engine.QueryInterface(ent, IID_Upgrade);
     692            if (cmpUpgrade)
     693                cmpUpgrade.CancelUpgrade(data.cmpPlayer);
     694        }
     695    },
     696
    645697    "dialog-answer": function(player, cmd, data)
    646698    {
    647699        // Currently nothing. Triggers can read it anyway, and send this
     
    15121564    return entities.filter(function(ent) { return CanControlUnitOrIsAlly(ent, player, controlAll);} );
    15131565}
    15141566
    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 
    15891567Engine.RegisterGlobal("GetFormationRequirements", GetFormationRequirements);
    15901568Engine.RegisterGlobal("CanMoveEntsIntoFormation", CanMoveEntsIntoFormation);
    15911569Engine.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 INVALID_ENTITY.
     4var ChangeEntityTemplate = function(oldEnt, newTemplate)
     5{
     6    // Done un/packing, copy our parameters to the final entity
     7    var newEnt = Engine.AddEntity(newTemplate);
     8    if (newEnt == INVALID_ENTITY)
     9    {
     10        // Error (e.g. invalid template names)
     11        error("Transform.js: Error replacing entity " + oldEnt + " for a '" + newTemplate + "'");
     12        return INVALID_ENTITY;
     13    }
     14
     15    var cmpPosition = Engine.QueryInterface(oldEnt, IID_Position);
     16    var cmpNewPosition = Engine.QueryInterface(newEnt, 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(oldEnt, IID_Ownership);
     31    var cmpNewOwnership = Engine.QueryInterface(newEnt, IID_Ownership);
     32    if (cmpOwnership && cmpNewOwnership)
     33        cmpNewOwnership.SetOwner(cmpOwnership.GetOwner());
     34
     35    // Copy control groups
     36    var cmpObstruction = Engine.QueryInterface(oldEnt, IID_Obstruction);
     37    var cmpNewObstruction = Engine.QueryInterface(newEnt, 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(oldEnt, IID_Health);
     46    var cmpNewHealth = Engine.QueryInterface(newEnt, 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(oldEnt, IID_UnitAI);
     54    var cmpNewUnitAI = Engine.QueryInterface(newEnt, 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(oldEnt, IID_Guard);
     68    var cmpNewGuard = Engine.QueryInterface(newEnt, IID_Guard);
     69    if (cmpGuard && cmpNewGuard)
     70        cmpNewGuard.SetEntities(cmpGuard.GetEntities());
     71
     72    TransferGarrisonedUnits(oldEnt, newEnt);
     73
     74    Engine.BroadcastMessage(MT_EntityRenamed, { entity: oldEnt, newEnt: newEnt });
     75
     76    // Destroy current entity
     77    Engine.DestroyEntity(oldEnt);
     78
     79    return newEnt;
     80};
     81
     82var CanGarrisonedChangeTemplate = function(ent, Template)
     83{
     84    var cmpPosition = Engine.QueryInterface(ent, IID_Position);
     85    var unitAI = Engine.QueryInterface(ent, 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        // TODO: change this if that ever becomes possibles
     90        return false;
     91    }
     92    return true;
     93}
     94
     95var ObstructionsBlockingTemplateChange = function(ent, Template)
     96{
     97    var previewEntity = Engine.AddEntity("preview|"+Template);
     98
     99    if (previewEntity == INVALID_ENTITY)
     100        return true;
     101
     102    var cmpBuildRestrictions = Engine.QueryInterface(previewEntity, IID_BuildRestrictions);
     103    var cmpPosition = Engine.QueryInterface(ent, IID_Position);
     104    var cmpOwnership = Engine.QueryInterface(ent, IID_Ownership);
     105
     106    // Return false if no ownership as BuildRestrictions.CheckPlacement needs an owner and I have no idea if false or true is better
     107    // Plus there are no real entities without owners currently.
     108    if (!cmpBuildRestrictions || !cmpPosition || !cmpOwnership)
     109        return DeleteEntityAndReturnFalse(previewEntity, false);
     110
     111    var pos = cmpPosition.GetPosition2D();
     112    var angle = cmpPosition.GetRotation();
     113    // move us away to prevent our own obstruction from blocking the upgrade.
     114    cmpPosition.MoveOutOfWorld();
     115
     116    var cmpNewPosition = Engine.QueryInterface(previewEntity, IID_Position);
     117    cmpNewPosition.JumpTo(pos.x, pos.y);
     118    cmpNewPosition.SetYRotation(angle.y);
     119
     120    var cmpNewOwnership = Engine.QueryInterface(previewEntity, IID_Ownership);
     121    cmpNewOwnership.SetOwner(cmpOwnership.GetOwner());
     122
     123    var checkPlacement = cmpBuildRestrictions.CheckPlacement();
     124    if (checkPlacement && !checkPlacement.success)
     125        return DeleteEntityAndReturnFalse(previewEntity, true);
     126
     127    var cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
     128    var template = cmpTemplateManager.GetTemplate(cmpTemplateManager.GetCurrentTemplateName());
     129    var newTemplate = cmpTemplateManager.GetTemplate(Template);
     130
     131    // Check if units are blocking our template change
     132    if (canTransform && template.Obstruction && newTemplate.Obstruction)
     133    {
     134        // This only needs to be done if the new template is strictly bigger than the old one
     135        // "Obstructions" are annoying to test so just check.
     136        if (newTemplate.Obstruction.Obstructions
     137            || (template.Obstruction.Static && (template.Obstruction.Static.width > newTemplate.Obstruction.Static.width
     138                                            || template.Obstruction.Static.depth > newTemplate.Obstruction.Static.depth))
     139            || (template.Obstruction.Unit && template.Obstruction.Unit.radius > newTemplate.Obstruction.Unit.radius))
     140        {
     141            var cmpNewObstruction = Engine.QueryInterface(previewEntity, IID_Obstruction); 
     142            if (cmpNewObstruction && cmpNewObstruction.GetBlockMovementFlag())
     143            {
     144                // Check for units
     145                var collisions = cmpNewObstruction.GetEntityCollisions(false, true);
     146                if (collisions.length !== 0)
     147                    return DeleteEntityAndReturnFalse(previewEntity, true);
     148            }
     149        }
     150    }
     151
     152    // Move preview entity out of world so it won't interfere with additional calls
     153    //    to this function for ent on the same sim update.
     154    // Specifically, CheckPlacement() would incorrectly spot and fail on earlier preview entities
     155    //    if those are left in the world.
     156    cmpNewPosition.MoveOutOfWorld();
     157    cmpPosition.JumpTo(pos.x, pos.y);
     158    cmpPosition.SetYRotation(angle.y);
     159
     160    return DeleteEntityAndReturnFalse(previewEntity, false);
     161};
     162
     163var DeleteEntityAndReturn = function(ent, ret)
     164{
     165    Engine.DestroyEntity(previewEntity);
     166    return ret;
     167};
     168
     169var TransferGarrisonedUnits = function(oldEnt, newEnt)
     170{
     171    // Transfer garrisoned units if possible, or unload them
     172    var cmpGarrison = Engine.QueryInterface(oldEnt, IID_GarrisonHolder);
     173    var cmpNewGarrison = Engine.QueryInterface(newEnt, IID_GarrisonHolder);
     174    if (!cmpNewGarrison || !cmpGarrison || cmpGarrison.GetEntities().length === 0 )
     175        return; // nothing to do as the code will by default unload all.
     176
     177    var garrisonedEntities = cmpGarrison.GetEntities().slice();
     178    for (var j = 0; j < garrisonedEntities.length; ++j)
     179    {
     180        var cmpUnitAI = Engine.QueryInterface(garrisonedEntities[j], IID_UnitAI);
     181        cmpGarrison.Eject(garrisonedEntities[j]);
     182        cmpUnitAI.Autogarrison(newEnt);
     183        cmpNewGarrison.Garrison(garrisonedEntities[j]);
     184    }
     185};
     186
     187Engine.RegisterGlobal("ChangeEntityTemplate", ChangeEntityTemplate);
     188Engine.RegisterGlobal("CanGarrisonedChangeTemplate", CanGarrisonedChangeTemplate);
     189Engine.RegisterGlobal("ObstructionsBlockingTemplateChange", ObstructionsBlockingTemplateChange);
  • 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>