Move damage types definition to a new helper similar to how resources are handled.

This should make adding new damage types a little easier, however such
an
extension would still need changes to the AI, and to all templates that
have Armour, Attack, or DeathDamage.

Reviewed By: elexis
Differential Revision: https://code.wildfiregames.com/D866
This was SVN commit r20203.
This commit is contained in:
leper
2017-09-18 16:33:56 +00:00
parent 2e02c88d2c
commit 725aa8a686
16 changed files with 116 additions and 106 deletions
@@ -0,0 +1,22 @@
function DamageTypes()
{
// TODO: load these from files
this.names = {
"Hack": markForTranslationWithContext("damage type", "Hack"),
"Pierce": markForTranslationWithContext("damage type", "Pierce"),
"Crush": markForTranslationWithContext("damage type", "Crush"),
};
deepfreeze(this.names);
}
DamageTypes.prototype.GetNames = function()
{
return this.names;
};
DamageTypes.prototype.GetTypes = function()
{
return Object.keys(this.names);
};
@@ -117,11 +117,12 @@ function GetModifiedTemplateDataValue(template, value_path, mod_key, player, mod
* of properties. * of properties.
* @param {object} auraTemplates - In the form of { key: { "auraName": "", "auraDescription": "" } }. * @param {object} auraTemplates - In the form of { key: { "auraName": "", "auraDescription": "" } }.
* @param {object} resources - An instance of the Resources prototype. * @param {object} resources - An instance of the Resources prototype.
* @param {object} damageTypes - An instance of the DamageTypes prototype.
* @param {object} modifiers - Modifications from auto-researched techs, unit upgrades * @param {object} modifiers - Modifications from auto-researched techs, unit upgrades
* etc. Optional as only used if there's no player * etc. Optional as only used if there's no player
* id provided. * id provided.
*/ */
function GetTemplateDataHelper(template, player, auraTemplates, resources, modifiers={}) function GetTemplateDataHelper(template, player, auraTemplates, resources, damageTypes, modifiers={})
{ {
// Return data either from template (in tech tree) or sim state (ingame). // Return data either from template (in tech tree) or sim state (ingame).
// @param {string} value_path - Route to the value within the template. // @param {string} value_path - Route to the value within the template.
@@ -133,11 +134,11 @@ function GetTemplateDataHelper(template, player, auraTemplates, resources, modif
let ret = {}; let ret = {};
if (template.Armour) if (template.Armour)
ret.armour = { {
"hack": getEntityValue("Armour/Hack"), ret.armour = {};
"pierce": getEntityValue("Armour/Pierce"), for (let damageType of damageTypes.GetTypes())
"crush": getEntityValue("Armour/Crush") ret.armour[damageType] = getEntityValue("Armour/" + damageType);
}; }
if (template.Attack) if (template.Attack)
{ {
@@ -155,38 +156,38 @@ function GetTemplateDataHelper(template, player, auraTemplates, resources, modif
else else
{ {
ret.attack[type] = { ret.attack[type] = {
"hack": getAttackStat("Hack"),
"pierce": getAttackStat("Pierce"),
"crush": getAttackStat("Crush"),
"minRange": getAttackStat("MinRange"), "minRange": getAttackStat("MinRange"),
"maxRange": getAttackStat("MaxRange"), "maxRange": getAttackStat("MaxRange"),
"elevationBonus": getAttackStat("ElevationBonus") "elevationBonus": getAttackStat("ElevationBonus")
}; };
for (let damageType of damageTypes.GetTypes())
ret.attack[type][damageType] = getAttackStat(damageType);
ret.attack[type].elevationAdaptedRange = Math.sqrt(ret.attack[type].maxRange * ret.attack[type].elevationAdaptedRange = Math.sqrt(ret.attack[type].maxRange *
(2 * ret.attack[type].elevationBonus + ret.attack[type].maxRange)); (2 * ret.attack[type].elevationBonus + ret.attack[type].maxRange));
} }
ret.attack[type].repeatTime = getAttackStat("RepeatTime"); ret.attack[type].repeatTime = getAttackStat("RepeatTime");
if (template.Attack[type].Splash) if (template.Attack[type].Splash)
{
ret.attack[type].splash = { ret.attack[type].splash = {
"hack": getAttackStat("Splash/Hack"),
"pierce": getAttackStat("Splash/Pierce"),
"crush": getAttackStat("Splash/Crush"),
// true if undefined // true if undefined
"friendlyFire": template.Attack[type].Splash.FriendlyFire != "false", "friendlyFire": template.Attack[type].Splash.FriendlyFire != "false",
"shape": template.Attack[type].Splash.Shape "shape": template.Attack[type].Splash.Shape
}; };
for (let damageType of damageTypes.GetTypes())
ret.attack[type].splash[damageType] = getAttackStat("Splash/" + damageType);
}
} }
} }
if (template.DeathDamage) if (template.DeathDamage)
{ {
ret.deathDamage = { ret.deathDamage = {
"hack": getEntityValue("DeathDamage/Hack"),
"pierce": getEntityValue("DeathDamage/Pierce"),
"crush": getEntityValue("DeathDamage/Crush"),
"friendlyFire": template.DeathDamage.FriendlyFire != "false" "friendlyFire": template.DeathDamage.FriendlyFire != "false"
}; };
for (let damageType of damageTypes.GetTypes())
ret.deathDamage[damageType] = getEntityValue("DeathDamage/" + damageType);
} }
if (template.Auras) if (template.Auras)
@@ -11,11 +11,7 @@ var g_AttackTypes = {
"Capture": translate("Capture Attack:") "Capture": translate("Capture Attack:")
}; };
var g_DamageTypes = { var g_DamageTypes = new DamageTypes();
"hack": translate("Hack"),
"pierce": translate("Pierce"),
"crush": translate("Crush"),
};
var g_SplashDamageTypes = { var g_SplashDamageTypes = {
"Circular": translate("Circular Splash Damage"), "Circular": translate("Circular Splash Damage"),
@@ -188,7 +184,7 @@ function getArmorTooltip(template)
Object.keys(template.armour).map( Object.keys(template.armour).map(
dmgType => sprintf(translate("%(damage)s %(damageType)s %(armorPercentage)s"), { dmgType => sprintf(translate("%(damage)s %(damageType)s %(armorPercentage)s"), {
"damage": template.armour[dmgType].toFixed(1), "damage": template.armour[dmgType].toFixed(1),
"damageType": unitFont(g_DamageTypes[dmgType]), "damageType": unitFont(translateWithContext("damage type", g_DamageTypes.GetNames()[dmgType])),
"armorPercentage": "armorPercentage":
'[font="sans-10"]' + '[font="sans-10"]' +
sprintf(translate("(%(armorPercentage)s)"), { sprintf(translate("(%(armorPercentage)s)"), {
@@ -204,11 +200,11 @@ function damageTypesToText(dmg)
if (!dmg) if (!dmg)
return '[font="sans-12"]' + translate("(None)") + '[/font]'; return '[font="sans-12"]' + translate("(None)") + '[/font]';
return Object.keys(g_DamageTypes).filter( return g_DamageTypes.GetTypes().filter(
dmgType => dmg[dmgType]).map( dmgType => dmg[dmgType]).map(
dmgType => sprintf(translate("%(damage)s %(damageType)s"), { dmgType => sprintf(translate("%(damage)s %(damageType)s"), {
"damage": dmg[dmgType].toFixed(1), "damage": dmg[dmgType].toFixed(1),
"damageType": unitFont(g_DamageTypes[dmgType]) "damageType": unitFont(translateWithContext("damage type", g_DamageTypes.GetNames()[dmgType]))
})).join(commaFont(translate(", "))); })).join(commaFont(translate(", ")));
} }
@@ -23,7 +23,7 @@ function getActualUpgradeData(upgradesInfo)
{ {
upgrade.entity = upgrade.entity.replace("{civ}", g_SelectedCiv); upgrade.entity = upgrade.entity.replace("{civ}", g_SelectedCiv);
let data = GetTemplateDataHelper(loadTemplate(upgrade.entity), null, g_AuraData, g_ResourceData); let data = GetTemplateDataHelper(loadTemplate(upgrade.entity), null, g_AuraData, g_ResourceData, g_DamageTypes);
data.cost = upgrade.cost; data.cost = upgrade.cost;
data.icon = upgrade.icon || data.icon; data.icon = upgrade.icon || data.icon;
data.tooltip = upgrade.tooltip || data.tooltip; data.tooltip = upgrade.tooltip || data.tooltip;
@@ -177,7 +177,7 @@ function unravelPhases(techs)
function GetTemplateData(templateName) function GetTemplateData(templateName)
{ {
var template = loadTemplate(templateName); var template = loadTemplate(templateName);
return GetTemplateDataHelper(template, null, g_AuraData, g_ResourceData, g_CurrentModifiers); return GetTemplateDataHelper(template, null, g_AuraData, g_ResourceData, g_DamageTypes, g_CurrentModifiers);
} }
function isPairTech(technologyCode) function isPairTech(technologyCode)
@@ -17,6 +17,7 @@ var g_CivData = loadCivData(true, false);
*/ */
var g_ParsedData = {}; var g_ParsedData = {};
var g_ResourceData = new Resources(); var g_ResourceData = new Resources();
var g_DamageTypes = new DamageTypes();
// This must be defined after the g_TechnologyData cache object is declared. // This must be defined after the g_TechnologyData cache object is declared.
var g_AutoResearchTechList = findAllAutoResearchedTechs(); var g_AutoResearchTechList = findAllAutoResearchedTechs();
@@ -101,7 +102,7 @@ function loadUnit(templateName)
return null; return null;
let template = loadTemplate(templateName); let template = loadTemplate(templateName);
let unit = GetTemplateDataHelper(template, null, g_AuraData, g_ResourceData, g_CurrentModifiers); let unit = GetTemplateDataHelper(template, null, g_AuraData, g_ResourceData, g_DamageTypes, g_CurrentModifiers);
if (template.ProductionQueue) if (template.ProductionQueue)
{ {
@@ -157,7 +158,7 @@ function loadStructure(templateName)
return null; return null;
let template = loadTemplate(templateName); let template = loadTemplate(templateName);
let structure = GetTemplateDataHelper(template, null, g_AuraData, g_ResourceData, g_CurrentModifiers); let structure = GetTemplateDataHelper(template, null, g_AuraData, g_ResourceData, g_DamageTypes, g_CurrentModifiers);
structure.production = { structure.production = {
"technology": [], "technology": [],
@@ -214,14 +214,14 @@ m.Template = m.Class({
return +this.get("Cost/PopulationBonus"); return +this.get("Cost/PopulationBonus");
}, },
armourStrengths: function() { "armourStrengths": function() {
if (!this.get("Armour")) if (!this.get("Armour"))
return undefined; return undefined;
return { return {
hack: +this.get("Armour/Hack"), "Hack": +this.get("Armour/Hack"),
pierce: +this.get("Armour/Pierce"), "Pierce": +this.get("Armour/Pierce"),
crush: +this.get("Armour/Crush") "Crush": +this.get("Armour/Crush")
}; };
}, },
@@ -246,14 +246,14 @@ m.Template = m.Class({
}; };
}, },
attackStrengths: function(type) { "attackStrengths": function(type) {
if (!this.get("Attack/" + type +"")) if (!this.get("Attack/" + type +""))
return undefined; return undefined;
return { return {
hack: +(this.get("Attack/" + type + "/Hack") || 0), "Hack": +(this.get("Attack/" + type + "/Hack") || 0),
pierce: +(this.get("Attack/" + type + "/Pierce") || 0), "Pierce": +(this.get("Attack/" + type + "/Pierce") || 0),
crush: +(this.get("Attack/" + type + "/Crush") || 0) "Crush": +(this.get("Attack/" + type + "/Crush") || 0)
}; };
}, },
@@ -28,13 +28,13 @@ m.getMaxStrength = function(ent, againstClass)
val *= ent.getMultiplierAgainst(type, againstClass); val *= ent.getMultiplierAgainst(type, againstClass);
switch (str) switch (str)
{ {
case "crush": case "Crush":
strength += val * 0.085 / 3; strength += val * 0.085 / 3;
break; break;
case "hack": case "Hack":
strength += val * 0.075 / 3; strength += val * 0.075 / 3;
break; break;
case "pierce": case "Pierce":
strength += val * 0.065 / 3; strength += val * 0.065 / 3;
break; break;
default: default:
@@ -70,13 +70,13 @@ m.getMaxStrength = function(ent, againstClass)
let val = parseFloat(armourStrength[str]); let val = parseFloat(armourStrength[str]);
switch (str) switch (str)
{ {
case "crush": case "Crush":
strength += val * 0.085 / 3; strength += val * 0.085 / 3;
break; break;
case "hack": case "Hack":
strength += val * 0.075 / 3; strength += val * 0.075 / 3;
break; break;
case "pierce": case "Pierce":
strength += val * 0.065 / 3; strength += val * 0.065 / 3;
break; break;
default: default:
@@ -7,27 +7,11 @@ Armour.prototype.Schema =
"<Pierce>0.0</Pierce>" + "<Pierce>0.0</Pierce>" +
"<Crush>5.0</Crush>" + "<Crush>5.0</Crush>" +
"</a:example>" + "</a:example>" +
"<element name='Hack' a:help='Hack damage protection'>" + DamageTypes.BuildSchema("damage protection") +
"<ref name='nonNegativeDecimal'/>" +
"</element>" +
"<element name='Pierce' a:help='Pierce damage protection'>" +
"<ref name='nonNegativeDecimal'/>" +
"</element>" +
"<element name='Crush' a:help='Crush damage protection'>" +
"<ref name='nonNegativeDecimal'/>" +
"</element>" +
"<optional>" + "<optional>" +
"<element name='Foundation' a:help='Armour given to building foundations'>" + "<element name='Foundation' a:help='Armour given to building foundations'>" +
"<interleave>" + "<interleave>" +
"<element name='Hack' a:help='Hack damage protection'>" + DamageTypes.BuildSchema("damage protection") +
"<ref name='nonNegativeDecimal'/>" +
"</element>" +
"<element name='Pierce' a:help='Pierce damage protection'>" +
"<ref name='nonNegativeDecimal'/>" +
"</element>" +
"<element name='Crush' a:help='Crush damage protection'>" +
"<ref name='nonNegativeDecimal'/>" +
"</element>" +
"</interleave>" + "</interleave>" +
"</element>" + "</element>" +
"</optional>"; "</optional>";
@@ -85,11 +69,11 @@ Armour.prototype.GetArmourStrengths = function()
var foundation = Engine.QueryInterface(this.entity, IID_Foundation) && this.template.Foundation; var foundation = Engine.QueryInterface(this.entity, IID_Foundation) && this.template.Foundation;
return { let ret = {};
"hack": applyMods("Hack", foundation), for (let damageType of DamageTypes.GetTypes())
"pierce": applyMods("Pierce", foundation), ret[damageType] = applyMods(damageType, foundation);
"crush": applyMods("Crush", foundation)
}; return ret;
}; };
Engine.RegisterComponentType(IID_DamageReceiver, "Armour", Armour); Engine.RegisterComponentType(IID_DamageReceiver, "Armour", Armour);
@@ -100,9 +100,7 @@ Attack.prototype.Schema =
"<optional>" + "<optional>" +
"<element name='Melee'>" + "<element name='Melee'>" +
"<interleave>" + "<interleave>" +
"<element name='Hack' a:help='Hack damage strength'><ref name='nonNegativeDecimal'/></element>" + DamageTypes.BuildSchema("damage strength") +
"<element name='Pierce' a:help='Pierce damage strength'><ref name='nonNegativeDecimal'/></element>" +
"<element name='Crush' a:help='Crush damage strength'><ref name='nonNegativeDecimal'/></element>" +
"<element name='MaxRange' a:help='Maximum attack range (in metres)'><ref name='nonNegativeDecimal'/></element>" + "<element name='MaxRange' a:help='Maximum attack range (in metres)'><ref name='nonNegativeDecimal'/></element>" +
"<element name='PrepareTime' a:help='Time from the start of the attack command until the attack actually occurs (in milliseconds). This value relative to RepeatTime should closely match the \"event\" point in the actor&apos;s attack animation'>" + "<element name='PrepareTime' a:help='Time from the start of the attack command until the attack actually occurs (in milliseconds). This value relative to RepeatTime should closely match the \"event\" point in the actor&apos;s attack animation'>" +
"<data type='nonNegativeInteger'/>" + "<data type='nonNegativeInteger'/>" +
@@ -119,9 +117,7 @@ Attack.prototype.Schema =
"<optional>" + "<optional>" +
"<element name='Ranged'>" + "<element name='Ranged'>" +
"<interleave>" + "<interleave>" +
"<element name='Hack' a:help='Hack damage strength'><ref name='nonNegativeDecimal'/></element>" + DamageTypes.BuildSchema("damage strength") +
"<element name='Pierce' a:help='Pierce damage strength'><ref name='nonNegativeDecimal'/></element>" +
"<element name='Crush' a:help='Crush damage strength'><ref name='nonNegativeDecimal'/></element>" +
"<element name='MaxRange' a:help='Maximum attack range (in metres)'><ref name='nonNegativeDecimal'/></element>" + "<element name='MaxRange' a:help='Maximum attack range (in metres)'><ref name='nonNegativeDecimal'/></element>" +
"<element name='MinRange' a:help='Minimum attack range (in metres)'><ref name='nonNegativeDecimal'/></element>" + "<element name='MinRange' a:help='Minimum attack range (in metres)'><ref name='nonNegativeDecimal'/></element>" +
"<optional>"+ "<optional>"+
@@ -149,9 +145,7 @@ Attack.prototype.Schema =
"<element name='Shape' a:help='Shape of the splash damage, can be circular or linear'><text/></element>" + "<element name='Shape' a:help='Shape of the splash damage, can be circular or linear'><text/></element>" +
"<element name='Range' a:help='Size of the area affected by the splash'><ref name='nonNegativeDecimal'/></element>" + "<element name='Range' a:help='Size of the area affected by the splash'><ref name='nonNegativeDecimal'/></element>" +
"<element name='FriendlyFire' a:help='Whether the splash damage can hurt non enemy units'><data type='boolean'/></element>" + "<element name='FriendlyFire' a:help='Whether the splash damage can hurt non enemy units'><data type='boolean'/></element>" +
"<element name='Hack' a:help='Hack damage strength'><ref name='nonNegativeDecimal'/></element>" + DamageTypes.BuildSchema("damage strength") +
"<element name='Pierce' a:help='Pierce damage strength'><ref name='nonNegativeDecimal'/></element>" +
"<element name='Crush' a:help='Crush damage strength'><ref name='nonNegativeDecimal'/></element>" +
Attack.prototype.bonusesSchema + Attack.prototype.bonusesSchema +
"</interleave>" + "</interleave>" +
"</element>" + "</element>" +
@@ -176,9 +170,7 @@ Attack.prototype.Schema =
"<optional>" + "<optional>" +
"<element name='Slaughter' a:help='A special attack to kill domestic animals'>" + "<element name='Slaughter' a:help='A special attack to kill domestic animals'>" +
"<interleave>" + "<interleave>" +
"<element name='Hack' a:help='Hack damage strength'><ref name='nonNegativeDecimal'/></element>" + DamageTypes.BuildSchema("damage strength") +
"<element name='Pierce' a:help='Pierce damage strength'><ref name='nonNegativeDecimal'/></element>" +
"<element name='Crush' a:help='Crush damage strength'><ref name='nonNegativeDecimal'/></element>" +
"<element name='MaxRange'><ref name='nonNegativeDecimal'/></element>" + // TODO: how do these work? "<element name='MaxRange'><ref name='nonNegativeDecimal'/></element>" + // TODO: how do these work?
Attack.prototype.bonusesSchema + Attack.prototype.bonusesSchema +
Attack.prototype.preferredClassesSchema + Attack.prototype.preferredClassesSchema +
@@ -403,11 +395,11 @@ Attack.prototype.GetAttackStrengths = function(type)
if (type == "Capture") if (type == "Capture")
return { "value": applyMods("Value") }; return { "value": applyMods("Value") };
return { let ret = {};
"hack": applyMods("Hack"), for (let damageType of DamageTypes.GetTypes())
"pierce": applyMods("Pierce"), ret[damageType] = applyMods(damageType);
"crush": applyMods("Crush")
}; return ret;
}; };
Attack.prototype.GetSplashDamage = function(type) Attack.prototype.GetSplashDamage = function(type)
@@ -502,7 +494,6 @@ Attack.prototype.PerformAttack = function(type, target)
let cmpProjectileManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ProjectileManager); let cmpProjectileManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ProjectileManager);
let id = cmpProjectileManager.LaunchProjectileAtPoint(this.entity, realTargetPosition, horizSpeed, gravity); let id = cmpProjectileManager.LaunchProjectileAtPoint(this.entity, realTargetPosition, horizSpeed, gravity);
cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
let data = { let data = {
"type": type, "type": type,
"attacker": this.entity, "attacker": this.entity,
@@ -31,9 +31,7 @@ DeathDamage.prototype.Schema =
"<element name='Shape' a:help='Shape of the splash damage, can be circular'><text/></element>" + "<element name='Shape' a:help='Shape of the splash damage, can be circular'><text/></element>" +
"<element name='Range' a:help='Size of the area affected by the splash'><ref name='nonNegativeDecimal'/></element>" + "<element name='Range' a:help='Size of the area affected by the splash'><ref name='nonNegativeDecimal'/></element>" +
"<element name='FriendlyFire' a:help='Whether the splash damage can hurt non enemy units'><data type='boolean'/></element>" + "<element name='FriendlyFire' a:help='Whether the splash damage can hurt non enemy units'><data type='boolean'/></element>" +
"<element name='Hack' a:help='Hack damage strength'><ref name='nonNegativeDecimal'/></element>" + DamageTypes.BuildSchema("damage strength") +
"<element name='Pierce' a:help='Pierce damage strength'><ref name='nonNegativeDecimal'/></element>" +
"<element name='Crush' a:help='Crush damage strength'><ref name='nonNegativeDecimal'/></element>" +
DeathDamage.prototype.bonusesSchema; DeathDamage.prototype.bonusesSchema;
DeathDamage.prototype.Init = function() DeathDamage.prototype.Init = function()
@@ -48,11 +46,11 @@ DeathDamage.prototype.GetDeathDamageStrengths = function()
let applyMods = damageType => let applyMods = damageType =>
ApplyValueModificationsToEntity("DeathDamage/" + damageType, +(this.template[damageType] || 0), this.entity); ApplyValueModificationsToEntity("DeathDamage/" + damageType, +(this.template[damageType] || 0), this.entity);
return { let ret = {};
"hack": applyMods("Hack"), for (let damageType of DamageTypes.GetTypes())
"pierce": applyMods("Pierce"), ret[damageType] = applyMods(damageType);
"crush": applyMods("Crush")
}; return ret;
}; };
DeathDamage.prototype.GetBonusTemplate = function() DeathDamage.prototype.GetBonusTemplate = function()
@@ -656,14 +656,14 @@ GuiInterface.prototype.GetTemplateData = function(player, name)
let aurasTemplate = {}; let aurasTemplate = {};
if (!template.Auras) if (!template.Auras)
return GetTemplateDataHelper(template, player, aurasTemplate, Resources); return GetTemplateDataHelper(template, player, aurasTemplate, Resources, DamageTypes);
// Add aura name and description loaded from JSON file // Add aura name and description loaded from JSON file
let auraNames = template.Auras._string.split(/\s+/); let auraNames = template.Auras._string.split(/\s+/);
let cmpDataTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_DataTemplateManager); let cmpDataTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_DataTemplateManager);
for (let name of auraNames) for (let name of auraNames)
aurasTemplate[name] = cmpDataTemplateManager.GetAuraTemplate(name); aurasTemplate[name] = cmpDataTemplateManager.GetAuraTemplate(name);
return GetTemplateDataHelper(template, player, aurasTemplate, Resources); return GetTemplateDataHelper(template, player, aurasTemplate, Resources, DamageTypes);
}; };
GuiInterface.prototype.GetTechnologyData = function(player, data) GuiInterface.prototype.GetTechnologyData = function(player, data)
@@ -1,4 +1,5 @@
Engine.LoadHelperScript("DamageBonus.js"); Engine.LoadHelperScript("DamageBonus.js");
Engine.LoadHelperScript("DamageTypes.js");
Engine.LoadHelperScript("Player.js"); Engine.LoadHelperScript("Player.js");
Engine.LoadHelperScript("ValueModification.js"); Engine.LoadHelperScript("ValueModification.js");
Engine.LoadComponentScript("interfaces/Auras.js"); Engine.LoadComponentScript("interfaces/Auras.js");
@@ -139,15 +140,15 @@ attackComponentTest(undefined, true ,(attacker, cmpAttack, defender) => {
TS_ASSERT_UNEVAL_EQUALS(cmpAttack.GetAttackStrengths("Capture"), { "value": 8 }); TS_ASSERT_UNEVAL_EQUALS(cmpAttack.GetAttackStrengths("Capture"), { "value": 8 });
TS_ASSERT_UNEVAL_EQUALS(cmpAttack.GetAttackStrengths("Ranged"), { TS_ASSERT_UNEVAL_EQUALS(cmpAttack.GetAttackStrengths("Ranged"), {
"hack": 0, "Hack": 0,
"pierce": 10, "Pierce": 10,
"crush": 0 "Crush": 0
}); });
TS_ASSERT_UNEVAL_EQUALS(cmpAttack.GetAttackStrengths("Ranged.Splash"), { TS_ASSERT_UNEVAL_EQUALS(cmpAttack.GetAttackStrengths("Ranged.Splash"), {
"hack": 0.0, "Hack": 0.0,
"pierce": 15.0, "Pierce": 15.0,
"crush": 35.0 "Crush": 35.0
}); });
TS_ASSERT_UNEVAL_EQUALS(cmpAttack.GetTimers("Ranged"), { TS_ASSERT_UNEVAL_EQUALS(cmpAttack.GetTimers("Ranged"), {
@@ -160,7 +161,13 @@ attackComponentTest(undefined, true ,(attacker, cmpAttack, defender) => {
"repeat": 1000 "repeat": 1000
}); });
TS_ASSERT_UNEVAL_EQUALS(cmpAttack.GetSplashDamage("Ranged"), { "hack": 0, "pierce": 15, "crush": 35, "friendlyFire": false, "shape": "Circular" }); TS_ASSERT_UNEVAL_EQUALS(cmpAttack.GetSplashDamage("Ranged"), {
"Hack": 0,
"Pierce": 15,
"Crush": 35,
"friendlyFire": false,
"shape": "Circular"
});
}); });
for (let className of ["Infantry", "Cavalry"]) for (let className of ["Infantry", "Cavalry"])
@@ -1,4 +1,5 @@
Engine.LoadHelperScript("DamageBonus.js"); Engine.LoadHelperScript("DamageBonus.js");
Engine.LoadHelperScript("DamageTypes.js");
Engine.LoadHelperScript("Player.js"); Engine.LoadHelperScript("Player.js");
Engine.LoadHelperScript("Sound.js"); Engine.LoadHelperScript("Sound.js");
Engine.LoadHelperScript("ValueModification.js"); Engine.LoadHelperScript("ValueModification.js");
@@ -1,4 +1,5 @@
Engine.LoadHelperScript("DamageBonus.js"); Engine.LoadHelperScript("DamageBonus.js");
Engine.LoadHelperScript("DamageTypes.js");
Engine.LoadHelperScript("ValueModification.js"); Engine.LoadHelperScript("ValueModification.js");
Engine.LoadComponentScript("interfaces/AuraManager.js"); Engine.LoadComponentScript("interfaces/AuraManager.js");
Engine.LoadComponentScript("interfaces/Damage.js"); Engine.LoadComponentScript("interfaces/Damage.js");
@@ -26,9 +27,9 @@ let template = {
}; };
let modifiedDamage = { let modifiedDamage = {
"hack": 0.0, "Hack": 0.0,
"pierce": 215.0, "Pierce": 215.0,
"crush": 35.0 "Crush": 35.0
}; };
let cmpDeathDamage = ConstructComponent(deadEnt, "DeathDamage", template); let cmpDeathDamage = ConstructComponent(deadEnt, "DeathDamage", template);
@@ -126,11 +126,11 @@ cmpUpgrade.owner = playerID;
* To start with, no techs are researched... * To start with, no techs are researched...
*/ */
// T1: Check the cost of the upgrade without a player value being passed (as it would be in the structree). // T1: Check the cost of the upgrade without a player value being passed (as it would be in the structree).
let parsed_template = GetTemplateDataHelper(template, null, {}, Resources); let parsed_template = GetTemplateDataHelper(template, null, {}, Resources, DamageTypes);
TS_ASSERT_UNEVAL_EQUALS(parsed_template.upgrades[0].cost, { "stone": 100, "wood": 50, "time": 100 }); TS_ASSERT_UNEVAL_EQUALS(parsed_template.upgrades[0].cost, { "stone": 100, "wood": 50, "time": 100 });
// T2: Check the value, with a player ID (as it would be in-session). // T2: Check the value, with a player ID (as it would be in-session).
parsed_template = GetTemplateDataHelper(template, playerID, {}, Resources); parsed_template = GetTemplateDataHelper(template, playerID, {}, Resources, DamageTypes);
TS_ASSERT_UNEVAL_EQUALS(parsed_template.upgrades[0].cost, { "stone": 100, "wood": 50, "time": 100 }); TS_ASSERT_UNEVAL_EQUALS(parsed_template.upgrades[0].cost, { "stone": 100, "wood": 50, "time": 100 });
// T3: Check that the value is correct within the Update Component. // T3: Check that the value is correct within the Update Component.
@@ -144,11 +144,11 @@ cmpUpgrade.Upgrade("structures/"+civCode+"_defense_tower");
isResearched = true; isResearched = true;
// T4: Check that the player-less value hasn't increased... // T4: Check that the player-less value hasn't increased...
parsed_template = GetTemplateDataHelper(template, null, {}, Resources); parsed_template = GetTemplateDataHelper(template, null, {}, Resources, DamageTypes);
TS_ASSERT_UNEVAL_EQUALS(parsed_template.upgrades[0].cost, { "stone": 100, "wood": 50, "time": 100 }); TS_ASSERT_UNEVAL_EQUALS(parsed_template.upgrades[0].cost, { "stone": 100, "wood": 50, "time": 100 });
// T5: ...but the player-backed value has. // T5: ...but the player-backed value has.
parsed_template = GetTemplateDataHelper(template, playerID, {}, Resources); parsed_template = GetTemplateDataHelper(template, playerID, {}, Resources, DamageTypes);
TS_ASSERT_UNEVAL_EQUALS(parsed_template.upgrades[0].cost, { "stone": 160, "wood": 25, "time": 90 }); TS_ASSERT_UNEVAL_EQUALS(parsed_template.upgrades[0].cost, { "stone": 160, "wood": 25, "time": 90 });
// T6: The upgrade component should still be using the old resource cost (but new time cost) for the upgrade in progress... // T6: The upgrade component should still be using the old resource cost (but new time cost) for the upgrade in progress...
@@ -0,0 +1,8 @@
DamageTypes.prototype.BuildSchema = function(helptext = "")
{
return this.GetTypes().reduce((schema, type) =>
schema + "<element name='"+type+"' a:help='"+type+" "+helptext+"'><ref name='nonNegativeDecimal'/></element>",
"");
};
DamageTypes = new DamageTypes();