From ad27deeb9d799dd604e5c2741ef93e3ff85db57d Mon Sep 17 00:00:00 2001 From: sanderd17 Date: Mon, 20 Apr 2015 07:45:45 +0000 Subject: [PATCH] Implement building capturing. Fixes #996 This was SVN commit r16550. --- .../mods/public/globalscripts/Templates.js | 32 ++- .../public/gui/common/functions_utility.js | 12 +- .../data/mods/public/gui/common/tooltips.js | 12 +- .../public/gui/session/selection_details.js | 108 ++++++--- .../multiple_details_area.xml | 11 +- .../single_details_area.xml | 17 +- .../mods/public/gui/session/unit_actions.js | 11 +- .../public/simulation/components/AIProxy.js | 7 + .../public/simulation/components/Attack.js | 82 ++++++- .../simulation/components/Capturable.js | 212 ++++++++++++++++++ .../public/simulation/components/Fogging.js | 7 + .../simulation/components/GuiInterface.js | 28 ++- .../public/simulation/components/Mirage.js | 28 +++ .../mods/public/simulation/components/Pack.js | 10 + .../simulation/components/TerritoryDecay.js | 18 +- .../public/simulation/components/UnitAI.js | 21 +- .../components/interfaces/Capturable.js | 5 + .../data/technologies/decay_outpost.json | 2 +- .../technologies/romans/decay_logistics.json | 2 +- .../public/simulation/helpers/Commands.js | 12 +- .../structures/merc_camp_egyptian.xml | 2 +- .../structures/ptol_mercenary_camp.xml | 2 +- .../structures/ptol_military_colony.xml | 2 +- .../templates/structures/rome_army_camp.xml | 2 +- .../structures/rome_siege_wall_gate.xml | 2 +- .../structures/rome_siege_wall_long.xml | 2 +- .../structures/rome_siege_wall_medium.xml | 2 +- .../structures/rome_siege_wall_short.xml | 2 +- .../structures/rome_siege_wall_tower.xml | 2 +- .../templates/structures/rome_tent.xml | 2 +- .../structures/sele_military_colony.xml | 2 +- .../templates/template_structure.xml | 7 +- .../template_structure_civic_civil_centre.xml | 3 + .../template_structure_civic_house.xml | 3 + .../template_structure_defense_outpost.xml | 2 +- .../template_structure_defense_wall.xml | 1 + .../template_structure_defense_wall_gate.xml | 1 + .../template_structure_defense_wall_tower.xml | 1 + .../template_structure_economic_farmstead.xml | 3 + ...template_structure_economic_storehouse.xml | 3 + .../template_structure_military_fortress.xml | 3 + .../template_structure_resource_field.xml | 1 + .../templates/template_structure_wonder.xml | 3 + .../templates/template_unit_cavalry.xml | 5 + .../templates/template_unit_champion.xml | 7 + .../template_unit_champion_elephant_melee.xml | 2 +- .../template_unit_hero_elephant_melee.xml | 2 +- .../templates/template_unit_infantry.xml | 5 + .../template_unit_mechanical_siege.xml | 5 + 49 files changed, 607 insertions(+), 109 deletions(-) create mode 100644 binaries/data/mods/public/simulation/components/Capturable.js create mode 100644 binaries/data/mods/public/simulation/components/interfaces/Capturable.js diff --git a/binaries/data/mods/public/globalscripts/Templates.js b/binaries/data/mods/public/globalscripts/Templates.js index 0e689af4a4..306adac175 100644 --- a/binaries/data/mods/public/globalscripts/Templates.js +++ b/binaries/data/mods/public/globalscripts/Templates.js @@ -90,18 +90,28 @@ function GetTemplateDataHelper(template, player) if (template.Attack) { - ret.attack = {}; - for (var type in template.Attack) + let getAttackStat = function(type, stat) { - ret.attack[type] = { - "hack": func("Attack/"+type+"/Hack", +(template.Attack[type].Hack || 0), player, template), - "pierce": func("Attack/"+type+"/Pierce", +(template.Attack[type].Pierce || 0), player, template), - "crush": func("Attack/"+type+"/Crush", +(template.Attack[type].Crush || 0), player, template), - "minRange": func("Attack/"+type+"/MinRange", +(template.Attack[type].MinRange || 0), player, template), - "maxRange": func("Attack/"+type+"/MaxRange", +template.Attack[type].MaxRange, player, template), - "elevationBonus": func("Attack/"+type+"/ElevationBonus", +(template.Attack[type].ElevationBonus || 0), player, template), - "repeatTime": +(template.Attack[type].RepeatTime || 0), - }; + return func("Attack/"+type+"/"+stat, +(template.Attack[type][stat] || 0), player, template); + }; + + ret.attack = {}; + for (let type in template.Attack) + { + if (type == "Capture") + ret.attack.Capture = { + "value": getAttackStat(type,"Value"), + }; + else + ret.attack[type] = { + "hack": getAttackStat(type, "Hack"), + "pierce": getAttackStat(type, "Pierce"), + "crush": getAttackStat(type, "Crush"), + "minRange": getAttackStat(type, "MinRange"), + "maxRange": getAttackStat(type, "MaxRange"), + "elevationBonus": getAttackStat(type, "ElevationBonus"), + }; + ret.attack[type].repeatTime = +(template.Attack[type].RepeatTime || 0); } } diff --git a/binaries/data/mods/public/gui/common/functions_utility.js b/binaries/data/mods/public/gui/common/functions_utility.js index 536a43989c..b6370023cc 100644 --- a/binaries/data/mods/public/gui/common/functions_utility.js +++ b/binaries/data/mods/public/gui/common/functions_utility.js @@ -166,12 +166,16 @@ function initGameSpeeds() // ==================================================================== // Convert integer color values to string (for use in GUI objects) -function rgbToGuiColor(color) +function rgbToGuiColor(color, alpha) { + var ret; if (color && ("r" in color) && ("g" in color) && ("b" in color)) - return color.r + " " + color.g + " " + color.b; - - return "0 0 0"; + ret = color.r + " " + color.g + " " + color.b; + else + ret = "0 0 0"; + if (alpha) + ret += " " + alpha; + return ret; } // ==================================================================== diff --git a/binaries/data/mods/public/gui/common/tooltips.js b/binaries/data/mods/public/gui/common/tooltips.js index 278d134f3f..c7ed20d779 100644 --- a/binaries/data/mods/public/gui/common/tooltips.js +++ b/binaries/data/mods/public/gui/common/tooltips.js @@ -140,6 +140,7 @@ function getAttackTypeLabel(type) if (type === "Charge") return translate("Charge Attack:"); if (type === "Melee") return translate("Melee Attack:"); if (type === "Ranged") return translate("Ranged Attack:"); + if (type === "Capture") return translate("Capture Attack:"); warn(sprintf("Internationalization: Unexpected attack type found with code ā€˜%(attackType)s’. This attack type must be internationalized.", { attackType: type })); return translate("Attack:"); @@ -169,6 +170,15 @@ function getAttackTooltip(template) }); var attackLabel = txtFormats.header[0] + getAttackTypeLabel(type) + txtFormats.header[1]; + if (type == "Capture") + { + attacks.push(sprintf(translate("%(attackLabel)s %(details)s, %(rate)s"), { + attackLabel: attackLabel, + details: template.attack[type].value, + rate: rate + })); + continue; + } if (type != "Ranged") { attacks.push(sprintf(translate("%(attackLabel)s %(details)s, %(rate)s"), { @@ -206,7 +216,7 @@ function getAttackTooltip(template) })); } - return attacks.join(translate(", ")); + return attacks.join("\n"); } /** diff --git a/binaries/data/mods/public/gui/session/selection_details.js b/binaries/data/mods/public/gui/session/selection_details.js index 880ac99ccf..ca0d135189 100644 --- a/binaries/data/mods/public/gui/session/selection_details.js +++ b/binaries/data/mods/public/gui/session/selection_details.js @@ -58,6 +58,7 @@ function displaySingle(entState, template) } // Hitpoints + Engine.GetGUIObjectByName("healthSection").hidden = !entState.hitpoints; if (entState.hitpoints) { var unitHealthBar = Engine.GetGUIObjectByName("healthBar"); @@ -79,21 +80,44 @@ function displaySingle(entState, template) hitpoints: Math.ceil(entState.hitpoints), maxHitpoints: entState.maxHitpoints }); - Engine.GetGUIObjectByName("healthSection").hidden = false; } - else + + // CapturePoints + Engine.GetGUIObjectByName("captureSection").hidden = !entState.capturePoints; + if (entState.capturePoints) { - Engine.GetGUIObjectByName("healthSection").hidden = true; + let setCaptureBarPart = function(playerID, startSize) + { + var unitCaptureBar = Engine.GetGUIObjectByName("captureBar["+playerID+"]"); + var sizeObj = unitCaptureBar.size; + sizeObj.rleft = startSize; + + var size = 100*Math.max(0, Math.min(1, entState.capturePoints[playerID] / entState.maxCapturePoints)); + sizeObj.rright = startSize + size; + unitCaptureBar.size = sizeObj; + unitCaptureBar.sprite = "color: " + rgbToGuiColor(g_Players[playerID].color, 128); + unitCaptureBar.hidden=false; + return startSize + size; + } + + // first handle the owner's points, to keep those points on the left for clarity + let size = setCaptureBarPart(entState.player, 0); + + for (let i in entState.capturePoints) + if (i != entState.player) + size = setCaptureBarPart(i, size); + + + Engine.GetGUIObjectByName("captureStats").caption = sprintf(translate("%(capturePoints)s / %(maxCapturePoints)s"), { + capturePoints: Math.ceil(entState.capturePoints[entState.player]), + maxCapturePoints: entState.maxCapturePoints + }); } // TODO: Stamina - var player = Engine.GetPlayerID(); - if (entState.stamina && (entState.player == player || g_DevSettings.controlAll)) - Engine.GetGUIObjectByName("staminaSection").hidden = false; - else - Engine.GetGUIObjectByName("staminaSection").hidden = true; // Experience + Engine.GetGUIObjectByName("experience").hidden = !entState.promotion; if (entState.promotion) { var experienceBar = Engine.GetGUIObjectByName("experienceBar"); @@ -112,14 +136,10 @@ function displaySingle(entState, template) experience: "[font=\"sans-bold-13\"]" + translate("Experience:") + "[/font]", current: Math.floor(entState.promotion.curr) }); - Engine.GetGUIObjectByName("experience").hidden = false; - } - else - { - Engine.GetGUIObjectByName("experience").hidden = true; } // Resource stats + Engine.GetGUIObjectByName("resourceSection").hidden = !entState.resourceSupply; if (entState.resourceSupply) { var resources = entState.resourceSupply.isInfinite ? translate("āˆž") : // Infinity symbol @@ -136,15 +156,10 @@ function displaySingle(entState, template) Engine.GetGUIObjectByName("resourceStats").caption = resources; if (entState.hitpoints) - Engine.GetGUIObjectByName("resourceSection").size = Engine.GetGUIObjectByName("staminaSection").size; + Engine.GetGUIObjectByName("resourceSection").size = Engine.GetGUIObjectByName("captureSection").size; else Engine.GetGUIObjectByName("resourceSection").size = Engine.GetGUIObjectByName("healthSection").size; - Engine.GetGUIObjectByName("resourceSection").hidden = false; - } - else - { - Engine.GetGUIObjectByName("resourceSection").hidden = true; } // Resource carrying @@ -290,20 +305,29 @@ function displayMultiple(selection, template) { var averageHealth = 0; var maxHealth = 0; + var maxCapturePoints = 0; + var capturePoints = (new Array(9)).fill(0); + var playerID = 0; for (var i = 0; i < selection.length; i++) { var entState = GetEntityState(selection[i]) - if (entState) + if (!entState) + continue; + playerID = entState.player; // trust that all selected entities have the same owner + if (entState.hitpoints) { - if (entState.hitpoints) - { - averageHealth += entState.hitpoints; - maxHealth += entState.maxHitpoints; - } + averageHealth += entState.hitpoints; + maxHealth += entState.maxHitpoints; + } + if (entState.capturePoints) + { + maxCapturePoints += entState.maxCapturePoints; + capturePoints = entState.capturePoints.map(function(v, i) { return v + capturePoints[i]; }); } } + Engine.GetGUIObjectByName("healthMultiple").hidden = averageHealth <= 0; if (averageHealth > 0) { var unitHealthBar = Engine.GetGUIObjectByName("healthBarMultiple"); @@ -313,13 +337,37 @@ function displayMultiple(selection, template) var hitpointsLabel = "[font=\"sans-bold-13\"]" + translate("Hitpoints:") + "[/font]" var hitpoints = sprintf(translate("%(label)s %(current)s / %(max)s"), { label: hitpointsLabel, current: averageHealth, max: maxHealth }); - var healthMultiple = Engine.GetGUIObjectByName("healthMultiple"); - healthMultiple.tooltip = hitpoints; - healthMultiple.hidden = false; + Engine.GetGUIObjectByName("healthMultiple").tooltip = hitpoints; } - else + + Engine.GetGUIObjectByName("captureMultiple").hidden = maxCapturePoints <= 0; + if (maxCapturePoints > 0) { - Engine.GetGUIObjectByName("healthMultiple").hidden = true; + let setCaptureBarPart = function(playerID, startSize) + { + var unitCaptureBar = Engine.GetGUIObjectByName("captureBarMultiple["+playerID+"]"); + var sizeObj = unitCaptureBar.size; + sizeObj.rtop = startSize; + + var size = 100*Math.max(0, Math.min(1, capturePoints[playerID] / maxCapturePoints)); + sizeObj.rbottom = startSize + size; + unitCaptureBar.size = sizeObj; + unitCaptureBar.sprite = "color: " + rgbToGuiColor(g_Players[playerID].color, 128); + unitCaptureBar.hidden=false; + return startSize + size; + } + + let size = 0; + for (let i in entState.capturePoints) + if (i != playerID) + size = setCaptureBarPart(i, size); + + // last handle the owner's points, to keep those points on the bottom for clarity + setCaptureBarPart(playerID, size); + + var capturePointsLabel = "[font=\"sans-bold-13\"]" + translate("Capture points:") + "[/font]" + var capturePointsTooltip = sprintf(translate("%(label)s %(current)s / %(max)s"), { label: capturePointsLabel, current: Math.ceil(capturePoints[playerID]), max: Math.ceil(maxCapturePoints) }); + Engine.GetGUIObjectByName("captureMultiple").tooltip = capturePointsTooltip; } // TODO: Stamina diff --git a/binaries/data/mods/public/gui/session/selection_panels_middle/multiple_details_area.xml b/binaries/data/mods/public/gui/session/selection_panels_middle/multiple_details_area.xml index 20a84e472d..9f7dd3ecea 100644 --- a/binaries/data/mods/public/gui/session/selection_panels_middle/multiple_details_area.xml +++ b/binaries/data/mods/public/gui/session/selection_panels_middle/multiple_details_area.xml @@ -33,12 +33,13 @@ - - - Stamina + + + Capture points - - + + diff --git a/binaries/data/mods/public/gui/session/selection_panels_middle/single_details_area.xml b/binaries/data/mods/public/gui/session/selection_panels_middle/single_details_area.xml index 990956525e..6d7a9a09c6 100644 --- a/binaries/data/mods/public/gui/session/selection_panels_middle/single_details_area.xml +++ b/binaries/data/mods/public/gui/session/selection_panels_middle/single_details_area.xml @@ -20,16 +20,17 @@ - - - - Stamina: + + + + Capture points: - - + + - - + + diff --git a/binaries/data/mods/public/gui/session/unit_actions.js b/binaries/data/mods/public/gui/session/unit_actions.js index ce693b0b76..08eda3b501 100644 --- a/binaries/data/mods/public/gui/session/unit_actions.js +++ b/binaries/data/mods/public/gui/session/unit_actions.js @@ -99,9 +99,7 @@ var unitActions = { if (!entState.attack || !targetState.hitpoints) return false; - if (playerCheck(entState, targetState, ["Neutral", "Enemy"])) - return {"possible": Engine.GuiInterfaceCall("CanAttack", {"entity": entState.id, "target": targetState.id})}; - return false; + return {"possible": Engine.GuiInterfaceCall("CanAttack", {"entity": entState.id, "target": targetState.id})}; }, "hotkeyActionCheck": function(target) { @@ -672,6 +670,13 @@ var g_EntityCommands = "icon": "kill_small.png" }; + if (entState.capturePoints && entState.capturePoints[entState.player] < entState.maxCapturePoints / 2) + return { + "tooltip": translate("You cannot destroy this entity as you own less than half the capture points"), + "icon": "kill_small.png" + }; + + return { "tooltip": translate("Delete"), "icon": "kill_small.png" diff --git a/binaries/data/mods/public/simulation/components/AIProxy.js b/binaries/data/mods/public/simulation/components/AIProxy.js index 008fcb3921..9b3606a1b9 100644 --- a/binaries/data/mods/public/simulation/components/AIProxy.js +++ b/binaries/data/mods/public/simulation/components/AIProxy.js @@ -111,6 +111,13 @@ AIProxy.prototype.OnHealthChanged = function(msg) this.changes.hitpoints = msg.to; }; +AIProxy.prototype.OnCapturePointsChanged = function(msg) +{ + if (!this.NotifyChange()) + return; + this.changes.capturePoints = msg.capturePoints; +}; + AIProxy.prototype.OnUnitIdleChanged = function(msg) { if (!this.NotifyChange()) diff --git a/binaries/data/mods/public/simulation/components/Attack.js b/binaries/data/mods/public/simulation/components/Attack.js index 491a384d7d..9a0acafe7f 100644 --- a/binaries/data/mods/public/simulation/components/Attack.js +++ b/binaries/data/mods/public/simulation/components/Attack.js @@ -158,6 +158,20 @@ Attack.prototype.Schema = "" + "" + "" + + "" + + "" + + "" + + "" + + "" + + "" + // TODO: it shouldn't be stretched + "" + + "" + + Attack.prototype.bonusesSchema + + Attack.prototype.preferredClassesSchema + + Attack.prototype.restrictedClassesSchema + + "" + + "" + + "" + "" + "" + "" + @@ -198,6 +212,7 @@ Attack.prototype.GetAttackTypes = function() if (this.template.Charge) ret.push("Charge"); if (this.template.Melee) ret.push("Melee"); if (this.template.Ranged) ret.push("Ranged"); + if (this.template.Capture) ret.push("Capture"); return ret; }; @@ -223,6 +238,10 @@ Attack.prototype.GetRestrictedClasses = function(type) Attack.prototype.CanAttack = function(target) { + var cmpArmour = Engine.QueryInterface(target, IID_DamageReceiver); + if (!cmpArmour) + return false; + var cmpFormation = Engine.QueryInterface(target, IID_Formation); if (cmpFormation) return true; @@ -309,23 +328,40 @@ Attack.prototype.GetBestAttackAgainst = function(target) if (cmpFormation) return this.GetBestAttack(); - const cmpIdentity = Engine.QueryInterface(target, IID_Identity); + var cmpIdentity = Engine.QueryInterface(target, IID_Identity); if (!cmpIdentity) return undefined; - const targetClasses = cmpIdentity.GetClassesList(); - const isTargetClass = function (value, i, a) { return targetClasses.indexOf(value) != -1; }; - const types = this.GetAttackTypes(); - const attack = this; - const isAllowed = function (value, i, a) { return !attack.GetRestrictedClasses(value).some(isTargetClass); } - const isPreferred = function (value, i, a) { return attack.GetPreferredClasses(value).some(isTargetClass); } - const byPreference = function (a, b) { return (types.indexOf(a) + (isPreferred(a) ? types.length : 0) ) - (types.indexOf(b) + (isPreferred(b) ? types.length : 0) ); } + + var targetClasses = cmpIdentity.GetClassesList(); + var isTargetClass = function (className) { return targetClasses.indexOf(className) != -1; }; // Always slaughter domestic animals instead of using a normal attack if (isTargetClass("Domestic") && this.template.Slaughter) return "Slaughter"; - return types.filter(isAllowed).sort(byPreference).pop(); + var attack = this; + var isAllowed = function (type) { return !attack.GetRestrictedClasses(type).some(isTargetClass); } + + var types = this.GetAttackTypes().filter(isAllowed); + + // check if the target is capturable + var captureIndex = types.indexOf("Capture") + if (captureIndex != -1) + { + var cmpCapturable = Engine.QueryInterface(target, IID_Capturable); + var cmpPlayer = QueryOwnerInterface(this.entity); + if (cmpPlayer && cmpCapturable && cmpCapturable.CanCapture(cmpPlayer.GetPlayerID())) + return "Capture"; + // not captureable, so remove this attack + types.splice(captureIndex, 1); + } + + var isPreferred = function (className) { return attack.GetPreferredClasses(className).some(isTargetClass); } + var byPreference = function (a, b) { return (types.indexOf(a) + (isPreferred(a) ? types.length : 0) ) - (types.indexOf(b) + (isPreferred(b) ? types.length : 0) ); } + + + return types.sort(byPreference).pop(); }; Attack.prototype.CompareEntitiesByPreference = function(a, b) @@ -367,7 +403,10 @@ Attack.prototype.GetAttackStrengths = function(type) { return ApplyValueModificationsToEntity("Attack/" + type + splash + "/" + damageType, +(template[damageType] || 0), self.entity); }; - + + if (type == "Capture") + return {value: applyMods("Value")}; + return { hack: applyMods("Hack"), pierce: applyMods("Pierce"), @@ -517,6 +556,25 @@ Attack.prototype.PerformAttack = function(type, target) var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); cmpTimer.SetTimeout(this.entity, IID_Attack, "MissileHit", timeToTarget*1000, {"type": type, "target": target, "position": realTargetPosition, "direction": missileDirection, "projectileId": id, "playerId":playerId}); } + else if (type == "Capture") + { + var multiplier = this.GetAttackBonus(type, target); + var cmpHealth = Engine.QueryInterface(target, IID_Health); + if (!cmpHealth || cmpHealth.GetHitpoints() == 0) + return; + multiplier *= cmpHealth.GetMaxHitpoints() / cmpHealth.GetHitpoints(); + + var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); + if (!cmpOwnership || cmpOwnership.GetOwner() == -1) + return; + var owner = cmpOwnership.GetOwner(); + var cmpCapturable = Engine.QueryInterface(target, IID_Capturable); + if (!cmpCapturable || !cmpCapturable.CanCapture(owner)) + return; + + var strength = this.GetAttackStrengths("Capture").value; + cmpCapturable.Reduce(strength * multiplier, owner); + } else { // Melee attack - hurt the target immediately @@ -585,7 +643,7 @@ Attack.prototype.MissileHit = function(data, lateness) // If friendlyFire isn't enabled, get all player enemies to pass to "Damage.CauseSplashDamage". if (friendlyFire == "false") { - var cmpPlayer = Engine.QueryInterface(Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetPlayerByID(data.playerId), IID_Player) + var cmpPlayer = QueryPlayerIDInterface(data.playerId); playersToDamage = cmpPlayer.GetEnemies(); } // Damage the units. @@ -607,7 +665,7 @@ Attack.prototype.MissileHit = function(data, lateness) else { // If we didn't hit the main target look for nearby units - var cmpPlayer = Engine.QueryInterface(Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetPlayerByID(data.playerId), IID_Player) + var cmpPlayer = QueryPlayerIDInterface(data.playerId); var ents = Damage.EntitiesNearPoint(Vector2D.from3D(data.position), targetPosition.horizDistanceTo(data.position) * 2, cmpPlayer.GetEnemies()); for (var i = 0; i < ents.length; i++) diff --git a/binaries/data/mods/public/simulation/components/Capturable.js b/binaries/data/mods/public/simulation/components/Capturable.js new file mode 100644 index 0000000000..2616a818cc --- /dev/null +++ b/binaries/data/mods/public/simulation/components/Capturable.js @@ -0,0 +1,212 @@ +function Capturable() {} + +Capturable.prototype.Schema = + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + ""; + +Capturable.prototype.Init = function() +{ + // Cache this value + this.maxCp = +this.template.CapturePoints; + this.cp = []; + this.startRegenTimer(); +}; + +//// Interface functions //// + +/** + * Returns the current capture points array + */ +Capturable.prototype.GetCapturePoints = function() +{ + return this.cp; +}; + +Capturable.prototype.GetMaxCapturePoints = function() +{ + return this.maxCp; +}; + +/** + * Set the new capture points, used for cloning entities + * The caller should assure that the sum of capture points + * matches the max. + */ +Capturable.prototype.SetCapturePoints = function(capturePointsArray) +{ + this.cp = capturePointsArray; +}; + +/** + * Reduces the amount of capture points of an entity, + * in favour of the player of the source + * Returns the number of capture points actually taken + */ +Capturable.prototype.Reduce = function(amount, playerID) +{ + var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); + if (!cmpOwnership || cmpOwnership.GetOwner() == -1) + return 0; + + var cmpPlayerSource = QueryPlayerIDInterface(playerID); + if (!cmpPlayerSource) + return 0; + + // Before changing the value, activate Fogging if necessary to hide changes + var cmpFogging = Engine.QueryInterface(this.entity, IID_Fogging); + if (cmpFogging) + cmpFogging.Activate(); + + var enemiesFilter = function(v, i) { return v > 0 && !cmpPlayerSource.IsAlly(i); }; + var numberOfEnemies = this.cp.filter(enemiesFilter).length; + + if (numberOfEnemies == 0) + return 0; + + // distribute the capture points over all enemies + var distributedAmount = amount / numberOfEnemies; + for (let i in this.cp) + { + if (cmpPlayerSource.IsAlly(i)) + continue; + if (this.cp[i] > distributedAmount) + this.cp[i] -= distributedAmount; + else + this.cp[i] = 0; + } + + // give all cp taken to the player + var takenCp = this.maxCp - this.cp.reduce(function(a, b) { return a + b; }); + this.cp[playerID] += takenCp; + + this.startRegenTimer(); + + Engine.PostMessage(this.entity, MT_CapturePointsChanged, { "capturePoints": this.cp }) + + if (this.cp[cmpOwnership.GetOwner()] > 0) + return takenCp; + + // if all cp has been taken from the owner, convert it to the best player + var bestPlayer = 0; + for (let i in this.cp) + if (this.cp[i] >= this.cp[bestPlayer]) + bestPlayer = +i; + + cmpOwnership.SetOwner(bestPlayer); + + return takenCp; +}; + +/** + * Check if the source can (re)capture points from this building + */ +Capturable.prototype.CanCapture = function(playerID) +{ + var cmpPlayerSource = QueryPlayerIDInterface(playerID); + + if (!cmpPlayerSource) + warn(source + " has no player component defined on its owner "); + var cp = this.GetCapturePoints() + var sourceEnemyCp = 0; + for (let i in this.GetCapturePoints()) + if (!cmpPlayerSource.IsAlly(i)) + sourceEnemyCp += cp[i]; + return sourceEnemyCp > 0; +}; + +//// Private functions //// + +Capturable.prototype.GetRegenRate = function() +{ + var regenRate = +this.template.RegenRate; + regenRate = ApplyValueModificationsToEntity("Capturable/RegenRate", regenRate, this.entity); + + var cmpGarrisonHolder = Engine.QueryInterface(this.entity, IID_GarrisonHolder); + if (!cmpGarrisonHolder) + return regenRate; + + var garrisonRegenRate = +this.template.GarrisonRegenRate; + garrisonRegenRate = ApplyValueModificationsToEntity("Capturable/GarrisonRegenRate", garrisonRegenRate, this.entity); + var garrisonedUnits = cmpGarrisonHolder.GetEntities().length; + return regenRate + garrisonedUnits * garrisonRegenRate; +}; + +Capturable.prototype.RegenCapturePoints = function() +{ + var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); + if (!cmpOwnership || cmpOwnership.GetOwner() == -1) + return; + + var takenCp = this.Reduce(this.GetRegenRate(), cmpOwnership.GetOwner()) + if (takenCp > 0) + return; + + // no capture points taken, stop the timer + var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); + cmpTimer.CancelTimer(this.regenTimer); + this.regenTimer = 0; +}; + +/** + * Start the regeneration timer when no timer exists + * When nothing can be regenerated (f.e. because the + * rate is 0, or because it is fully regenerated), + * the timer stops automatically after one execution. + */ +Capturable.prototype.startRegenTimer = function() +{ + if (this.regenTimer) + return; + var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); + this.regenTimer = cmpTimer.SetInterval(this.entity, IID_Capturable, "RegenCapturePoints", 1000, 1000, null); +}; + +//// Message Listeners //// + +Capturable.prototype.OnValueModification = function(msg) +{ + if (msg.component != "Capturable") + return; + + var oldMaxCp = this.GetMaxCapturePoints(); + this.maxCp = ApplyValueModificationsToEntity("Capturable/Max", +this.template.Max, this.entity); + if (oldMaxCp == this.maxCp) + return; + + var scale = this.maxCp / oldMaxCp; + for (let i in this.cp) + this.cp[i] *= scale; + Engine.PostMessage(this.entity, MT_CapturePointsChanged, { "capturePoints": this.cp }); + this.startRegenTimer(); +}; + +Capturable.prototype.OnGarrisonedUnitsChanged = function(msg) +{ + this.startRegenTimer(); +}; + +Capturable.prototype.OnOwnershipChanged = function(msg) +{ + this.startRegenTimer(); + + if (msg.from != -1) + return; + + // initialise the capture points when created + this.cp = []; + var cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager); + for (let i = 0; i < cmpPlayerManager.GetNumPlayers(); ++i) + if (i == msg.to) + this.cp[i] = this.maxCp; + else + this.cp[i] = 0; +}; + +Engine.RegisterComponentType(IID_Capturable, "Capturable", Capturable); diff --git a/binaries/data/mods/public/simulation/components/Fogging.js b/binaries/data/mods/public/simulation/components/Fogging.js index c897e7aa52..0b75d06097 100644 --- a/binaries/data/mods/public/simulation/components/Fogging.js +++ b/binaries/data/mods/public/simulation/components/Fogging.js @@ -125,6 +125,13 @@ Fogging.prototype.LoadMirage = function(player) cmpHealth.IsRepairable() && (cmpHealth.GetHitpoints() < cmpHealth.GetMaxHitpoints()) ); + var cmpCapturable = Engine.QueryInterface(this.entity, IID_Capturable); + if (cmpCapturable) + cmpMirage.CopyCapturable( + cmpCapturable.GetCapturePoints(), + cmpCapturable.GetMaxCapturePoints() + ); + var cmpResourceSupply = Engine.QueryInterface(this.entity, IID_ResourceSupply); if (cmpResourceSupply) cmpMirage.CopyResourceSupply( diff --git a/binaries/data/mods/public/simulation/components/GuiInterface.js b/binaries/data/mods/public/simulation/components/GuiInterface.js index e22fc3a109..d9c33e0036 100644 --- a/binaries/data/mods/public/simulation/components/GuiInterface.js +++ b/binaries/data/mods/public/simulation/components/GuiInterface.js @@ -267,6 +267,18 @@ GuiInterface.prototype.GetEntityState = function(player, ent) ret.needsRepair = cmpMirage.NeedsRepair(); } + var cmpCapturable = Engine.QueryInterface(ent, IID_Capturable); + if (cmpCapturable) + { + ret.capturePoints = cmpCapturable.GetCapturePoints(); + ret.maxCapturePoints = cmpCapturable.GetMaxCapturePoints(); + } + if (cmpMirage && cmpMirage.Capturable()) + { + ret.capturePoints = cmpMirage.GetCapturePoints(); + ret.maxCapturePoints = cmpMirage.GetMaxCapturePoints(); + } + var cmpBuilder = Engine.QueryInterface(ent, IID_Builder); if (cmpBuilder) ret.builder = true; @@ -1701,8 +1713,22 @@ GuiInterface.prototype.CanAttack = function(player, data) var cmpAttack = Engine.QueryInterface(data.entity, IID_Attack); if (!cmpAttack) return false; + var cmpEntityPlayer = QueryOwnerInterface(data.entity, IID_Player); + var cmpTargetPlayer = QueryOwnerInterface(data.target, IID_Player); + if (!cmpEntityPlayer || !cmpTargetPlayer) + return false; - return cmpAttack.CanAttack(data.target); + + // if the owner is an enemy, it's up to the attack component to decide + if (!cmpEntityPlayer.IsAlly(cmpTargetPlayer.GetPlayerID())) + return cmpAttack.CanAttack(data.target); + + // if the owner is an ally, we could still want to capture some capture points back + var cmpCapturable = Engine.QueryInterface(data.target, IID_Capturable); + if (cmpCapturable && cmpCapturable.CanCapture(cmpEntityPlayer.GetPlayerID()) && cmpAttack.GetAttackTypes().indexOf("Capture") != -1) + return cmpAttack.CanAttack(data.target); + + return false; }; /* diff --git a/binaries/data/mods/public/simulation/components/Mirage.js b/binaries/data/mods/public/simulation/components/Mirage.js index 5a08620f60..6f876356c6 100644 --- a/binaries/data/mods/public/simulation/components/Mirage.js +++ b/binaries/data/mods/public/simulation/components/Mirage.js @@ -21,6 +21,10 @@ Mirage.prototype.Init = function() this.hitpoints = null; this.needsRepair = null; + this.capturable = false; + this.capturePoints = []; + this.maxCapturePoints = 0; + this.resourceSupply = false; this.maxAmount = null; this.amount = null; @@ -94,6 +98,30 @@ Mirage.prototype.NeedsRepair = function() return this.needsRepair; }; +// Capture data + +Mirage.prototype.CopyCapturable = function(capturePoints, maxCapturePoints) +{ + this.capturable = true; + this.capturePoints = capturePoints; + this.maxCapturePoints = maxCapturePoints; +}; + +Mirage.prototype.Capturable = function() +{ + return this.capturable; +}; + +Mirage.prototype.GetMaxCapturePoints = function() +{ + return this.maxCapturePoints; +}; + +Mirage.prototype.GetCapturePoints = function() +{ + return this.capturePoints; +}; + // ResourceSupply data Mirage.prototype.CopyResourceSupply = function(maxAmount, amount, type, isInfinite) diff --git a/binaries/data/mods/public/simulation/components/Pack.js b/binaries/data/mods/public/simulation/components/Pack.js index 0861b46599..1be41604cd 100644 --- a/binaries/data/mods/public/simulation/components/Pack.js +++ b/binaries/data/mods/public/simulation/components/Pack.js @@ -148,6 +148,16 @@ Pack.prototype.PackProgress = function(data, lateness) var cmpNewOwnership = Engine.QueryInterface(newEntity, IID_Ownership); cmpNewOwnership.SetOwner(cmpOwnership.GetOwner()); + // rescale capture points + var cmpCapturable = Engine.QueryInterface(this.entity, IID_Capturable); + var cmpNewCapturable = Engine.QueryInterface(newEntity, IID_Capturable); + if (cmpCapturable && cmpNewCapturable) + { + let scale = cmpCapturable.GetMaxCapturePoints() / cmpNewCapturable.GetMaxCapturePoints(); + let newCp = cmpCapturable.GetCapturePoints().map(function (v) { return v / scale; }); + cmpNewCapturable.SetCapturePoints(newCp); + } + // Maintain current health level var cmpHealth = Engine.QueryInterface(this.entity, IID_Health); var cmpNewHealth = Engine.QueryInterface(newEntity, IID_Health); diff --git a/binaries/data/mods/public/simulation/components/TerritoryDecay.js b/binaries/data/mods/public/simulation/components/TerritoryDecay.js index d0089de1e6..1f2fa2624d 100644 --- a/binaries/data/mods/public/simulation/components/TerritoryDecay.js +++ b/binaries/data/mods/public/simulation/components/TerritoryDecay.js @@ -1,7 +1,7 @@ function TerritoryDecay() {} TerritoryDecay.prototype.Schema = - "" + + "" + "" + ""; @@ -33,8 +33,6 @@ TerritoryDecay.prototype.IsConnected = function() var tileOwner = cmpTerritoryManager.GetOwner(pos.x, pos.y); if (tileOwner != cmpOwnership.GetOwner()) return false; - // TODO: this should probably use the same territory restriction - // logic as BuildRestrictions, to handle allies etc return cmpTerritoryManager.IsConnected(pos.x, pos.y); }; @@ -64,7 +62,7 @@ TerritoryDecay.prototype.UpdateDecayState = function() if (connected) var decaying = false; else - var decaying = (Math.round(ApplyValueModificationsToEntity("TerritoryDecay/HealthDecayRate", +this.template.HealthDecayRate, this.entity)) > 0); + var decaying = (Math.round(ApplyValueModificationsToEntity("TerritoryDecay/DecayRate", +this.template.DecayRate, this.entity)) > 0); if (decaying === this.decaying) return; this.decaying = decaying; @@ -88,13 +86,17 @@ TerritoryDecay.prototype.OnOwnershipChanged = function(msg) TerritoryDecay.prototype.Decay = function() { - var cmpHealth = Engine.QueryInterface(this.entity, IID_Health); - if (!cmpHealth) + var cmpCapturable = Engine.QueryInterface(this.entity, IID_Capturable); + if (!cmpCapturable) return; // error - var decayRate = ApplyValueModificationsToEntity("TerritoryDecay/HealthDecayRate", +this.template.HealthDecayRate, this.entity); + var decayRate = ApplyValueModificationsToEntity( + "TerritoryDecay/DecayRate", + +this.template.DecayRate, + this.entity); - cmpHealth.Reduce(Math.round(decayRate)); + // Reduce capture points in favour of Gaia + cmpCapturable.Reduce(decayRate, 0); }; Engine.RegisterComponentType(IID_TerritoryDecay, "TerritoryDecay", TerritoryDecay); diff --git a/binaries/data/mods/public/simulation/components/UnitAI.js b/binaries/data/mods/public/simulation/components/UnitAI.js index 84c500e1b7..7b21541322 100644 --- a/binaries/data/mods/public/simulation/components/UnitAI.js +++ b/binaries/data/mods/public/simulation/components/UnitAI.js @@ -5559,20 +5559,25 @@ UnitAI.prototype.CanAttack = function(target, forceResponse) return false; var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); - if (!cmpOwnership) + if (!cmpOwnership || cmpOwnership.GetOwner() < 0) return false; + var owner = cmpOwnership.GetOwner(); // Verify that the target is an attackable resource supply like a domestic animal // or that it isn't owned by an ally of this entity's player or is responding to // an attack. - var owner = cmpOwnership.GetOwner(); - if (!this.MustKillGatherTarget(target) - && !(IsOwnedByEnemyOfPlayer(owner, target) - || IsOwnedByNeutralOfPlayer(owner, target) - || (forceResponse && !IsOwnedByPlayer(owner, target)))) - return false; + if (this.MustKillGatherTarget(target)) + return true; - return true; + var cmpCapturable = Engine.QueryInterface(target, IID_Capturable); + if (cmpCapturable && cmpCapturable.CanCapture(owner) && cmpAttack.GetAttackTypes().indexOf("Capture") != -1) + return true; + + if (IsOwnedByEnemyOfPlayer(owner, target) || IsOwnedByNeutralOfPlayer(owner, target)) + return true; + if (forceResponse && !IsOwnedByPlayer(owner, target)) + return true; + return false; }; UnitAI.prototype.CanGarrison = function(target) diff --git a/binaries/data/mods/public/simulation/components/interfaces/Capturable.js b/binaries/data/mods/public/simulation/components/interfaces/Capturable.js new file mode 100644 index 0000000000..4368331103 --- /dev/null +++ b/binaries/data/mods/public/simulation/components/interfaces/Capturable.js @@ -0,0 +1,5 @@ +Engine.RegisterInterface("Capturable"); + +// Message in the form of {"capturePoints": [gaia, p1, p2, ...]} +Engine.RegisterMessageType("CapturePointsChanged"); + diff --git a/binaries/data/mods/public/simulation/data/technologies/decay_outpost.json b/binaries/data/mods/public/simulation/data/technologies/decay_outpost.json index 404772f8db..d79e022c99 100644 --- a/binaries/data/mods/public/simulation/data/technologies/decay_outpost.json +++ b/binaries/data/mods/public/simulation/data/technologies/decay_outpost.json @@ -7,7 +7,7 @@ "icon": "blocks_three.png", "researchTime": 40, "tooltip": "Territory decay -50% for Outposts.", - "modifications": [{"value": "TerritoryDecay/HealthDecayRate", "multiply": 0.5}], + "modifications": [{"value": "TerritoryDecay/DecayRate", "multiply": 0.5}], "affects": ["Outpost"], "soundComplete": "interface/alarm/alarm_upgradearmory.xml" } diff --git a/binaries/data/mods/public/simulation/data/technologies/romans/decay_logistics.json b/binaries/data/mods/public/simulation/data/technologies/romans/decay_logistics.json index 06ac834d9e..06ca4da19a 100644 --- a/binaries/data/mods/public/simulation/data/technologies/romans/decay_logistics.json +++ b/binaries/data/mods/public/simulation/data/technologies/romans/decay_logistics.json @@ -7,7 +7,7 @@ "icon": "handcart_empty.png", "researchTime": 40, "tooltip": "Entrenched Camps and Siege Walls decay 50% slower.", - "modifications": [{"value": "TerritoryDecay/HealthDecayRate", "multiply": 0.5}], + "modifications": [{"value": "TerritoryDecay/DecayRate", "multiply": 0.5}], "affects": ["ArmyCamp", "SiegeWall"], "soundComplete": "interface/alarm/alarm_upgradearmory.xml" } diff --git a/binaries/data/mods/public/simulation/helpers/Commands.js b/binaries/data/mods/public/simulation/helpers/Commands.js index e90b4d5e65..1caaa4ca45 100644 --- a/binaries/data/mods/public/simulation/helpers/Commands.js +++ b/binaries/data/mods/public/simulation/helpers/Commands.js @@ -349,8 +349,18 @@ var commands = { "delete-entities": function(player, cmd, data) { - for each (var ent in data.entities) + for (let ent of data.entities) { + // don't allow to delete entities who are half-captured + var cmpCapturable = Engine.QueryInterface(ent, IID_Capturable); + if (cmpCapturable) + { + var capturePoints = cmpCapturable.GetCapturePoints(); + var maxCapturePoints = cmpCapturable.GetMaxCapturePoints(); + if (capturePoints[player] < maxCapturePoints / 2) + return; + } + // either kill or delete the entity var cmpHealth = Engine.QueryInterface(ent, IID_Health); if (cmpHealth) { diff --git a/binaries/data/mods/public/simulation/templates/structures/merc_camp_egyptian.xml b/binaries/data/mods/public/simulation/templates/structures/merc_camp_egyptian.xml index 25d5b2945f..2e57ac809d 100644 --- a/binaries/data/mods/public/simulation/templates/structures/merc_camp_egyptian.xml +++ b/binaries/data/mods/public/simulation/templates/structures/merc_camp_egyptian.xml @@ -60,7 +60,7 @@ - 1 + 1 diff --git a/binaries/data/mods/public/simulation/templates/structures/ptol_mercenary_camp.xml b/binaries/data/mods/public/simulation/templates/structures/ptol_mercenary_camp.xml index eb8f1e3cbe..adeef3af62 100644 --- a/binaries/data/mods/public/simulation/templates/structures/ptol_mercenary_camp.xml +++ b/binaries/data/mods/public/simulation/templates/structures/ptol_mercenary_camp.xml @@ -62,7 +62,7 @@ - 1 + 1 diff --git a/binaries/data/mods/public/simulation/templates/structures/ptol_military_colony.xml b/binaries/data/mods/public/simulation/templates/structures/ptol_military_colony.xml index 3ceee1edb7..a89f66c9c5 100644 --- a/binaries/data/mods/public/simulation/templates/structures/ptol_military_colony.xml +++ b/binaries/data/mods/public/simulation/templates/structures/ptol_military_colony.xml @@ -76,7 +76,7 @@ - 1 + 1 80 diff --git a/binaries/data/mods/public/simulation/templates/structures/rome_army_camp.xml b/binaries/data/mods/public/simulation/templates/structures/rome_army_camp.xml index ac90cde455..97fd2927e7 100644 --- a/binaries/data/mods/public/simulation/templates/structures/rome_army_camp.xml +++ b/binaries/data/mods/public/simulation/templates/structures/rome_army_camp.xml @@ -76,7 +76,7 @@ - 10 + 10 diff --git a/binaries/data/mods/public/simulation/templates/structures/rome_siege_wall_gate.xml b/binaries/data/mods/public/simulation/templates/structures/rome_siege_wall_gate.xml index 5b71e460dd..043c79fcca 100644 --- a/binaries/data/mods/public/simulation/templates/structures/rome_siege_wall_gate.xml +++ b/binaries/data/mods/public/simulation/templates/structures/rome_siege_wall_gate.xml @@ -44,7 +44,7 @@ - 1 + 1 diff --git a/binaries/data/mods/public/simulation/templates/structures/rome_siege_wall_long.xml b/binaries/data/mods/public/simulation/templates/structures/rome_siege_wall_long.xml index f04025e86d..d23385c521 100644 --- a/binaries/data/mods/public/simulation/templates/structures/rome_siege_wall_long.xml +++ b/binaries/data/mods/public/simulation/templates/structures/rome_siege_wall_long.xml @@ -62,7 +62,7 @@ - 1 + 1 diff --git a/binaries/data/mods/public/simulation/templates/structures/rome_siege_wall_medium.xml b/binaries/data/mods/public/simulation/templates/structures/rome_siege_wall_medium.xml index 80549e75e6..dcb9c96676 100644 --- a/binaries/data/mods/public/simulation/templates/structures/rome_siege_wall_medium.xml +++ b/binaries/data/mods/public/simulation/templates/structures/rome_siege_wall_medium.xml @@ -55,7 +55,7 @@ - 1 + 1 diff --git a/binaries/data/mods/public/simulation/templates/structures/rome_siege_wall_short.xml b/binaries/data/mods/public/simulation/templates/structures/rome_siege_wall_short.xml index 63f2bf7ca8..2ec4273180 100644 --- a/binaries/data/mods/public/simulation/templates/structures/rome_siege_wall_short.xml +++ b/binaries/data/mods/public/simulation/templates/structures/rome_siege_wall_short.xml @@ -42,7 +42,7 @@ - 1 + 1 diff --git a/binaries/data/mods/public/simulation/templates/structures/rome_siege_wall_tower.xml b/binaries/data/mods/public/simulation/templates/structures/rome_siege_wall_tower.xml index 90ad9e7b22..797589f314 100644 --- a/binaries/data/mods/public/simulation/templates/structures/rome_siege_wall_tower.xml +++ b/binaries/data/mods/public/simulation/templates/structures/rome_siege_wall_tower.xml @@ -36,7 +36,7 @@ - 1 + 1 diff --git a/binaries/data/mods/public/simulation/templates/structures/rome_tent.xml b/binaries/data/mods/public/simulation/templates/structures/rome_tent.xml index b8daf9e052..4478082fac 100644 --- a/binaries/data/mods/public/simulation/templates/structures/rome_tent.xml +++ b/binaries/data/mods/public/simulation/templates/structures/rome_tent.xml @@ -50,7 +50,7 @@ - 1 + 1 diff --git a/binaries/data/mods/public/simulation/templates/structures/sele_military_colony.xml b/binaries/data/mods/public/simulation/templates/structures/sele_military_colony.xml index 091ac25c15..405d433dff 100644 --- a/binaries/data/mods/public/simulation/templates/structures/sele_military_colony.xml +++ b/binaries/data/mods/public/simulation/templates/structures/sele_military_colony.xml @@ -75,7 +75,7 @@ - 1 + 1 80 diff --git a/binaries/data/mods/public/simulation/templates/template_structure.xml b/binaries/data/mods/public/simulation/templates/template_structure.xml index 8c78ce588d..9b07eefd15 100644 --- a/binaries/data/mods/public/simulation/templates/template_structure.xml +++ b/binaries/data/mods/public/simulation/templates/template_structure.xml @@ -20,6 +20,11 @@ land own + + 1000 + 0 + 3 + 0 0 @@ -100,7 +105,7 @@ 12.0 - 5 + 5 true diff --git a/binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre.xml b/binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre.xml index 76a3aa16cc..ba9d9c6727 100644 --- a/binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre.xml +++ b/binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre.xml @@ -35,6 +35,9 @@ 200 + + 3000 + 20 500 diff --git a/binaries/data/mods/public/simulation/templates/template_structure_civic_house.xml b/binaries/data/mods/public/simulation/templates/template_structure_civic_house.xml index 9631826a9a..69846bccb8 100644 --- a/binaries/data/mods/public/simulation/templates/template_structure_civic_house.xml +++ b/binaries/data/mods/public/simulation/templates/template_structure_civic_house.xml @@ -3,6 +3,9 @@ House + + 300 + 5 30 diff --git a/binaries/data/mods/public/simulation/templates/template_structure_defense_outpost.xml b/binaries/data/mods/public/simulation/templates/template_structure_defense_outpost.xml index 0e68c5484e..2ea5c125b3 100644 --- a/binaries/data/mods/public/simulation/templates/template_structure_defense_outpost.xml +++ b/binaries/data/mods/public/simulation/templates/template_structure_defense_outpost.xml @@ -90,7 +90,7 @@ 18.0 - 2 + 2 80 diff --git a/binaries/data/mods/public/simulation/templates/template_structure_defense_wall.xml b/binaries/data/mods/public/simulation/templates/template_structure_defense_wall.xml index 62b3c64357..18314fe31f 100644 --- a/binaries/data/mods/public/simulation/templates/template_structure_defense_wall.xml +++ b/binaries/data/mods/public/simulation/templates/template_structure_defense_wall.xml @@ -4,6 +4,7 @@ land-shore Wall + 10 diff --git a/binaries/data/mods/public/simulation/templates/template_structure_defense_wall_gate.xml b/binaries/data/mods/public/simulation/templates/template_structure_defense_wall_gate.xml index 4617435805..121b99afb6 100644 --- a/binaries/data/mods/public/simulation/templates/template_structure_defense_wall_gate.xml +++ b/binaries/data/mods/public/simulation/templates/template_structure_defense_wall_gate.xml @@ -6,6 +6,7 @@ Wall + 0 diff --git a/binaries/data/mods/public/simulation/templates/template_structure_defense_wall_tower.xml b/binaries/data/mods/public/simulation/templates/template_structure_defense_wall_tower.xml index e3ab986a41..1875b314d0 100644 --- a/binaries/data/mods/public/simulation/templates/template_structure_defense_wall_tower.xml +++ b/binaries/data/mods/public/simulation/templates/template_structure_defense_wall_tower.xml @@ -23,6 +23,7 @@ land-shore Wall + 120 diff --git a/binaries/data/mods/public/simulation/templates/template_structure_economic_farmstead.xml b/binaries/data/mods/public/simulation/templates/template_structure_economic_farmstead.xml index 0875006bc4..ed4371a52c 100644 --- a/binaries/data/mods/public/simulation/templates/template_structure_economic_farmstead.xml +++ b/binaries/data/mods/public/simulation/templates/template_structure_economic_farmstead.xml @@ -3,6 +3,9 @@ Farmstead + + 300 + 45 diff --git a/binaries/data/mods/public/simulation/templates/template_structure_economic_storehouse.xml b/binaries/data/mods/public/simulation/templates/template_structure_economic_storehouse.xml index 55b9bbb5af..f8f658804d 100644 --- a/binaries/data/mods/public/simulation/templates/template_structure_economic_storehouse.xml +++ b/binaries/data/mods/public/simulation/templates/template_structure_economic_storehouse.xml @@ -3,6 +3,9 @@ Storehouse + + 300 + 40 diff --git a/binaries/data/mods/public/simulation/templates/template_structure_military_fortress.xml b/binaries/data/mods/public/simulation/templates/template_structure_military_fortress.xml index 080293410e..73cd16ffe5 100644 --- a/binaries/data/mods/public/simulation/templates/template_structure_military_fortress.xml +++ b/binaries/data/mods/public/simulation/templates/template_structure_military_fortress.xml @@ -26,6 +26,9 @@ 80 + + 4000 + 10 300 diff --git a/binaries/data/mods/public/simulation/templates/template_structure_resource_field.xml b/binaries/data/mods/public/simulation/templates/template_structure_resource_field.xml index 3c1d2f5f07..1ac6dbf7e5 100644 --- a/binaries/data/mods/public/simulation/templates/template_structure_resource_field.xml +++ b/binaries/data/mods/public/simulation/templates/template_structure_resource_field.xml @@ -8,6 +8,7 @@ Field + 50 diff --git a/binaries/data/mods/public/simulation/templates/template_structure_wonder.xml b/binaries/data/mods/public/simulation/templates/template_structure_wonder.xml index 32ef116445..c403f0c793 100644 --- a/binaries/data/mods/public/simulation/templates/template_structure_wonder.xml +++ b/binaries/data/mods/public/simulation/templates/template_structure_wonder.xml @@ -13,6 +13,9 @@ Wonder + + 5000 + 1000 diff --git a/binaries/data/mods/public/simulation/templates/template_unit_cavalry.xml b/binaries/data/mods/public/simulation/templates/template_unit_cavalry.xml index 8bbfb5bbcc..f799246005 100644 --- a/binaries/data/mods/public/simulation/templates/template_unit_cavalry.xml +++ b/binaries/data/mods/public/simulation/templates/template_unit_cavalry.xml @@ -6,6 +6,11 @@ 15 + + 3 + 4 + 1000 + 100.0 0.0 diff --git a/binaries/data/mods/public/simulation/templates/template_unit_champion.xml b/binaries/data/mods/public/simulation/templates/template_unit_champion.xml index 25df518961..0fd6b05d66 100644 --- a/binaries/data/mods/public/simulation/templates/template_unit_champion.xml +++ b/binaries/data/mods/public/simulation/templates/template_unit_champion.xml @@ -1,5 +1,12 @@ + + + 3 + 4 + 1000 + + Champion Unit Organic Human diff --git a/binaries/data/mods/public/simulation/templates/template_unit_champion_elephant_melee.xml b/binaries/data/mods/public/simulation/templates/template_unit_champion_elephant_melee.xml index 520e5d5c3e..e734460e62 100644 --- a/binaries/data/mods/public/simulation/templates/template_unit_champion_elephant_melee.xml +++ b/binaries/data/mods/public/simulation/templates/template_unit_champion_elephant_melee.xml @@ -1,6 +1,6 @@ - + 20 0 diff --git a/binaries/data/mods/public/simulation/templates/template_unit_hero_elephant_melee.xml b/binaries/data/mods/public/simulation/templates/template_unit_hero_elephant_melee.xml index df041b95aa..c9dd17d664 100644 --- a/binaries/data/mods/public/simulation/templates/template_unit_hero_elephant_melee.xml +++ b/binaries/data/mods/public/simulation/templates/template_unit_hero_elephant_melee.xml @@ -5,7 +5,7 @@ 10 12 - + 17.5 0 diff --git a/binaries/data/mods/public/simulation/templates/template_unit_infantry.xml b/binaries/data/mods/public/simulation/templates/template_unit_infantry.xml index c4fb3932b1..fc53d0c7c5 100644 --- a/binaries/data/mods/public/simulation/templates/template_unit_infantry.xml +++ b/binaries/data/mods/public/simulation/templates/template_unit_infantry.xml @@ -6,6 +6,11 @@ 15 + + 3 + 4 + 1000 + 50.0 0.0 diff --git a/binaries/data/mods/public/simulation/templates/template_unit_mechanical_siege.xml b/binaries/data/mods/public/simulation/templates/template_unit_mechanical_siege.xml index fa4c783241..001bee2e0d 100644 --- a/binaries/data/mods/public/simulation/templates/template_unit_mechanical_siege.xml +++ b/binaries/data/mods/public/simulation/templates/template_unit_mechanical_siege.xml @@ -5,6 +5,11 @@ 5 5 + + 100 + 0 + 1.5 + 5