Ticket #996: capture.4.diff
File capture.4.diff, 55.7 KB (added by , 9 years ago) |
---|
-
binaries/data/mods/public/globalscripts/Templates.js
90 90 91 91 if (template.Attack) 92 92 { 93 let getAttackStat = function(type, stat) 94 { 95 return func("Attack/"+type+"/"+stat, +(template.Attack[type][stat] || 0), player, template); 96 }; 97 93 98 ret.attack = {}; 94 for ( vartype in template.Attack)99 for (let type in template.Attack) 95 100 { 96 ret.attack[type] = { 97 "hack": func("Attack/"+type+"/Hack", +(template.Attack[type].Hack || 0), player, template), 98 "pierce": func("Attack/"+type+"/Pierce", +(template.Attack[type].Pierce || 0), player, template), 99 "crush": func("Attack/"+type+"/Crush", +(template.Attack[type].Crush || 0), player, template), 100 "minRange": func("Attack/"+type+"/MinRange", +(template.Attack[type].MinRange || 0), player, template), 101 "maxRange": func("Attack/"+type+"/MaxRange", +template.Attack[type].MaxRange, player, template), 102 "elevationBonus": func("Attack/"+type+"/ElevationBonus", +(template.Attack[type].ElevationBonus || 0), player, template), 103 "repeatTime": +(template.Attack[type].RepeatTime || 0), 104 }; 101 if (type == "Capture") 102 ret.attack.Capture = { 103 "value": getAttackStat(type,"Value"), 104 }; 105 else 106 ret.attack[type] = { 107 "hack": getAttackStat(type, "Hack"), 108 "pierce": getAttackStat(type, "Pierce"), 109 "crush": getAttackStat(type, "Crush"), 110 "minRange": getAttackStat(type, "MinRange"), 111 "maxRange": getAttackStat(type, "MaxRange"), 112 "elevationBonus": getAttackStat(type, "ElevationBonus"), 113 }; 114 ret.attack[type].repeatTime = +(template.Attack[type].RepeatTime || 0); 105 115 } 106 116 } 107 117 -
binaries/data/mods/public/gui/common/functions_utility.js
166 166 // ==================================================================== 167 167 168 168 // Convert integer color values to string (for use in GUI objects) 169 function rgbToGuiColor(color )169 function rgbToGuiColor(color, alpha) 170 170 { 171 var ret; 171 172 if (color && ("r" in color) && ("g" in color) && ("b" in color)) 172 return color.r + " " + color.g + " " + color.b; 173 174 return "0 0 0"; 173 ret = color.r + " " + color.g + " " + color.b; 174 else 175 ret = "0 0 0"; 176 if (alpha) 177 ret += " " + alpha; 178 return ret; 175 179 } 176 180 177 181 // ==================================================================== -
binaries/data/mods/public/gui/common/tooltips.js
140 140 if (type === "Charge") return translate("Charge Attack:"); 141 141 if (type === "Melee") return translate("Melee Attack:"); 142 142 if (type === "Ranged") return translate("Ranged Attack:"); 143 if (type === "Capture") return translate("Capture Attack:"); 143 144 144 145 warn(sprintf("Internationalization: Unexpected attack type found with code ‘%(attackType)s’. This attack type must be internationalized.", { attackType: type })); 145 146 return translate("Attack:"); … … 169 170 }); 170 171 171 172 var attackLabel = txtFormats.header[0] + getAttackTypeLabel(type) + txtFormats.header[1]; 173 if (type == "Capture") 174 { 175 attacks.push(sprintf(translate("%(attackLabel)s %(details)s, %(rate)s"), { 176 attackLabel: attackLabel, 177 details: template.attack[type].value, 178 rate: rate 179 })); 180 continue; 181 } 172 182 if (type != "Ranged") 173 183 { 174 184 attacks.push(sprintf(translate("%(attackLabel)s %(details)s, %(rate)s"), { … … 206 216 })); 207 217 } 208 218 209 return attacks.join( translate(", "));219 return attacks.join("\n"); 210 220 } 211 221 212 222 /** -
binaries/data/mods/public/gui/session/selection_details.js
58 58 } 59 59 60 60 // Hitpoints 61 Engine.GetGUIObjectByName("healthSection").hidden = !entState.hitpoints; 61 62 if (entState.hitpoints) 62 63 { 63 64 var unitHealthBar = Engine.GetGUIObjectByName("healthBar"); … … 79 80 hitpoints: Math.ceil(entState.hitpoints), 80 81 maxHitpoints: entState.maxHitpoints 81 82 }); 82 Engine.GetGUIObjectByName("healthSection").hidden = false;83 83 } 84 else 84 85 // CapturePoints 86 Engine.GetGUIObjectByName("captureSection").hidden = !entState.capturePoints; 87 if (entState.capturePoints) 85 88 { 86 Engine.GetGUIObjectByName("healthSection").hidden = true; 89 let setCaptureBarPart = function(playerID, startSize) 90 { 91 var unitCaptureBar = Engine.GetGUIObjectByName("captureBar["+playerID+"]"); 92 var sizeObj = unitCaptureBar.size; 93 sizeObj.rleft = startSize; 94 95 var size = 100*Math.max(0, Math.min(1, entState.capturePoints[playerID] / entState.maxCapturePoints)); 96 sizeObj.rright = startSize + size; 97 unitCaptureBar.size = sizeObj; 98 unitCaptureBar.sprite = "color: " + rgbToGuiColor(g_Players[playerID].color, 128); 99 unitCaptureBar.hidden=false; 100 return startSize + size; 101 } 102 103 // first handle the owner's points, to keep those points on the left for clarity 104 let size = setCaptureBarPart(entState.player, 0); 105 106 for (let i in entState.capturePoints) 107 if (i != entState.player) 108 size = setCaptureBarPart(i, size); 109 110 111 Engine.GetGUIObjectByName("captureStats").caption = sprintf(translate("%(capturePoints)s / %(maxCapturePoints)s"), { 112 capturePoints: Math.ceil(entState.capturePoints[entState.player]), 113 maxCapturePoints: entState.maxCapturePoints 114 }); 87 115 } 88 116 89 117 // TODO: Stamina 90 var player = Engine.GetPlayerID();91 if (entState.stamina && (entState.player == player || g_DevSettings.controlAll))92 Engine.GetGUIObjectByName("staminaSection").hidden = false;93 else94 Engine.GetGUIObjectByName("staminaSection").hidden = true;95 118 96 119 // Experience 120 Engine.GetGUIObjectByName("experience").hidden = !entState.promotion; 97 121 if (entState.promotion) 98 122 { 99 123 var experienceBar = Engine.GetGUIObjectByName("experienceBar"); … … 112 136 experience: "[font=\"sans-bold-13\"]" + translate("Experience:") + "[/font]", 113 137 current: Math.floor(entState.promotion.curr) 114 138 }); 115 Engine.GetGUIObjectByName("experience").hidden = false;116 139 } 117 else118 {119 Engine.GetGUIObjectByName("experience").hidden = true;120 }121 140 122 141 // Resource stats 142 Engine.GetGUIObjectByName("resourceSection").hidden = !entState.resourceSupply; 123 143 if (entState.resourceSupply) 124 144 { 125 145 var resources = entState.resourceSupply.isInfinite ? translate("∞") : // Infinity symbol … … 136 156 Engine.GetGUIObjectByName("resourceStats").caption = resources; 137 157 138 158 if (entState.hitpoints) 139 Engine.GetGUIObjectByName("resourceSection").size = Engine.GetGUIObjectByName(" staminaSection").size;159 Engine.GetGUIObjectByName("resourceSection").size = Engine.GetGUIObjectByName("captureSection").size; 140 160 else 141 161 Engine.GetGUIObjectByName("resourceSection").size = Engine.GetGUIObjectByName("healthSection").size; 142 162 143 Engine.GetGUIObjectByName("resourceSection").hidden = false;144 163 } 145 else146 {147 Engine.GetGUIObjectByName("resourceSection").hidden = true;148 }149 164 150 165 // Resource carrying 151 166 if (entState.resourceCarrying && entState.resourceCarrying.length) … … 290 305 { 291 306 var averageHealth = 0; 292 307 var maxHealth = 0; 308 var maxCapturePoints = 0; 309 var capturePoints = (new Array(9)).fill(0); 310 var playerID = 0; 293 311 294 312 for (var i = 0; i < selection.length; i++) 295 313 { 296 314 var entState = GetEntityState(selection[i]) 297 if (entState) 315 if (!entState) 316 continue; 317 playerID = entState.player; // trust that all selected entities have the same owner 318 if (entState.hitpoints) 298 319 { 299 if (entState.hitpoints) 300 { 301 averageHealth += entState.hitpoints; 302 maxHealth += entState.maxHitpoints; 303 } 320 averageHealth += entState.hitpoints; 321 maxHealth += entState.maxHitpoints; 304 322 } 323 if (entState.capturePoints) 324 { 325 maxCapturePoints += entState.maxCapturePoints; 326 capturePoints = entState.capturePoints.map(function(v, i) { return v + capturePoints[i]; }); 327 } 305 328 } 306 329 330 Engine.GetGUIObjectByName("healthMultiple").hidden = averageHealth <= 0; 307 331 if (averageHealth > 0) 308 332 { 309 333 var unitHealthBar = Engine.GetGUIObjectByName("healthBarMultiple"); … … 313 337 314 338 var hitpointsLabel = "[font=\"sans-bold-13\"]" + translate("Hitpoints:") + "[/font]" 315 339 var hitpoints = sprintf(translate("%(label)s %(current)s / %(max)s"), { label: hitpointsLabel, current: averageHealth, max: maxHealth }); 316 var healthMultiple = Engine.GetGUIObjectByName("healthMultiple"); 317 healthMultiple.tooltip = hitpoints; 318 healthMultiple.hidden = false; 340 Engine.GetGUIObjectByName("healthMultiple").tooltip = hitpoints; 319 341 } 320 else 342 343 Engine.GetGUIObjectByName("captureMultiple").hidden = maxCapturePoints <= 0; 344 if (maxCapturePoints > 0) 321 345 { 322 Engine.GetGUIObjectByName("healthMultiple").hidden = true; 346 let setCaptureBarPart = function(playerID, startSize) 347 { 348 var unitCaptureBar = Engine.GetGUIObjectByName("captureBarMultiple["+playerID+"]"); 349 var sizeObj = unitCaptureBar.size; 350 sizeObj.rtop = startSize; 351 352 var size = 100*Math.max(0, Math.min(1, capturePoints[playerID] / maxCapturePoints)); 353 sizeObj.rbottom = startSize + size; 354 unitCaptureBar.size = sizeObj; 355 unitCaptureBar.sprite = "color: " + rgbToGuiColor(g_Players[playerID].color, 128); 356 unitCaptureBar.hidden=false; 357 return startSize + size; 358 } 359 360 let size = 0; 361 for (let i in entState.capturePoints) 362 if (i != playerID) 363 size = setCaptureBarPart(i, size); 364 365 // last handle the owner's points, to keep those points on the bottom for clarity 366 setCaptureBarPart(playerID, size); 367 368 var capturePointsLabel = "[font=\"sans-bold-13\"]" + translate("Capture points:") + "[/font]" 369 var capturePointsTooltip = sprintf(translate("%(label)s %(current)s / %(max)s"), { label: capturePointsLabel, current: Math.ceil(capturePoints[playerID]), max: Math.ceil(maxCapturePoints) }); 370 Engine.GetGUIObjectByName("captureMultiple").tooltip = capturePointsTooltip; 323 371 } 324 372 325 373 // TODO: Stamina -
binaries/data/mods/public/gui/session/selection_panels_middle/multiple_details_area.xml
33 33 <object type="image" sprite="statsBarShaderVertical" ghost="true"/> 34 34 </object> 35 35 36 <!-- Staminabar -->37 <object size="15 0 22 100%" type="image" name=" staminaMultiple" tooltip_style="sessionToolTipBold">38 <translatableAttribute id="tooltip"> Stamina</translatableAttribute>36 <!-- Capture bar --> 37 <object size="15 0 22 100%" type="image" name="captureMultiple" tooltip_style="sessionToolTipBold"> 38 <translatableAttribute id="tooltip">Capture points</translatableAttribute> 39 39 <object type="image" sprite="barBorder" ghost="true" size="-1 -1 100%+1 100%+1"/> 40 <object type="image" sprite="staminaBackground" ghost="true"/> 41 <object type="image" sprite="staminaForeground" ghost="true" name="staminaBarMultiple"/> 40 <repeat count="9"> 41 <object type="image" sprite="playerColorBackground" ghost="true" name="captureBarMultiple[n]" hidden="true"/> 42 </repeat> 42 43 <object type="image" sprite="statsBarShaderVertical" ghost="true"/> 43 44 </object> 44 45 </object> -
binaries/data/mods/public/gui/session/selection_panels_middle/single_details_area.xml
20 20 </object> 21 21 </object> 22 22 23 <!-- Staminabar -->24 <object size="88 28 100% 52" name=" staminaSection">25 <object size="0 0 100% 16" name=" staminaLabel" type="text" style="StatsTextLeft" ghost="true">26 <translatableAttribute id="tooltip"> Stamina:</translatableAttribute>23 <!-- Capture bar --> 24 <object size="88 28 100% 52" name="captureSection"> 25 <object size="0 0 100% 16" name="captureLabel" type="text" style="StatsTextLeft" ghost="true"> 26 <translatableAttribute id="tooltip">Capture points:</translatableAttribute> 27 27 </object> 28 <object size="0 0 100% 16" name=" staminaStats" type="text" style="StatsTextRight" ghost="true"/>29 <object size="1 16 100% 23" name=" stamina" type="image">28 <object size="0 0 100% 16" name="captureStats" type="text" style="StatsTextRight" ghost="true"/> 29 <object size="1 16 100% 23" name="capture" type="image"> 30 30 <object type="image" sprite="barBorder" ghost="true" size="-1 -1 100%+1 100%+1"/> 31 <object type="image" sprite="staminaBackground" ghost="true"/> 32 <object type="image" sprite="staminaForeground" ghost="true" name="staminaBar"/> 31 <repeat count="9"> 32 <object type="image" sprite="playerColorBackground" ghost="true" name="captureBar[n]" hidden="true"/> 33 </repeat> 33 34 <object type="image" sprite="statsBarShaderHorizontal" ghost="true"/> 34 35 </object> 35 36 </object> -
binaries/data/mods/public/gui/session/unit_actions.js
99 99 { 100 100 if (!entState.attack || !targetState.hitpoints) 101 101 return false; 102 if (playerCheck(entState, targetState, ["Neutral", "Enemy"])) 103 return {"possible": Engine.GuiInterfaceCall("CanAttack", {"entity": entState.id, "target": targetState.id})}; 104 return false; 102 return {"possible": Engine.GuiInterfaceCall("CanAttack", {"entity": entState.id, "target": targetState.id})}; 105 103 }, 106 104 "hotkeyActionCheck": function(target) 107 105 { … … 672 670 "icon": "kill_small.png" 673 671 }; 674 672 673 if (entState.capturePoints && entState.capturePoints[entState.player] < entState.maxCapturePoints / 2) 674 return { 675 "tooltip": translate("You cannot destroy this entity as you own less than half the capture points"), 676 "icon": "kill_small.png" 677 }; 678 679 675 680 return { 676 681 "tooltip": translate("Delete"), 677 682 "icon": "kill_small.png" -
binaries/data/mods/public/simulation/components/AIProxy.js
111 111 this.changes.hitpoints = msg.to; 112 112 }; 113 113 114 AIProxy.prototype.OnCapturePointsChanged = function(msg) 115 { 116 if (!this.NotifyChange()) 117 return; 118 this.changes.capturePoints = msg.capturePoints; 119 }; 120 114 121 AIProxy.prototype.OnUnitIdleChanged = function(msg) 115 122 { 116 123 if (!this.NotifyChange()) -
binaries/data/mods/public/simulation/components/Attack.js
159 159 "</element>" + 160 160 "</optional>" + 161 161 "<optional>" + 162 "<element name='Capture'>" + 163 "<interleave>" + 164 "<element name='Value' a:help='Capture points value'><ref name='nonNegativeDecimal'/></element>" + 165 "<element name='MaxRange' a:help='Maximum attack range (in meters)'><ref name='nonNegativeDecimal'/></element>" + 166 "<element name='RepeatTime' a:help='Time between attacks (in milliseconds). The attack animation will be stretched to match this time'>" + // TODO: it shouldn't be stretched 167 "<data type='positiveInteger'/>" + 168 "</element>" + 169 Attack.prototype.bonusesSchema + 170 Attack.prototype.preferredClassesSchema + 171 Attack.prototype.restrictedClassesSchema + 172 "</interleave>" + 173 "</element>" + 174 "</optional>" + 175 "<optional>" + 162 176 "<element name='Charge'>" + 163 177 "<interleave>" + 164 178 "<element name='Hack' a:help='Hack damage strength'><ref name='nonNegativeDecimal'/></element>" + … … 198 212 if (this.template.Charge) ret.push("Charge"); 199 213 if (this.template.Melee) ret.push("Melee"); 200 214 if (this.template.Ranged) ret.push("Ranged"); 215 if (this.template.Capture) ret.push("Capture"); 201 216 return ret; 202 217 }; 203 218 … … 223 238 224 239 Attack.prototype.CanAttack = function(target) 225 240 { 241 var cmpArmour = Engine.QueryInterface(target, IID_DamageReceiver); 242 if (!cmpArmour) 243 return false; 244 226 245 var cmpFormation = Engine.QueryInterface(target, IID_Formation); 227 246 if (cmpFormation) 228 247 return true; … … 309 328 if (cmpFormation) 310 329 return this.GetBestAttack(); 311 330 312 constcmpIdentity = Engine.QueryInterface(target, IID_Identity);331 var cmpIdentity = Engine.QueryInterface(target, IID_Identity); 313 332 if (!cmpIdentity) 314 333 return undefined; 315 334 316 const targetClasses = cmpIdentity.GetClassesList();317 const isTargetClass = function (value, i, a) { return targetClasses.indexOf(value) != -1; };318 const types = this.GetAttackTypes();319 const attack = this;320 const isAllowed = function (value, i, a) { return !attack.GetRestrictedClasses(value).some(isTargetClass); }321 const isPreferred = function (value, i, a) { return attack.GetPreferredClasses(value).some(isTargetClass); }322 const byPreference = function (a, b) { return (types.indexOf(a) + (isPreferred(a) ? types.length : 0) ) - (types.indexOf(b) + (isPreferred(b) ? types.length : 0) ); }323 335 336 var targetClasses = cmpIdentity.GetClassesList(); 337 var isTargetClass = function (className) { return targetClasses.indexOf(className) != -1; }; 338 324 339 // Always slaughter domestic animals instead of using a normal attack 325 340 if (isTargetClass("Domestic") && this.template.Slaughter) 326 341 return "Slaughter"; 327 342 328 return types.filter(isAllowed).sort(byPreference).pop(); 343 var attack = this; 344 var isAllowed = function (type) { return !attack.GetRestrictedClasses(type).some(isTargetClass); } 345 346 var types = this.GetAttackTypes().filter(isAllowed); 347 348 // check if the target is capturable 349 var captureIndex = types.indexOf("Capture") 350 if (captureIndex != -1) 351 { 352 var cmpCapturable = Engine.QueryInterface(target, IID_Capturable); 353 var cmpPlayer = QueryOwnerInterface(this.entity); 354 if (cmpPlayer && cmpCapturable && cmpCapturable.CanCapture(cmpPlayer.GetPlayerID())) 355 return "Capture"; 356 // not captureable, so remove this attack 357 types.splice(captureIndex, 1); 358 } 359 360 var isPreferred = function (className) { return attack.GetPreferredClasses(className).some(isTargetClass); } 361 var byPreference = function (a, b) { return (types.indexOf(a) + (isPreferred(a) ? types.length : 0) ) - (types.indexOf(b) + (isPreferred(b) ? types.length : 0) ); } 362 363 364 return types.sort(byPreference).pop(); 329 365 }; 330 366 331 367 Attack.prototype.CompareEntitiesByPreference = function(a, b) … … 367 403 { 368 404 return ApplyValueModificationsToEntity("Attack/" + type + splash + "/" + damageType, +(template[damageType] || 0), self.entity); 369 405 }; 370 406 407 if (type == "Capture") 408 return {value: applyMods("Value")}; 409 371 410 return { 372 411 hack: applyMods("Hack"), 373 412 pierce: applyMods("Pierce"), … … 517 556 var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); 518 557 cmpTimer.SetTimeout(this.entity, IID_Attack, "MissileHit", timeToTarget*1000, {"type": type, "target": target, "position": realTargetPosition, "direction": missileDirection, "projectileId": id, "playerId":playerId}); 519 558 } 559 else if (type == "Capture") 560 { 561 var multiplier = this.GetAttackBonus(type, target); 562 var cmpHealth = Engine.QueryInterface(target, IID_Health); 563 if (!cmpHealth || cmpHealth.GetHitpoints() == 0) 564 return; 565 multiplier *= cmpHealth.GetMaxHitpoints() / cmpHealth.GetHitpoints(); 566 567 var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); 568 if (!cmpOwnership || cmpOwnership.GetOwner() == -1) 569 return; 570 var owner = cmpOwnership.GetOwner(); 571 var cmpCapturable = Engine.QueryInterface(target, IID_Capturable); 572 if (!cmpCapturable || !cmpCapturable.CanCapture(owner)) 573 return; 574 575 var strength = this.GetAttackStrengths("Capture").value; 576 cmpCapturable.Reduce(strength * multiplier, owner); 577 } 520 578 else 521 579 { 522 580 // Melee attack - hurt the target immediately … … 585 643 // If friendlyFire isn't enabled, get all player enemies to pass to "Damage.CauseSplashDamage". 586 644 if (friendlyFire == "false") 587 645 { 588 var cmpPlayer = Engine.QueryInterface(Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetPlayerByID(data.playerId), IID_Player)646 var cmpPlayer = QueryPlayerIDInterface(data.playerId); 589 647 playersToDamage = cmpPlayer.GetEnemies(); 590 648 } 591 649 // Damage the units. … … 607 665 else 608 666 { 609 667 // If we didn't hit the main target look for nearby units 610 var cmpPlayer = Engine.QueryInterface(Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetPlayerByID(data.playerId), IID_Player)668 var cmpPlayer = QueryPlayerIDInterface(data.playerId); 611 669 var ents = Damage.EntitiesNearPoint(Vector2D.from3D(data.position), targetPosition.horizDistanceTo(data.position) * 2, cmpPlayer.GetEnemies()); 612 670 613 671 for (var i = 0; i < ents.length; i++) -
binaries/data/mods/public/simulation/components/Capturable.js
1 function Capturable() {} 2 3 Capturable.prototype.Schema = 4 "<element name='CapturePoints' a:help='Maximum capture points'>" + 5 "<ref name='positiveDecimal'/>" + 6 "</element>" + 7 "<element name='RegenRate' a:help='Number of capture are regenerated per second in favour of the owner'>" + 8 "<ref name='nonNegativeDecimal'/>" + 9 "</element>" + 10 "<element name='GarrisonRegenRate' a:help='Number of capture are regenerated per second and per garrisoned unit in favour of the owner'>" + 11 "<ref name='nonNegativeDecimal'/>" + 12 "</element>"; 13 14 Capturable.prototype.Init = function() 15 { 16 // Cache this value 17 this.maxCp = +this.template.CapturePoints; 18 this.cp = []; 19 this.startRegenTimer(); 20 }; 21 22 //// Interface functions //// 23 24 /** 25 * Returns the current capture points array 26 */ 27 Capturable.prototype.GetCapturePoints = function() 28 { 29 return this.cp; 30 }; 31 32 Capturable.prototype.GetMaxCapturePoints = function() 33 { 34 return this.maxCp; 35 }; 36 37 /** 38 * Set the new capture points, used for cloning entities 39 * The caller should assure that the sum of capture points 40 * matches the max. 41 */ 42 Capturable.prototype.SetCapturePoints = function(capturePointsArray) 43 { 44 this.cp = capturePointsArray; 45 }; 46 47 /** 48 * Reduces the amount of capture points of an entity, 49 * in favour of the player of the source 50 * Returns the number of capture points actually taken 51 */ 52 Capturable.prototype.Reduce = function(amount, playerID) 53 { 54 var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); 55 if (!cmpOwnership || cmpOwnership.GetOwner() == -1) 56 return 0; 57 58 var cmpPlayerSource = QueryPlayerIDInterface(playerID); 59 if (!cmpPlayerSource) 60 return 0; 61 62 // Before changing the value, activate Fogging if necessary to hide changes 63 var cmpFogging = Engine.QueryInterface(this.entity, IID_Fogging); 64 if (cmpFogging) 65 cmpFogging.Activate(); 66 67 var enemiesFilter = function(v, i) { return v > 0 && !cmpPlayerSource.IsAlly(i); }; 68 var numberOfEnemies = this.cp.filter(enemiesFilter).length; 69 70 if (numberOfEnemies == 0) 71 return 0; 72 73 // distribute the capture points over all enemies 74 var distributedAmount = amount / numberOfEnemies; 75 for (let i in this.cp) 76 { 77 if (cmpPlayerSource.IsAlly(i)) 78 continue; 79 if (this.cp[i] > distributedAmount) 80 this.cp[i] -= distributedAmount; 81 else 82 this.cp[i] = 0; 83 } 84 85 // give all cp taken to the player 86 var takenCp = this.maxCp - this.cp.reduce(function(a, b) { return a + b; }); 87 this.cp[playerID] += takenCp; 88 89 this.startRegenTimer(); 90 91 Engine.PostMessage(this.entity, MT_CapturePointsChanged, { "capturePoints": this.cp }) 92 93 if (this.cp[cmpOwnership.GetOwner()] > 0) 94 return takenCp; 95 96 // if all cp has been taken from the owner, convert it to the best player 97 var bestPlayer = 0; 98 for (let i in this.cp) 99 if (this.cp[i] >= this.cp[bestPlayer]) 100 bestPlayer = +i; 101 102 cmpOwnership.SetOwner(bestPlayer); 103 104 return takenCp; 105 }; 106 107 /** 108 * Check if the source can (re)capture points from this building 109 */ 110 Capturable.prototype.CanCapture = function(playerID) 111 { 112 var cmpPlayerSource = QueryPlayerIDInterface(playerID); 113 114 if (!cmpPlayerSource) 115 warn(source + " has no player component defined on its owner "); 116 var cp = this.GetCapturePoints() 117 var sourceEnemyCp = 0; 118 for (let i in this.GetCapturePoints()) 119 if (!cmpPlayerSource.IsAlly(i)) 120 sourceEnemyCp += cp[i]; 121 return sourceEnemyCp > 0; 122 }; 123 124 //// Private functions //// 125 126 Capturable.prototype.GetRegenRate = function() 127 { 128 var regenRate = +this.template.RegenRate; 129 regenRate = ApplyValueModificationsToEntity("Capturable/RegenRate", regenRate, this.entity); 130 131 var cmpGarrisonHolder = Engine.QueryInterface(this.entity, IID_GarrisonHolder); 132 if (!cmpGarrisonHolder) 133 return regenRate; 134 135 var garrisonRegenRate = +this.template.GarrisonRegenRate; 136 garrisonRegenRate = ApplyValueModificationsToEntity("Capturable/GarrisonRegenRate", garrisonRegenRate, this.entity); 137 var garrisonedUnits = cmpGarrisonHolder.GetEntities().length; 138 return regenRate + garrisonedUnits * garrisonRegenRate; 139 }; 140 141 Capturable.prototype.RegenCapturePoints = function() 142 { 143 var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); 144 if (!cmpOwnership || cmpOwnership.GetOwner() == -1) 145 return; 146 147 var takenCp = this.Reduce(this.GetRegenRate(), cmpOwnership.GetOwner()) 148 if (takenCp > 0) 149 return; 150 151 // no capture points taken, stop the timer 152 var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); 153 cmpTimer.CancelTimer(this.regenTimer); 154 this.regenTimer = 0; 155 }; 156 157 /** 158 * Start the regeneration timer when no timer exists 159 * When nothing can be regenerated (f.e. because the 160 * rate is 0, or because it is fully regenerated), 161 * the timer stops automatically after one execution. 162 */ 163 Capturable.prototype.startRegenTimer = function() 164 { 165 if (this.regenTimer) 166 return; 167 var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); 168 this.regenTimer = cmpTimer.SetInterval(this.entity, IID_Capturable, "RegenCapturePoints", 1000, 1000, null); 169 }; 170 171 //// Message Listeners //// 172 173 Capturable.prototype.OnValueModification = function(msg) 174 { 175 if (msg.component != "Capturable") 176 return; 177 178 var oldMaxCp = this.GetMaxCapturePoints(); 179 this.maxCp = ApplyValueModificationsToEntity("Capturable/Max", +this.template.Max, this.entity); 180 if (oldMaxCp == this.maxCp) 181 return; 182 183 var scale = this.maxCp / oldMaxCp; 184 for (let i in this.cp) 185 this.cp[i] *= scale; 186 Engine.PostMessage(this.entity, MT_CapturePointsChanged, { "capturePoints": this.cp }); 187 this.startRegenTimer(); 188 }; 189 190 Capturable.prototype.OnGarrisonedUnitsChanged = function(msg) 191 { 192 this.startRegenTimer(); 193 }; 194 195 Capturable.prototype.OnOwnershipChanged = function(msg) 196 { 197 this.startRegenTimer(); 198 199 if (msg.from != -1) 200 return; 201 202 // initialise the capture points when created 203 this.cp = []; 204 var cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager); 205 for (let i = 0; i < cmpPlayerManager.GetNumPlayers(); ++i) 206 if (i == msg.to) 207 this.cp[i] = this.maxCp; 208 else 209 this.cp[i] = 0; 210 }; 211 212 Engine.RegisterComponentType(IID_Capturable, "Capturable", Capturable); -
binaries/data/mods/public/simulation/components/Fogging.js
125 125 cmpHealth.IsRepairable() && (cmpHealth.GetHitpoints() < cmpHealth.GetMaxHitpoints()) 126 126 ); 127 127 128 var cmpCapturable = Engine.QueryInterface(this.entity, IID_Capturable); 129 if (cmpCapturable) 130 cmpMirage.CopyCapturable( 131 cmpCapturable.GetCapturePoints(), 132 cmpCapturable.GetMaxCapturePoints() 133 ); 134 128 135 var cmpResourceSupply = Engine.QueryInterface(this.entity, IID_ResourceSupply); 129 136 if (cmpResourceSupply) 130 137 cmpMirage.CopyResourceSupply( -
binaries/data/mods/public/simulation/components/GuiInterface.js
267 267 ret.needsRepair = cmpMirage.NeedsRepair(); 268 268 } 269 269 270 var cmpCapturable = Engine.QueryInterface(ent, IID_Capturable); 271 if (cmpCapturable) 272 { 273 ret.capturePoints = cmpCapturable.GetCapturePoints(); 274 ret.maxCapturePoints = cmpCapturable.GetMaxCapturePoints(); 275 } 276 if (cmpMirage && cmpMirage.Capturable()) 277 { 278 ret.capturePoints = cmpMirage.GetCapturePoints(); 279 ret.maxCapturePoints = cmpMirage.GetMaxCapturePoints(); 280 } 281 270 282 var cmpBuilder = Engine.QueryInterface(ent, IID_Builder); 271 283 if (cmpBuilder) 272 284 ret.builder = true; … … 1701 1713 var cmpAttack = Engine.QueryInterface(data.entity, IID_Attack); 1702 1714 if (!cmpAttack) 1703 1715 return false; 1716 var cmpEntityPlayer = QueryOwnerInterface(data.entity, IID_Player); 1717 var cmpTargetPlayer = QueryOwnerInterface(data.target, IID_Player); 1718 if (!cmpEntityPlayer || !cmpTargetPlayer) 1719 return false; 1704 1720 1705 return cmpAttack.CanAttack(data.target); 1721 1722 // if the owner is an enemy, it's up to the attack component to decide 1723 if (!cmpEntityPlayer.IsAlly(cmpTargetPlayer.GetPlayerID())) 1724 return cmpAttack.CanAttack(data.target); 1725 1726 // if the owner is an ally, we could still want to capture some capture points back 1727 var cmpCapturable = Engine.QueryInterface(data.target, IID_Capturable); 1728 if (cmpCapturable && cmpCapturable.CanCapture(cmpEntityPlayer.GetPlayerID()) && cmpAttack.GetAttackTypes().indexOf("Capture") != -1) 1729 return cmpAttack.CanAttack(data.target); 1730 1731 return false; 1706 1732 }; 1707 1733 1708 1734 /* -
binaries/data/mods/public/simulation/components/Mirage.js
21 21 this.hitpoints = null; 22 22 this.needsRepair = null; 23 23 24 this.capturable = false; 25 this.capturePoints = []; 26 this.maxCapturePoints = 0; 27 24 28 this.resourceSupply = false; 25 29 this.maxAmount = null; 26 30 this.amount = null; … … 94 98 return this.needsRepair; 95 99 }; 96 100 101 // Capture data 102 103 Mirage.prototype.CopyCapturable = function(capturePoints, maxCapturePoints) 104 { 105 this.capturable = true; 106 this.capturePoints = capturePoints; 107 this.maxCapturePoints = maxCapturePoints; 108 }; 109 110 Mirage.prototype.Capturable = function() 111 { 112 return this.capturable; 113 }; 114 115 Mirage.prototype.GetMaxCapturePoints = function() 116 { 117 return this.maxCapturePoints; 118 }; 119 120 Mirage.prototype.GetCapturePoints = function() 121 { 122 return this.capturePoints; 123 }; 124 97 125 // ResourceSupply data 98 126 99 127 Mirage.prototype.CopyResourceSupply = function(maxAmount, amount, type, isInfinite) -
binaries/data/mods/public/simulation/components/Pack.js
148 148 var cmpNewOwnership = Engine.QueryInterface(newEntity, IID_Ownership); 149 149 cmpNewOwnership.SetOwner(cmpOwnership.GetOwner()); 150 150 151 // rescale capture points 152 var cmpCapturable = Engine.QueryInterface(this.entity, IID_Capturable); 153 var cmpNewCapturable = Engine.QueryInterface(newEntity, IID_Capturable); 154 if (cmpCapturable && cmpNewCapturable) 155 { 156 let scale = cmpCapturable.GetMaxCapturePoints() / cmpNewCapturable.GetMaxCapturePoints(); 157 let newCp = cmpCapturable.GetCapturePoints().map(function (v) { return v / scale; }); 158 cmpNewCapturable.SetCapturePoints(newCp); 159 } 160 151 161 // Maintain current health level 152 162 var cmpHealth = Engine.QueryInterface(this.entity, IID_Health); 153 163 var cmpNewHealth = Engine.QueryInterface(newEntity, IID_Health); -
binaries/data/mods/public/simulation/components/TerritoryDecay.js
1 1 function TerritoryDecay() {} 2 2 3 3 TerritoryDecay.prototype.Schema = 4 "<element name=' HealthDecayRate' a:help='Decay rate in hitpoints per second'>" +4 "<element name='DecayRate' a:help='Decay rate in hitpoints per second'>" + 5 5 "<data type='positiveInteger'/>" + 6 6 "</element>"; 7 7 … … 33 33 var tileOwner = cmpTerritoryManager.GetOwner(pos.x, pos.y); 34 34 if (tileOwner != cmpOwnership.GetOwner()) 35 35 return false; 36 // TODO: this should probably use the same territory restriction37 // logic as BuildRestrictions, to handle allies etc38 36 39 37 return cmpTerritoryManager.IsConnected(pos.x, pos.y); 40 38 }; … … 64 62 if (connected) 65 63 var decaying = false; 66 64 else 67 var decaying = (Math.round(ApplyValueModificationsToEntity("TerritoryDecay/ HealthDecayRate", +this.template.HealthDecayRate, this.entity)) > 0);65 var decaying = (Math.round(ApplyValueModificationsToEntity("TerritoryDecay/DecayRate", +this.template.DecayRate, this.entity)) > 0); 68 66 if (decaying === this.decaying) 69 67 return; 70 68 this.decaying = decaying; … … 88 86 89 87 TerritoryDecay.prototype.Decay = function() 90 88 { 91 var cmp Health = Engine.QueryInterface(this.entity, IID_Health);92 if (!cmp Health)89 var cmpCapturable = Engine.QueryInterface(this.entity, IID_Capturable); 90 if (!cmpCapturable) 93 91 return; // error 94 92 95 var decayRate = ApplyValueModificationsToEntity("TerritoryDecay/HealthDecayRate", +this.template.HealthDecayRate, this.entity); 93 var decayRate = ApplyValueModificationsToEntity( 94 "TerritoryDecay/DecayRate", 95 +this.template.DecayRate, 96 this.entity); 96 97 97 cmpHealth.Reduce(Math.round(decayRate)); 98 // Reduce capture points in favour of Gaia 99 cmpCapturable.Reduce(decayRate, 0); 98 100 }; 99 101 100 102 Engine.RegisterComponentType(IID_TerritoryDecay, "TerritoryDecay", TerritoryDecay); -
binaries/data/mods/public/simulation/components/UnitAI.js
5559 5559 return false; 5560 5560 5561 5561 var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); 5562 if (!cmpOwnership )5562 if (!cmpOwnership || cmpOwnership.GetOwner() < 0) 5563 5563 return false; 5564 var owner = cmpOwnership.GetOwner(); 5564 5565 5565 5566 // Verify that the target is an attackable resource supply like a domestic animal 5566 5567 // or that it isn't owned by an ally of this entity's player or is responding to 5567 5568 // an attack. 5568 var owner = cmpOwnership.GetOwner(); 5569 if (!this.MustKillGatherTarget(target) 5570 && !(IsOwnedByEnemyOfPlayer(owner, target) 5571 || IsOwnedByNeutralOfPlayer(owner, target) 5572 || (forceResponse && !IsOwnedByPlayer(owner, target)))) 5573 return false; 5569 if (this.MustKillGatherTarget(target)) 5570 return true; 5574 5571 5575 return true; 5572 var cmpCapturable = Engine.QueryInterface(target, IID_Capturable); 5573 if (cmpCapturable && cmpCapturable.CanCapture(owner) && cmpAttack.GetAttackTypes().indexOf("Capture") != -1) 5574 return true; 5575 5576 if (IsOwnedByEnemyOfPlayer(owner, target) || IsOwnedByNeutralOfPlayer(owner, target)) 5577 return true; 5578 if (forceResponse && !IsOwnedByPlayer(owner, target)) 5579 return true; 5580 return false; 5576 5581 }; 5577 5582 5578 5583 UnitAI.prototype.CanGarrison = function(target) -
binaries/data/mods/public/simulation/components/interfaces/Capturable.js
1 Engine.RegisterInterface("Capturable"); 2 3 // Message in the form of {"capturePoints": [gaia, p1, p2, ...]} 4 Engine.RegisterMessageType("CapturePointsChanged"); 5 -
binaries/data/mods/public/simulation/data/technologies/decay_outpost.json
7 7 "icon": "blocks_three.png", 8 8 "researchTime": 40, 9 9 "tooltip": "Territory decay -50% for Outposts.", 10 "modifications": [{"value": "TerritoryDecay/ HealthDecayRate", "multiply": 0.5}],10 "modifications": [{"value": "TerritoryDecay/DecayRate", "multiply": 0.5}], 11 11 "affects": ["Outpost"], 12 12 "soundComplete": "interface/alarm/alarm_upgradearmory.xml" 13 13 } -
binaries/data/mods/public/simulation/data/technologies/romans/decay_logistics.json
7 7 "icon": "handcart_empty.png", 8 8 "researchTime": 40, 9 9 "tooltip": "Entrenched Camps and Siege Walls decay 50% slower.", 10 "modifications": [{"value": "TerritoryDecay/ HealthDecayRate", "multiply": 0.5}],10 "modifications": [{"value": "TerritoryDecay/DecayRate", "multiply": 0.5}], 11 11 "affects": ["ArmyCamp", "SiegeWall"], 12 12 "soundComplete": "interface/alarm/alarm_upgradearmory.xml" 13 13 } -
binaries/data/mods/public/simulation/helpers/Commands.js
349 349 350 350 "delete-entities": function(player, cmd, data) 351 351 { 352 for each (var ent indata.entities)352 for (let ent of data.entities) 353 353 { 354 // don't allow to delete entities who are half-captured 355 var cmpCapturable = Engine.QueryInterface(ent, IID_Capturable); 356 if (cmpCapturable) 357 { 358 var capturePoints = cmpCapturable.GetCapturePoints(); 359 var maxCapturePoints = cmpCapturable.GetMaxCapturePoints(); 360 if (capturePoints[player] < maxCapturePoints / 2) 361 return; 362 } 363 // either kill or delete the entity 354 364 var cmpHealth = Engine.QueryInterface(ent, IID_Health); 355 365 if (cmpHealth) 356 366 { -
binaries/data/mods/public/simulation/templates/structures/merc_camp_egyptian.xml
60 60 </SoundGroups> 61 61 </Sound> 62 62 <TerritoryDecay> 63 < HealthDecayRate>1</HealthDecayRate>63 <DecayRate>1</DecayRate> 64 64 </TerritoryDecay> 65 65 <TerritoryInfluence disable=""/> 66 66 <VisualActor> -
binaries/data/mods/public/simulation/templates/structures/ptol_mercenary_camp.xml
62 62 </SoundGroups> 63 63 </Sound> 64 64 <TerritoryDecay> 65 < HealthDecayRate>1</HealthDecayRate>65 <DecayRate>1</DecayRate> 66 66 </TerritoryDecay> 67 67 <TerritoryInfluence disable=""/> 68 68 <VisualActor> -
binaries/data/mods/public/simulation/templates/structures/ptol_military_colony.xml
76 76 </SoundGroups> 77 77 </Sound> 78 78 <TerritoryDecay> 79 < HealthDecayRate>1</HealthDecayRate>79 <DecayRate>1</DecayRate> 80 80 </TerritoryDecay> 81 81 <TerritoryInfluence> 82 82 <Radius>80</Radius> -
binaries/data/mods/public/simulation/templates/structures/rome_army_camp.xml
76 76 </SoundGroups> 77 77 </Sound> 78 78 <TerritoryDecay> 79 < HealthDecayRate>10</HealthDecayRate>79 <DecayRate>10</DecayRate> 80 80 </TerritoryDecay> 81 81 <TerritoryInfluence disable=""/> 82 82 <ProductionQueue> -
binaries/data/mods/public/simulation/templates/structures/rome_siege_wall_gate.xml
44 44 </Obstructions> 45 45 </Obstruction> 46 46 <TerritoryDecay> 47 < HealthDecayRate>1</HealthDecayRate>47 <DecayRate>1</DecayRate> 48 48 </TerritoryDecay> 49 49 <TerritoryInfluence disable=""/> 50 50 <VisualActor> -
binaries/data/mods/public/simulation/templates/structures/rome_siege_wall_long.xml
62 62 <Static width="37.0" depth="5.0"/> 63 63 </Obstruction> 64 64 <TerritoryDecay> 65 < HealthDecayRate>1</HealthDecayRate>65 <DecayRate>1</DecayRate> 66 66 </TerritoryDecay> 67 67 <TerritoryInfluence disable=""/> 68 68 <VisualActor> -
binaries/data/mods/public/simulation/templates/structures/rome_siege_wall_medium.xml
55 55 <Static width="25.0" depth="5.0"/> 56 56 </Obstruction> 57 57 <TerritoryDecay> 58 < HealthDecayRate>1</HealthDecayRate>58 <DecayRate>1</DecayRate> 59 59 </TerritoryDecay> 60 60 <TerritoryInfluence disable=""/> 61 61 <VisualActor> -
binaries/data/mods/public/simulation/templates/structures/rome_siege_wall_short.xml
42 42 <Static width="13.0" depth="5.0"/> 43 43 </Obstruction> 44 44 <TerritoryDecay> 45 < HealthDecayRate>1</HealthDecayRate>45 <DecayRate>1</DecayRate> 46 46 </TerritoryDecay> 47 47 <TerritoryInfluence disable=""/> 48 48 <VisualActor> -
binaries/data/mods/public/simulation/templates/structures/rome_siege_wall_tower.xml
36 36 <Static width="7.0" depth="7.0"/> 37 37 </Obstruction> 38 38 <TerritoryDecay> 39 < HealthDecayRate>1</HealthDecayRate>39 <DecayRate>1</DecayRate> 40 40 </TerritoryDecay> 41 41 <TerritoryInfluence disable=""/> 42 42 <VisualActor> -
binaries/data/mods/public/simulation/templates/structures/rome_tent.xml
50 50 </SoundGroups> 51 51 </Sound> 52 52 <TerritoryDecay> 53 < HealthDecayRate>1</HealthDecayRate>53 <DecayRate>1</DecayRate> 54 54 </TerritoryDecay> 55 55 <TerritoryInfluence disable=""/> 56 56 <VisualActor> -
binaries/data/mods/public/simulation/templates/structures/sele_military_colony.xml
75 75 </SoundGroups> 76 76 </Sound> 77 77 <TerritoryDecay> 78 < HealthDecayRate>1</HealthDecayRate>78 <DecayRate>1</DecayRate> 79 79 </TerritoryDecay> 80 80 <TerritoryInfluence> 81 81 <Radius>80</Radius> -
binaries/data/mods/public/simulation/templates/template_structure.xml
20 20 <PlacementType>land</PlacementType> 21 21 <Territory>own</Territory> 22 22 </BuildRestrictions> 23 <Capturable> 24 <CapturePoints>1000</CapturePoints> 25 <RegenRate>0</RegenRate> 26 <GarrisonRegenRate>3</GarrisonRegenRate> 27 </Capturable> 23 28 <Cost> 24 29 <Population>0</Population> 25 30 <PopulationBonus>0</PopulationBonus> … … 100 105 <HeightOffset>12.0</HeightOffset> 101 106 </StatusBars> 102 107 <TerritoryDecay> 103 < HealthDecayRate>5</HealthDecayRate>108 <DecayRate>5</DecayRate> 104 109 </TerritoryDecay> 105 110 <Visibility> 106 111 <RetainInFog>true</RetainInFog> -
binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre.xml
35 35 <MinDistance>200</MinDistance> 36 36 </Distance> 37 37 </BuildRestrictions> 38 <Capturable> 39 <CapturePoints>3000</CapturePoints> 40 </Capturable> 38 41 <Cost> 39 42 <PopulationBonus>20</PopulationBonus> 40 43 <BuildTime>500</BuildTime> -
binaries/data/mods/public/simulation/templates/template_structure_civic_house.xml
3 3 <BuildRestrictions> 4 4 <Category>House</Category> 5 5 </BuildRestrictions> 6 <Capturable> 7 <CapturePoints>300</CapturePoints> 8 </Capturable> 6 9 <Cost> 7 10 <PopulationBonus>5</PopulationBonus> 8 11 <BuildTime>30</BuildTime> -
binaries/data/mods/public/simulation/templates/template_structure_defense_outpost.xml
90 90 <HeightOffset>18.0</HeightOffset> 91 91 </StatusBars> 92 92 <TerritoryDecay> 93 < HealthDecayRate>2</HealthDecayRate>93 <DecayRate>2</DecayRate> 94 94 </TerritoryDecay> 95 95 <Vision> 96 96 <Range>80</Range> -
binaries/data/mods/public/simulation/templates/template_structure_defense_wall.xml
4 4 <PlacementType>land-shore</PlacementType> 5 5 <Category>Wall</Category> 6 6 </BuildRestrictions> 7 <Capturable disable=""/> 7 8 <Cost> 8 9 <BuildTime>10</BuildTime> 9 10 <Resources> -
binaries/data/mods/public/simulation/templates/template_structure_defense_wall_gate.xml
6 6 <BuildRestrictions> 7 7 <Category>Wall</Category> 8 8 </BuildRestrictions> 9 <Capturable disable=""/> 9 10 <Cost> 10 11 <BuildTime>0</BuildTime> 11 12 <Resources> -
binaries/data/mods/public/simulation/templates/template_structure_defense_wall_tower.xml
23 23 <PlacementType>land-shore</PlacementType> 24 24 <Category>Wall</Category> 25 25 </BuildRestrictions> 26 <Capturable disable=""/> 26 27 <Cost> 27 28 <BuildTime>120</BuildTime> 28 29 <Resources> -
binaries/data/mods/public/simulation/templates/template_structure_economic_farmstead.xml
3 3 <BuildRestrictions> 4 4 <Category>Farmstead</Category> 5 5 </BuildRestrictions> 6 <Capturable> 7 <CapturePoints>300</CapturePoints> 8 </Capturable> 6 9 <Cost> 7 10 <BuildTime>45</BuildTime> 8 11 <Resources> -
binaries/data/mods/public/simulation/templates/template_structure_economic_storehouse.xml
3 3 <BuildRestrictions> 4 4 <Category>Storehouse</Category> 5 5 </BuildRestrictions> 6 <Capturable> 7 <CapturePoints>300</CapturePoints> 8 </Capturable> 6 9 <Cost> 7 10 <BuildTime>40</BuildTime> 8 11 <Resources> -
binaries/data/mods/public/simulation/templates/template_structure_military_fortress.xml
26 26 <MinDistance>80</MinDistance> 27 27 </Distance> 28 28 </BuildRestrictions> 29 <Capturable> 30 <CapturePoints>4000</CapturePoints> 31 </Capturable> 29 32 <Cost> 30 33 <PopulationBonus>10</PopulationBonus> 31 34 <BuildTime>300</BuildTime> -
binaries/data/mods/public/simulation/templates/template_structure_resource_field.xml
8 8 <BuildRestrictions> 9 9 <Category>Field</Category> 10 10 </BuildRestrictions> 11 <Capturable disable=""/> 11 12 <Cost> 12 13 <BuildTime>50</BuildTime> 13 14 <Resources> -
binaries/data/mods/public/simulation/templates/template_structure_wonder.xml
13 13 <BuildRestrictions> 14 14 <Category>Wonder</Category> 15 15 </BuildRestrictions> 16 <Capturable> 17 <CapturePoints>5000</CapturePoints> 18 </Capturable> 16 19 <Cost> 17 20 <BuildTime>1000</BuildTime> 18 21 <Resources> -
binaries/data/mods/public/simulation/templates/template_unit_cavalry.xml
6 6 <Crush>15</Crush> 7 7 </Armour> 8 8 <Attack> 9 <Capture> 10 <Value>3</Value> 11 <MaxRange>4</MaxRange> 12 <RepeatTime>1000</RepeatTime> 13 </Capture> 9 14 <Slaughter> 10 15 <Hack>100.0</Hack> 11 16 <Pierce>0.0</Pierce> -
binaries/data/mods/public/simulation/templates/template_unit_champion.xml
1 1 <?xml version="1.0" encoding="utf-8"?> 2 2 <Entity parent="template_unit"> 3 <Attack> 4 <Capture> 5 <Value>3</Value> 6 <MaxRange>4</MaxRange> 7 <RepeatTime>1000</RepeatTime> 8 </Capture> 9 </Attack> 3 10 <Identity> 4 11 <GenericName>Champion Unit</GenericName> 5 12 <Classes datatype="tokens">Organic Human</Classes> -
binaries/data/mods/public/simulation/templates/template_unit_champion_elephant_melee.xml
1 1 <?xml version="1.0" encoding="utf-8"?> 2 2 <Entity parent="template_unit_champion_elephant"> 3 <Attack >3 <Attack replace=""> 4 4 <Melee> 5 5 <Hack>20</Hack> 6 6 <Pierce>0</Pierce> -
binaries/data/mods/public/simulation/templates/template_unit_hero_elephant_melee.xml
5 5 <Pierce>10</Pierce> 6 6 <Crush>12</Crush> 7 7 </Armour> 8 <Attack >8 <Attack replace=""> 9 9 <Melee> 10 10 <Hack>17.5</Hack> 11 11 <Pierce>0</Pierce> -
binaries/data/mods/public/simulation/templates/template_unit_infantry.xml
6 6 <Crush>15</Crush> 7 7 </Armour> 8 8 <Attack> 9 <Capture> 10 <Value>3</Value> 11 <MaxRange>4</MaxRange> 12 <RepeatTime>1000</RepeatTime> 13 </Capture> 9 14 <Slaughter> 10 15 <Hack>50.0</Hack> 11 16 <Pierce>0.0</Pierce> -
binaries/data/mods/public/simulation/templates/template_unit_mechanical_siege.xml
5 5 <Pierce>5</Pierce> 6 6 <Crush>5</Crush> 7 7 </Armour> 8 <Capturable> 9 <CapturePoints>100</CapturePoints> 10 <RegenRate>0</RegenRate> 11 <GarrisonRegenRate>1.5</GarrisonRegenRate> 12 </Capturable> 8 13 <Cost> 9 14 <Population>5</Population> 10 15 </Cost>