Ticket #2706: UpgradeComponent.6.patch
File UpgradeComponent.6.patch, 45.9 KB (added by , 8 years ago) |
---|
-
data/mods/public/globalscripts/Templates.js
226 226 }; 227 227 ret.icon = template.Identity.Icon; 228 228 ret.tooltip = template.Identity.Tooltip; 229 ret.gateConversionTooltip = template.Identity.GateConversionTooltip;230 229 ret.requiredTechnology = template.Identity.RequiredTechnology; 231 230 ret.visibleIdentityClasses = GetVisibleIdentityClasses(template.Identity); 232 231 } -
data/mods/public/gui/session/unit_commands.js
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, "Gate": 0, "Pack": 0, "Upgrade": 0}; 3 3 4 4 /** 5 5 * Set the position of a panel object according to the index, … … 279 279 sum += g_unitPanelButtons["Pack"]; 280 280 if (g_SelectionPanels["Gate"].used) 281 281 sum += g_unitPanelButtons["Gate"]; 282 if (g_SelectionPanels["Upgrade"].used) 283 sum += g_unitPanelButtons["Upgrade"]; 282 284 return sum; 283 285 } -
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.js
472 472 }, 473 473 "getItems": function(unitEntState, selection) 474 474 { 475 // Allow long wall pieces to be converted to gates476 var longWallTypes = {};477 var walls = [];478 475 var gates = []; 479 476 for (var ent of selection) 480 477 { 481 478 var state = GetEntityState(ent); 482 if ( hasClass(state, "LongWall") && !state.gate && !longWallTypes[state.template])479 if (state.gate && !gates.length) 483 480 { 484 var gateTemplate = getWallGateTemplate(state.id);485 if (gateTemplate)486 {487 var tooltipString = GetTemplateDataWithoutLocalization(state.template).gateConversionTooltip;488 if (!tooltipString)489 {490 warn(state.template + " is supposed to be convertable to a gate, but it's missing the GateConversionTooltip in the Identity template");491 tooltipString = "";492 }493 walls.push({494 "tooltip": translate(tooltipString),495 "template": gateTemplate,496 "callback": function (item) { transformWallToGate(item.template); }497 });498 }499 500 // We only need one entity per type.501 longWallTypes[state.template] = true;502 }503 else if (state.gate && !gates.length)504 {505 481 gates.push({ 506 482 "gate": state.gate, 507 483 "tooltip": translate("Lock Gate"), … … 520 496 for (var j = 0; j < gates.length; ++j) 521 497 delete gates[j].gate.locked; 522 498 } 523 524 // Place wall conversion options after gate lock/unlock icons. 525 var items = gates.concat(walls); 526 return items; 499 return gates; 527 500 }, 528 501 "setAction": function(data) 529 502 { … … 531 504 }, 532 505 "setTooltip": function(data) 533 506 { 534 var tooltip = data.item.tooltip; 535 if (data.item.template) 536 { 537 data.template = GetTemplateData(data.item.template); 538 data.wallCount = data.selection.reduce(function (count, ent) { 539 var state = GetEntityState(ent); 540 if (hasClass(state, "LongWall") && !state.gate) 541 count++; 542 return count; 543 }, 0); 544 545 tooltip += "\n" + getEntityCostTooltip(data.template, data.wallCount); 546 547 548 data.neededResources = Engine.GuiInterfaceCall("GetNeededResources", multiplyEntityCosts(data.template, data.wallCount)); 549 if (data.neededResources) 550 tooltip += getNeededResourcesTooltip(data.neededResources); 551 } 552 data.button.tooltip = tooltip; 507 data.button.tooltip = data.item.tooltip; 553 508 }, 554 509 "setGraphics": function(data) 555 510 { 556 data.affordableMask.hidden = !data.neededResources;557 511 var gateIcon; 558 512 if (data.item.gate) 559 513 { 560 // If already a gate, show locking actions514 // Show locking actions 561 515 gateIcon = "icons/lock_" + GATE_ACTIONS[data.item.locked ? 0 : 1] + "ed.png"; 562 516 if (data.item.gate.locked === undefined) 563 517 data.guiSelection.hidden = false; … … 564 518 else 565 519 data.guiSelection.hidden = data.item.gate.locked != data.item.locked; 566 520 } 567 else568 {569 // otherwise show gate upgrade icon570 var template = GetTemplateData(data.item.template);571 if (!template)572 return;573 gateIcon = data.template.icon ? "portraits/" + data.template.icon : "icons/gate_closed.png";574 data.guiSelection.hidden = true;575 }576 577 521 data.icon.sprite = "stretched:session/" + gateIcon; 578 522 }, 579 523 "setPosition": function(data) … … 648 592 }, 649 593 }; 650 594 595 // UPGRADE 596 g_SelectionPanels.Upgrade = { 597 "getMaxNumberOfItems": function() 598 { 599 return 24 - getNumberOfRightPanelButtons(); 600 }, 601 "getItems": function(unitEntState, selection) 602 { 603 // Interface becomes complicated with multiple units and this is meant per-entity, so prevent it if the selection has multiple units. 604 // TODO: if the units are all the same, this should probably still be possible. 605 if (selection.length > 1) 606 return false; 607 608 if (!unitEntState.upgrade) 609 return false; 610 611 var items = []; 612 613 for (let upgrade of unitEntState.upgrade.upgrades) 614 { 615 var item = {}; 616 item.entType = upgrade.entity; 617 item.template = GetTemplateData(upgrade.entity); 618 if (!item.template) // abort if no template 619 return false; 620 621 item.icon = upgrade.icon; 622 if (!item.icon) 623 item.icon = "portraits/" + item.template.icon; 624 625 if (upgrade.requiredTechnology !== null) 626 { 627 item.requiredTechnology = upgrade.requiredTechnology; 628 if (!item.requiredTechnology && item.template.requiredTechnology) 629 item.requiredTechnology = item.template.requiredTechnology 630 } 631 item.cost = upgrade.cost; 632 item.time = upgrade.time; 633 634 if (unitEntState.upgrade.progress === undefined) 635 { 636 item.upgrading = UPGRADING_NOT_STARTED; 637 item.tooltip = sprintf(translate("Upgrade into a %(name)s.%(tooltip)s"), { name: item.template.name.generic, tooltip: (upgrade.tooltip? "\n" + upgrade.tooltip : "") }); 638 item.callback = function(data) { upgradeEntity(data.entType); }; 639 } 640 else if (unitEntState.upgrade.template !== upgrade.entity) 641 { 642 item.upgrading = UPGRADING_CHOSEN_OTHER; 643 item.tooltip = translate("Cannot upgrade when the entity is already upgrading."); 644 item.callback = function(data) { }; 645 } 646 else 647 { 648 item.upgrading = unitEntState.upgrade.progress; 649 item.tooltip = translate("Cancel Upgrading"); 650 item.callback = function(data) { cancelUpgradeEntity(); }; 651 } 652 items.push(item); 653 } 654 return items; 655 }, 656 "addData" : function(data) 657 { 658 data.item.technologyEnabled = true; 659 if (data.item.requiredTechnology) 660 data.item.technologyEnabled = Engine.GuiInterfaceCall("IsTechnologyResearched", data.item.requiredTechnology); 661 if (data.item.cost) 662 { 663 var totalCost = {}; 664 for (let i in data.item.cost) 665 totalCost[i] = data.item.cost[i]; 666 data.item.neededResources = Engine.GuiInterfaceCall("GetNeededResources", totalCost); 667 } 668 data.item.limits = getEntityLimitAndCount(data.playerState, data.item.entType); 669 return true; 670 }, 671 "setAction": function(data) 672 { 673 data.button.onPress = function() { data.item.callback(data.item); }; 674 }, 675 "setTooltip": function(data) 676 { 677 var tooltip = data.item.tooltip; 678 679 if (data.item.upgrading !== UPGRADING_NOT_STARTED) 680 { 681 data.button.tooltip = tooltip; 682 return; 683 } 684 685 if (data.item.cost) 686 tooltip += "\n" + getEntityCostTooltip(data.item); 687 688 tooltip += formatLimitString(data.item.limits.entLimit, data.item.limits.entCount, data.item.limits.entLimitChangers); 689 if (!data.item.technologyEnabled) 690 { 691 var techName = getEntityNames(GetTechnologyData(data.item.requiredTechnology)); 692 tooltip += "\n" + sprintf(translate("Requires %(technology)s"), { technology: techName }); 693 } 694 if (data.item.neededResources) 695 tooltip += getNeededResourcesTooltip(data.item.neededResources); 696 697 data.button.tooltip = tooltip; 698 }, 699 "setGraphics": function(data) 700 { 701 var grayscale = ""; 702 if (data.item.upgrading == UPGRADING_CHOSEN_OTHER || !data.item.technologyEnabled || (data.item.limits.canBeAddedCount == 0 && data.item.upgrading == UPGRADING_NOT_STARTED)) 703 { 704 data.button.enabled = false; 705 grayscale = "grayscale:"; 706 data.affordableMask.hidden = false; 707 data.affordableMask.sprite = "colour: 0 0 0 127"; 708 } 709 else if (data.item.upgrading == UPGRADING_NOT_STARTED && data.item.neededResources) 710 { 711 data.button.enabled = false; 712 data.affordableMask.hidden = false; 713 data.affordableMask.sprite = resourcesToAlphaMask(data.item.neededResources); 714 } 715 716 data.icon.sprite = "stretched:" + grayscale + "session/" + data.item.icon; 717 718 var guiObject = Engine.GetGUIObjectByName("unitUpgradeProgressSlider["+data.i+"]"); 719 var size = guiObject.size; 720 if (data.item.upgrading < 0) 721 size.top = size.right; 722 else 723 size.top = size.left + Math.round(Math.max(0,data.item.upgrading) * (size.right - size.left)); 724 guiObject.size = size; 725 }, 726 "setPosition": function(data) 727 { 728 var index = data.i + getNumberOfRightPanelButtons(); 729 setPanelObjectPosition(data.button, index, data.rowLength); 730 }, 731 }; 732 651 733 // QUEUE 652 734 g_SelectionPanels.Queue = { 653 735 "getMaxNumberOfItems": function() … … 1139 1221 // RIGHT PANE 1140 1222 "Gate", // must always be shown on gates 1141 1223 "Pack", // must always be shown on packable entities 1224 "Upgrade", // must always be shown on upgradable entities 1142 1225 "Training", 1143 1226 "Construction", 1144 1227 "Research", // normal together with training -
data/mods/public/gui/session/input.js
1643 1643 }); 1644 1644 } 1645 1645 1646 // Transform a wall to a gate1647 function transformWallToGate(template)1646 // Upgrade an entity to another 1647 function upgradeEntity(Template) 1648 1648 { 1649 1649 var selection = g_Selection.toList(); 1650 1650 Engine.PostNetworkCommand({ 1651 "type": "wall-to-gate", 1652 "entities": selection.filter( function(e) { return getWallGateTemplate(e) == template; } ), 1653 "template": template, 1651 "type": "upgrade", 1652 "entities": selection, 1653 "template": Template, 1654 "queued": false 1654 1655 }); 1655 1656 } 1656 1657 1657 // Gets the gate form (if any) of a given long wall piece1658 function getWallGateTemplate(entity)1658 // Cancel upgrading entities 1659 function cancelUpgradeEntity() 1659 1660 { 1660 // TODO: find the gate template name in a better way 1661 var entState = GetEntityState(entity); 1662 var index; 1663 1664 if (entState && !entState.foundation && hasClass(entState, "LongWall") && (index = entState.template.indexOf("long")) >= 0) 1665 return entState.template.substr(0, index) + "gate"; 1666 return undefined; 1661 var selection = g_Selection.toList(); 1662 Engine.PostNetworkCommand({ 1663 "type": "cancel-upgrade", 1664 "entities": selection, 1665 "queued": false 1666 }); 1667 1667 } 1668 1668 1669 1669 // Set the camera to follow the given unit -
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/selection_panels_right/gate_panel.xml
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
7 7 <object name="unitGateButton[n]" hidden="true" style="iconButton" type="button" size="0 0 46 46" tooltip_style="sessionToolTipBottom"> 8 8 <object name="unitGateIcon[n]" type="image" ghost="true" size="3 3 43 43"/> 9 9 <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="color: 255 0 0 127"/>11 10 </object> 12 11 </repeat> 13 12 </object> -
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/Pack.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
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/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/GuiInterface.js
232 232 "guard": null, 233 233 "mirage": null, 234 234 "pack": null, 235 "upgrade" : null, 235 236 "player": -1, 236 237 "position": null, 237 238 "production": null, … … 295 296 }; 296 297 } 297 298 299 var cmpUpgrade = Engine.QueryInterface(ent, IID_Upgrade); 300 if (cmpUpgrade) 301 { 302 ret.upgrade = { 303 "upgrades" : cmpUpgrade.GetUpgrades(), 304 "progress": cmpUpgrade.GetProgress(), 305 "template": cmpUpgrade.GetUpgradingTo() 306 }; 307 } 308 298 309 var cmpProductionQueue = Engine.QueryInterface(ent, IID_ProductionQueue); 299 310 if (cmpProductionQueue) 300 311 { -
data/mods/public/simulation/components/interfaces/Upgrade.js
1 Engine.RegisterInterface("Upgrade"); -
data/mods/public/simulation/helpers/Transform.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
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/helpers/Commands.js
Property changes on: data/mods/public/simulation/helpers/Transform.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 each (var ent in data.entities)584 {585 TryTransformWallToGate(ent, data.cmpPlayer, cmd.template);586 }587 },588 589 581 "lock-gate": function(player, cmd, data) 590 582 { 591 583 for each (var ent in data.entities) … … 670 662 } 671 663 }, 672 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 673 724 "attack-request": function(player, cmd, data) 674 725 { 675 726 // Send a chat message to human players … … 1563 1614 return entities.filter(function(ent) { return CanControlUnitOrIsAlly(ent, player, controlAll);} ); 1564 1615 } 1565 1616 1566 /**1567 * Try to transform a wall to a gate1568 */1569 function TryTransformWallToGate(ent, cmpPlayer, template)1570 {1571 var cmpIdentity = Engine.QueryInterface(ent, IID_Identity);1572 if (!cmpIdentity)1573 return;1574 1575 // Check if this is a valid long wall segment1576 if (!cmpIdentity.HasClass("LongWall"))1577 {1578 if (g_DebugCommands)1579 warn("Invalid command: invalid wall conversion to gate for player "+player+": "+uneval(cmd));1580 return;1581 }1582 1583 var civ = cmpIdentity.GetCiv();1584 var gate = Engine.AddEntity(template);1585 1586 var cmpCost = Engine.QueryInterface(gate, IID_Cost);1587 if (!cmpPlayer.TrySubtractResources(cmpCost.GetResourceCosts()))1588 {1589 if (g_DebugCommands)1590 warn("Invalid command: convert gate cost check failed for player "+player+": "+uneval(cmd));1591 1592 Engine.DestroyEntity(gate);1593 return;1594 }1595 1596 ReplaceBuildingWith(ent, gate);1597 }1598 1599 /**1600 * Unconditionally replace a building with another one1601 */1602 function ReplaceBuildingWith(ent, building)1603 {1604 // Move the building to the right place1605 var cmpPosition = Engine.QueryInterface(ent, IID_Position);1606 var cmpBuildingPosition = Engine.QueryInterface(building, IID_Position);1607 var pos = cmpPosition.GetPosition2D();1608 cmpBuildingPosition.JumpTo(pos.x, pos.y);1609 var rot = cmpPosition.GetRotation();1610 cmpBuildingPosition.SetYRotation(rot.y);1611 cmpBuildingPosition.SetXZRotation(rot.x, rot.z);1612 1613 // Copy ownership1614 var cmpOwnership = Engine.QueryInterface(ent, IID_Ownership);1615 var cmpBuildingOwnership = Engine.QueryInterface(building, IID_Ownership);1616 cmpBuildingOwnership.SetOwner(cmpOwnership.GetOwner());1617 1618 // Copy control groups1619 var cmpObstruction = Engine.QueryInterface(ent, IID_Obstruction);1620 var cmpBuildingObstruction = Engine.QueryInterface(building, IID_Obstruction);1621 cmpBuildingObstruction.SetControlGroup(cmpObstruction.GetControlGroup());1622 cmpBuildingObstruction.SetControlGroup2(cmpObstruction.GetControlGroup2());1623 1624 // Copy health level from the old entity to the new1625 var cmpHealth = Engine.QueryInterface(ent, IID_Health);1626 var cmpBuildingHealth = Engine.QueryInterface(building, IID_Health);1627 var healthFraction = Math.max(0, Math.min(1, cmpHealth.GetHitpoints() / cmpHealth.GetMaxHitpoints()));1628 var buildingHitpoints = Math.round(cmpBuildingHealth.GetMaxHitpoints() * healthFraction);1629 cmpBuildingHealth.SetHitpoints(buildingHitpoints);1630 1631 PlaySound("constructed", building);1632 1633 Engine.PostMessage(ent, MT_ConstructionFinished,1634 { "entity": ent, "newentity": building });1635 Engine.BroadcastMessage(MT_EntityRenamed, { entity: ent, newentity: building });1636 1637 Engine.DestroyEntity(ent);1638 }1639 1640 1617 Engine.RegisterGlobal("GetFormationRequirements", GetFormationRequirements); 1641 1618 Engine.RegisterGlobal("CanMoveEntsIntoFormation", CanMoveEntsIntoFormation); 1642 1619 Engine.RegisterGlobal("GetDockAngle", GetDockAngle); -
data/mods/public/simulation/templates/template_structure_defense_wall_long.xml
56 56 <Identity> 57 57 <Classes datatype="tokens">LongWall</Classes> 58 58 <Tooltip>Long wall segments can be converted to gates.</Tooltip> 59 <GateConversionTooltip>Convert Stone Wall into City Gate</GateConversionTooltip>60 59 </Identity> 60 <Upgrade> 61 <Gate> 62 <Entity>structures/{civ}_wall_gate</Entity> 63 <Tooltip>This will allow you to let units circulate through your fortifications.</Tooltip> 64 <Cost> 65 <stone>60</stone> 66 </Cost> 67 <Time>10000</Time> 68 </Gate> 69 </Upgrade> 61 70 </Entity> -
data/mods/public/simulation/templates/other/palisades_rocks_long.xml
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 <History>A cheap, quick defensive structure constructed with sharpened tree trunks</History> 32 31 <Icon>gaia/special_palisade.png</Icon> … … 46 45 <WallPiece> 47 46 <Length>11.0</Length> 48 47 </WallPiece> 48 <Upgrade> 49 <Gate> 50 <Entity>other/palisades_rocks_gate</Entity> 51 <Cost> 52 <stone>0</stone> 53 <wood>20</wood> 54 </Cost> 55 <Time>5000</Time> 56 </Gate> 57 </Upgrade> 49 58 </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>