mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-06-17 22:03:56 -07:00
Easier introduction of new damage types.
725aa8a686 introduced a DamageTypes.js global script similar to the
resources one. However, we never actually need to refer to this script
since we can always use the damage types provided by the
template/context/object we are looping over/...
There is one exception to this for AI weighting of damage types.
However, since damage types are not stored in files, this is strictly
equivalent to hardcoding them in the global script and was deemed
acceptable.
Patch By: freagarach
Reviewed By: wraitii
Refs #4801 (by invalidating it for now, though such helper files might
be useful in the future if damage types require more metadata).
Differential Revision: https://code.wildfiregames.com/D1938
This was SVN commit r22527.
This commit is contained in:
parent
32e8ed51aa
commit
6643613b54
19 changed files with 95 additions and 115 deletions
|
|
@ -1,22 +0,0 @@
|
|||
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);
|
||||
};
|
||||
|
|
@ -165,8 +165,9 @@ function GetTemplateDataHelper(template, player, auraTemplates, resources, damag
|
|||
if (template.Armour)
|
||||
{
|
||||
ret.armour = {};
|
||||
for (let damageType of damageTypes.GetTypes())
|
||||
ret.armour[damageType] = getEntityValue("Armour/" + damageType);
|
||||
for (let damageType in template.Armour)
|
||||
if (damageType != "Foundation")
|
||||
ret.armour[damageType] = getEntityValue("Armour/" + damageType);
|
||||
}
|
||||
|
||||
if (template.Attack)
|
||||
|
|
@ -190,7 +191,7 @@ function GetTemplateDataHelper(template, player, auraTemplates, resources, damag
|
|||
"elevationBonus": getAttackStat("ElevationBonus"),
|
||||
"damage": {}
|
||||
};
|
||||
for (let damageType of damageTypes.GetTypes())
|
||||
for (let damageType in template.Attack[type].Damage)
|
||||
ret.attack[type].damage[damageType] = getAttackStat("Damage/" + damageType);
|
||||
|
||||
ret.attack[type].elevationAdaptedRange = Math.sqrt(ret.attack[type].maxRange *
|
||||
|
|
@ -206,7 +207,7 @@ function GetTemplateDataHelper(template, player, auraTemplates, resources, damag
|
|||
"shape": template.Attack[type].Splash.Shape,
|
||||
"damage": {}
|
||||
};
|
||||
for (let damageType of damageTypes.GetTypes())
|
||||
for (let damageType in template.Attack[type].Splash.Damage)
|
||||
ret.attack[type].splash.damage[damageType] = getAttackStat("Splash/Damage/" + damageType);
|
||||
}
|
||||
}
|
||||
|
|
@ -218,7 +219,7 @@ function GetTemplateDataHelper(template, player, auraTemplates, resources, damag
|
|||
"friendlyFire": template.DeathDamage.FriendlyFire != "false",
|
||||
"damage": {}
|
||||
};
|
||||
for (let damageType of damageTypes.GetTypes())
|
||||
for (let damageType in template.DeathDamage.Damage)
|
||||
ret.deathDamage.damage[damageType] = getEntityValue("DeathDamage/Damage/" + damageType);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,8 +14,6 @@ var g_AttackTypes = {
|
|||
"Capture": translate("Capture Attack:")
|
||||
};
|
||||
|
||||
var g_DamageTypes = new DamageTypes();
|
||||
|
||||
var g_SplashDamageTypes = {
|
||||
"Circular": translate("Circular Splash Damage"),
|
||||
"Linear": translate("Linear Splash Damage")
|
||||
|
|
@ -222,7 +220,7 @@ function getArmorTooltip(template)
|
|||
Object.keys(template.armour).map(
|
||||
dmgType => sprintf(translate("%(damage)s %(damageType)s %(armorPercentage)s"), {
|
||||
"damage": template.armour[dmgType].toFixed(1),
|
||||
"damageType": unitFont(translateWithContext("damage type", g_DamageTypes.GetNames()[dmgType])),
|
||||
"damageType": unitFont(translateWithContext("damage type", dmgType)),
|
||||
"armorPercentage":
|
||||
'[font="sans-10"]' +
|
||||
sprintf(translate("(%(armorPercentage)s)"), {
|
||||
|
|
@ -238,11 +236,10 @@ function damageTypesToText(dmg)
|
|||
if (!dmg)
|
||||
return '[font="sans-12"]' + translate("(None)") + '[/font]';
|
||||
|
||||
return g_DamageTypes.GetTypes().filter(
|
||||
dmgType => dmg[dmgType]).map(
|
||||
return Object.keys(dmg).filter(dmgType => dmg[dmgType]).map(
|
||||
dmgType => sprintf(translate("%(damage)s %(damageType)s"), {
|
||||
"damage": dmg[dmgType].toFixed(1),
|
||||
"damageType": unitFont(translateWithContext("damage type", g_DamageTypes.GetNames()[dmgType]))
|
||||
"damageType": unitFont(translateWithContext("damage type", dmgType))
|
||||
})).join(commaFont(translate(", ")));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ function getActualUpgradeData(upgradesInfo)
|
|||
{
|
||||
upgrade.entity = upgrade.entity.replace(/\{(civ|native)\}/g, g_SelectedCiv);
|
||||
|
||||
let data = GetTemplateDataHelper(loadTemplate(upgrade.entity), null, g_AuraData, g_ResourceData, g_DamageTypes);
|
||||
let data = GetTemplateDataHelper(loadTemplate(upgrade.entity), null, g_AuraData, g_ResourceData);
|
||||
data.name.internal = upgrade.entity;
|
||||
data.cost = upgrade.cost;
|
||||
data.icon = upgrade.icon || data.icon;
|
||||
|
|
@ -124,8 +124,8 @@ function getPhaseOfTemplate(template)
|
|||
*/
|
||||
function GetTemplateData(templateName)
|
||||
{
|
||||
var template = loadTemplate(templateName);
|
||||
return GetTemplateDataHelper(template, null, g_AuraData, g_ResourceData, g_DamageTypes, g_CurrentModifiers);
|
||||
let template = loadTemplate(templateName);
|
||||
return GetTemplateDataHelper(template, null, g_AuraData, g_ResourceData, g_CurrentModifiers);
|
||||
}
|
||||
|
||||
function isPairTech(technologyCode)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ var g_CivData = loadCivData(true, false);
|
|||
*/
|
||||
var g_ParsedData = {};
|
||||
var g_ResourceData = new Resources();
|
||||
var g_DamageTypes = new DamageTypes();
|
||||
|
||||
// This must be defined after the g_TechnologyData cache object is declared.
|
||||
var g_AutoResearchTechList = findAllAutoResearchedTechs();
|
||||
|
|
@ -110,7 +109,7 @@ function loadEntityTemplate(templateName)
|
|||
return null;
|
||||
|
||||
let template = loadTemplate(templateName);
|
||||
let parsed = GetTemplateDataHelper(template, null, g_AuraData, g_ResourceData, g_DamageTypes, g_CurrentModifiers);
|
||||
let parsed = GetTemplateDataHelper(template, null, g_AuraData, g_ResourceData, g_CurrentModifiers);
|
||||
parsed.name.internal = templateName;
|
||||
|
||||
parsed.history = template.Identity.History;
|
||||
|
|
|
|||
|
|
@ -262,7 +262,7 @@ function getWallElement(element, style)
|
|||
function readyWallElement(path, civCode)
|
||||
{
|
||||
path = path.replace(/\{civ\}/g, civCode);
|
||||
let template = GetTemplateDataHelper(Engine.GetTemplate(path), null, null, {}, g_DamageTypes, {});
|
||||
let template = GetTemplateDataHelper(Engine.GetTemplate(path), null, null, {}, {});
|
||||
let length = template.wallPiece ? template.wallPiece.length : template.obstruction.shape.width;
|
||||
|
||||
return deepfreeze({
|
||||
|
|
|
|||
|
|
@ -21,8 +21,6 @@ const TERRAIN_SEPARATOR = "|";
|
|||
const SEA_LEVEL = 20.0;
|
||||
const HEIGHT_UNITS_PER_METRE = 92;
|
||||
|
||||
const g_DamageTypes = new DamageTypes();
|
||||
|
||||
/**
|
||||
* Constants needed for heightmap_manipulation.js
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -198,14 +198,16 @@ m.Template = m.Class({
|
|||
"getPopulationBonus": function() { return +this.get("Cost/PopulationBonus"); },
|
||||
|
||||
"armourStrengths": function() {
|
||||
if (!this.get("Armour"))
|
||||
let armourDamageTypes = this.get("Armour");
|
||||
if (!armourDamageTypes)
|
||||
return undefined;
|
||||
|
||||
return {
|
||||
"Hack": +this.get("Armour/Hack"),
|
||||
"Pierce": +this.get("Armour/Pierce"),
|
||||
"Crush": +this.get("Armour/Crush")
|
||||
};
|
||||
let armour = {};
|
||||
for (let damageType in armourDamageTypes)
|
||||
if (damageType != "Foundation")
|
||||
armour[damageType] = +armourDamageTypes[damageType];
|
||||
|
||||
return armour;
|
||||
},
|
||||
|
||||
"attackTypes": function() {
|
||||
|
|
@ -229,14 +231,15 @@ m.Template = m.Class({
|
|||
},
|
||||
|
||||
"attackStrengths": function(type) {
|
||||
if (!this.get("Attack/" + type +""))
|
||||
let attackDamageTypes = this.get("Attack/" + type + "/Damage");
|
||||
if (!attackDamageTypes)
|
||||
return undefined;
|
||||
|
||||
return {
|
||||
"Hack": +(this.get("Attack/" + type + "/Damage/Hack") || 0),
|
||||
"Pierce": +(this.get("Attack/" + type + "/Damage/Pierce") || 0),
|
||||
"Crush": +(this.get("Attack/" + type + "/Damage/Crush") || 0)
|
||||
};
|
||||
let damage = {};
|
||||
for (let damageType in attackDamageTypes)
|
||||
damage[damageType] = +attackDamageTypes[damageType];
|
||||
|
||||
return damage;
|
||||
},
|
||||
|
||||
"captureStrength": function() {
|
||||
|
|
|
|||
|
|
@ -24,6 +24,14 @@ m.Config = function(difficulty, behavior)
|
|||
"popForBlacksmith": 65,
|
||||
"numSentryTowers": 1
|
||||
};
|
||||
|
||||
// Define damage type importance factors here.
|
||||
this.DamageTypeImportance = {
|
||||
"Hack": 0.085,
|
||||
"Pierce": 0.075,
|
||||
"Crush": 0.065
|
||||
};
|
||||
|
||||
this.Economy = {
|
||||
"popPhase2": 38, // How many units we want before aging to phase2.
|
||||
"workPhase3": 65, // How many workers we want before aging to phase3.
|
||||
|
|
|
|||
|
|
@ -488,7 +488,7 @@ m.DefenseArmy.prototype.evaluateStrength = function(ent, isOwn, remove)
|
|||
entStrength = 2;
|
||||
}
|
||||
else
|
||||
entStrength = m.getMaxStrength(ent);
|
||||
entStrength = m.getMaxStrength(ent, this.Config.debug, this.Config.DamageTypeImportance);
|
||||
|
||||
// TODO adapt the getMaxStrength function for animals.
|
||||
// For the time being, just increase it for elephants as the returned value is too small.
|
||||
|
|
|
|||
|
|
@ -486,7 +486,7 @@ m.DefenseManager.prototype.assignDefenders = function(gameState)
|
|||
else if (aMin === undefined)
|
||||
continue;
|
||||
|
||||
armiesNeeding[aMin].need -= m.getMaxStrength(ent);
|
||||
armiesNeeding[aMin].need -= m.getMaxStrength(ent, this.Config.debug, this.Config.DamageTypeImportance);
|
||||
armiesNeeding[aMin].army.addOwn(gameState, potentialDefenders[i]);
|
||||
armiesNeeding[aMin].army.assignUnit(gameState, potentialDefenders[i]);
|
||||
potentialDefenders[i] = undefined;
|
||||
|
|
|
|||
|
|
@ -8,10 +8,11 @@ m.isSiegeUnit = function(ent)
|
|||
};
|
||||
|
||||
/** returns some sort of DPS * health factor. If you specify a class, it'll use the modifiers against that class too. */
|
||||
m.getMaxStrength = function(ent, againstClass)
|
||||
m.getMaxStrength = function(ent, debugLevel, DamageTypeImportance, againstClass)
|
||||
{
|
||||
let strength = 0;
|
||||
let attackTypes = ent.attackTypes();
|
||||
let damageTypes = Object.keys(DamageTypeImportance);
|
||||
if (!attackTypes)
|
||||
return strength;
|
||||
|
||||
|
|
@ -26,20 +27,10 @@ m.getMaxStrength = function(ent, againstClass)
|
|||
let val = parseFloat(attackStrength[str]);
|
||||
if (againstClass)
|
||||
val *= ent.getMultiplierAgainst(type, againstClass);
|
||||
switch (str)
|
||||
{
|
||||
case "Crush":
|
||||
strength += val * 0.085 / 3;
|
||||
break;
|
||||
case "Hack":
|
||||
strength += val * 0.075 / 3;
|
||||
break;
|
||||
case "Pierce":
|
||||
strength += val * 0.065 / 3;
|
||||
break;
|
||||
default:
|
||||
API3.warn("Petra: " + str + " unknown attackStrength in getMaxStrength");
|
||||
}
|
||||
if (DamageTypeImportance[str])
|
||||
strength += DamageTypeImportance[str] * val / damageTypes.length;
|
||||
else if (debugLevel > 0)
|
||||
API3.warn("Petra: " + str + " unknown attackStrength in getMaxStrength (please add " + str + " to config.js).");
|
||||
}
|
||||
|
||||
let attackRange = ent.attackRange(type);
|
||||
|
|
@ -68,20 +59,10 @@ m.getMaxStrength = function(ent, againstClass)
|
|||
for (let str in armourStrength)
|
||||
{
|
||||
let val = parseFloat(armourStrength[str]);
|
||||
switch (str)
|
||||
{
|
||||
case "Crush":
|
||||
strength += val * 0.085 / 3;
|
||||
break;
|
||||
case "Hack":
|
||||
strength += val * 0.075 / 3;
|
||||
break;
|
||||
case "Pierce":
|
||||
strength += val * 0.065 / 3;
|
||||
break;
|
||||
default:
|
||||
API3.warn("Petra: " + str + " unknown armourStrength in getMaxStrength");
|
||||
}
|
||||
if (DamageTypeImportance[str])
|
||||
strength += DamageTypeImportance[str] * val / damageTypes.length;
|
||||
else if (debugLevel > 0)
|
||||
API3.warn("Petra: " + str + " unknown armourStrength in getMaxStrength (please add " + str + " to config.js).");
|
||||
}
|
||||
|
||||
return strength * ent.maxHitpoints() / 100.0;
|
||||
|
|
|
|||
|
|
@ -776,13 +776,13 @@ m.HQ.prototype.findBestTrainableUnit = function(gameState, classes, requirements
|
|||
{
|
||||
if (param[0] == "strength")
|
||||
{
|
||||
aValue += m.getMaxStrength(a[1]) * param[1];
|
||||
bValue += m.getMaxStrength(b[1]) * param[1];
|
||||
aValue += m.getMaxStrength(a[1], gameState.ai.Config.debug, gameState.ai.Config.DamageTypeImportance) * param[1];
|
||||
bValue += m.getMaxStrength(b[1], gameState.ai.Config.debug, gameState.ai.Config.DamageTypeImportance) * param[1];
|
||||
}
|
||||
else if (param[0] == "siegeStrength")
|
||||
{
|
||||
aValue += m.getMaxStrength(a[1], "Structure") * param[1];
|
||||
bValue += m.getMaxStrength(b[1], "Structure") * param[1];
|
||||
aValue += m.getMaxStrength(a[1], gameState.ai.Config.debug, gameState.ai.Config.DamageTypeImportance, "Structure") * param[1];
|
||||
bValue += m.getMaxStrength(b[1], gameState.ai.Config.debug, gameState.ai.Config.DamageTypeImportance, "Structure") * param[1];
|
||||
}
|
||||
else if (param[0] == "speed")
|
||||
{
|
||||
|
|
|
|||
|
|
@ -7,11 +7,11 @@ Armour.prototype.Schema =
|
|||
"<Pierce>0.0</Pierce>" +
|
||||
"<Crush>5.0</Crush>" +
|
||||
"</a:example>" +
|
||||
DamageTypes.BuildSchema("damage protection") +
|
||||
BuildDamageTypesSchema("damage protection") +
|
||||
"<optional>" +
|
||||
"<element name='Foundation' a:help='Armour given to building foundations'>" +
|
||||
"<interleave>" +
|
||||
DamageTypes.BuildSchema("damage protection") +
|
||||
BuildDamageTypesSchema("damage protection") +
|
||||
"</interleave>" +
|
||||
"</element>" +
|
||||
"</optional>";
|
||||
|
|
@ -59,9 +59,9 @@ Armour.prototype.TakeDamage = function(strengths, multiplier = 1)
|
|||
|
||||
Armour.prototype.GetArmourStrengths = function()
|
||||
{
|
||||
// Work out the armour values with technology effects
|
||||
var applyMods = (type, foundation) => {
|
||||
var strength;
|
||||
// Work out the armour values with technology effects.
|
||||
let applyMods = (type, foundation) => {
|
||||
let strength;
|
||||
if (foundation)
|
||||
{
|
||||
strength = +this.template.Foundation[type];
|
||||
|
|
@ -73,11 +73,12 @@ Armour.prototype.GetArmourStrengths = function()
|
|||
return ApplyValueModificationsToEntity("Armour/" + type, strength, this.entity);
|
||||
};
|
||||
|
||||
var foundation = Engine.QueryInterface(this.entity, IID_Foundation) && this.template.Foundation;
|
||||
let foundation = Engine.QueryInterface(this.entity, IID_Foundation) && this.template.Foundation;
|
||||
|
||||
let ret = {};
|
||||
for (let damageType of DamageTypes.GetTypes())
|
||||
ret[damageType] = applyMods(damageType, foundation);
|
||||
for (let damageType in this.template)
|
||||
if (damageType != "Foundation")
|
||||
ret[damageType] = applyMods(damageType, foundation);
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ Attack.prototype.Schema =
|
|||
"<element name='Melee'>" +
|
||||
"<interleave>" +
|
||||
"<element name='Damage'>" +
|
||||
DamageTypes.BuildSchema("damage strength") +
|
||||
BuildDamageTypesSchema("damage strength") +
|
||||
"</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's attack animation'>" +
|
||||
|
|
@ -150,7 +150,7 @@ Attack.prototype.Schema =
|
|||
"<element name='Ranged'>" +
|
||||
"<interleave>" +
|
||||
"<element name='Damage'>" +
|
||||
DamageTypes.BuildSchema("damage strength") +
|
||||
BuildDamageTypesSchema("damage strength") +
|
||||
"</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>" +
|
||||
|
|
@ -180,7 +180,7 @@ Attack.prototype.Schema =
|
|||
"<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='Damage'>" +
|
||||
DamageTypes.BuildSchema("damage strength") +
|
||||
BuildDamageTypesSchema("damage strength") +
|
||||
"</element>" +
|
||||
Attack.prototype.bonusesSchema +
|
||||
"</interleave>" +
|
||||
|
|
@ -242,7 +242,7 @@ Attack.prototype.Schema =
|
|||
"<element name='Slaughter' a:help='A special attack to kill domestic animals'>" +
|
||||
"<interleave>" +
|
||||
"<element name='Damage'>" +
|
||||
DamageTypes.BuildSchema("damage strength") +
|
||||
BuildDamageTypesSchema("damage strength") +
|
||||
"</element>" +
|
||||
"<element name='MaxRange'><ref name='nonNegativeDecimal'/></element>" + // TODO: how do these work?
|
||||
Attack.prototype.bonusesSchema +
|
||||
|
|
@ -470,7 +470,7 @@ Attack.prototype.GetAttackStrengths = function(type)
|
|||
return { "value": ApplyValueModificationsToEntity("Attack/Capture/Value", +(template.Value || 0), this.entity) };
|
||||
|
||||
let ret = {};
|
||||
for (let damageType of DamageTypes.GetTypes())
|
||||
for (let damageType in template.Damage)
|
||||
ret[damageType] = applyMods(damageType);
|
||||
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ DeathDamage.prototype.Schema =
|
|||
"<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='Damage'>" +
|
||||
DamageTypes.BuildSchema("damage strength") +
|
||||
BuildDamageTypesSchema("damage strength") +
|
||||
"</element>" +
|
||||
DeathDamage.prototype.bonusesSchema;
|
||||
|
||||
|
|
@ -51,7 +51,7 @@ DeathDamage.prototype.GetDeathDamageStrengths = function()
|
|||
ApplyValueModificationsToEntity("DeathDamage/Damage/" + damageType, +(this.template.Damage[damageType] || 0), this.entity);
|
||||
|
||||
let ret = {};
|
||||
for (let damageType of DamageTypes.GetTypes())
|
||||
for (let damageType in this.template.Damage)
|
||||
ret[damageType] = applyMods(damageType);
|
||||
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -547,14 +547,14 @@ GuiInterface.prototype.GetTemplateData = function(player, templateName)
|
|||
let aurasTemplate = {};
|
||||
|
||||
if (!template.Auras)
|
||||
return GetTemplateDataHelper(template, player, aurasTemplate, Resources, DamageTypes);
|
||||
return GetTemplateDataHelper(template, player, aurasTemplate, Resources);
|
||||
|
||||
let auraNames = template.Auras._string.split(/\s+/);
|
||||
|
||||
for (let name of auraNames)
|
||||
aurasTemplate[name] = AuraTemplates.Get(name);
|
||||
|
||||
return GetTemplateDataHelper(template, player, aurasTemplate, Resources, DamageTypes);
|
||||
return GetTemplateDataHelper(template, player, aurasTemplate, Resources);
|
||||
};
|
||||
|
||||
GuiInterface.prototype.IsTechnologyResearched = function(player, data)
|
||||
|
|
|
|||
|
|
@ -126,11 +126,11 @@ cmpUpgrade.owner = playerID;
|
|||
* 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).
|
||||
let parsed_template = GetTemplateDataHelper(template, null, {}, Resources, DamageTypes);
|
||||
let parsed_template = GetTemplateDataHelper(template, null, {}, Resources);
|
||||
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).
|
||||
parsed_template = GetTemplateDataHelper(template, playerID, {}, Resources, DamageTypes);
|
||||
parsed_template = GetTemplateDataHelper(template, playerID, {}, Resources);
|
||||
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.
|
||||
|
|
@ -144,11 +144,11 @@ cmpUpgrade.Upgrade("structures/"+civCode+"_defense_tower");
|
|||
isResearched = true;
|
||||
|
||||
// T4: Check that the player-less value hasn't increased...
|
||||
parsed_template = GetTemplateDataHelper(template, null, {}, Resources, DamageTypes);
|
||||
parsed_template = GetTemplateDataHelper(template, null, {}, Resources);
|
||||
TS_ASSERT_UNEVAL_EQUALS(parsed_template.upgrades[0].cost, { "stone": 100, "wood": 50, "time": 100 });
|
||||
|
||||
// T5: ...but the player-backed value has.
|
||||
parsed_template = GetTemplateDataHelper(template, playerID, {}, Resources, DamageTypes);
|
||||
parsed_template = GetTemplateDataHelper(template, playerID, {}, Resources);
|
||||
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...
|
||||
|
|
|
|||
|
|
@ -1,8 +1,22 @@
|
|||
DamageTypes.prototype.BuildSchema = function(helptext = "")
|
||||
/**
|
||||
* Builds a RelaxRNG schema based on currently valid elements.
|
||||
*
|
||||
* To prevent validation errors, disabled damage types are included in the schema.
|
||||
*
|
||||
* @param {string} helptext - Text displayed as help
|
||||
* @return {string} - RelaxNG schema string
|
||||
*/
|
||||
function BuildDamageTypesSchema(helptext = "")
|
||||
{
|
||||
return "<interleave>" + this.GetTypes().reduce((schema, type) =>
|
||||
schema + "<element name='"+type+"' a:help='"+type+" "+helptext+"'><ref name='nonNegativeDecimal'/></element>",
|
||||
"") + "</interleave>";
|
||||
};
|
||||
return "<oneOrMore>" +
|
||||
"<element a:help='" + helptext + "'>" +
|
||||
"<anyName>" +
|
||||
// Armour requires Foundation to not be a damage type.
|
||||
"<except><name>Foundation</name></except>" +
|
||||
"</anyName>" +
|
||||
"<ref name='nonNegativeDecimal' />" +
|
||||
"</element>" +
|
||||
"</oneOrMore>";
|
||||
}
|
||||
|
||||
DamageTypes = new DamageTypes();
|
||||
Engine.RegisterGlobal("BuildDamageTypesSchema", BuildDamageTypesSchema);
|
||||
|
|
|
|||
Loading…
Reference in a new issue