Ticket #2706: UpgradeComponent.7.patch
File UpgradeComponent.7.patch, 45.8 KB (added by , 8 years ago) |
---|
-
data/mods/public/globalscripts/Templates.js
233 233 }; 234 234 ret.icon = template.Identity.Icon; 235 235 ret.tooltip = template.Identity.Tooltip; 236 ret.gateConversionTooltip = template.Identity.GateConversionTooltip;237 236 ret.requiredTechnology = template.Identity.RequiredTechnology; 238 237 ret.visibleIdentityClasses = GetVisibleIdentityClasses(template.Identity); 239 238 } -
data/mods/public/gui/session/input.js
1641 1641 }); 1642 1642 } 1643 1643 1644 // Transform a wall to a gate1645 function transformWallToGate(template)1644 // Upgrade an entity to another 1645 function upgradeEntity(Template) 1646 1646 { 1647 1647 var selection = g_Selection.toList(); 1648 1648 Engine.PostNetworkCommand({ 1649 "type": "wall-to-gate", 1650 "entities": selection.filter( function(e) { return getWallGateTemplate(e) == template; } ), 1651 "template": template, 1649 "type": "upgrade", 1650 "entities": selection, 1651 "template": Template, 1652 "queued": false 1652 1653 }); 1653 1654 } 1654 1655 1655 // Gets the gate form (if any) of a given long wall piece1656 function getWallGateTemplate(entity)1656 // Cancel upgrading entities 1657 function cancelUpgradeEntity() 1657 1658 { 1658 // TODO: find the gate template name in a better way 1659 var entState = GetEntityState(entity); 1660 var index; 1661 1662 if (entState && !entState.foundation && hasClass(entState, "LongWall") && (index = entState.template.indexOf("long")) >= 0) 1663 return entState.template.substr(0, index) + "gate"; 1664 return undefined; 1659 var selection = g_Selection.toList(); 1660 Engine.PostNetworkCommand({ 1661 "type": "cancel-upgrade", 1662 "entities": selection, 1663 "queued": false 1664 }); 1665 1665 } 1666 1666 1667 1667 // Set the camera to follow the given unit -
data/mods/public/gui/session/selection_panels.js
501 501 } 502 502 }; 503 503 504 // GATE505 g_SelectionPanels.Gate = {506 "getMaxNumberOfItems": function()507 {508 return 24 - getNumberOfRightPanelButtons();509 },510 "getItems": function(unitEntState, selection)511 {512 // Allow long wall pieces to be converted to gates513 var longWallTypes = {};514 var walls = [];515 var gates = [];516 for (var ent of selection)517 {518 var state = GetEntityState(ent);519 if (hasClass(state, "LongWall") && !state.gate && !longWallTypes[state.template])520 {521 var gateTemplate = getWallGateTemplate(state.id);522 if (gateTemplate)523 {524 var tooltipString = GetTemplateDataWithoutLocalization(state.template).gateConversionTooltip;525 if (!tooltipString)526 {527 warn(state.template + " is supposed to be convertable to a gate, but it's missing the GateConversionTooltip in the Identity template");528 tooltipString = "";529 }530 walls.push({531 "tooltip": translate(tooltipString),532 "template": gateTemplate,533 "callback": function (item) { transformWallToGate(item.template); }534 });535 }536 537 // We only need one entity per type.538 longWallTypes[state.template] = true;539 }540 else if (state.gate && !gates.length)541 {542 gates.push({543 "gate": state.gate,544 "tooltip": translate("Lock Gate"),545 "locked": true,546 "callback": function (item) { lockGate(item.locked); }547 });548 gates.push({549 "gate": state.gate,550 "tooltip": translate("Unlock Gate"),551 "locked": false,552 "callback": function (item) { lockGate(item.locked); }553 });554 }555 // Show both 'locked' and 'unlocked' as active if the selected gates have both lock states.556 else if (state.gate && state.gate.locked != gates[0].gate.locked)557 for (var j = 0; j < gates.length; ++j)558 delete gates[j].gate.locked;559 }560 561 // Place wall conversion options after gate lock/unlock icons.562 var items = gates.concat(walls);563 return items;564 },565 "setAction": function(data)566 {567 data.button.onPress = function() {data.item.callback(data.item); };568 },569 "setTooltip": function(data)570 {571 var tooltip = data.item.tooltip;572 if (data.item.template)573 {574 data.template = GetTemplateData(data.item.template);575 data.wallCount = data.selection.reduce(function (count, ent) {576 var state = GetEntityState(ent);577 if (hasClass(state, "LongWall") && !state.gate)578 ++count;579 return count;580 }, 0);581 582 tooltip += "\n" + getEntityCostTooltip(data.template, data.wallCount);583 584 data.neededResources = Engine.GuiInterfaceCall("GetNeededResources", {585 "cost": multiplyEntityCosts(data.template, data.wallCount)586 });587 588 if (data.neededResources)589 tooltip += getNeededResourcesTooltip(data.neededResources);590 }591 data.button.tooltip = tooltip;592 },593 "setGraphics": function(data)594 {595 data.button.enabled = controlsPlayer(data.unitEntState.player);596 var gateIcon;597 if (data.item.gate)598 {599 // If already a gate, show locking actions600 gateIcon = "icons/lock_" + GATE_ACTIONS[data.item.locked ? 0 : 1] + "ed.png";601 if (data.item.gate.locked === undefined)602 data.guiSelection.hidden = false;603 else604 data.guiSelection.hidden = data.item.gate.locked != data.item.locked;605 }606 else607 {608 // otherwise show gate upgrade icon609 var template = GetTemplateData(data.item.template);610 if (!template)611 return;612 gateIcon = data.template.icon ? "portraits/" + data.template.icon : "icons/gate_closed.png";613 data.guiSelection.hidden = true;614 }615 616 data.icon.sprite = (data.neededResources ? resourcesToAlphaMask(data.neededResources) + ":" : "") + "stretched:session/" + gateIcon;617 },618 "setPosition": function(data)619 {620 var index = data.i + getNumberOfRightPanelButtons();621 setPanelObjectPosition(data.button, index, data.rowLength);622 }623 };624 625 504 // PACK 626 505 g_SelectionPanels.Pack = { 627 506 "getMaxNumberOfItems": function() … … 689 568 } 690 569 }; 691 570 571 // UPGRADE 572 g_SelectionPanels.Upgrade = { 573 "getMaxNumberOfItems": function() 574 { 575 return 24 - getNumberOfRightPanelButtons(); 576 }, 577 "getItems": function(unitEntState, selection) 578 { 579 // Interface becomes complicated with multiple units and this is meant per-entity, so prevent it if the selection has multiple units. 580 // TODO: if the units are all the same, this should probably still be possible. 581 if (selection.length > 1) 582 return false; 583 584 if (!unitEntState.upgrade) 585 return false; 586 587 var items = []; 588 589 for (let upgrade of unitEntState.upgrade.upgrades) 590 { 591 var item = {}; 592 item.entType = upgrade.entity; 593 item.template = GetTemplateData(upgrade.entity); 594 if (!item.template) // abort if no template 595 return false; 596 597 item.icon = upgrade.icon; 598 if (!item.icon) 599 item.icon = "portraits/" + item.template.icon; 600 601 if (upgrade.requiredTechnology !== null) 602 { 603 item.requiredTechnology = upgrade.requiredTechnology; 604 if (!item.requiredTechnology && item.template.requiredTechnology) 605 item.requiredTechnology = item.template.requiredTechnology 606 } 607 item.cost = upgrade.cost; 608 item.time = upgrade.time; 609 610 if (unitEntState.upgrade.progress === undefined) 611 { 612 item.upgrading = UPGRADING_NOT_STARTED; 613 item.tooltip = sprintf(translate("Upgrade into a %(name)s.%(tooltip)s"), { name: item.template.name.generic, tooltip: (upgrade.tooltip? "\n" + upgrade.tooltip : "") }); 614 item.callback = function(data) { upgradeEntity(data.entType); }; 615 } 616 else if (unitEntState.upgrade.template !== upgrade.entity) 617 { 618 item.upgrading = UPGRADING_CHOSEN_OTHER; 619 item.tooltip = translate("Cannot upgrade when the entity is already upgrading."); 620 item.callback = function(data) { }; 621 } 622 else 623 { 624 item.upgrading = unitEntState.upgrade.progress; 625 item.tooltip = translate("Cancel Upgrading"); 626 item.callback = function(data) { cancelUpgradeEntity(); }; 627 } 628 items.push(item); 629 } 630 return items; 631 }, 632 "addData" : function(data) 633 { 634 data.item.technologyEnabled = true; 635 if (data.item.requiredTechnology) 636 data.item.technologyEnabled = Engine.GuiInterfaceCall("IsTechnologyResearched", data.item.requiredTechnology); 637 if (data.item.cost) 638 { 639 var totalCost = {}; 640 for (let i in data.item.cost) 641 totalCost[i] = data.item.cost[i]; 642 data.item.neededResources = Engine.GuiInterfaceCall("GetNeededResources", totalCost); 643 } 644 data.item.limits = getEntityLimitAndCount(data.playerState, data.item.entType); 645 return true; 646 }, 647 "setAction": function(data) 648 { 649 data.button.onPress = function() { data.item.callback(data.item); }; 650 }, 651 "setTooltip": function(data) 652 { 653 var tooltip = data.item.tooltip; 654 655 if (data.item.upgrading !== UPGRADING_NOT_STARTED) 656 { 657 data.button.tooltip = tooltip; 658 return; 659 } 660 661 if (data.item.cost) 662 tooltip += "\n" + getEntityCostTooltip(data.item); 663 664 tooltip += formatLimitString(data.item.limits.entLimit, data.item.limits.entCount, data.item.limits.entLimitChangers); 665 if (!data.item.technologyEnabled) 666 { 667 var techName = getEntityNames(GetTechnologyData(data.item.requiredTechnology)); 668 tooltip += "\n" + sprintf(translate("Requires %(technology)s"), { technology: techName }); 669 } 670 if (data.item.neededResources) 671 tooltip += getNeededResourcesTooltip(data.item.neededResources); 672 673 data.button.tooltip = tooltip; 674 }, 675 "setGraphics": function(data) 676 { 677 var grayscale = ""; 678 if (data.item.upgrading == UPGRADING_CHOSEN_OTHER || !data.item.technologyEnabled || (data.item.limits.canBeAddedCount == 0 && data.item.upgrading == UPGRADING_NOT_STARTED)) 679 { 680 data.button.enabled = false; 681 grayscale = "grayscale:"; 682 data.affordableMask.hidden = false; 683 data.affordableMask.sprite = "colour: 0 0 0 127"; 684 } 685 else if (data.item.upgrading == UPGRADING_NOT_STARTED && data.item.neededResources) 686 { 687 data.button.enabled = false; 688 data.affordableMask.hidden = false; 689 data.affordableMask.sprite = resourcesToAlphaMask(data.item.neededResources); 690 } 691 692 data.icon.sprite = "stretched:" + grayscale + "session/" + data.item.icon; 693 694 var guiObject = Engine.GetGUIObjectByName("unitUpgradeProgressSlider["+data.i+"]"); 695 var size = guiObject.size; 696 if (data.item.upgrading < 0) 697 size.top = size.right; 698 else 699 size.top = size.left + Math.round(Math.max(0,data.item.upgrading) * (size.right - size.left)); 700 guiObject.size = size; 701 }, 702 "setPosition": function(data) 703 { 704 var index = data.i + getNumberOfRightPanelButtons(); 705 setPanelObjectPosition(data.button, index, data.rowLength); 706 }, 707 }; 708 692 709 // QUEUE 693 710 g_SelectionPanels.Queue = { 694 711 "getMaxNumberOfItems": function() … … 1163 1180 "Stance", // normal together with formation 1164 1181 1165 1182 // RIGHT PANE 1166 "Gate", // must always be shown on gates1167 1183 "Pack", // must always be shown on packable entities 1184 "Upgrade", // must always be shown on upgradable entities 1168 1185 "Training", 1169 1186 "Construction", 1170 1187 "Research", // normal together with training -
data/mods/public/gui/session/selection_panels_helpers.js
8 8 // Gate constants 9 9 const GATE_ACTIONS = ["lock", "unlock"]; 10 10 11 // upgrade constants 12 const UPGRADING_NOT_STARTED = -2; 13 const UPGRADING_CHOSEN_OTHER = -1; 14 11 15 // ============================================== 12 16 // BARTER HELPERS 13 17 // Resources to sell on barter panel -
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> -
data/mods/public/gui/session/unit_commands.js
Property changes on: 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
1 1 // 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, "Alert": 0, "Barter": 0, "Construction": 0, "Command": 0, "AllyCommand": 0, "Stance": 0, " Gate": 0, "Pack": 0};2 var g_unitPanelButtons = {"Selection": 0, "Queue": 0, "Formation": 0, "Garrison": 0, "Training": 0, "Research": 0, "Alert": 0, "Barter": 0, "Construction": 0, "Command": 0, "AllyCommand": 0, "Stance": 0, "Pack": 0, "Upgrade": 0}; 3 3 4 4 /** 5 5 * Set the position of a panel object according to the index, … … 252 252 { 253 253 var sum = 0; 254 254 255 for (let prop of ["Construction", "Training", "Pack", " Gate"])255 for (let prop of ["Construction", "Training", "Pack", "Upgrade"]) 256 256 if (g_SelectionPanels[prop].used) 257 257 sum += g_unitPanelButtons[prop]; 258 258 -
data/mods/public/simulation/components/GuiInterface.js
236 236 "guard": null, 237 237 "mirage": null, 238 238 "pack": null, 239 "upgrade" : null, 239 240 "player": -1, 240 241 "position": null, 241 242 "production": null, … … 295 296 "progress": cmpPack.GetProgress(), 296 297 }; 297 298 299 var cmpUpgrade = Engine.QueryInterface(ent, IID_Upgrade); 300 if (cmpUpgrade) 301 ret.upgrade = { 302 "upgrades" : cmpUpgrade.GetUpgrades(), 303 "progress": cmpUpgrade.GetProgress(), 304 "template": cmpUpgrade.GetUpgradingTo() 305 }; 306 298 307 let cmpProductionQueue = Engine.QueryInterface(ent, IID_ProductionQueue); 299 308 if (cmpProductionQueue) 300 309 ret.production = { -
data/mods/public/simulation/components/Identity.js
40 40 "</element>" + 41 41 "</optional>" + 42 42 "<optional>" + 43 "<element name='GateConversionTooltip'>" +44 "<text/>" +45 "</element>" +46 "</optional>" +47 "<optional>" +48 43 "<element name='Rollover'>" + 49 44 "<text/>" + 50 45 "</element>" + -
data/mods/public/simulation/components/Pack.js
116 116 117 117 Pack.prototype.PackProgress = function(data, lateness) 118 118 { 119 if (this.elapsedTime >=this.GetPackTime())119 if (this.elapsedTime < this.GetPackTime()) 120 120 { 121 this.SetElapsedTime(this.GetElapsedTime() + PACKING_INTERVAL + lateness); 122 return; 123 } 124 121 125 this.CancelTimer(); 122 126 123 127 this.packed = !this.packed; 124 this.packing = false;125 128 Engine.PostMessage(this.entity, MT_PackFinished, { packed: this.packed }); 126 129 127 // Done un/packing, copy our parameters to the final entity 128 var newEntity = Engine.AddEntity(this.template.Entity); 129 if (newEntity == INVALID_ENTITY) 130 { 131 // Error (e.g. invalid template names) 132 error("PackProgress: Error creating entity for '" + this.template.Entity + "'"); 133 return; 134 } 130 var newEntity = ChangeEntityTemplate(this.entity, this.template.Entity); 135 131 136 var cmpPosition = Engine.QueryInterface(this.entity, IID_Position); 137 var cmpNewPosition = Engine.QueryInterface(newEntity, IID_Position); 138 if (cmpPosition.IsInWorld()) 132 if (newEntity) 139 133 { 140 var pos = cmpPosition.GetPosition2D();141 cmpNewPosition.JumpTo(pos.x, pos.y);142 }143 var rot = cmpPosition.GetRotation();144 cmpNewPosition.SetYRotation(rot.y);145 cmpNewPosition.SetXZRotation(rot.x, rot.z);146 cmpNewPosition.SetHeightOffset(cmpPosition.GetHeightOffset());147 148 var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);149 var cmpNewOwnership = Engine.QueryInterface(newEntity, IID_Ownership);150 cmpNewOwnership.SetOwner(cmpOwnership.GetOwner());151 152 // rescale capture points153 var cmpCapturable = Engine.QueryInterface(this.entity, IID_Capturable);154 var cmpNewCapturable = Engine.QueryInterface(newEntity, IID_Capturable);155 if (cmpCapturable && cmpNewCapturable)156 {157 let scale = cmpCapturable.GetMaxCapturePoints() / cmpNewCapturable.GetMaxCapturePoints();158 let newCp = cmpCapturable.GetCapturePoints().map(function (v) { return v / scale; });159 cmpNewCapturable.SetCapturePoints(newCp);160 }161 162 // Maintain current health level163 var cmpHealth = Engine.QueryInterface(this.entity, IID_Health);164 var cmpNewHealth = Engine.QueryInterface(newEntity, IID_Health);165 var healthLevel = Math.max(0, Math.min(1, cmpHealth.GetHitpoints() / cmpHealth.GetMaxHitpoints()));166 cmpNewHealth.SetHitpoints(Math.round(cmpNewHealth.GetMaxHitpoints() * healthLevel));167 168 var cmpUnitAI = Engine.QueryInterface(this.entity, IID_UnitAI);169 var cmpNewUnitAI = Engine.QueryInterface(newEntity, IID_UnitAI);170 if (cmpUnitAI && cmpNewUnitAI)171 {172 var pos = cmpUnitAI.GetHeldPosition();173 if (pos)174 cmpNewUnitAI.SetHeldPosition(pos.x, pos.z);175 if (cmpUnitAI.GetStanceName())176 cmpNewUnitAI.SwitchToStance(cmpUnitAI.GetStanceName());177 cmpNewUnitAI.AddOrders(cmpUnitAI.GetOrders());178 cmpNewUnitAI.SetGuardOf(cmpUnitAI.IsGuardOf());179 }180 181 // Maintain the list of guards182 var cmpGuard = Engine.QueryInterface(this.entity, IID_Guard);183 var cmpNewGuard = Engine.QueryInterface(newEntity, IID_Guard);184 if (cmpGuard && cmpNewGuard)185 cmpNewGuard.SetEntities(cmpGuard.GetEntities());186 187 Engine.BroadcastMessage(MT_EntityRenamed, { entity: this.entity, newentity: newEntity });188 189 // Play notification sound190 134 var sound = this.packed ? "packed" : "unpacked"; 191 135 PlaySound(sound, newEntity); 192 193 // Destroy current entity194 Engine.DestroyEntity(this.entity);195 136 } 196 else197 {198 this.SetElapsedTime(this.GetElapsedTime() + PACKING_INTERVAL + lateness);199 }200 137 }; 201 138 202 139 Engine.RegisterComponentType(IID_Pack, "Pack", Pack); -
data/mods/public/simulation/components/Upgrade.js
1 function Upgrade() {} 2 3 const UPGRADING_PROGRESS_INTERVAL = 250; 4 5 Upgrade.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 55 Upgrade.prototype.Init = function() 56 { 57 this.upgrading = false; 58 this.elapsedTime = 0; 59 this.timer = undefined; 60 61 this.upgradeTemplates = {}; 62 63 for (let choice in this.template) 64 { 65 let cmpIdentity = Engine.QueryInterface(this.entity, IID_Identity); 66 let name = this.template[choice].Entity; 67 if (cmpIdentity) 68 name = name.replace(/\{civ\}/g, cmpIdentity.GetCiv()); 69 if (this.upgradeTemplates.name != undefined) 70 warn("Upgrade Component: entity " + this.entity + " has two upgrades to the same entity, only the last will be used."); 71 this.upgradeTemplates[name] = choice; 72 } 73 }; 74 75 // On owner change, abort the upgrade 76 // This will also deal with the "OnDestroy" case. 77 Upgrade.prototype.OnOwnershipChanged = function(msg) 78 { 79 this.CancelUpgrade(); 80 81 if (msg.to !== -1) 82 this.owner = msg.to; 83 }; 84 85 Upgrade.prototype.ChangeUpgradedEntityCount = function(amount) 86 { 87 if (!this.IsUpgrading()) 88 return; 89 var cmpTempMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); 90 var template = cmpTempMan.GetTemplate(this.upgrading); 91 if (template.TrainingRestrictions) 92 var category = template.TrainingRestrictions.Category; 93 else if (template.BuildRestrictions) 94 var category = template.BuildRestrictions.Category; 95 96 var cmpEntityLimits = QueryPlayerIDInterface(this.owner, IID_EntityLimits); 97 cmpEntityLimits.ChangeCount(category,amount); 98 }; 99 100 Upgrade.prototype.CanUpgradeTo = function(template) 101 { 102 return this.upgradeTemplates[template] !== undefined; 103 }; 104 105 Upgrade.prototype.GetUpgrades = function() 106 { 107 var ret = []; 108 109 var cmpIdentity = Engine.QueryInterface(this.entity, IID_Identity); 110 111 for (let option in this.template) 112 { 113 let choice = this.template[option]; 114 let entType = choice.Entity; 115 if (cmpIdentity) 116 entType = entType.replace(/\{civ\}/g, cmpIdentity.GetCiv()); 117 118 let hasCosts = false; 119 let cost = {}; 120 if (choice.Cost) 121 { 122 hasCosts = true; 123 for (var type in choice.Cost) 124 cost[type] = ApplyValueModificationsToTemplate("Upgrade/Cost/"+type, +choice.Cost[type], this.owner, entType); 125 } 126 if (choice.Time) 127 { 128 hasCosts = true; 129 cost["time"] = ApplyValueModificationsToTemplate("Upgrade/Time", +choice.Time/1000.0, this.owner, entType); 130 } 131 ret.push( 132 { 133 "entity": entType, 134 "icon": choice.Icon || undefined, 135 "cost": hasCosts ? cost : undefined, 136 "tooltip": choice.Tooltip || undefined, 137 "requiredTechnology": "RequiredTechnology" in choice ? choice.RequiredTechnology : null, 138 }); 139 } 140 141 return ret; 142 }; 143 144 Upgrade.prototype.CancelTimer = function() 145 { 146 if (!this.timer) 147 return; 148 149 var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); 150 cmpTimer.CancelTimer(this.timer); 151 this.timer = undefined; 152 }; 153 154 Upgrade.prototype.IsUpgrading = function() 155 { 156 return this.upgrading !== false; 157 }; 158 159 Upgrade.prototype.GetUpgradingTo = function() 160 { 161 return this.upgrading; 162 }; 163 164 Upgrade.prototype.WillCheckPlacementRestrictions = function(template) 165 { 166 if (!this.upgradeTemplates[template]) 167 return undefined; 168 169 return this.template[this.upgradeTemplates[template]].CheckPlacementRestrictions != undefined; 170 }; 171 172 Upgrade.prototype.GetRequiredTechnology = function(templateArg) 173 { 174 if (!this.upgradeTemplates[templateArg]) 175 return undefined; 176 177 var choice = this.upgradeTemplates[templateArg]; 178 179 if ("RequiredTechnology" in this.template[choice] && this.template[choice].RequiredTechnology === undefined) 180 { 181 var cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); 182 var template = cmpTemplateManager.GetTemplate(this.template[choice].Entity); 183 if (template.Identity.RequiredTechnology) 184 return template.Identity.RequiredTechnology; 185 } 186 else if ("RequiredTechnology" in this.template[choice]) 187 return this.template[choice].RequiredTechnology; 188 189 return null; 190 }; 191 192 Upgrade.prototype.GetResourceCosts = function(template) 193 { 194 if (!this.upgradeTemplates[template]) 195 return undefined; 196 197 var choice = this.upgradeTemplates[template]; 198 if (!this.template[choice].Cost) 199 return {}; 200 201 var costs = {}; 202 for (var r in this.template[choice].Cost) 203 { 204 costs[r] = +this.template[choice].Cost[r]; 205 costs[r] = ApplyValueModificationsToEntity("Upgrade/Cost/"+r, costs[r], this.entity); 206 } 207 return costs; 208 }; 209 210 Upgrade.prototype.Upgrade = function(template) 211 { 212 if (this.IsUpgrading()) 213 return false; 214 215 if (!this.upgradeTemplates[template]) 216 return false; 217 218 var cmpPlayer = QueryOwnerInterface(this.entity, IID_Player); 219 220 if (!cmpPlayer.TrySubtractResources(this.GetResourceCosts(template))) 221 return false; 222 223 this.upgrading = template; 224 225 // Prevent cheating 226 this.ChangeUpgradedEntityCount(1); 227 228 if (this.GetUpgradeTime(template) !== 0) 229 { 230 var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); 231 this.timer = cmpTimer.SetInterval(this.entity, IID_Upgrade, "UpgradeProgress", 0, UPGRADING_PROGRESS_INTERVAL, { "upgrading": template }); 232 } 233 else 234 this.UpgradeProgress(); 235 236 return true; 237 }; 238 239 Upgrade.prototype.CancelUpgrade = function() 240 { 241 if (this.IsUpgrading() === false) 242 return; 243 244 var cmpPlayer = QueryOwnerInterface(this.entity, IID_Player); 245 if (cmpPlayer) 246 { 247 var costs = this.GetResourceCosts(this.upgrading); 248 cmpPlayer.AddResources(costs); 249 } 250 251 this.ChangeUpgradedEntityCount(-1); 252 253 this.upgrading = false; 254 this.CancelTimer(); 255 this.SetElapsedTime(0); 256 }; 257 258 Upgrade.prototype.GetUpgradeTime = function(templateArg) 259 { 260 var template = this.upgrading || templateArg; 261 var choice = this.upgradeTemplates[template]; 262 if (!choice) 263 return undefined; 264 return this.template[choice].Time ? ApplyValueModificationsToEntity("Upgrade/Time", +this.template[choice].Time, this.entity) : 0; 265 }; 266 267 Upgrade.prototype.GetElapsedTime = function() 268 { 269 return this.elapsedTime; 270 }; 271 272 Upgrade.prototype.GetProgress = function() 273 { 274 if (!this.IsUpgrading()) 275 return undefined; 276 return this.GetUpgradeTime() == 0 ? 1 : this.elapsedTime / this.GetUpgradeTime(); 277 }; 278 279 Upgrade.prototype.SetElapsedTime = function(time) 280 { 281 this.elapsedTime = time; 282 }; 283 284 Upgrade.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 if (newEntity) 297 PlaySound("upgraded", newEntity); 298 }; 299 300 Engine.RegisterComponentType(IID_Upgrade, "Upgrade", Upgrade); -
data/mods/public/simulation/components/interfaces/Upgrade.js
Property changes on: data/mods/public/simulation/components/Upgrade.js ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property
1 Engine.RegisterInterface("Upgrade"); -
data/mods/public/simulation/helpers/Commands.js
Property changes on: data/mods/public/simulation/components/interfaces/Upgrade.js ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property
578 578 } 579 579 }, 580 580 581 "wall-to-gate": function(player, cmd, data)582 {583 for (let ent of data.entities)584 TryTransformWallToGate(ent, data.cmpPlayer, cmd);585 },586 587 581 "lock-gate": function(player, cmd, data) 588 582 { 589 583 for (let ent of data.entities) … … 668 662 } 669 663 }, 670 664 665 "upgrade": function(player, cmd, data) 666 { 667 for (let ent of data.entities) 668 { 669 var cmpUpgrade = Engine.QueryInterface(ent, IID_Upgrade); 670 671 if (!cmpUpgrade || !cmpUpgrade.CanUpgradeTo(cmd.template)) 672 continue; 673 674 if (cmpUpgrade.WillCheckPlacementRestrictions(cmd.template) && ObstructionsBlockingTemplateChange(ent, cmd.template)) 675 { 676 var notification = { "players": [data.cmpPlayer.GetPlayerID()], "message": "Cannot upgrade as distance requirements are not verified or terrain is obstructed." }; 677 var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface); 678 cmpGUIInterface.PushNotification(notification); 679 continue; 680 } 681 682 if (!CanGarrisonedChangeTemplate(ent, cmd.template)) 683 { 684 var notification = { "players": [data.cmpPlayer.GetPlayerID()], "message": "Cannot upgrade a garrisoned entity." }; 685 var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface); 686 cmpGUIInterface.PushNotification(notification); 687 continue; 688 } 689 690 // Check entity limits 691 var cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); 692 var template = cmpTemplateManager.GetTemplate(cmd.template); 693 var cmpEntityLimits = QueryPlayerIDInterface(player, IID_EntityLimits); 694 if ((template.TrainingRestrictions && !cmpEntityLimits.AllowedToTrain(template.TrainingRestrictions.Category, 1)) 695 || (template.BuildRestrictions && !cmpEntityLimits.AllowedToBuild(template.BuildRestrictions.Category))) 696 { 697 if (g_DebugCommands) 698 warn("Invalid command: build limits check failed for player " + player + ": " + uneval(cmd)); 699 continue; 700 } 701 702 var cmpTechnologyManager = QueryOwnerInterface(ent, IID_TechnologyManager); 703 if (cmpUpgrade.GetRequiredTechnology() && !cmpTechnologyManager.IsTechnologyResearched(cmpUpgrade.GetRequiredTechnology())) 704 { 705 if (g_DebugCommands) 706 warn("Invalid command: upgrading requires unresearched technology: " + uneval(cmd)); 707 continue; 708 } 709 710 cmpUpgrade.Upgrade(cmd.template, data.cmpPlayer); 711 } 712 }, 713 714 "cancel-upgrade": function(player, cmd, data) 715 { 716 for (let ent of data.entities) 717 { 718 var cmpUpgrade = Engine.QueryInterface(ent, IID_Upgrade); 719 if (cmpUpgrade) 720 cmpUpgrade.CancelUpgrade(data.cmpPlayer); 721 } 722 }, 723 671 724 "attack-request": function(player, cmd, data) 672 725 { 673 726 // Send a chat message to human players … … 1567 1620 return entities.filter(ent => CanControlUnitOrIsAlly(ent, player, controlAll)); 1568 1621 } 1569 1622 1570 /**1571 * Try to transform a wall to a gate1572 */1573 function TryTransformWallToGate(ent, cmpPlayer, cmd)1574 {1575 var cmpIdentity = Engine.QueryInterface(ent, IID_Identity);1576 if (!cmpIdentity)1577 return;1578 1579 if (!cmpIdentity.HasClass("LongWall"))1580 {1581 if (g_DebugCommands)1582 warn("Invalid command: invalid wall conversion to gate for player "+player+": "+uneval(cmd));1583 return;1584 }1585 1586 var civ = cmpIdentity.GetCiv();1587 var gate = Engine.AddEntity(cmd.template);1588 1589 var cmpCost = Engine.QueryInterface(gate, IID_Cost);1590 if (!cmpPlayer.TrySubtractResources(cmpCost.GetResourceCosts()))1591 {1592 if (g_DebugCommands)1593 warn("Invalid command: convert gate cost check failed for player "+player+": "+uneval(cmd));1594 1595 Engine.DestroyEntity(gate);1596 return;1597 }1598 1599 ReplaceBuildingWith(ent, gate);1600 }1601 1602 /**1603 * Unconditionally replace a building with another one1604 */1605 function ReplaceBuildingWith(ent, building)1606 {1607 // Move the building to the right place1608 var cmpPosition = Engine.QueryInterface(ent, IID_Position);1609 var cmpBuildingPosition = Engine.QueryInterface(building, IID_Position);1610 var pos = cmpPosition.GetPosition2D();1611 cmpBuildingPosition.JumpTo(pos.x, pos.y);1612 var rot = cmpPosition.GetRotation();1613 cmpBuildingPosition.SetYRotation(rot.y);1614 cmpBuildingPosition.SetXZRotation(rot.x, rot.z);1615 1616 // Copy ownership1617 var cmpOwnership = Engine.QueryInterface(ent, IID_Ownership);1618 var cmpBuildingOwnership = Engine.QueryInterface(building, IID_Ownership);1619 cmpBuildingOwnership.SetOwner(cmpOwnership.GetOwner());1620 1621 // Copy control groups1622 var cmpObstruction = Engine.QueryInterface(ent, IID_Obstruction);1623 var cmpBuildingObstruction = Engine.QueryInterface(building, IID_Obstruction);1624 cmpBuildingObstruction.SetControlGroup(cmpObstruction.GetControlGroup());1625 cmpBuildingObstruction.SetControlGroup2(cmpObstruction.GetControlGroup2());1626 1627 // Copy health level from the old entity to the new1628 var cmpHealth = Engine.QueryInterface(ent, IID_Health);1629 var cmpBuildingHealth = Engine.QueryInterface(building, IID_Health);1630 var healthFraction = Math.max(0, Math.min(1, cmpHealth.GetHitpoints() / cmpHealth.GetMaxHitpoints()));1631 var buildingHitpoints = Math.round(cmpBuildingHealth.GetMaxHitpoints() * healthFraction);1632 cmpBuildingHealth.SetHitpoints(buildingHitpoints);1633 1634 PlaySound("constructed", building);1635 1636 Engine.PostMessage(ent, MT_ConstructionFinished,1637 { "entity": ent, "newentity": building });1638 Engine.BroadcastMessage(MT_EntityRenamed, { entity: ent, newentity: building });1639 1640 Engine.DestroyEntity(ent);1641 }1642 1643 1623 Engine.RegisterGlobal("GetFormationRequirements", GetFormationRequirements); 1644 1624 Engine.RegisterGlobal("CanMoveEntsIntoFormation", CanMoveEntsIntoFormation); 1645 1625 Engine.RegisterGlobal("GetDockAngle", GetDockAngle); -
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. 4 var 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 // rescale capture points 45 var cmpCapturable = Engine.QueryInterface(oldEnt, IID_Capturable); 46 var cmpNewCapturable = Engine.QueryInterface(newEnt, IID_Capturable); 47 if (cmpCapturable && cmpNewCapturable) 48 { 49 let scale = cmpCapturable.GetMaxCapturePoints() / cmpNewCapturable.GetMaxCapturePoints(); 50 let newCp = cmpCapturable.GetCapturePoints().map(function (v) { return v / scale; }); 51 cmpNewCapturable.SetCapturePoints(newCp); 52 } 53 54 // Maintain current health level 55 var cmpHealth = Engine.QueryInterface(oldEnt, IID_Health); 56 var cmpNewHealth = Engine.QueryInterface(newEnt, IID_Health); 57 if (cmpHealth && cmpNewHealth) 58 { 59 var healthLevel = Math.max(0, Math.min(1, cmpHealth.GetHitpoints() / cmpHealth.GetMaxHitpoints())); 60 cmpNewHealth.SetHitpoints(Math.round(cmpNewHealth.GetMaxHitpoints() * healthLevel)); 61 } 62 63 var cmpUnitAI = Engine.QueryInterface(oldEnt, IID_UnitAI); 64 var cmpNewUnitAI = Engine.QueryInterface(newEnt, IID_UnitAI); 65 if (cmpUnitAI && cmpNewUnitAI) 66 { 67 var pos = cmpUnitAI.GetHeldPosition(); 68 if (pos) 69 cmpNewUnitAI.SetHeldPosition(pos.x, pos.z); 70 if (cmpUnitAI.GetStanceName()) 71 cmpNewUnitAI.SwitchToStance(cmpUnitAI.GetStanceName()); 72 cmpNewUnitAI.AddOrders(cmpUnitAI.GetOrders()); 73 cmpNewUnitAI.SetGuardOf(cmpUnitAI.IsGuardOf()); 74 } 75 76 // Maintain the list of guards 77 var cmpGuard = Engine.QueryInterface(oldEnt, IID_Guard); 78 var cmpNewGuard = Engine.QueryInterface(newEnt, IID_Guard); 79 if (cmpGuard && cmpNewGuard) 80 cmpNewGuard.SetEntities(cmpGuard.GetEntities()); 81 82 TransferGarrisonedUnits(oldEnt, newEnt); 83 84 Engine.BroadcastMessage(MT_EntityRenamed, { entity: oldEnt, newentity: newEnt }); 85 86 // Destroy current entity 87 Engine.DestroyEntity(oldEnt); 88 89 return newEnt; 90 }; 91 92 var CanGarrisonedChangeTemplate = function(ent, template) 93 { 94 var cmpPosition = Engine.QueryInterface(ent, IID_Position); 95 var unitAI = Engine.QueryInterface(ent, IID_UnitAI); 96 if (cmpPosition && !cmpPosition.IsInWorld() && unitAI && unitAI.IsGarrisoned()) 97 { 98 // We're a garrisoned unit, assume impossibility as I've been unable to find a way to get the holder ID. 99 // TODO: change this if that ever becomes possibles 100 return false; 101 } 102 return true; 103 } 104 105 var ObstructionsBlockingTemplateChange = function(ent, templateArg) 106 { 107 var previewEntity = Engine.AddEntity("preview|"+templateArg); 108 109 if (previewEntity == INVALID_ENTITY) 110 return true; 111 112 var cmpBuildRestrictions = Engine.QueryInterface(previewEntity, IID_BuildRestrictions); 113 var cmpPosition = Engine.QueryInterface(ent, IID_Position); 114 var cmpOwnership = Engine.QueryInterface(ent, IID_Ownership); 115 116 var cmpNewPosition = Engine.QueryInterface(previewEntity, IID_Position); 117 118 // Return false if no ownership as BuildRestrictions.CheckPlacement needs an owner and I have no idea if false or true is better 119 // Plus there are no real entities without owners currently. 120 if (!cmpBuildRestrictions || !cmpPosition || !cmpOwnership) 121 return DeleteEntityAndReturn(previewEntity, cmpPosition, pos, angle, cmpNewPosition, false); 122 123 var pos = cmpPosition.GetPosition2D(); 124 var angle = cmpPosition.GetRotation(); 125 // move us away to prevent our own obstruction from blocking the upgrade. 126 cmpPosition.MoveOutOfWorld(); 127 128 cmpNewPosition.JumpTo(pos.x, pos.y); 129 cmpNewPosition.SetYRotation(angle.y); 130 131 var cmpNewOwnership = Engine.QueryInterface(previewEntity, IID_Ownership); 132 cmpNewOwnership.SetOwner(cmpOwnership.GetOwner()); 133 134 var checkPlacement = cmpBuildRestrictions.CheckPlacement(); 135 136 if (checkPlacement && !checkPlacement.success) 137 return DeleteEntityAndReturn(previewEntity, cmpPosition, pos, angle, cmpNewPosition, true); 138 139 var cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); 140 var template = cmpTemplateManager.GetTemplate(cmpTemplateManager.GetCurrentTemplateName(ent)); 141 var newTemplate = cmpTemplateManager.GetTemplate(templateArg); 142 143 // Check if units are blocking our template change 144 if (template.Obstruction && newTemplate.Obstruction) 145 { 146 // This only needs to be done if the new template is strictly bigger than the old one 147 // "Obstructions" are annoying to test so just check. 148 // This is kind of ugly, sorry about that. 149 if (newTemplate.Obstruction.Obstructions 150 151 || (newTemplate.Obstruction.Static && template.Obstruction.Static 152 && (newTemplate.Obstruction.Static["@width"] > template.Obstruction.Static["@width"] 153 || newTemplate.Obstruction.Static["@depth"] > template.Obstruction.Static["@depth"])) 154 || (newTemplate.Obstruction.Static && template.Obstruction.Unit 155 && (newTemplate.Obstruction.Static["@width"] > template.Obstruction.Unit["@radius"] 156 || newTemplate.Obstruction.Static["@depth"] > template.Obstruction.Unit["@radius"])) 157 158 || (newTemplate.Obstruction.Unit && template.Obstruction.Unit 159 && newTemplate.Obstruction.Unit["@radius"] > template.Obstruction.Unit["@radius"]) 160 || (newTemplate.Obstruction.Unit && template.Obstruction.Static 161 && (newTemplate.Obstruction.Unit["@radius"] > template.Obstruction.Static["@width"] 162 || newTemplate.Obstruction.Unit["@radius"] > template.Obstruction.Static["@depth"]))) 163 { 164 var cmpNewObstruction = Engine.QueryInterface(previewEntity, IID_Obstruction); 165 if (cmpNewObstruction && cmpNewObstruction.GetBlockMovementFlag()) 166 { 167 // Check for units 168 var collisions = cmpNewObstruction.GetEntityCollisions(false, true); 169 if (collisions.length !== 0) 170 return DeleteEntityAndReturn(previewEntity, cmpPosition, pos, angle, cmpNewPosition, true); 171 } 172 } 173 } 174 175 return DeleteEntityAndReturn(previewEntity, cmpPosition, pos, angle, cmpNewPosition, false); 176 }; 177 178 var DeleteEntityAndReturn = function(ent, cmpPosition, position, angle, cmpNewPosition, ret) 179 { 180 cmpNewPosition.MoveOutOfWorld(); // prevent preview from interfering in the world 181 cmpPosition.JumpTo(position.x, position.y); 182 cmpPosition.SetYRotation(angle.y); 183 184 Engine.DestroyEntity(ent); 185 return ret; 186 }; 187 188 var TransferGarrisonedUnits = function(oldEnt, newEnt) 189 { 190 // Transfer garrisoned units if possible, or unload them 191 var cmpGarrison = Engine.QueryInterface(oldEnt, IID_GarrisonHolder); 192 var cmpNewGarrison = Engine.QueryInterface(newEnt, IID_GarrisonHolder); 193 if (!cmpNewGarrison || !cmpGarrison || cmpGarrison.GetEntities().length === 0 ) 194 return; // nothing to do as the code will by default unload all. 195 196 var garrisonedEntities = cmpGarrison.GetEntities().slice(); 197 for (var j = 0; j < garrisonedEntities.length; ++j) 198 { 199 var cmpUnitAI = Engine.QueryInterface(garrisonedEntities[j], IID_UnitAI); 200 cmpGarrison.Eject(garrisonedEntities[j]); 201 cmpUnitAI.Autogarrison(newEnt); 202 cmpNewGarrison.Garrison(garrisonedEntities[j]); 203 } 204 }; 205 206 Engine.RegisterGlobal("ChangeEntityTemplate", ChangeEntityTemplate); 207 Engine.RegisterGlobal("CanGarrisonedChangeTemplate", CanGarrisonedChangeTemplate); 208 Engine.RegisterGlobal("ObstructionsBlockingTemplateChange", ObstructionsBlockingTemplateChange); -
data/mods/public/simulation/templates/other/palisades_rocks_long.xml
Property changes on: data/mods/public/simulation/helpers/Transform.js ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property
26 26 <SelectionGroupName>other/wallset_palisade</SelectionGroupName> 27 27 <SpecificName>Palisade</SpecificName> 28 28 <GenericName>Wooden Wall</GenericName> 29 <GateConversionTooltip>Convert Wooden Wall into Wooden Gate</GateConversionTooltip>30 29 <Classes datatype="tokens">-StoneWall Palisade</Classes> 31 30 <Icon>gaia/special_palisade.png</Icon> 32 31 <RequiredTechnology>phase_village</RequiredTechnology> … … 45 44 <WallPiece> 46 45 <Length>11.0</Length> 47 46 </WallPiece> 47 <Upgrade> 48 <Gate> 49 <Entity>other/palisades_rocks_gate</Entity> 50 <Cost> 51 <stone>0</stone> 52 <wood>20</wood> 53 </Cost> 54 <Time>5000</Time> 55 </Gate> 56 </Upgrade> 48 57 </Entity> -
data/mods/public/simulation/templates/structures/rome_siege_wall_long.xml
55 55 </Classes> 56 56 <Icon>structures/palisade_wall.png</Icon> 57 57 <Tooltip>A wooden and turf palisade buildable in enemy and neutral territories.</Tooltip> 58 <GateConversionTooltip>Convert Siege Wall into Siege Wall Gate</GateConversionTooltip>59 58 <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> 60 59 </Identity> 61 60 <Obstruction> -
data/mods/public/simulation/templates/template_structure_defense_wall_long.xml
43 43 <Identity> 44 44 <Classes datatype="tokens">LongWall</Classes> 45 45 <Tooltip>Long wall segments can be converted to gates.</Tooltip> 46 <GateConversionTooltip>Convert Stone Wall into City Gate</GateConversionTooltip>47 46 </Identity> 47 <Upgrade> 48 <Gate> 49 <Entity>structures/{civ}_wall_gate</Entity> 50 <Tooltip>This will allow you to let units circulate through your fortifications.</Tooltip> 51 <Cost> 52 <stone>60</stone> 53 </Cost> 54 <Time>10000</Time> 55 </Gate> 56 </Upgrade> 48 57 </Entity>