diff --git a/binaries/data/mods/public/globalscripts/DamageTypes.js b/binaries/data/mods/public/globalscripts/DamageTypes.js deleted file mode 100644 index 4012a42be7..0000000000 --- a/binaries/data/mods/public/globalscripts/DamageTypes.js +++ /dev/null @@ -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); -}; diff --git a/binaries/data/mods/public/globalscripts/Templates.js b/binaries/data/mods/public/globalscripts/Templates.js index 083f3cca79..ea1dc89246 100644 --- a/binaries/data/mods/public/globalscripts/Templates.js +++ b/binaries/data/mods/public/globalscripts/Templates.js @@ -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); } diff --git a/binaries/data/mods/public/gui/common/tooltips.js b/binaries/data/mods/public/gui/common/tooltips.js index 55a917c399..51b6a22e61 100644 --- a/binaries/data/mods/public/gui/common/tooltips.js +++ b/binaries/data/mods/public/gui/common/tooltips.js @@ -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(", "))); } diff --git a/binaries/data/mods/public/gui/reference/common/helper.js b/binaries/data/mods/public/gui/reference/common/helper.js index 5e84a1ef74..304780acdd 100644 --- a/binaries/data/mods/public/gui/reference/common/helper.js +++ b/binaries/data/mods/public/gui/reference/common/helper.js @@ -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) diff --git a/binaries/data/mods/public/gui/reference/common/load.js b/binaries/data/mods/public/gui/reference/common/load.js index 50fc741275..442dcdd063 100644 --- a/binaries/data/mods/public/gui/reference/common/load.js +++ b/binaries/data/mods/public/gui/reference/common/load.js @@ -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; diff --git a/binaries/data/mods/public/maps/random/rmgen-common/wall_builder.js b/binaries/data/mods/public/maps/random/rmgen-common/wall_builder.js index 2c9684e0ae..d97cd08f22 100644 --- a/binaries/data/mods/public/maps/random/rmgen-common/wall_builder.js +++ b/binaries/data/mods/public/maps/random/rmgen-common/wall_builder.js @@ -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({ diff --git a/binaries/data/mods/public/maps/random/rmgen/library.js b/binaries/data/mods/public/maps/random/rmgen/library.js index 9d22cb9797..e958316e12 100644 --- a/binaries/data/mods/public/maps/random/rmgen/library.js +++ b/binaries/data/mods/public/maps/random/rmgen/library.js @@ -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 */ diff --git a/binaries/data/mods/public/simulation/ai/common-api/entity.js b/binaries/data/mods/public/simulation/ai/common-api/entity.js index 8b54a71f32..a5e0f0bd3f 100644 --- a/binaries/data/mods/public/simulation/ai/common-api/entity.js +++ b/binaries/data/mods/public/simulation/ai/common-api/entity.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() { diff --git a/binaries/data/mods/public/simulation/ai/petra/config.js b/binaries/data/mods/public/simulation/ai/petra/config.js index 77e4b56bfd..957d9979e6 100644 --- a/binaries/data/mods/public/simulation/ai/petra/config.js +++ b/binaries/data/mods/public/simulation/ai/petra/config.js @@ -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. diff --git a/binaries/data/mods/public/simulation/ai/petra/defenseArmy.js b/binaries/data/mods/public/simulation/ai/petra/defenseArmy.js index a5be2f2d17..2c85851c33 100644 --- a/binaries/data/mods/public/simulation/ai/petra/defenseArmy.js +++ b/binaries/data/mods/public/simulation/ai/petra/defenseArmy.js @@ -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. diff --git a/binaries/data/mods/public/simulation/ai/petra/defenseManager.js b/binaries/data/mods/public/simulation/ai/petra/defenseManager.js index b458d129b4..047aab5587 100644 --- a/binaries/data/mods/public/simulation/ai/petra/defenseManager.js +++ b/binaries/data/mods/public/simulation/ai/petra/defenseManager.js @@ -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; diff --git a/binaries/data/mods/public/simulation/ai/petra/entityExtend.js b/binaries/data/mods/public/simulation/ai/petra/entityExtend.js index 3edbdbfc30..ab4af81552 100644 --- a/binaries/data/mods/public/simulation/ai/petra/entityExtend.js +++ b/binaries/data/mods/public/simulation/ai/petra/entityExtend.js @@ -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; diff --git a/binaries/data/mods/public/simulation/ai/petra/headquarters.js b/binaries/data/mods/public/simulation/ai/petra/headquarters.js index 1c08ee9bf4..66ecc89b2c 100644 --- a/binaries/data/mods/public/simulation/ai/petra/headquarters.js +++ b/binaries/data/mods/public/simulation/ai/petra/headquarters.js @@ -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") { diff --git a/binaries/data/mods/public/simulation/components/Armour.js b/binaries/data/mods/public/simulation/components/Armour.js index bef3ea59f5..42fdc4b682 100644 --- a/binaries/data/mods/public/simulation/components/Armour.js +++ b/binaries/data/mods/public/simulation/components/Armour.js @@ -7,11 +7,11 @@ Armour.prototype.Schema = "0.0" + "5.0" + "" + - DamageTypes.BuildSchema("damage protection") + + BuildDamageTypesSchema("damage protection") + "" + "" + "" + - DamageTypes.BuildSchema("damage protection") + + BuildDamageTypesSchema("damage protection") + "" + "" + ""; @@ -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; }; diff --git a/binaries/data/mods/public/simulation/components/Attack.js b/binaries/data/mods/public/simulation/components/Attack.js index b259bbe4d8..4f8f74a29a 100644 --- a/binaries/data/mods/public/simulation/components/Attack.js +++ b/binaries/data/mods/public/simulation/components/Attack.js @@ -131,7 +131,7 @@ Attack.prototype.Schema = "" + "" + "" + - DamageTypes.BuildSchema("damage strength") + + BuildDamageTypesSchema("damage strength") + "" + "" + "" + @@ -150,7 +150,7 @@ Attack.prototype.Schema = "" + "" + "" + - DamageTypes.BuildSchema("damage strength") + + BuildDamageTypesSchema("damage strength") + "" + "" + "" + @@ -180,7 +180,7 @@ Attack.prototype.Schema = "" + "" + "" + - DamageTypes.BuildSchema("damage strength") + + BuildDamageTypesSchema("damage strength") + "" + Attack.prototype.bonusesSchema + "" + @@ -242,7 +242,7 @@ Attack.prototype.Schema = "" + "" + "" + - DamageTypes.BuildSchema("damage strength") + + BuildDamageTypesSchema("damage strength") + "" + "" + // 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; diff --git a/binaries/data/mods/public/simulation/components/DeathDamage.js b/binaries/data/mods/public/simulation/components/DeathDamage.js index d0f26864a7..1248679655 100644 --- a/binaries/data/mods/public/simulation/components/DeathDamage.js +++ b/binaries/data/mods/public/simulation/components/DeathDamage.js @@ -34,7 +34,7 @@ DeathDamage.prototype.Schema = "" + "" + "" + - DamageTypes.BuildSchema("damage strength") + + BuildDamageTypesSchema("damage strength") + "" + 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; diff --git a/binaries/data/mods/public/simulation/components/GuiInterface.js b/binaries/data/mods/public/simulation/components/GuiInterface.js index f58aa8a530..fd3421fedb 100644 --- a/binaries/data/mods/public/simulation/components/GuiInterface.js +++ b/binaries/data/mods/public/simulation/components/GuiInterface.js @@ -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) diff --git a/binaries/data/mods/public/simulation/components/tests/test_UpgradeModification.js b/binaries/data/mods/public/simulation/components/tests/test_UpgradeModification.js index 2eb3fd615c..3d7a6e1ce1 100644 --- a/binaries/data/mods/public/simulation/components/tests/test_UpgradeModification.js +++ b/binaries/data/mods/public/simulation/components/tests/test_UpgradeModification.js @@ -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... diff --git a/binaries/data/mods/public/simulation/helpers/DamageTypes.js b/binaries/data/mods/public/simulation/helpers/DamageTypes.js index fabd6d8b45..891c94efaf 100644 --- a/binaries/data/mods/public/simulation/helpers/DamageTypes.js +++ b/binaries/data/mods/public/simulation/helpers/DamageTypes.js @@ -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 "" + this.GetTypes().reduce((schema, type) => - schema + "", - "") + ""; -}; + return "" + + "" + + "" + + // Armour requires Foundation to not be a damage type. + "Foundation" + + "" + + "" + + "" + + ""; +} -DamageTypes = new DamageTypes(); +Engine.RegisterGlobal("BuildDamageTypesSchema", BuildDamageTypesSchema);