Ticket #2706: UpgradeComponent.5.patch
File UpgradeComponent.5.patch, 45.9 KB (added by , 8 years ago) |
---|
-
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 } -
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 } -
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 -
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 ? true : false;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 each (var upgrade in 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 (var 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 -
gui/session/input.js
1655 1655 }); 1656 1656 } 1657 1657 1658 // Transform a wall to a gate1659 function transformWallToGate(template)1658 // Upgrade an entity to another 1659 function upgradeEntity(Template) 1660 1660 { 1661 1661 var selection = g_Selection.toList(); 1662 1662 Engine.PostNetworkCommand({ 1663 "type": "wall-to-gate", 1664 "entities": selection.filter( function(e) { return getWallGateTemplate(e) == template; } ), 1665 "template": template, 1663 "type": "upgrade", 1664 "entities": selection, 1665 "template": Template, 1666 "queued": false 1666 1667 }); 1667 1668 } 1668 1669 1669 // Gets the gate form (if any) of a given long wall piece1670 function getWallGateTemplate(entity)1670 // Cancel upgrading entities 1671 function cancelUpgradeEntity() 1671 1672 { 1672 // TODO: find the gate template name in a better way 1673 var entState = GetEntityState(entity); 1674 var index; 1675 1676 if (entState && !entState.foundation && hasClass(entState, "LongWall") && (index = entState.template.indexOf("long")) >= 0) 1677 return entState.template.substr(0, index) + "gate"; 1678 return undefined; 1673 var selection = g_Selection.toList(); 1674 Engine.PostNetworkCommand({ 1675 "type": "cancel-upgrade", 1676 "entities": selection, 1677 "queued": false 1678 }); 1679 1679 } 1680 1680 1681 1681 // Set the camera to follow the given unit -
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> -
gui/session/selection_panels_right/gate_panel.xml
Property changes on: 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> -
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 (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 if (name in this.upgradeTemplates) 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 var category = null; 92 if (template.TrainingRestrictions) 93 category = template.TrainingRestrictions.Category; 94 else if (template.BuildRestrictions) 95 category = template.BuildRestrictions.Category; 96 97 var cmpEntityLimits = QueryPlayerIDInterface(this.owner, IID_EntityLimits); 98 cmpEntityLimits.ChangeCount(category,amount); 99 }; 100 101 Upgrade.prototype.CanUpgradeTo = function(template) 102 { 103 return this.upgradeTemplates[template] !== undefined; 104 }; 105 106 Upgrade.prototype.GetUpgrades = function() 107 { 108 var ret = []; 109 110 var cmpIdentity = Engine.QueryInterface(this.entity, IID_Identity); 111 112 for each (var choice in this.template) 113 { 114 var entType = choice.Entity; 115 if (cmpIdentity) 116 entType = entType.replace(/\{civ\}/g, cmpIdentity.GetCiv()); 117 118 var hasCosts = false; 119 var 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 { 148 var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); 149 cmpTimer.CancelTimer(this.timer); 150 this.timer = undefined; 151 } 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 ("CheckPlacementRestrictions" in this.template[this.upgradeTemplates[template]]); 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); -
simulation/components/Pack.js
Property changes on: 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); -
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>" + -
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, … … 294 295 }; 295 296 } 296 297 298 var cmpUpgrade = Engine.QueryInterface(ent, IID_Upgrade); 299 if (cmpUpgrade) 300 { 301 ret.upgrade = { 302 "upgrades" : cmpUpgrade.GetUpgrades(), 303 "progress": cmpUpgrade.GetProgress(), 304 "template": cmpUpgrade.GetUpgradingTo() 305 }; 306 } 307 297 308 var cmpProductionQueue = Engine.QueryInterface(ent, IID_ProductionQueue); 298 309 if (cmpProductionQueue) 299 310 { -
simulation/components/interfaces/Upgrade.js
1 Engine.RegisterInterface("Upgrade"); -
simulation/helpers/Transform.js
Property changes on: 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); -
simulation/helpers/Commands.js
Property changes on: simulation/helpers/Transform.js ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property
576 576 } 577 577 }, 578 578 579 "wall-to-gate": function(player, cmd, data)580 {581 for each (var ent in data.entities)582 {583 TryTransformWallToGate(ent, data.cmpPlayer, cmd.template);584 }585 },586 587 579 "lock-gate": function(player, cmd, data) 588 580 { 589 581 for each (var ent in data.entities) … … 668 660 } 669 661 }, 670 662 663 "upgrade": function(player, cmd, data) 664 { 665 for each (var ent in data.entities) 666 { 667 var cmpUpgrade = Engine.QueryInterface(ent, IID_Upgrade); 668 669 if (!cmpUpgrade || !cmpUpgrade.CanUpgradeTo(cmd.template)) 670 continue; 671 672 if (cmpUpgrade.WillCheckPlacementRestrictions(cmd.template) && ObstructionsBlockingTemplateChange(ent, cmd.template)) 673 { 674 var notification = {"players": [data.cmpPlayer.GetPlayerID()], "message": "Cannot upgrade as distance requirements are not verified or terrain is obstructed." }; 675 var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface); 676 cmpGUIInterface.PushNotification(notification); 677 continue; 678 } 679 680 if (!CanGarrisonedChangeTemplate(ent, cmd.template)) 681 { 682 var notification = {"players": [data.cmpPlayer.GetPlayerID()], "message": "Cannot upgrade a garrisoned entity." }; 683 var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface); 684 cmpGUIInterface.PushNotification(notification); 685 continue; 686 } 687 688 // Check entity limits 689 var cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); 690 var template = cmpTemplateManager.GetTemplate(cmd.template); 691 var cmpEntityLimits = QueryPlayerIDInterface(player, IID_EntityLimits); 692 if ((template.TrainingRestrictions && !cmpEntityLimits.AllowedToTrain(template.TrainingRestrictions.Category, 1)) 693 || (template.BuildRestrictions && !cmpEntityLimits.AllowedToBuild(template.BuildRestrictions.Category))) 694 { 695 if (g_DebugCommands) 696 warn("Invalid command: build limits check failed for player " + player + ": " + uneval(cmd)); 697 continue; 698 } 699 700 var cmpTechnologyManager = QueryOwnerInterface(ent, IID_TechnologyManager); 701 if (cmpUpgrade.GetRequiredTechnology() && !cmpTechnologyManager.IsTechnologyResearched(cmpUpgrade.GetRequiredTechnology())) 702 { 703 if (g_DebugCommands) 704 warn("Invalid command: upgrading requires unresearched technology: " + uneval(cmd)); 705 continue; 706 } 707 708 cmpUpgrade.Upgrade(cmd.template, data.cmpPlayer); 709 } 710 }, 711 712 "cancel-upgrade": function(player, cmd, data) 713 { 714 for each (var ent in data.entities) 715 { 716 var cmpUpgrade = Engine.QueryInterface(ent, IID_Upgrade); 717 if (cmpUpgrade) 718 cmpUpgrade.CancelUpgrade(data.cmpPlayer); 719 } 720 }, 721 671 722 "attack-request": function(player, cmd, data) 672 723 { 673 724 // Send a chat message to human players … … 1561 1612 return entities.filter(function(ent) { return CanControlUnitOrIsAlly(ent, player, controlAll);} ); 1562 1613 } 1563 1614 1564 /**1565 * Try to transform a wall to a gate1566 */1567 function TryTransformWallToGate(ent, cmpPlayer, template)1568 {1569 var cmpIdentity = Engine.QueryInterface(ent, IID_Identity);1570 if (!cmpIdentity)1571 return;1572 1573 // Check if this is a valid long wall segment1574 if (!cmpIdentity.HasClass("LongWall"))1575 {1576 if (g_DebugCommands)1577 warn("Invalid command: invalid wall conversion to gate for player "+player+": "+uneval(cmd));1578 return;1579 }1580 1581 var civ = cmpIdentity.GetCiv();1582 var gate = Engine.AddEntity(template);1583 1584 var cmpCost = Engine.QueryInterface(gate, IID_Cost);1585 if (!cmpPlayer.TrySubtractResources(cmpCost.GetResourceCosts()))1586 {1587 if (g_DebugCommands)1588 warn("Invalid command: convert gate cost check failed for player "+player+": "+uneval(cmd));1589 1590 Engine.DestroyEntity(gate);1591 return;1592 }1593 1594 ReplaceBuildingWith(ent, gate);1595 }1596 1597 /**1598 * Unconditionally replace a building with another one1599 */1600 function ReplaceBuildingWith(ent, building)1601 {1602 // Move the building to the right place1603 var cmpPosition = Engine.QueryInterface(ent, IID_Position);1604 var cmpBuildingPosition = Engine.QueryInterface(building, IID_Position);1605 var pos = cmpPosition.GetPosition2D();1606 cmpBuildingPosition.JumpTo(pos.x, pos.y);1607 var rot = cmpPosition.GetRotation();1608 cmpBuildingPosition.SetYRotation(rot.y);1609 cmpBuildingPosition.SetXZRotation(rot.x, rot.z);1610 1611 // Copy ownership1612 var cmpOwnership = Engine.QueryInterface(ent, IID_Ownership);1613 var cmpBuildingOwnership = Engine.QueryInterface(building, IID_Ownership);1614 cmpBuildingOwnership.SetOwner(cmpOwnership.GetOwner());1615 1616 // Copy control groups1617 var cmpObstruction = Engine.QueryInterface(ent, IID_Obstruction);1618 var cmpBuildingObstruction = Engine.QueryInterface(building, IID_Obstruction);1619 cmpBuildingObstruction.SetControlGroup(cmpObstruction.GetControlGroup());1620 cmpBuildingObstruction.SetControlGroup2(cmpObstruction.GetControlGroup2());1621 1622 // Copy health level from the old entity to the new1623 var cmpHealth = Engine.QueryInterface(ent, IID_Health);1624 var cmpBuildingHealth = Engine.QueryInterface(building, IID_Health);1625 var healthFraction = Math.max(0, Math.min(1, cmpHealth.GetHitpoints() / cmpHealth.GetMaxHitpoints()));1626 var buildingHitpoints = Math.round(cmpBuildingHealth.GetMaxHitpoints() * healthFraction);1627 cmpBuildingHealth.SetHitpoints(buildingHitpoints);1628 1629 PlaySound("constructed", building);1630 1631 Engine.PostMessage(ent, MT_ConstructionFinished,1632 { "entity": ent, "newentity": building });1633 Engine.BroadcastMessage(MT_EntityRenamed, { entity: ent, newentity: building });1634 1635 Engine.DestroyEntity(ent);1636 }1637 1638 1615 Engine.RegisterGlobal("GetFormationRequirements", GetFormationRequirements); 1639 1616 Engine.RegisterGlobal("CanMoveEntsIntoFormation", CanMoveEntsIntoFormation); 1640 1617 Engine.RegisterGlobal("GetDockAngle", GetDockAngle); -
simulation/templates/template_unit_support_female_citizen.xml
108 108 <RangeMin>0.0</RangeMin> 109 109 </Run> 110 110 </UnitMotion> 111 <Upgrade> 112 <ToTrader> 113 <Entity>units/{civ}_support_trader</Entity> 114 <Tooltip>Upgrade to a traderBiatch.</Tooltip> 115 <Cost> 116 <stone>60</stone> 117 </Cost> 118 <Time>0</Time> 119 </ToTrader> 120 <ToSlave> 121 <Entity>units/{civ}_support_slave</Entity> 122 <Tooltip>Haha!</Tooltip> 123 <Cost> 124 <food>10</food> 125 </Cost> 126 <Time>0</Time> 127 </ToSlave> 128 </Upgrade> 111 129 <Vision> 112 130 <Range>32</Range> 113 131 </Vision> -
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> -
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> -
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>