Ticket #2706: UpgradeComponent.patch
File UpgradeComponent.patch, 38.5 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 for (var ent of selection) 507 { 508 var state = GetEntityState(ent); 509 if (!state.upgrade) 510 continue; 511 512 for each (var upgrade in state.upgrade.upgrades) 513 { 514 var item = {}; 515 item.entType = upgrade.entity; 516 item.template = GetTemplateData(upgrade.entity); 517 if (!item.template) // abort if no template 518 return false; 519 520 item.icon = upgrade.icon; 521 if (!item.icon) 522 item.icon = "portraits/" + item.template.icon; 523 524 if (upgrade.requiredTechnology !== null) 525 { 526 item.requiredTechnology = upgrade.requiredTechnology; 527 if (!item.requiredTechnology && item.template.requiredTechnology) 528 item.requiredTechnology = item.template.requiredTechnology 529 } 530 item.cost = upgrade.cost; 531 item.time = upgrade.time; 532 533 if (state.upgrade.progress === undefined) 534 { 535 item.upgrading = -2; 536 item.tooltip = translate("Upgrade into a " + item.template.name.generic + (upgrade.tooltip? ".\n" + upgrade.tooltip : ".")); 537 item.callback = function(data) { upgradeEntity(data.entType); }; 538 } 539 else if (state.upgrade.template !== upgrade.entity) 540 { 541 item.upgrading = -1; 542 item.tooltip = translate("Cannot upgrade when the entity is already upgrading."); 543 item.callback = function(data) { }; 544 } 545 else 546 { 547 item.upgrading = state.upgrade.progress; 548 item.tooltip = translate("Cancel Upgrading"); 549 item.callback = function(data) { cancelUpgradeEntity(); }; 550 } 551 items.push(item); 552 } 553 } 554 return items; 555 }, 556 "addData" : function(data) 557 { 558 data.item.technologyEnabled = true; 559 if (data.item.requiredTechnology) 560 data.item.technologyEnabled = Engine.GuiInterfaceCall("IsTechnologyResearched", data.item.requiredTechnology); 561 if (data.item.cost) 562 { 563 var totalCost = { "food": 0, "wood": 0, "stone": 0, "metal": 0, "time": 0 }; // I've been unable to find an utility function for this, should be one though. 564 for (var i in data.item.cost) 565 totalCost[i] += data.item.cost[i]; 566 data.item.neededResources = Engine.GuiInterfaceCall("GetNeededResources", totalCost); 567 } 568 data.item.limits = getEntityLimitAndCount(data.playerState, data.item.entType); 569 return true; 570 }, 571 "setAction": function(data) 572 { 573 data.button.onPress = function() { data.item.callback(data.item); }; 574 }, 575 "setTooltip": function(data) 576 { 577 var tooltip = data.item.tooltip; 578 579 if (data.item.upgrading !== -2) 580 { 581 data.button.tooltip = tooltip; 582 return; 583 } 584 585 if (data.item.cost) 586 tooltip += "\n" + getEntityCostTooltip(data.item); 587 588 tooltip += formatLimitString(data.item.limits.entLimit, data.item.limits.entCount, data.item.limits.entLimitChangers); 589 if (!data.item.technologyEnabled) 590 { 591 var techName = getEntityNames(GetTechnologyData(data.item.requiredTechnology)); 592 tooltip += "\n" + sprintf(translate("Requires %(technology)s"), { technology: techName }); 593 } 594 if (data.item.neededResources) 595 tooltip += getNeededResourcesTooltip(data.item.neededResources); 596 597 data.button.tooltip = tooltip; 598 }, 599 "setGraphics": function(data) 600 { 601 var grayscale = ""; 602 if (data.item.upgrading == -1 || !data.item.technologyEnabled || (data.item.limits.canBeAddedCount == 0 && data.item.upgrading == -2)) 603 { 604 data.button.enabled = false; 605 grayscale = "grayscale:"; 606 data.affordableMask.hidden = false; 607 data.affordableMask.sprite = "colour: 0 0 0 127"; 608 } 609 else if (data.item.upgrading == -2 && data.item.neededResources) 610 { 611 data.button.enabled = false; 612 data.affordableMask.hidden = false; 613 data.affordableMask.sprite = resourcesToAlphaMask(data.item.neededResources); 614 } 615 616 data.icon.sprite = "stretched:" + grayscale + "session/" + data.item.icon; 617 618 619 var guiObject = Engine.GetGUIObjectByName("unitUpgradeProgressSlider["+data.i+"]"); 620 var size = guiObject.size; 621 if (data.item.upgrading < 0) 622 size.top = size.right; 623 else 624 size.top = size.left + Math.round(Math.max(0,data.item.upgrading) * (size.right - size.left)); 625 guiObject.size = size; 626 }, 627 "setPosition": function(data) 628 { 629 var index = data.i + getNumberOfRightPanelButtons(); 630 setPanelObjectPosition(data.button, index, data.rowLength); 631 }, 632 }; 633 544 634 // QUEUE 545 635 g_SelectionPanels.Queue = { 546 636 "getMaxNumberOfItems": function() … … 1015 1105 // RIGHT PANE 1016 1106 "Gate", // must always be shown on gates 1017 1107 "Pack", // must always be shown on packable entities 1108 "Upgrade", // must always be shown on upgradable entities 1018 1109 "Training", 1019 1110 "Construction", 1020 1111 "Research", // normal together with training -
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
180 180 "gate": null, 181 181 "guard": null, 182 182 "pack": null, 183 "upgrade" : null, 183 184 "player": -1, 184 185 "position": null, 185 186 "production": null, … … 232 233 }; 233 234 } 234 235 236 var cmpUpgrade = Engine.QueryInterface(ent, IID_Upgrade); 237 if (cmpUpgrade) 238 { 239 ret.upgrade = { 240 "upgrades" : cmpUpgrade.GetUpgrades(), 241 "progress": cmpUpgrade.GetProgress(), 242 "template": cmpUpgrade.GetUpgradingTo() 243 }; 244 } 245 235 246 var cmpProductionQueue = Engine.QueryInterface(ent, IID_ProductionQueue); 236 247 if (cmpProductionQueue) 237 248 { … … 653 664 }; 654 665 ret.icon = template.Identity.Icon; 655 666 ret.tooltip = template.Identity.Tooltip; 656 ret.gateConversionTooltip = template.Identity.GateConversionTooltip;657 667 ret.requiredTechnology = template.Identity.RequiredTechnology; 658 668 ret.visibleIdentityClasses = GetVisibleIdentityClasses(template.Identity); 659 669 } -
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/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 this.upgradeTemplates[name] = choice; 70 } 71 }; 72 73 // We need to know our owner for when we're destroyed. 74 Upgrade.prototype.OnOwnershipChanged = function(msg) 75 { 76 if (msg.to !== -1) 77 this.owner = msg.to; 78 }; 79 80 Upgrade.prototype.ChangeUpgradedEntityCount = function(amount) 81 { 82 if (!this.IsUpgrading()) 83 return; 84 var cmpTempMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); 85 var template = cmpTempMan.GetTemplate(this.upgrading); 86 var category = null; 87 if (template.TrainingRestrictions) 88 category = template.TrainingRestrictions.Category; 89 else if (template.BuildRestrictions) 90 category = template.BuildRestrictions.Category; 91 92 var cmpEntityLimits = QueryPlayerIDInterface(this.owner, IID_EntityLimits); 93 cmpEntityLimits.ChangeCount(category,amount); 94 } 95 96 Upgrade.prototype.OnDestroy = function() 97 { 98 var cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager); 99 var cmpPlayer = Engine.QueryInterface(cmpPlayerManager.GetPlayerByID(this.owner), IID_Player); 100 if (cmpPlayer) 101 { 102 var costs = this.GetResourceCosts(this.upgrading); 103 cmpPlayer.AddResources(costs); 104 } 105 if (this.GetProgress() < 1) 106 this.ChangeUpgradedEntityCount(-1); 107 this.CancelTimer(); 108 }; 109 110 Upgrade.prototype.CanUpgradeTo = function(Template) 111 { 112 return this.upgradeTemplates[Template] !== undefined; 113 }; 114 115 Upgrade.prototype.GetUpgrades = function() 116 { 117 var ret = []; 118 119 var cmpIdentity = Engine.QueryInterface(this.entity, IID_Identity); 120 121 for each (var choice in this.template) 122 { 123 var entType = choice.Entity; 124 if (cmpIdentity) 125 entType = entType.replace(/\{civ\}/g, cmpIdentity.GetCiv()); 126 127 var hasCosts = false; 128 var cost = {}; 129 if (choice.Cost) 130 { 131 hasCosts = true; 132 for (var type in choice.Cost) 133 cost[type] = ApplyValueModificationsToTemplate("Upgrade/Cost/"+type, +choice.Cost[type], this.owner, entType); 134 } 135 if (choice.Time) 136 { 137 hasCosts = true; 138 cost["time"] = ApplyValueModificationsToTemplate("Upgrade/Time", +choice.Time/1000.0, this.owner, entType); 139 } 140 ret.push( 141 { 142 "entity": entType, 143 "icon": choice.Icon || undefined, 144 "cost": hasCosts ? cost : undefined, 145 "tooltip": choice.Tooltip || undefined, 146 "requiredTechnology": "RequiredTechnology" in choice ? choice.RequiredTechnology : null, 147 }); 148 } 149 150 return ret; 151 }; 152 153 Upgrade.prototype.CancelTimer = function() 154 { 155 if (this.timer) 156 { 157 var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); 158 cmpTimer.CancelTimer(this.timer); 159 this.timer = undefined; 160 } 161 }; 162 163 Upgrade.prototype.IsUpgrading = function() 164 { 165 return this.upgrading !== false; 166 }; 167 168 Upgrade.prototype.GetUpgradingTo = function() 169 { 170 return this.upgrading; 171 }; 172 173 Upgrade.prototype.CheckPlacementRestrictions = function(Template) 174 { 175 if (!this.upgradeTemplates[Template]) 176 return undefined; 177 178 return ("CheckPlacementRestrictions" in this.template[this.upgradeTemplates[Template]]); 179 }; 180 181 Upgrade.prototype.GetRequiredTechnology = function(Template) 182 { 183 if (!this.upgradeTemplates[Template]) 184 return undefined; 185 186 var choice = this.upgradeTemplates[Template]; 187 188 if ("RequiredTechnology" in this.template[choice] && this.template[choice].RequiredTechnology === undefined) 189 { 190 var cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); 191 var template = cmpTemplateManager.GetTemplate(this.template[choice].Entity); 192 if (template.Identity.RequiredTechnology) 193 return template.Identity.RequiredTechnology; 194 } 195 else if ("RequiredTechnology" in this.template[choice]) 196 return this.template[choice].RequiredTechnology; 197 return null; 198 }; 199 200 Upgrade.prototype.GetResourceCosts = function(Template) 201 { 202 if (!this.upgradeTemplates[Template]) 203 return undefined; 204 205 var choice = this.upgradeTemplates[Template]; 206 if (!this.template[choice].Cost) 207 return {}; 208 209 var costs = {}; 210 for (var r in this.template[choice].Cost) 211 { 212 costs[r] = +this.template[choice].Cost[r]; 213 costs[r] = ApplyValueModificationsToEntity("Upgrade/Cost/"+r, costs[r], this.entity); 214 } 215 return costs; 216 }; 217 218 Upgrade.prototype.Upgrade = function(Template, PlayerComponent) 219 { 220 if (this.IsUpgrading()) 221 return false; 222 223 if (!this.upgradeTemplates[Template]) 224 return false; 225 226 var cmpPlayer = PlayerComponent; 227 if (!cmpPlayer) 228 { 229 var cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager); 230 var cmpPlayer = Engine.QueryInterface(cmpPlayerManager.GetPlayerByID(this.owner), IID_Player); 231 } 232 if (!cmpPlayer.TrySubtractResources(this.GetResourceCosts(Template))) 233 return false; 234 235 this.upgrading = Template; 236 237 // prevent cheating 238 this.ChangeUpgradedEntityCount(1); 239 240 if (this.GetUpgradeTime(Template) !== 0) 241 { 242 var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); 243 this.timer = cmpTimer.SetInterval(this.entity, IID_Upgrade, "UpgradeProgress", 0, UPGRADING_PROGRESS_INTERVAL, {"upgrading": Template}); 244 } 245 else 246 { 247 this.UpgradeProgress(); 248 } 249 return true; 250 }; 251 252 Upgrade.prototype.CancelUpgrade = function(PlayerComponent) 253 { 254 if (this.IsUpgrading() === false) 255 return; 256 257 var cmpPlayer = PlayerComponent; 258 if (!cmpPlayer) 259 { 260 var cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager); 261 var cmpPlayer = Engine.QueryInterface(cmpPlayerManager.GetPlayerByID(this.owner), IID_Player); 262 } 263 if (cmpPlayer) 264 { 265 var costs = this.GetResourceCosts(this.upgrading); 266 cmpPlayer.AddResources(costs); 267 } 268 269 this.ChangeUpgradedEntityCount(-1); 270 271 this.CancelTimer(); 272 this.upgrading = false; 273 this.SetElapsedTime(0); 274 }; 275 276 Upgrade.prototype.GetUpgradeTime = function(Template) 277 { 278 var template = this.upgrading || Template; 279 var choice = this.upgradeTemplates[template]; 280 if (!choice) 281 return undefined; 282 return this.template[choice].Time ? ApplyValueModificationsToEntity("Upgrade/Time", +this.template[choice].Time, this.entity) : 0; 283 }; 284 285 Upgrade.prototype.GetElapsedTime = function() 286 { 287 return this.elapsedTime; 288 }; 289 290 Upgrade.prototype.GetProgress = function() 291 { 292 // Hopefully undefined and 0 are the only thing that would trigger that. 293 if (!this.IsUpgrading()) 294 return undefined; 295 return this.GetUpgradeTime() == 0 ? 1 : this.elapsedTime / this.GetUpgradeTime(); 296 }; 297 298 Upgrade.prototype.SetElapsedTime = function(time) 299 { 300 this.elapsedTime = time; 301 }; 302 303 Upgrade.prototype.UpgradeProgress = function(data, lateness) 304 { 305 if (this.elapsedTime >= this.GetUpgradeTime()) 306 { 307 this.CancelTimer(); 308 309 var choice = this.upgradeTemplates[this.upgrading]; 310 311 // Done un/packing, copy our parameters to the final entity 312 var newEntity = Engine.AddEntity(this.upgrading); 313 if (newEntity == INVALID_ENTITY) 314 { 315 // Error (e.g. invalid template names) 316 error("UpgradeProgress: Error creating entity for '" + this.upgrading + "'"); 317 return; 318 } 319 320 var cmpPosition = Engine.QueryInterface(this.entity, IID_Position); 321 var cmpNewPosition = Engine.QueryInterface(newEntity, IID_Position); 322 if (cmpPosition.IsInWorld()) 323 { 324 var pos = cmpPosition.GetPosition2D(); 325 cmpNewPosition.JumpTo(pos.x, pos.y); 326 } 327 var rot = cmpPosition.GetRotation(); 328 cmpNewPosition.SetYRotation(rot.y); 329 cmpNewPosition.SetXZRotation(rot.x, rot.z); 330 cmpNewPosition.SetHeightOffset(cmpPosition.GetHeightOffset()); 331 332 var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); 333 var cmpNewOwnership = Engine.QueryInterface(newEntity, IID_Ownership); 334 cmpNewOwnership.SetOwner(cmpOwnership.GetOwner()); 335 336 // Copy control groups 337 var cmpObstruction = Engine.QueryInterface(this.entity, IID_Obstruction); 338 var cmpNewObstruction = Engine.QueryInterface(newEntity, IID_Obstruction); 339 if (cmpObstruction && cmpNewObstruction) 340 { 341 cmpNewObstruction.SetControlGroup(cmpObstruction.GetControlGroup()); 342 cmpNewObstruction.SetControlGroup2(cmpObstruction.GetControlGroup2()); 343 } 344 345 // Maintain current health level 346 var cmpHealth = Engine.QueryInterface(this.entity, IID_Health); 347 var cmpNewHealth = Engine.QueryInterface(newEntity, IID_Health); 348 var healthLevel = Math.max(0, Math.min(1, cmpHealth.GetHitpoints() / cmpHealth.GetMaxHitpoints())); 349 cmpNewHealth.SetHitpoints(Math.round(cmpNewHealth.GetMaxHitpoints() * healthLevel)); 350 351 var cmpUnitAI = Engine.QueryInterface(this.entity, IID_UnitAI); 352 var cmpNewUnitAI = Engine.QueryInterface(newEntity, IID_UnitAI); 353 if (cmpUnitAI && cmpNewUnitAI) 354 { 355 var pos = cmpUnitAI.GetHeldPosition(); 356 if (pos) 357 cmpNewUnitAI.SetHeldPosition(pos.x, pos.z); 358 if (cmpUnitAI.GetStanceName()) 359 cmpNewUnitAI.SwitchToStance(cmpUnitAI.GetStanceName()); 360 cmpNewUnitAI.AddOrders(cmpUnitAI.GetOrders()); 361 cmpNewUnitAI.SetGuardOf(cmpUnitAI.IsGuardOf()); 362 } 363 364 // Maintain the list of guards 365 var cmpGuard = Engine.QueryInterface(this.entity, IID_Guard); 366 var cmpNewGuard = Engine.QueryInterface(newEntity, IID_Guard); 367 if (cmpGuard && cmpNewGuard) 368 cmpNewGuard.SetEntities(cmpGuard.GetEntities()); 369 370 Engine.BroadcastMessage(MT_EntityRenamed, { entity: this.entity, newentity: newEntity }); 371 372 this.ChangeUpgradedEntityCount(-1); 373 374 // Play notification sound 375 PlaySound("upgraded", newEntity); 376 377 // Destroy current entity 378 Engine.DestroyEntity(this.entity); 379 } 380 else 381 { 382 this.SetElapsedTime(this.GetElapsedTime() + UPGRADING_PROGRESS_INTERVAL + lateness); 383 } 384 }; 385 386 /** 387 * @return True if the entity to transform into is allowed on the current terrain/territory. 388 False otherwise 389 */ 390 Upgrade.prototype.CanTransform = function (Template) 391 { 392 var canTransform = true; 393 394 var choice = this.upgradeTemplates[Template]; 395 if (!choice) 396 return false; 397 398 // Create a preview entity to check. 399 var previewEntityTemplate = Template; 400 var previewEntity = Engine.AddEntity("preview|"+previewEntityTemplate); 401 402 if (previewEntity == INVALID_ENTITY) 403 canTransform = false; 404 else 405 { 406 var cmpBuildRestrictions = Engine.QueryInterface(previewEntity, IID_BuildRestrictions); 407 if (cmpBuildRestrictions) 408 { 409 // Position and ownership needs to be set for placement checks 410 var cmpPosition = Engine.QueryInterface(this.entity, IID_Position); 411 if (!cmpPosition.IsInWorld()) 412 canTransform = false; 413 414 var pos = cmpPosition.GetPosition2D(); 415 var angle = cmpPosition.GetRotation(); 416 // move us away to avoid our obstruction blocking the upgrade. 417 cmpPosition.MoveOutOfWorld(); 418 419 var cmpNewPosition = Engine.QueryInterface(previewEntity, IID_Position); 420 cmpNewPosition.JumpTo(pos.x, pos.y); 421 cmpNewPosition.SetYRotation(angle.y); 422 423 var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); 424 var cmpNewOwnership = Engine.QueryInterface(previewEntity, IID_Ownership); 425 cmpNewOwnership.SetOwner(cmpOwnership.GetOwner()); 426 427 var checkPlacement = cmpBuildRestrictions.CheckPlacement(); 428 if (checkPlacement && !checkPlacement.success) 429 canTransform = false; 430 431 // TODO maybe: this is only really needed if the new obstruction is bigger. 432 var cmpNewObstruction = Engine.QueryInterface(previewEntity, IID_Obstruction); 433 if (canTransform && cmpNewObstruction && cmpNewObstruction.GetBlockMovementFlag()) 434 { 435 // Check for units 436 var collisions = cmpNewObstruction.GetEntityCollisions(false, true); 437 if (collisions.length !== 0) 438 canTransform = false; 439 } 440 441 // Move preview entity out of world so it won't interfere with additional calls 442 // to this function for this entity on the same sim update. 443 // Specifically, CheckPlacement() would incorrectly spot and fail on earlier preview entities 444 // if those are left in the world. 445 cmpNewPosition.MoveOutOfWorld(); 446 cmpPosition.JumpTo(pos.x, pos.y); 447 cmpPosition.SetYRotation(angle.y); 448 } 449 } 450 Engine.DestroyEntity(previewEntity); 451 return canTransform; 452 }; 453 454 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 var templateName = cmd.template; 645 646 if (!cmpUpgrade || !cmpUpgrade.CanUpgradeTo(templateName)) 647 continue; 648 649 if (cmpUpgrade.CheckPlacementRestrictions(templateName) && !cmpUpgrade.CanTransform(templateName)) 650 { 651 var notification = {"players": [data.cmpPlayer.GetPlayerID()], "message": "Cannot upgrade as distance requirements are not verified or terrain is obstructed." }; 652 var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface); 653 cmpGUIInterface.PushNotification(notification); 654 continue; 655 } 656 657 // Check entity limits 658 var cmpTempMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); 659 var template = cmpTempMan.GetTemplate(templateName); 660 var cmpEntityLimits = QueryPlayerIDInterface(player, IID_EntityLimits); 661 if ((template.TrainingRestrictions && !cmpEntityLimits.AllowedToTrain(template.TrainingRestrictions.Category,1)) 662 || (template.BuildRestrictions && !cmpEntityLimits.AllowedToBuild(template.BuildRestrictions.Category))) 663 { 664 if (g_DebugCommands) 665 warn("Invalid command: build limits check failed for player "+player+": "+uneval(cmd)); 666 continue; 667 } 668 669 var cmpTechnologyManager = QueryOwnerInterface(ent, IID_TechnologyManager); 670 if (cmpUpgrade.GetRequiredTechnology() && !cmpTechnologyManager.IsTechnologyResearched(cmpUpgrade.GetRequiredTechnology())) 671 { 672 if (g_DebugCommands) 673 warn("Invalid command: upgrading requires unresearched technology: " + uneval(cmd)); 674 continue; 675 } 676 677 cmpUpgrade.Upgrade(templateName, data.cmpPlayer); 678 } 679 }, 680 681 "cancel-upgrade": function(player, cmd, data) 682 { 683 for each (var ent in data.entities) 684 { 685 var cmpUpgrade = Engine.QueryInterface(ent, IID_Upgrade); 686 687 if (!cmpUpgrade) 688 continue 689 690 cmpUpgrade.CancelUpgrade(data.cmpPlayer); 691 } 692 }, 693 645 694 "dialog-answer": function(player, cmd, data) 646 695 { 647 696 // Currently nothing. Triggers can read it anyway, and send this … … 1512 1561 return entities.filter(function(ent) { return CanControlUnitOrIsAlly(ent, player, controlAll);} ); 1513 1562 } 1514 1563 1515 /**1516 * Try to transform a wall to a gate1517 */1518 function TryTransformWallToGate(ent, cmpPlayer, template)1519 {1520 var cmpIdentity = Engine.QueryInterface(ent, IID_Identity);1521 if (!cmpIdentity)1522 return;1523 1524 // Check if this is a valid long wall segment1525 if (!cmpIdentity.HasClass("LongWall"))1526 {1527 if (g_DebugCommands)1528 warn("Invalid command: invalid wall conversion to gate for player "+player+": "+uneval(cmd));1529 return;1530 }1531 1532 var civ = cmpIdentity.GetCiv();1533 var gate = Engine.AddEntity(template);1534 1535 var cmpCost = Engine.QueryInterface(gate, IID_Cost);1536 if (!cmpPlayer.TrySubtractResources(cmpCost.GetResourceCosts()))1537 {1538 if (g_DebugCommands)1539 warn("Invalid command: convert gate cost check failed for player "+player+": "+uneval(cmd));1540 1541 Engine.DestroyEntity(gate);1542 return;1543 }1544 1545 ReplaceBuildingWith(ent, gate);1546 }1547 1548 /**1549 * Unconditionally replace a building with another one1550 */1551 function ReplaceBuildingWith(ent, building)1552 {1553 // Move the building to the right place1554 var cmpPosition = Engine.QueryInterface(ent, IID_Position);1555 var cmpBuildingPosition = Engine.QueryInterface(building, IID_Position);1556 var pos = cmpPosition.GetPosition2D();1557 cmpBuildingPosition.JumpTo(pos.x, pos.y);1558 var rot = cmpPosition.GetRotation();1559 cmpBuildingPosition.SetYRotation(rot.y);1560 cmpBuildingPosition.SetXZRotation(rot.x, rot.z);1561 1562 // Copy ownership1563 var cmpOwnership = Engine.QueryInterface(ent, IID_Ownership);1564 var cmpBuildingOwnership = Engine.QueryInterface(building, IID_Ownership);1565 cmpBuildingOwnership.SetOwner(cmpOwnership.GetOwner());1566 1567 // Copy control groups1568 var cmpObstruction = Engine.QueryInterface(ent, IID_Obstruction);1569 var cmpBuildingObstruction = Engine.QueryInterface(building, IID_Obstruction);1570 cmpBuildingObstruction.SetControlGroup(cmpObstruction.GetControlGroup());1571 cmpBuildingObstruction.SetControlGroup2(cmpObstruction.GetControlGroup2());1572 1573 // Copy health level from the old entity to the new1574 var cmpHealth = Engine.QueryInterface(ent, IID_Health);1575 var cmpBuildingHealth = Engine.QueryInterface(building, IID_Health);1576 var healthFraction = Math.max(0, Math.min(1, cmpHealth.GetHitpoints() / cmpHealth.GetMaxHitpoints()));1577 var buildingHitpoints = Math.round(cmpBuildingHealth.GetMaxHitpoints() * healthFraction);1578 cmpBuildingHealth.SetHitpoints(buildingHitpoints);1579 1580 PlaySound("constructed", building);1581 1582 Engine.PostMessage(ent, MT_ConstructionFinished,1583 { "entity": ent, "newentity": building });1584 Engine.BroadcastMessage(MT_EntityRenamed, { entity: ent, newentity: building });1585 1586 Engine.DestroyEntity(ent);1587 }1588 1589 1564 Engine.RegisterGlobal("GetFormationRequirements", GetFormationRequirements); 1590 1565 Engine.RegisterGlobal("CanMoveEntsIntoFormation", CanMoveEntsIntoFormation); 1591 1566 Engine.RegisterGlobal("GetDockAngle", GetDockAngle); -
binaries/data/mods/public/simulation/templates/template_structure_defense_wall_long.xml
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>