Ticket #2706: UpgradeComponent.4.patch
File UpgradeComponent.4.patch, 45.6 KB (added by , 10 years ago) |
---|
-
binaries/data/mods/public/art/textures/ui/session/icons/upgrade.png
Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream
-
binaries/data/mods/public/gui/session/input.js
Property changes on: binaries/data/mods/public/art/textures/ui/session/icons/upgrade.png ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property
1614 1614 }); 1615 1615 } 1616 1616 1617 // Transform a wall to a gate1618 function transformWallToGate(template)1617 // Upgrade an entity to another 1618 function upgradeEntity(Template) 1619 1619 { 1620 1620 var selection = g_Selection.toList(); 1621 1621 Engine.PostNetworkCommand({ 1622 "type": "wall-to-gate", 1623 "entities": selection.filter( function(e) { return getWallGateTemplate(e) == template } ), 1624 "template": template, 1622 "type": "upgrade", 1623 "entities": selection, 1624 "template": Template, 1625 "queued": false 1625 1626 }); 1626 1627 } 1627 1628 1628 // Gets the gate form (if any) of a given long wall piece1629 function getWallGateTemplate(entity)1629 // Cancel upgrading entities 1630 function cancelUpgradeEntity() 1630 1631 { 1631 // TODO: find the gate template name in a better way 1632 var entState = GetEntityState(entity); 1633 var index; 1634 1635 if (entState && !entState.foundation && hasClass(entState, "LongWall") && (index = entState.template.indexOf("long")) >= 0) 1636 return entState.template.substr(0, index) + "gate"; 1637 return undefined; 1632 var selection = g_Selection.toList(); 1633 Engine.PostNetworkCommand({ 1634 "type": "cancel-upgrade", 1635 "entities": selection, 1636 "queued": false 1637 }); 1638 1638 } 1639 1639 1640 1640 // Set the camera to follow the given unit -
binaries/data/mods/public/gui/session/selection_panels.js
372 372 for (var i in selection) 373 373 { 374 374 var state = GetEntityState(selection[i]); 375 if ( hasClass(state, "LongWall") && !state.gate && !longWallTypes[state.template])375 if (state.gate && !gates.length) 376 376 { 377 var gateTemplate = getWallGateTemplate(state.id);378 if (gateTemplate)379 {380 var tooltipString = GetTemplateDataWithoutLocalization(state.template).gateConversionTooltip;381 if (!tooltipString)382 {383 warn(state.template + " is supposed to be convertable to a gate, but it's missing the GateConversionTooltip in the Identity template");384 tooltipString = "";385 }386 walls.push({387 "tooltip": translate(tooltipString),388 "template": gateTemplate,389 "callback": function (item) { transformWallToGate(item.template); }390 });391 }392 393 // We only need one entity per type.394 longWallTypes[state.template] = true;395 }396 else if (state.gate && !gates.length)397 {398 377 gates.push({ 399 378 "gate": state.gate, 400 379 "tooltip": translate("Lock Gate"), … … 424 403 }, 425 404 "setTooltip": function(data) 426 405 { 427 var tooltip = data.item.tooltip; 428 if (data.item.template) 429 { 430 data.template = GetTemplateData(data.item.template); 431 data.wallCount = data.selection.reduce(function (count, ent) { 432 var state = GetEntityState(ent); 433 if (hasClass(state, "LongWall") && !state.gate) 434 count++; 435 return count; 436 }, 0); 437 438 tooltip += "\n" + getEntityCostTooltip(data.template, data.wallCount); 439 440 441 data.neededResources = Engine.GuiInterfaceCall("GetNeededResources", multiplyEntityCosts(data.template, data.wallCount)); 442 if (data.neededResources) 443 tooltip += getNeededResourcesTooltip(data.neededResources); 444 } 445 data.button.tooltip = tooltip; 406 data.button.tooltip = data.item.tooltip; 446 407 }, 447 408 "setGraphics": function(data) 448 409 { 449 data.affordableMask.hidden == data.neededResources ? true : false;450 410 var gateIcon; 451 411 if (data.item.gate) 452 412 { 453 // If already a gate, show locking actions413 // Show locking actions 454 414 gateIcon = "icons/lock_" + GATE_ACTIONS[data.item.locked ? 0 : 1] + "ed.png"; 455 415 if (data.item.gate.locked === undefined) 456 416 data.guiSelection.hidden = false … … 457 417 else 458 418 data.guiSelection.hidden = data.item.gate.locked != data.item.locked; 459 419 } 460 else461 {462 // otherwise show gate upgrade icon463 var template = GetTemplateData(data.item.template);464 if (!template)465 return;466 gateIcon = data.template.icon ? "portraits/" + data.template.icon : "icons/gate_closed.png";467 data.guiSelection.hidden = true;468 }469 470 420 data.icon.sprite = "stretched:session/" + gateIcon; 471 421 }, 472 422 "setPosition": function(data) … … 541 491 }, 542 492 }; 543 493 494 // UPGRADE 495 g_SelectionPanels.Upgrade = { 496 "getMaxNumberOfItems": function() 497 { 498 return 24 - getNumberOfRightPanelButtons(); 499 }, 500 "getItems": function(unitEntState, selection) 501 { 502 // Interface becomes complicated with multiple units and this is meant per-entity, so prevent it if the selection has multiple units. 503 if (selection.length > 1) 504 return false; 505 var items = []; 506 507 if (!unitEntState.upgrade) 508 return false; 509 510 for each (var upgrade in unitEntState.upgrade.upgrades) 511 { 512 var item = {}; 513 item.entType = upgrade.entity; 514 item.template = GetTemplateData(upgrade.entity); 515 if (!item.template) // abort if no template 516 return false; 517 518 item.icon = upgrade.icon; 519 if (!item.icon) 520 item.icon = "portraits/" + item.template.icon; 521 522 if (upgrade.requiredTechnology !== null) 523 { 524 item.requiredTechnology = upgrade.requiredTechnology; 525 if (!item.requiredTechnology && item.template.requiredTechnology) 526 item.requiredTechnology = item.template.requiredTechnology 527 } 528 item.cost = upgrade.cost; 529 item.time = upgrade.time; 530 531 if (unitEntState.upgrade.progress === undefined) 532 { 533 item.upgrading = UPGRADING_NOT_STARTED; 534 item.tooltip = sprintf(translate("Upgrade into a %(name)s.%(tooltip)s"), { name: item.template.name.generic, tooltip: (upgrade.tooltip? "\n" + upgrade.tooltip : "") }); 535 item.callback = function(data) { upgradeEntity(data.entType); }; 536 } 537 else if (unitEntState.upgrade.template !== upgrade.entity) 538 { 539 item.upgrading = UPGRADING_CHOSEN_OTHER; 540 item.tooltip = translate("Cannot upgrade when the entity is already upgrading."); 541 item.callback = function(data) { }; 542 } 543 else 544 { 545 item.upgrading = unitEntState.upgrade.progress; 546 item.tooltip = translate("Cancel Upgrading"); 547 item.callback = function(data) { cancelUpgradeEntity(); }; 548 } 549 items.push(item); 550 } 551 return items; 552 }, 553 "addData" : function(data) 554 { 555 data.item.technologyEnabled = true; 556 if (data.item.requiredTechnology) 557 data.item.technologyEnabled = Engine.GuiInterfaceCall("IsTechnologyResearched", data.item.requiredTechnology); 558 if (data.item.cost) 559 { 560 var totalCost = {}; 561 for (var i in data.item.cost) 562 totalCost[i] = data.item.cost[i]; 563 data.item.neededResources = Engine.GuiInterfaceCall("GetNeededResources", totalCost); 564 } 565 data.item.limits = getEntityLimitAndCount(data.playerState, data.item.entType); 566 return true; 567 }, 568 "setAction": function(data) 569 { 570 data.button.onPress = function() { data.item.callback(data.item); }; 571 }, 572 "setTooltip": function(data) 573 { 574 var tooltip = data.item.tooltip; 575 576 if (data.item.upgrading !== UPGRADING_NOT_STARTED) 577 { 578 data.button.tooltip = tooltip; 579 return; 580 } 581 582 if (data.item.cost) 583 tooltip += "\n" + getEntityCostTooltip(data.item); 584 585 tooltip += formatLimitString(data.item.limits.entLimit, data.item.limits.entCount, data.item.limits.entLimitChangers); 586 if (!data.item.technologyEnabled) 587 { 588 var techName = getEntityNames(GetTechnologyData(data.item.requiredTechnology)); 589 tooltip += "\n" + sprintf(translate("Requires %(technology)s"), { technology: techName }); 590 } 591 if (data.item.neededResources) 592 tooltip += getNeededResourcesTooltip(data.item.neededResources); 593 594 data.button.tooltip = tooltip; 595 }, 596 "setGraphics": function(data) 597 { 598 var grayscale = ""; 599 if (data.item.upgrading == UPGRADING_CHOSEN_OTHER || !data.item.technologyEnabled || (data.item.limits.canBeAddedCount == 0 && data.item.upgrading == UPGRADING_NOT_STARTED)) 600 { 601 data.button.enabled = false; 602 grayscale = "grayscale:"; 603 data.affordableMask.hidden = false; 604 data.affordableMask.sprite = "colour: 0 0 0 127"; 605 } 606 else if (data.item.upgrading == UPGRADING_NOT_STARTED && data.item.neededResources) 607 { 608 data.button.enabled = false; 609 data.affordableMask.hidden = false; 610 data.affordableMask.sprite = resourcesToAlphaMask(data.item.neededResources); 611 } 612 613 data.icon.sprite = "stretched:" + grayscale + "session/" + data.item.icon; 614 615 var guiObject = Engine.GetGUIObjectByName("unitUpgradeProgressSlider["+data.i+"]"); 616 var size = guiObject.size; 617 if (data.item.upgrading < 0) 618 size.top = size.right; 619 else 620 size.top = size.left + Math.round(Math.max(0,data.item.upgrading) * (size.right - size.left)); 621 guiObject.size = size; 622 }, 623 "setPosition": function(data) 624 { 625 var index = data.i + getNumberOfRightPanelButtons(); 626 setPanelObjectPosition(data.button, index, data.rowLength); 627 }, 628 }; 629 544 630 // QUEUE 545 631 g_SelectionPanels.Queue = { 546 632 "getMaxNumberOfItems": function() … … 1015 1101 // RIGHT PANE 1016 1102 "Gate", // must always be shown on gates 1017 1103 "Pack", // must always be shown on packable entities 1104 "Upgrade", // must always be shown on upgradable entities 1018 1105 "Training", 1019 1106 "Construction", 1020 1107 "Research", // normal together with training -
binaries/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 -
binaries/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, "Barter": 0, "Construction": 0, "Command": 0, "Stance": 0, "Gate": 0, "Pack": 0 };2 var g_unitPanelButtons = {"Selection": 0, "Queue": 0, "Formation": 0, "Garrison": 0, "Training": 0, "Research": 0, "Barter": 0, "Construction": 0, "Command": 0, "Stance": 0, "Gate": 0, "Pack": 0, "Upgrade": 0}; 3 3 4 4 /** 5 5 * Set the position of a panel object according to the index, … … 289 289 sum += g_unitPanelButtons["Pack"]; 290 290 if (g_SelectionPanels["Gate"].used) 291 291 sum += g_unitPanelButtons["Gate"]; 292 if (g_SelectionPanels["Upgrade"].used) 293 sum += g_unitPanelButtons["Upgrade"]; 292 294 return sum; 293 295 } -
binaries/data/mods/public/gui/session/selection_panels_right/gate_panel.xml
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="colour: 255 0 0 127"/>11 10 </object> 12 11 </repeat> 13 12 </object> -
binaries/data/mods/public/gui/session/selection_panels_right/upgrade_panel.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <object name="unitUpgradePanel" 3 size="10 12 100% 100%" 4 > 5 <object size="0 0 100% 100%"> 6 <repeat count="8"> 7 <object name="unitUpgradeButton[n]" hidden="true" style="iconButton" type="button" size="0 0 46 46" tooltip_style="sessionToolTipBottom"> 8 <object name="unitUpgradeIcon[n]" type="image" ghost="true" size="3 3 43 43"/> 9 <object name="unitUpgradeUpgradeIcon[n]" type="image" ghost="true" size="3 3 43 43" sprite="stretched:session/icons/upgrade.png"/> 10 <object name="unitUpgradeProgressSlider[n]" type="image" sprite="queueProgressSlider" ghost="true" size="3 3 43 43" z="20"/> 11 <object name="unitUpgradeSelection[n]" hidden="true" type="image" ghost="true" size="3 3 43 43" sprite="stretched:session/icons/corners.png"/> 12 <object name="unitUpgradeUnaffordable[n]" hidden="true" type="image" ghost="true" size="3 3 43 43" sprite="colour: 255 0 0 127"/> 13 </object> 14 </repeat> 15 </object> 16 </object> -
binaries/data/mods/public/simulation/components/GuiInterface.js
Property changes on: binaries/data/mods/public/gui/session/selection_panels_right/upgrade_panel.xml ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property
181 181 "gate": null, 182 182 "guard": null, 183 183 "pack": null, 184 "upgrade" : null, 184 185 "player": -1, 185 186 "position": null, 186 187 "production": null, … … 242 243 }; 243 244 } 244 245 246 var cmpUpgrade = Engine.QueryInterface(ent, IID_Upgrade); 247 if (cmpUpgrade) 248 { 249 ret.upgrade = { 250 "upgrades" : cmpUpgrade.GetUpgrades(), 251 "progress": cmpUpgrade.GetProgress(), 252 "template": cmpUpgrade.GetUpgradingTo() 253 }; 254 } 255 245 256 var cmpProductionQueue = Engine.QueryInterface(ent, IID_ProductionQueue); 246 257 if (cmpProductionQueue) 247 258 { … … 692 703 }; 693 704 ret.icon = template.Identity.Icon; 694 705 ret.tooltip = template.Identity.Tooltip; 695 ret.gateConversionTooltip = template.Identity.GateConversionTooltip;696 706 ret.requiredTechnology = template.Identity.RequiredTechnology; 697 707 ret.visibleIdentityClasses = GetVisibleIdentityClasses(template.Identity); 698 708 } -
binaries/data/mods/public/simulation/components/Identity.js
30 30 "</element>" + 31 31 "</optional>" + 32 32 "<optional>" + 33 "<element name='GateConversionTooltip'>" +34 "<text/>" +35 "</element>" +36 "</optional>" +37 "<optional>" +38 33 "<element name='Rollover'>" + 39 34 "<text/>" + 40 35 "</element>" + -
binaries/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.CancelTimer(); 121 this.SetElapsedTime(this.GetElapsedTime() + PACKING_INTERVAL + lateness); 122 return; 123 } 122 124 123 this.packed = !this.packed; 124 Engine.PostMessage(this.entity, MT_PackFinished, { packed: this.packed }); 125 this.CancelTimer(); 125 126 126 // Done un/packing, copy our parameters to the final entity 127 var newEntity = Engine.AddEntity(this.template.Entity); 128 if (newEntity == INVALID_ENTITY) 129 { 130 // Error (e.g. invalid template names) 131 error("PackProgress: Error creating entity for '" + this.template.Entity + "'"); 132 return; 133 } 127 this.packed = !this.packed; 128 Engine.PostMessage(this.entity, MT_PackFinished, { packed: this.packed }); 134 129 135 var cmpPosition = Engine.QueryInterface(this.entity, IID_Position); 136 var cmpNewPosition = Engine.QueryInterface(newEntity, IID_Position); 137 if (cmpPosition.IsInWorld()) 138 { 139 var pos = cmpPosition.GetPosition2D(); 140 cmpNewPosition.JumpTo(pos.x, pos.y); 141 } 142 var rot = cmpPosition.GetRotation(); 143 cmpNewPosition.SetYRotation(rot.y); 144 cmpNewPosition.SetXZRotation(rot.x, rot.z); 145 cmpNewPosition.SetHeightOffset(cmpPosition.GetHeightOffset()); 130 var newEntity = ChangeEntityTemplate(this.entity, this.template.Entity); 146 131 147 var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); 148 var cmpNewOwnership = Engine.QueryInterface(newEntity, IID_Ownership); 149 cmpNewOwnership.SetOwner(cmpOwnership.GetOwner()); 150 151 // Maintain current health level 152 var cmpHealth = Engine.QueryInterface(this.entity, IID_Health); 153 var cmpNewHealth = Engine.QueryInterface(newEntity, IID_Health); 154 var healthLevel = Math.max(0, Math.min(1, cmpHealth.GetHitpoints() / cmpHealth.GetMaxHitpoints())); 155 cmpNewHealth.SetHitpoints(Math.round(cmpNewHealth.GetMaxHitpoints() * healthLevel)); 156 157 var cmpUnitAI = Engine.QueryInterface(this.entity, IID_UnitAI); 158 var cmpNewUnitAI = Engine.QueryInterface(newEntity, IID_UnitAI); 159 if (cmpUnitAI && cmpNewUnitAI) 160 { 161 var pos = cmpUnitAI.GetHeldPosition(); 162 if (pos) 163 cmpNewUnitAI.SetHeldPosition(pos.x, pos.z); 164 if (cmpUnitAI.GetStanceName()) 165 cmpNewUnitAI.SwitchToStance(cmpUnitAI.GetStanceName()); 166 cmpNewUnitAI.AddOrders(cmpUnitAI.GetOrders()); 167 cmpNewUnitAI.SetGuardOf(cmpUnitAI.IsGuardOf()); 168 } 169 170 // Maintain the list of guards 171 var cmpGuard = Engine.QueryInterface(this.entity, IID_Guard); 172 var cmpNewGuard = Engine.QueryInterface(newEntity, IID_Guard); 173 if (cmpGuard && cmpNewGuard) 174 cmpNewGuard.SetEntities(cmpGuard.GetEntities()); 175 176 Engine.BroadcastMessage(MT_EntityRenamed, { entity: this.entity, newentity: newEntity }); 177 178 // Play notification sound 132 if (newEntity) 133 { 179 134 var sound = this.packed ? "packed" : "unpacked"; 180 135 PlaySound(sound, newEntity); 181 182 // Destroy current entity183 Engine.DestroyEntity(this.entity);184 136 } 185 else186 {187 this.SetElapsedTime(this.GetElapsedTime() + PACKING_INTERVAL + lateness);188 }189 137 }; 190 138 191 139 Engine.RegisterComponentType(IID_Pack, "Pack", Pack); -
binaries/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 (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); -
binaries/data/mods/public/simulation/components/interfaces/Upgrade.js
Property changes on: binaries/data/mods/public/simulation/components/Upgrade.js ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property
1 Engine.RegisterInterface("Upgrade"); -
binaries/data/mods/public/simulation/helpers/Commands.js
Property changes on: binaries/data/mods/public/simulation/components/interfaces/Upgrade.js ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property
551 551 } 552 552 }, 553 553 554 "wall-to-gate": function(player, cmd, data)555 {556 for each (var ent in data.entities)557 {558 TryTransformWallToGate(ent, data.cmpPlayer, cmd.template);559 }560 },561 562 554 "lock-gate": function(player, cmd, data) 563 555 { 564 556 for each (var ent in data.entities) … … 642 634 } 643 635 } 644 636 }, 637 638 "upgrade": function(player, cmd, data) 639 { 640 for each (var ent in data.entities) 641 { 642 var cmpUpgrade = Engine.QueryInterface(ent, IID_Upgrade); 643 644 if (!cmpUpgrade || !cmpUpgrade.CanUpgradeTo(cmd.template)) 645 continue; 646 647 if (cmpUpgrade.WillCheckPlacementRestrictions(cmd.template) && ObstructionsBlockingTemplateChange(ent, cmd.template)) 648 { 649 var notification = {"players": [data.cmpPlayer.GetPlayerID()], "message": "Cannot upgrade as distance requirements are not verified or terrain is obstructed." }; 650 var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface); 651 cmpGUIInterface.PushNotification(notification); 652 continue; 653 } 654 655 if (!CanGarrisonedChangeTemplate(ent, cmd.template)) 656 { 657 var notification = {"players": [data.cmpPlayer.GetPlayerID()], "message": "Cannot upgrade a garrisoned entity." }; 658 var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface); 659 cmpGUIInterface.PushNotification(notification); 660 continue; 661 } 662 663 // Check entity limits 664 var cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); 665 var template = cmpTemplateManager.GetTemplate(cmd.template); 666 var cmpEntityLimits = QueryPlayerIDInterface(player, IID_EntityLimits); 667 if ((template.TrainingRestrictions && !cmpEntityLimits.AllowedToTrain(template.TrainingRestrictions.Category, 1)) 668 || (template.BuildRestrictions && !cmpEntityLimits.AllowedToBuild(template.BuildRestrictions.Category))) 669 { 670 if (g_DebugCommands) 671 warn("Invalid command: build limits check failed for player " + player + ": " + uneval(cmd)); 672 continue; 673 } 674 675 var cmpTechnologyManager = QueryOwnerInterface(ent, IID_TechnologyManager); 676 if (cmpUpgrade.GetRequiredTechnology() && !cmpTechnologyManager.IsTechnologyResearched(cmpUpgrade.GetRequiredTechnology())) 677 { 678 if (g_DebugCommands) 679 warn("Invalid command: upgrading requires unresearched technology: " + uneval(cmd)); 680 continue; 681 } 682 683 cmpUpgrade.Upgrade(cmd.template, data.cmpPlayer); 684 } 685 }, 686 687 "cancel-upgrade": function(player, cmd, data) 688 { 689 for each (var ent in data.entities) 690 { 691 var cmpUpgrade = Engine.QueryInterface(ent, IID_Upgrade); 692 if (cmpUpgrade) 693 cmpUpgrade.CancelUpgrade(data.cmpPlayer); 694 } 695 }, 696 645 697 "dialog-answer": function(player, cmd, data) 646 698 { 647 699 // Currently nothing. Triggers can read it anyway, and send this … … 1517 1569 return entities.filter(function(ent) { return CanControlUnitOrIsAlly(ent, player, controlAll);} ); 1518 1570 } 1519 1571 1520 /**1521 * Try to transform a wall to a gate1522 */1523 function TryTransformWallToGate(ent, cmpPlayer, template)1524 {1525 var cmpIdentity = Engine.QueryInterface(ent, IID_Identity);1526 if (!cmpIdentity)1527 return;1528 1529 // Check if this is a valid long wall segment1530 if (!cmpIdentity.HasClass("LongWall"))1531 {1532 if (g_DebugCommands)1533 warn("Invalid command: invalid wall conversion to gate for player "+player+": "+uneval(cmd));1534 return;1535 }1536 1537 var civ = cmpIdentity.GetCiv();1538 var gate = Engine.AddEntity(template);1539 1540 var cmpCost = Engine.QueryInterface(gate, IID_Cost);1541 if (!cmpPlayer.TrySubtractResources(cmpCost.GetResourceCosts()))1542 {1543 if (g_DebugCommands)1544 warn("Invalid command: convert gate cost check failed for player "+player+": "+uneval(cmd));1545 1546 Engine.DestroyEntity(gate);1547 return;1548 }1549 1550 ReplaceBuildingWith(ent, gate);1551 }1552 1553 /**1554 * Unconditionally replace a building with another one1555 */1556 function ReplaceBuildingWith(ent, building)1557 {1558 // Move the building to the right place1559 var cmpPosition = Engine.QueryInterface(ent, IID_Position);1560 var cmpBuildingPosition = Engine.QueryInterface(building, IID_Position);1561 var pos = cmpPosition.GetPosition2D();1562 cmpBuildingPosition.JumpTo(pos.x, pos.y);1563 var rot = cmpPosition.GetRotation();1564 cmpBuildingPosition.SetYRotation(rot.y);1565 cmpBuildingPosition.SetXZRotation(rot.x, rot.z);1566 1567 // Copy ownership1568 var cmpOwnership = Engine.QueryInterface(ent, IID_Ownership);1569 var cmpBuildingOwnership = Engine.QueryInterface(building, IID_Ownership);1570 cmpBuildingOwnership.SetOwner(cmpOwnership.GetOwner());1571 1572 // Copy control groups1573 var cmpObstruction = Engine.QueryInterface(ent, IID_Obstruction);1574 var cmpBuildingObstruction = Engine.QueryInterface(building, IID_Obstruction);1575 cmpBuildingObstruction.SetControlGroup(cmpObstruction.GetControlGroup());1576 cmpBuildingObstruction.SetControlGroup2(cmpObstruction.GetControlGroup2());1577 1578 // Copy health level from the old entity to the new1579 var cmpHealth = Engine.QueryInterface(ent, IID_Health);1580 var cmpBuildingHealth = Engine.QueryInterface(building, IID_Health);1581 var healthFraction = Math.max(0, Math.min(1, cmpHealth.GetHitpoints() / cmpHealth.GetMaxHitpoints()));1582 var buildingHitpoints = Math.round(cmpBuildingHealth.GetMaxHitpoints() * healthFraction);1583 cmpBuildingHealth.SetHitpoints(buildingHitpoints);1584 1585 PlaySound("constructed", building);1586 1587 Engine.PostMessage(ent, MT_ConstructionFinished,1588 { "entity": ent, "newentity": building });1589 Engine.BroadcastMessage(MT_EntityRenamed, { entity: ent, newentity: building });1590 1591 Engine.DestroyEntity(ent);1592 }1593 1594 1572 Engine.RegisterGlobal("GetFormationRequirements", GetFormationRequirements); 1595 1573 Engine.RegisterGlobal("CanMoveEntsIntoFormation", CanMoveEntsIntoFormation); 1596 1574 Engine.RegisterGlobal("GetDockAngle", GetDockAngle); -
binaries/data/mods/public/simulation/helpers/Transform.js
1 // Helper functions to change an entity's template and check if the transformation is possible 2 3 // returns the ID of the new entity or INVALID_ENTITY. 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 // Maintain current health level 45 var cmpHealth = Engine.QueryInterface(oldEnt, IID_Health); 46 var cmpNewHealth = Engine.QueryInterface(newEnt, IID_Health); 47 if (cmpHealth && cmpNewHealth) 48 { 49 var healthLevel = Math.max(0, Math.min(1, cmpHealth.GetHitpoints() / cmpHealth.GetMaxHitpoints())); 50 cmpNewHealth.SetHitpoints(Math.round(cmpNewHealth.GetMaxHitpoints() * healthLevel)); 51 } 52 53 var cmpUnitAI = Engine.QueryInterface(oldEnt, IID_UnitAI); 54 var cmpNewUnitAI = Engine.QueryInterface(newEnt, IID_UnitAI); 55 if (cmpUnitAI && cmpNewUnitAI) 56 { 57 var pos = cmpUnitAI.GetHeldPosition(); 58 if (pos) 59 cmpNewUnitAI.SetHeldPosition(pos.x, pos.z); 60 if (cmpUnitAI.GetStanceName()) 61 cmpNewUnitAI.SwitchToStance(cmpUnitAI.GetStanceName()); 62 cmpNewUnitAI.AddOrders(cmpUnitAI.GetOrders()); 63 cmpNewUnitAI.SetGuardOf(cmpUnitAI.IsGuardOf()); 64 } 65 66 // Maintain the list of guards 67 var cmpGuard = Engine.QueryInterface(oldEnt, IID_Guard); 68 var cmpNewGuard = Engine.QueryInterface(newEnt, IID_Guard); 69 if (cmpGuard && cmpNewGuard) 70 cmpNewGuard.SetEntities(cmpGuard.GetEntities()); 71 72 TransferGarrisonedUnits(oldEnt, newEnt); 73 74 Engine.BroadcastMessage(MT_EntityRenamed, { entity: oldEnt, newentity: newEnt }); 75 76 // Destroy current entity 77 Engine.DestroyEntity(oldEnt); 78 79 return newEnt; 80 }; 81 82 var CanGarrisonedChangeTemplate = function(ent, template) 83 { 84 var cmpPosition = Engine.QueryInterface(ent, IID_Position); 85 var unitAI = Engine.QueryInterface(ent, IID_UnitAI); 86 if (cmpPosition && !cmpPosition.IsInWorld() && unitAI && unitAI.IsGarrisoned()) 87 { 88 // We're a garrisoned unit, assume impossibility as I've been unable to find a way to get the holder ID. 89 // TODO: change this if that ever becomes possibles 90 return false; 91 } 92 return true; 93 } 94 95 var ObstructionsBlockingTemplateChange = function(ent, templateArg) 96 { 97 var previewEntity = Engine.AddEntity("preview|"+templateArg); 98 99 if (previewEntity == INVALID_ENTITY) 100 return true; 101 102 var cmpBuildRestrictions = Engine.QueryInterface(previewEntity, IID_BuildRestrictions); 103 var cmpPosition = Engine.QueryInterface(ent, IID_Position); 104 var cmpOwnership = Engine.QueryInterface(ent, IID_Ownership); 105 106 var cmpNewPosition = Engine.QueryInterface(previewEntity, IID_Position); 107 108 // Return false if no ownership as BuildRestrictions.CheckPlacement needs an owner and I have no idea if false or true is better 109 // Plus there are no real entities without owners currently. 110 if (!cmpBuildRestrictions || !cmpPosition || !cmpOwnership) 111 return DeleteEntityAndReturn(previewEntity, cmpPosition, pos, angle, cmpNewPosition, false); 112 113 var pos = cmpPosition.GetPosition2D(); 114 var angle = cmpPosition.GetRotation(); 115 // move us away to prevent our own obstruction from blocking the upgrade. 116 cmpPosition.MoveOutOfWorld(); 117 118 cmpNewPosition.JumpTo(pos.x, pos.y); 119 cmpNewPosition.SetYRotation(angle.y); 120 121 var cmpNewOwnership = Engine.QueryInterface(previewEntity, IID_Ownership); 122 cmpNewOwnership.SetOwner(cmpOwnership.GetOwner()); 123 124 var checkPlacement = cmpBuildRestrictions.CheckPlacement(); 125 126 if (checkPlacement && !checkPlacement.success) 127 return DeleteEntityAndReturn(previewEntity, cmpPosition, pos, angle, cmpNewPosition, true); 128 129 var cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); 130 var template = cmpTemplateManager.GetTemplate(cmpTemplateManager.GetCurrentTemplateName(ent)); 131 var newTemplate = cmpTemplateManager.GetTemplate(templateArg); 132 133 // Check if units are blocking our template change 134 if (template.Obstruction && newTemplate.Obstruction) 135 { 136 // This only needs to be done if the new template is strictly bigger than the old one 137 // "Obstructions" are annoying to test so just check. 138 // This is kind of ugly, sorry about that. 139 if (newTemplate.Obstruction.Obstructions 140 141 || (newTemplate.Obstruction.Static && template.Obstruction.Static 142 && (newTemplate.Obstruction.Static["@width"] > template.Obstruction.Static["@width"] 143 || newTemplate.Obstruction.Static["@depth"] > template.Obstruction.Static["@depth"])) 144 || (newTemplate.Obstruction.Static && template.Obstruction.Unit 145 && (newTemplate.Obstruction.Static["@width"] > template.Obstruction.Unit["@radius"] 146 || newTemplate.Obstruction.Static["@depth"] > template.Obstruction.Unit["@radius"])) 147 148 || (newTemplate.Obstruction.Unit && template.Obstruction.Unit 149 && newTemplate.Obstruction.Unit["@radius"] > template.Obstruction.Unit["@radius"]) 150 || (newTemplate.Obstruction.Unit && template.Obstruction.Static 151 && (newTemplate.Obstruction.Unit["@radius"] > template.Obstruction.Static["@width"] 152 || newTemplate.Obstruction.Unit["@radius"] > template.Obstruction.Static["@depth"]))) 153 { 154 var cmpNewObstruction = Engine.QueryInterface(previewEntity, IID_Obstruction); 155 if (cmpNewObstruction && cmpNewObstruction.GetBlockMovementFlag()) 156 { 157 // Check for units 158 var collisions = cmpNewObstruction.GetEntityCollisions(false, true); 159 if (collisions.length !== 0) 160 return DeleteEntityAndReturn(previewEntity, cmpPosition, pos, angle, cmpNewPosition, true); 161 } 162 } 163 } 164 165 return DeleteEntityAndReturn(previewEntity, cmpPosition, pos, angle, cmpNewPosition, false); 166 }; 167 168 var DeleteEntityAndReturn = function(ent, cmpPosition, position, angle, cmpNewPosition, ret) 169 { 170 cmpNewPosition.MoveOutOfWorld(); // prevent preview from interfering in the world 171 cmpPosition.JumpTo(position.x, position.y); 172 cmpPosition.SetYRotation(angle.y); 173 174 Engine.DestroyEntity(ent); 175 return ret; 176 }; 177 178 var TransferGarrisonedUnits = function(oldEnt, newEnt) 179 { 180 // Transfer garrisoned units if possible, or unload them 181 var cmpGarrison = Engine.QueryInterface(oldEnt, IID_GarrisonHolder); 182 var cmpNewGarrison = Engine.QueryInterface(newEnt, IID_GarrisonHolder); 183 if (!cmpNewGarrison || !cmpGarrison || cmpGarrison.GetEntities().length === 0 ) 184 return; // nothing to do as the code will by default unload all. 185 186 var garrisonedEntities = cmpGarrison.GetEntities().slice(); 187 for (var j = 0; j < garrisonedEntities.length; ++j) 188 { 189 var cmpUnitAI = Engine.QueryInterface(garrisonedEntities[j], IID_UnitAI); 190 cmpGarrison.Eject(garrisonedEntities[j]); 191 cmpUnitAI.Autogarrison(newEnt); 192 cmpNewGarrison.Garrison(garrisonedEntities[j]); 193 } 194 }; 195 196 Engine.RegisterGlobal("ChangeEntityTemplate", ChangeEntityTemplate); 197 Engine.RegisterGlobal("CanGarrisonedChangeTemplate", CanGarrisonedChangeTemplate); 198 Engine.RegisterGlobal("ObstructionsBlockingTemplateChange", ObstructionsBlockingTemplateChange); -
binaries/data/mods/public/simulation/templates/template_structure_defense_wall_long.xml
Property changes on: binaries/data/mods/public/simulation/helpers/Transform.js ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property
51 51 <Identity> 52 52 <Classes datatype="tokens">LongWall</Classes> 53 53 <Tooltip>Long wall segments can be converted to gates.</Tooltip> 54 <GateConversionTooltip>Convert Stone Wall into City Gate</GateConversionTooltip>55 54 </Identity> 55 <Upgrade> 56 <Gate> 57 <Entity>structures/{civ}_wall_gate</Entity> 58 <Tooltip>This will allow you to let units circulate through your fortifications.</Tooltip> 59 <Cost> 60 <stone>60</stone> 61 </Cost> 62 <Time>10000</Time> 63 </Gate> 64 </Upgrade> 56 65 </Entity> -
binaries/data/mods/public/simulation/templates/other/palisades_rocks_long.xml
21 21 <SelectionGroupName>other/wallset_palisade</SelectionGroupName> 22 22 <SpecificName>Palisade</SpecificName> 23 23 <GenericName>Wooden Wall</GenericName> 24 <GateConversionTooltip>Convert Wooden Wall into Wooden Gate</GateConversionTooltip>25 24 <Classes datatype="tokens">-StoneWall Palisade</Classes> 26 25 <History>A cheap, quick defensive structure constructed with sharpened tree trunks</History> 27 26 <Icon>gaia/special_palisade.png</Icon> … … 41 40 <WallPiece> 42 41 <Length>11.0</Length> 43 42 </WallPiece> 43 <Upgrade> 44 <Gate> 45 <Entity>other/palisades_rocks_gate</Entity> 46 <Cost> 47 <stone>0</stone> 48 <wood>20</wood> 49 </Cost> 50 <Time>5000</Time> 51 </Gate> 52 </Upgrade> 44 53 </Entity> -
binaries/data/mods/public/simulation/templates/structures/rome_siege_wall_long.xml
55 55 </Classes> 56 56 <Icon>structures/palisade.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>