Ticket #2706: UpgradeComponentRC-fixed4.patch
File UpgradeComponentRC-fixed4.patch, 46.0 KB (added by , 8 years ago) |
---|
-
binaries/data/mods/public/globalscripts/Templates.js
233 233 }; 234 234 ret.icon = template.Identity.Icon; 235 235 ret.tooltip = template.Identity.Tooltip; 236 ret.gateConversionTooltip = template.Identity.GateConversionTooltip;237 236 ret.requiredTechnology = template.Identity.RequiredTechnology; 238 237 ret.visibleIdentityClasses = GetVisibleIdentityClasses(template.Identity); 239 238 } -
binaries/data/mods/public/gui/common/tooltips.js
288 288 trainNum = 1; 289 289 290 290 let totalCosts = multiplyEntityCosts(template, trainNum); 291 totalCosts.time = Math.ceil(template.cost.time * (entity ? Engine.GuiInterfaceCall("GetBatchTime", { "entity": entity, "batchSize": trainNum }) : 1)); 291 if (template.cost.time) 292 totalCosts.time = Math.ceil(template.cost.time * (entity ? Engine.GuiInterfaceCall("GetBatchTime", { "entity": entity, "batchSize": trainNum }) : 1)); 292 293 293 294 let costs = []; 294 295 -
binaries/data/mods/public/gui/session/input.js
1641 1641 }); 1642 1642 } 1643 1643 1644 // Transform a wall to a gate1645 function transformWallToGate(template)1644 // Upgrade an entity to another 1645 function upgradeEntity(Template) 1646 1646 { 1647 1647 var selection = g_Selection.toList(); 1648 1648 Engine.PostNetworkCommand({ 1649 "type": "wall-to-gate", 1650 "entities": selection.filter( function(e) { return getWallGateTemplate(e) == template; } ), 1651 "template": template, 1649 "type": "upgrade", 1650 "entities": selection, 1651 "template": Template, 1652 "queued": false 1652 1653 }); 1653 1654 } 1654 1655 1655 // Gets the gate form (if any) of a given long wall piece1656 function getWallGateTemplate(entity)1656 // Cancel upgrading entities 1657 function cancelUpgradeEntity() 1657 1658 { 1658 // TODO: find the gate template name in a better way 1659 var entState = GetEntityState(entity); 1660 var index; 1661 1662 if (entState && !entState.foundation && hasClass(entState, "LongWall") && (index = entState.template.indexOf("long")) >= 0) 1663 return entState.template.substr(0, index) + "gate"; 1664 return undefined; 1659 var selection = g_Selection.toList(); 1660 Engine.PostNetworkCommand({ 1661 "type": "cancel-upgrade", 1662 "entities": selection, 1663 "queued": false 1664 }); 1665 1665 } 1666 1666 1667 1667 // Set the camera to follow the given unit -
binaries/data/mods/public/gui/session/selection_panels.js
446 446 }, 447 447 "getItems": function(unitEntState, selection) 448 448 { 449 // Allow long wall pieces to be converted to gates450 let longWallTypes = {};451 let walls = [];452 449 let gates = []; 453 450 for (let ent of selection) 454 451 { 455 452 let state = GetEntityState(ent); 456 if ( hasClass(state, "LongWall") && !state.gate && !longWallTypes[state.template])453 if (state.gate && !gates.length) 457 454 { 458 let gateTemplate = getWallGateTemplate(state.id);459 if (gateTemplate)460 {461 let tooltipString = GetTemplateDataWithoutLocalization(state.template).gateConversionTooltip;462 if (!tooltipString)463 {464 warn(state.template + " is supposed to be convertable to a gate, but it's missing the GateConversionTooltip in the Identity template");465 tooltipString = "";466 }467 walls.push({468 "tooltip": translate(tooltipString),469 "template": gateTemplate,470 "callback": function (item) { transformWallToGate(item.template); }471 });472 }473 474 // We only need one entity per type.475 longWallTypes[state.template] = true;476 }477 else if (state.gate && !gates.length)478 {479 455 gates.push({ 480 456 "gate": state.gate, 481 457 "tooltip": translate("Lock Gate"), … … 495 471 delete gates[j].gate.locked; 496 472 } 497 473 498 // Place wall conversion options after gate lock/unlock icons. 499 return gates.concat(walls); 474 return gates; 500 475 }, 501 476 "setupButton": function(data) 502 477 { … … 503 478 data.button.onPress = function() {data.item.callback(data.item); }; 504 479 505 480 let tooltip = data.item.tooltip; 506 if (data.item.template) 507 { 508 data.template = GetTemplateData(data.item.template); 509 data.wallCount = data.selection.reduce(function (count, ent) { 510 let state = GetEntityState(ent); 511 if (hasClass(state, "LongWall") && !state.gate) 512 ++count; 513 return count; 514 }, 0); 481 data.button.tooltip = data.item.tooltip; 515 482 516 tooltip += "\n" + getEntityCostTooltip(data.template, data.wallCount);517 518 data.neededResources = Engine.GuiInterfaceCall("GetNeededResources", {519 "cost": multiplyEntityCosts(data.template, data.wallCount)520 });521 522 if (data.neededResources)523 tooltip += getNeededResourcesTooltip(data.neededResources);524 }525 data.button.tooltip = tooltip;526 527 483 data.button.enabled = controlsPlayer(data.unitEntState.player); 528 484 let gateIcon; 529 485 if (data.item.gate) 530 486 { 531 // If already a gate, show locking actions487 // Show locking actions 532 488 gateIcon = "icons/lock_" + GATE_ACTIONS[data.item.locked ? 0 : 1] + "ed.png"; 533 489 if (data.item.gate.locked === undefined) 534 490 data.guiSelection.hidden = false; … … 535 491 else 536 492 data.guiSelection.hidden = data.item.gate.locked != data.item.locked; 537 493 } 538 else539 {540 // Otherwise show gate upgrade icon541 let template = GetTemplateData(data.item.template);542 if (!template)543 return false;544 gateIcon = data.template.icon ? "portraits/" + data.template.icon : "icons/gate_closed.png";545 data.guiSelection.hidden = true;546 }547 494 548 495 data.icon.sprite = (data.neededResources ? resourcesToAlphaMask(data.neededResources) + ":" : "") + "stretched:session/" + gateIcon; 549 496 … … 584 531 } 585 532 let items = []; 586 533 if (checks.packButton) 587 items.push({ "packing": false, "packed": false, "tooltip": translate("Pack"), "callback": function() { packUnit(true); } }); 534 items.push({ 535 "packing": false, 536 "packed": false, 537 "tooltip": translate("Pack"), 538 "callback": function() { packUnit(true); } 539 }); 588 540 if (checks.unpackButton) 589 items.push({ "packing": false, "packed": true, "tooltip": translate("Unpack"), "callback": function() { packUnit(false); } }); 541 items.push({ 542 "packing": false, 543 "packed": true, 544 "tooltip": translate("Unpack"), 545 "callback": function() { packUnit(false); } 546 }); 590 547 if (checks.packCancelButton) 591 items.push({ "packing": true, "packed": false, "tooltip": translate("Cancel Packing"), "callback": function() { cancelPackUnit(true); } }); 548 items.push({ 549 "packing": true, 550 "packed": false, 551 "tooltip": translate("Cancel Packing"), 552 "callback": function() { cancelPackUnit(true); } 553 }); 592 554 if (checks.unpackCancelButton) 593 items.push({ "packing": true, "packed": true, "tooltip": translate("Cancel Unpacking"), "callback": function() { cancelPackUnit(false); } }); 555 items.push({ 556 "packing": true, 557 "packed": true, 558 "tooltip": translate("Cancel Unpacking"), 559 "callback": function() { cancelPackUnit(false); } 560 }); 594 561 return items; 595 562 }, 596 563 "setupButton": function(data) … … 1027 994 } 1028 995 }; 1029 996 997 g_SelectionPanels.Upgrade = { 998 "getMaxNumberOfItems": function() 999 { 1000 return 24 - getNumberOfRightPanelButtons(); 1001 }, 1002 "getItems": function(unitEntState, selection) 1003 { 1004 // Interface becomes complicated with multiple units and this is meant per-entity, so prevent it if the selection has multiple units. 1005 // TODO: if the units are all the same, this should probably still be possible. 1006 if (selection.length > 1) 1007 return false; 1030 1008 1009 if (!unitEntState.upgrade) 1010 return false; 1031 1011 1012 var items = []; 1013 1014 for (let upgrade of unitEntState.upgrade.upgrades) 1015 { 1016 var item = { 1017 "entity": upgrade.entity, 1018 "cost": upgrade.cost, 1019 "time": upgrade.time, 1020 "icon": upgrade.icon, 1021 "tooltip": upgrade.tooltip, 1022 "requiredTechnology": upgrade.requiredTechnology, 1023 }; 1024 items.push(item); 1025 } 1026 return items; 1027 }, 1028 "setupButton" : function(data) 1029 { 1030 let template = GetTemplateData(data.item.entity); 1031 if (!template) 1032 return false; 1033 1034 let isUpgrading = data.unitEntState.upgrade.template == data.item.entity; 1035 let progress = data.unitEntState.upgrade.progress || 0; 1036 1037 let technologyEnabled = true; 1038 let requiredTechnology = data.item.requiredTechnology; 1039 1040 if (requiredTechnology) 1041 technologyEnabled = Engine.GuiInterfaceCall("IsTechnologyResearched", { 1042 "tech": requiredTechnology, 1043 "player": data.unitEntState.player 1044 }); 1045 1046 let neededResources; 1047 if (data.item.cost) 1048 neededResources = Engine.GuiInterfaceCall("GetNeededResources", { 1049 "cost": data.item.cost, 1050 "player": data.unitEntState.player 1051 }); 1052 1053 let limits = getEntityLimitAndCount(data.playerState, data.item.entity); 1054 1055 let tooltip; 1056 if (!progress) 1057 { 1058 tooltip = sprintf(translate("Upgrade into a %(name)s.%(tooltip)s"), { 1059 "name": template.name.generic, 1060 "tooltip": (data.item.tooltip? "\n" + data.item.tooltip : "") 1061 }); 1062 if (data.item.cost) 1063 tooltip += "\n" + getEntityCostTooltip(data.item); 1064 1065 tooltip += formatLimitString(limits.entLimit, limits.entCount, limits.entLimitChangers); 1066 if (!technologyEnabled) 1067 tooltip += "\n" + sprintf(translate("Requires %(technology)s"), { 1068 "technology": getEntityNames(GetTechnologyData(requiredTechnology)) 1069 }); 1070 if (neededResources) 1071 tooltip += getNeededResourcesTooltip(neededResources); 1072 1073 data.button.onPress = function() { upgradeEntity(data.item.entity); }; 1074 } 1075 else if (isUpgrading) 1076 { 1077 tooltip = translate("Cancel Upgrading"); 1078 data.button.onPress = function() { cancelUpgradeEntity(); }; 1079 } 1080 else 1081 { 1082 tooltip = translate("Cannot upgrade when the entity is already upgrading."); 1083 data.button.onPress = function() {}; 1084 } 1085 data.button.tooltip = tooltip; 1086 1087 let modifier = ""; 1088 if (!isUpgrading) 1089 { 1090 if (progress || !technologyEnabled || limits.canBeAddedCount == 0) 1091 { 1092 data.button.enabled = false; 1093 modifier = "color:0 0 0 127:grayscale:"; 1094 } 1095 else if (neededResources) 1096 { 1097 data.button.enabled = false; 1098 modifier = resourcesToAlphaMask(neededResources) + ":"; 1099 } 1100 } 1101 1102 data.icon.sprite = modifier + "stretched:session/" + 1103 (data.item.icon || "portraits/" + template.icon); 1104 1105 let progressOverlay = Engine.GetGUIObjectByName("unitUpgradeProgressSlider[" + data.i + "]"); 1106 if (isUpgrading) 1107 { 1108 let size = progressOverlay.size; 1109 size.top = size.left + Math.round(progress * (size.right - size.left)); 1110 progressOverlay.size = size; 1111 progressOverlay.hidden = false; 1112 } 1113 else 1114 progressOverlay.hidden = true; 1115 1116 let index = data.i + getNumberOfRightPanelButtons(); 1117 setPanelObjectPosition(data.button, index, data.rowLength); 1118 return true; 1119 }, 1120 }; 1121 1122 1123 1032 1124 /** 1033 1125 * If two panels need the same space, so they collide, 1034 1126 * the one appearing first in the order is rendered. … … 1046 1138 // RIGHT PANE 1047 1139 "Gate", // Must always be shown on gates 1048 1140 "Pack", // Must always be shown on packable entities 1141 "Upgrade", // Must always be shown on upgradable entities 1049 1142 "Training", 1050 1143 "Construction", 1051 1144 "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/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> 13 </repeat> 14 </object> 15 </object> -
binaries/data/mods/public/gui/session/unit_commands.js
Property changes on: binaries/data/mods/public/gui/session/selection_panels_right/upgrade_panel.xml ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +text/xml \ No newline at end of property
1 1 // The number of currently visible buttons (used to optimise showing/hiding) 2 var g_unitPanelButtons = { "Selection": 0, "Queue": 0, "Formation": 0, "Garrison": 0, "Training": 0, "Research": 0, "Alert": 0, "Barter": 0, "Construction": 0, "Command": 0, "AllyCommand": 0, "Stance": 0, "Gate": 0, "Pack": 0};2 var g_unitPanelButtons = { "Selection": 0, "Queue": 0, "Formation": 0, "Garrison": 0, "Training": 0, "Research": 0, "Alert": 0, "Barter": 0, "Construction": 0, "Command": 0, "AllyCommand": 0, "Stance": 0, "Gate":0, "Pack": 0, "Upgrade": 0 }; 3 3 4 4 /** 5 5 * Set the position of a panel object according to the index, … … 225 225 { 226 226 var sum = 0; 227 227 228 for (let prop of ["Construction", "Training", "Pack", "Gate" ])228 for (let prop of ["Construction", "Training", "Pack", "Gate", "Upgrade"]) 229 229 if (g_SelectionPanels[prop].used) 230 230 sum += g_unitPanelButtons[prop]; 231 231 -
binaries/data/mods/public/simulation/components/GuiInterface.js
237 237 "market": null, 238 238 "mirage": null, 239 239 "pack": null, 240 "upgrade" : null, 240 241 "player": -1, 241 242 "position": null, 242 243 "production": null, … … 303 304 "progress": cmpPack.GetProgress(), 304 305 }; 305 306 307 var cmpUpgrade = Engine.QueryInterface(ent, IID_Upgrade); 308 if (cmpUpgrade) 309 ret.upgrade = { 310 "upgrades" : cmpUpgrade.GetUpgrades(), 311 "progress": cmpUpgrade.GetProgress(), 312 "template": cmpUpgrade.GetUpgradingTo() 313 }; 314 306 315 let cmpProductionQueue = Engine.QueryInterface(ent, IID_ProductionQueue); 307 316 if (cmpProductionQueue) 308 317 ret.production = { -
binaries/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>" + -
binaries/data/mods/public/simulation/components/interfaces/Upgrade.js
1 Engine.RegisterInterface("Upgrade"); -
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.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()) 139 { 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 points 153 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 level 163 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 guards 182 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 sound 132 if (newEntity) 133 { 190 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); -
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 (nb:GUI only)'><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) 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 (let 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": this.GetRequiredTechnology(option), 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; 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 // is undefined by default so use X in Y 170 return "CheckPlacementRestrictions" in this.template[this.upgradeTemplates[template]]; 171 }; 172 173 Upgrade.prototype.GetRequiredTechnology = function(templateArg) 174 { 175 let choice = this.upgradeTemplates[templateArg] || templateArg 176 177 if ("RequiredTechnology" in this.template[choice] && !this.template[choice].RequiredTechnology) 178 { 179 let cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); 180 let cmpIdentity = Engine.QueryInterface(this.entity, IID_Identity); 181 let entType = this.template[choice].Entity; 182 if (cmpIdentity) 183 entType = entType.replace(/\{civ\}/g, cmpIdentity.GetCiv()); 184 let template = cmpTemplateManager.GetTemplate(entType); 185 if (template.Identity.RequiredTechnology) 186 return template.Identity.RequiredTechnology; 187 } 188 else if (this.template[choice].RequiredTechnology) 189 return this.template[choice].RequiredTechnology; 190 191 return undefined; 192 }; 193 194 Upgrade.prototype.GetResourceCosts = function(template) 195 { 196 if (!this.upgradeTemplates[template]) 197 return undefined; 198 199 var choice = this.upgradeTemplates[template]; 200 if (!this.template[choice].Cost) 201 return {}; 202 203 var costs = {}; 204 for (let r in this.template[choice].Cost) 205 { 206 costs[r] = ApplyValueModificationsToEntity("Upgrade/Cost/"+r, +this.template[choice].Cost[r], this.entity); 207 } 208 return costs; 209 }; 210 211 Upgrade.prototype.Upgrade = function(template) 212 { 213 if (this.IsUpgrading()) 214 return false; 215 216 if (!this.upgradeTemplates[template]) 217 return false; 218 219 var cmpPlayer = QueryOwnerInterface(this.entity, IID_Player); 220 221 if (!cmpPlayer.TrySubtractResources(this.GetResourceCosts(template))) 222 return false; 223 224 this.upgrading = template; 225 226 // Prevent cheating 227 this.ChangeUpgradedEntityCount(1); 228 229 if (this.GetUpgradeTime(template) !== 0) 230 { 231 var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); 232 this.timer = cmpTimer.SetInterval(this.entity, IID_Upgrade, "UpgradeProgress", 0, UPGRADING_PROGRESS_INTERVAL, { "upgrading": template }); 233 } 234 else 235 this.UpgradeProgress(); 236 237 return true; 238 }; 239 240 Upgrade.prototype.CancelUpgrade = function() 241 { 242 if (this.IsUpgrading() === false) 243 return; 244 245 var cmpPlayer = QueryOwnerInterface(this.entity, IID_Player); 246 if (cmpPlayer) 247 { 248 var costs = this.GetResourceCosts(this.upgrading); 249 cmpPlayer.AddResources(costs); 250 } 251 252 this.ChangeUpgradedEntityCount(-1); 253 254 this.upgrading = false; 255 this.CancelTimer(); 256 this.SetElapsedTime(0); 257 }; 258 259 Upgrade.prototype.GetUpgradeTime = function(templateArg) 260 { 261 var template = this.upgrading || templateArg; 262 var choice = this.upgradeTemplates[template]; 263 if (!choice) 264 return undefined; 265 return this.template[choice].Time ? ApplyValueModificationsToEntity("Upgrade/Time", +this.template[choice].Time, this.entity) : 0; 266 }; 267 268 Upgrade.prototype.GetElapsedTime = function() 269 { 270 return this.elapsedTime; 271 }; 272 273 Upgrade.prototype.GetProgress = function() 274 { 275 if (!this.IsUpgrading()) 276 return undefined; 277 return this.GetUpgradeTime() == 0 ? 1 : this.elapsedTime / this.GetUpgradeTime(); 278 }; 279 280 Upgrade.prototype.SetElapsedTime = function(time) 281 { 282 this.elapsedTime = time; 283 }; 284 285 Upgrade.prototype.UpgradeProgress = function(data, lateness) 286 { 287 if (this.elapsedTime < this.GetUpgradeTime()) 288 { 289 this.SetElapsedTime(this.GetElapsedTime() + UPGRADING_PROGRESS_INTERVAL + lateness); 290 return; 291 } 292 293 this.CancelTimer(); 294 295 var newEntity = ChangeEntityTemplate(this.entity, this.upgrading); 296 297 if (newEntity) 298 PlaySound("upgraded", newEntity); 299 }; 300 301 Engine.RegisterComponentType(IID_Upgrade, "Upgrade", Upgrade); -
binaries/data/mods/public/simulation/helpers/Commands.js
578 578 } 579 579 }, 580 580 581 "wall-to-gate": function(player, cmd, data)582 {583 for (let ent of data.entities)584 TryTransformWallToGate(ent, data.cmpPlayer, cmd);585 },586 587 581 "lock-gate": function(player, cmd, data) 588 582 { 589 583 for (let ent of data.entities) … … 668 662 } 669 663 }, 670 664 665 "upgrade": function(player, cmd, data) 666 { 667 for (let ent of data.entities) 668 { 669 var cmpUpgrade = Engine.QueryInterface(ent, IID_Upgrade); 670 671 if (!cmpUpgrade || !cmpUpgrade.CanUpgradeTo(cmd.template)) 672 continue; 673 674 if (cmpUpgrade.WillCheckPlacementRestrictions(cmd.template) && ObstructionsBlockingTemplateChange(ent, cmd.template)) 675 { 676 var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface); 677 cmpGUIInterface.PushNotification({ 678 "players": [data.cmpPlayer.GetPlayerID()], 679 "message": markForTranslation("Cannot upgrade as distance requirements are not verified or terrain is obstructed.") 680 }); 681 continue; 682 } 683 684 if (!CanGarrisonedChangeTemplate(ent, cmd.template)) 685 { 686 var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface); 687 cmpGUIInterface.PushNotification({ 688 "players": [data.cmpPlayer.GetPlayerID()], 689 "message": markForTranslation("Cannot upgrade a garrisoned entity.") 690 }); 691 continue; 692 } 693 694 // Check entity limits 695 var cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); 696 var template = cmpTemplateManager.GetTemplate(cmd.template); 697 var cmpEntityLimits = QueryPlayerIDInterface(player, IID_EntityLimits); 698 if (template.TrainingRestrictions && !cmpEntityLimits.AllowedToTrain(template.TrainingRestrictions.Category, 1) || 699 template.BuildRestrictions && !cmpEntityLimits.AllowedToBuild(template.BuildRestrictions.Category)) 700 { 701 if (g_DebugCommands) 702 warn("Invalid command: build limits check failed for player " + player + ": " + uneval(cmd)); 703 continue; 704 } 705 706 var cmpTechnologyManager = QueryOwnerInterface(ent, IID_TechnologyManager); 707 if (cmpUpgrade.GetRequiredTechnology(cmd.template) && !cmpTechnologyManager.IsTechnologyResearched(cmpUpgrade.GetRequiredTechnology(cmd.template))) 708 { 709 if (g_DebugCommands) 710 warn("Invalid command: upgrading requires unresearched technology: " + uneval(cmd)); 711 continue; 712 } 713 714 cmpUpgrade.Upgrade(cmd.template, data.cmpPlayer); 715 } 716 }, 717 718 "cancel-upgrade": function(player, cmd, data) 719 { 720 for (let ent of data.entities) 721 { 722 let cmpUpgrade = Engine.QueryInterface(ent, IID_Upgrade); 723 if (cmpUpgrade) 724 cmpUpgrade.CancelUpgrade(data.cmpPlayer); 725 } 726 }, 671 727 "attack-request": function(player, cmd, data) 672 728 { 673 729 // Send a chat message to human players … … 1567 1623 return entities.filter(ent => CanControlUnitOrIsAlly(ent, player, controlAll)); 1568 1624 } 1569 1625 1570 /**1571 * Try to transform a wall to a gate1572 */1573 function TryTransformWallToGate(ent, cmpPlayer, cmd)1574 {1575 var cmpIdentity = Engine.QueryInterface(ent, IID_Identity);1576 if (!cmpIdentity)1577 return;1578 1579 if (!cmpIdentity.HasClass("LongWall"))1580 {1581 if (g_DebugCommands)1582 warn("Invalid command: invalid wall conversion to gate for player "+player+": "+uneval(cmd));1583 return;1584 }1585 1586 var gate = Engine.AddEntity(cmd.template);1587 1588 var cmpCost = Engine.QueryInterface(gate, IID_Cost);1589 if (!cmpPlayer.TrySubtractResources(cmpCost.GetResourceCosts()))1590 {1591 if (g_DebugCommands)1592 warn("Invalid command: convert gate cost check failed for player "+player+": "+uneval(cmd));1593 1594 Engine.DestroyEntity(gate);1595 return;1596 }1597 1598 ReplaceBuildingWith(ent, gate);1599 }1600 1601 /**1602 * Unconditionally replace a building with another one1603 */1604 function ReplaceBuildingWith(ent, building)1605 {1606 // Move the building to the right place1607 var cmpPosition = Engine.QueryInterface(ent, IID_Position);1608 var cmpBuildingPosition = Engine.QueryInterface(building, IID_Position);1609 var pos = cmpPosition.GetPosition2D();1610 cmpBuildingPosition.JumpTo(pos.x, pos.y);1611 var rot = cmpPosition.GetRotation();1612 cmpBuildingPosition.SetYRotation(rot.y);1613 cmpBuildingPosition.SetXZRotation(rot.x, rot.z);1614 1615 // Copy ownership1616 var cmpOwnership = Engine.QueryInterface(ent, IID_Ownership);1617 var cmpBuildingOwnership = Engine.QueryInterface(building, IID_Ownership);1618 cmpBuildingOwnership.SetOwner(cmpOwnership.GetOwner());1619 1620 // Copy control groups1621 var cmpObstruction = Engine.QueryInterface(ent, IID_Obstruction);1622 var cmpBuildingObstruction = Engine.QueryInterface(building, IID_Obstruction);1623 cmpBuildingObstruction.SetControlGroup(cmpObstruction.GetControlGroup());1624 cmpBuildingObstruction.SetControlGroup2(cmpObstruction.GetControlGroup2());1625 1626 // Copy health level from the old entity to the new1627 var cmpHealth = Engine.QueryInterface(ent, IID_Health);1628 var cmpBuildingHealth = Engine.QueryInterface(building, IID_Health);1629 var healthFraction = Math.max(0, Math.min(1, cmpHealth.GetHitpoints() / cmpHealth.GetMaxHitpoints()));1630 var buildingHitpoints = Math.round(cmpBuildingHealth.GetMaxHitpoints() * healthFraction);1631 cmpBuildingHealth.SetHitpoints(buildingHitpoints);1632 1633 PlaySound("constructed", building);1634 1635 Engine.PostMessage(ent, MT_ConstructionFinished,1636 { "entity": ent, "newentity": building });1637 Engine.BroadcastMessage(MT_EntityRenamed, { entity: ent, newentity: building });1638 1639 Engine.DestroyEntity(ent);1640 }1641 1642 1626 Engine.RegisterGlobal("GetFormationRequirements", GetFormationRequirements); 1643 1627 Engine.RegisterGlobal("CanMoveEntsIntoFormation", CanMoveEntsIntoFormation); 1644 1628 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 // 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(v => 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) 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 // prevent preview from interfering in the world 181 cmpNewPosition.MoveOutOfWorld(); 182 cmpPosition.JumpTo(position.x, position.y); 183 cmpPosition.SetYRotation(angle.y); 184 185 Engine.DestroyEntity(ent); 186 return ret; 187 }; 188 189 var TransferGarrisonedUnits = function(oldEnt, newEnt) 190 { 191 // Transfer garrisoned units if possible, or unload them 192 var cmpGarrison = Engine.QueryInterface(oldEnt, IID_GarrisonHolder); 193 var cmpNewGarrison = Engine.QueryInterface(newEnt, IID_GarrisonHolder); 194 if (!cmpNewGarrison || !cmpGarrison || !cmpGarrison.GetEntities().length) 195 return; // nothing to do as the code will by default unload all. 196 197 var garrisonedEntities = cmpGarrison.GetEntities().slice(); 198 for (let j in garrisonedEntities) 199 { 200 var cmpUnitAI = Engine.QueryInterface(garrisonedEntities[j], IID_UnitAI); 201 cmpGarrison.Eject(garrisonedEntities[j]); 202 cmpUnitAI.Autogarrison(newEnt); 203 cmpNewGarrison.Garrison(garrisonedEntities[j]); 204 } 205 }; 206 207 Engine.RegisterGlobal("ChangeEntityTemplate", ChangeEntityTemplate); 208 Engine.RegisterGlobal("CanGarrisonedChangeTemplate", CanGarrisonedChangeTemplate); 209 Engine.RegisterGlobal("ObstructionsBlockingTemplateChange", ObstructionsBlockingTemplateChange); -
binaries/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 <Icon>gaia/special_palisade.png</Icon> 32 31 <RequiredTechnology>phase_village</RequiredTechnology> … … 45 44 <WallPiece> 46 45 <Length>11.0</Length> 47 46 </WallPiece> 47 <Upgrade> 48 <Gate> 49 <Entity>other/palisades_rocks_gate</Entity> 50 <Cost> 51 <stone>0</stone> 52 <wood>20</wood> 53 </Cost> 54 <Time>5000</Time> 55 </Gate> 56 </Upgrade> 48 57 </Entity> -
binaries/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> -
binaries/data/mods/public/simulation/templates/template_structure_defense_wall_long.xml
38 38 <Identity> 39 39 <Classes datatype="tokens">LongWall</Classes> 40 40 <Tooltip>Long wall segments can be converted to gates.</Tooltip> 41 <GateConversionTooltip>Convert Stone Wall into City Gate</GateConversionTooltip>42 41 </Identity> 42 <Upgrade> 43 <Gate> 44 <Entity>structures/{civ}_wall_gate</Entity> 45 <Tooltip>This will allow you to let units circulate through your fortifications.</Tooltip> 46 <Cost> 47 <stone>60</stone> 48 </Cost> 49 <Time>10000</Time> 50 </Gate> 51 </Upgrade> 43 52 </Entity>