Elemental: Reforged - Data Modding Guide
This guide covers how to create data mods for Elemental: Reforged. Data mods let you add new units, spells, items, improvements, and more -- or modify and remove existing ones -- using XML files.
1. Getting Started
Mod Folder Location
All mods live under your Documents folder:
Documents\My Games\ElementalReforged\Mods\
The game automatically creates a User subfolder for local mods. You can also create your own named folder.
Mod Folder Structure
Mods/
YourModName/
Data/
GameCore/ <-- Most game definitions go here
Core Stamps/ <-- Terrain stamps
Effects/ <-- Particle/visual effects
Scenarios/ <-- Scenario definitions
Animations/ <-- Custom animations
Core Tiles/ <-- Tile designs (recursive)
Core World/ <-- World data (recursive)
CutScenes/ <-- Cutscene definitions
Place your XML files in the appropriate subdirectory. The game scans these paths when mods are enabled and merges them with the base game data.
Enabling Your Mod
Launch the game
From the main menu, open the Mod Manager
Enable the User folder (or your custom mod folder)
Adjust load order if you have multiple mods (later mods override earlier ones)
Restart or start a new game
All game data is defined in XML files. Here's the basic structure:
<?xml version='1.0' encoding='utf-8'?>
<RootElement>
<DataType InternalName="MyDefinition">
<Property1>value</Property1>
<Property2>value</Property2>
</DataType>
</RootElement>
Key rules:
Every definition needs an InternalName attribute -- this is its unique identifier
The root element name varies by file but doesn't affect parsing
Text values for player-visible strings should use localization keys (e.g., TXT_MY_MOD_UNIT_NAME), but you can use plain text for testing
Boolean values are 0 (false) or 1 (true)
Colors are comma-separated: R,G,B or R,G,B,A (0-255)
3. Core Data Types
Here are the most commonly modded data types and the XML tags they use:
Units
<UnitTypes>
<UnitType InternalName="MyCustomUnit">
<DisplayName>My Custom Unit</DisplayName>
<Description>A powerful warrior.</Description>
<Class>Adventurer</Class>
<Allegiance>Empire</Allegiance>
<CreatureType>Champion</CreatureType>
<RaceType>Race_Type_Men</RaceType>
<Gender>Male</Gender>
<IsChampion>1</IsChampion>
<Unique>0</Unique>
<CanBeDesigned>0</CanBeDesigned>
<SpawnRating>1</SpawnRating>
<!-- Stats at level 1 -->
<LevelMilestone InternalName="L1">
<Level>1</Level>
<UnitStat_HitPoints>30</UnitStat_HitPoints>
<UnitStat_Accuracy>85</UnitStat_Accuracy>
<UnitStat_CombatSpeed>24</UnitStat_CombatSpeed>
</LevelMilestone>
<!-- Starting equipment (by InternalName) -->
<AutoCreateEquipment>IronSword</AutoCreateEquipment>
<Equipment>F_Male_Head_01</Equipment>
<!-- Starting abilities -->
<SelectedAbilityBonusOption>Fire1</SelectedAbilityBonusOption>
<!-- Visual setup -->
<ModelPath>Gfx\HKB\Units\F_Male_Mesh_01.hkb</ModelPath>
<SkeletonPath>Gfx\HKB\Units\K_Male_Skeleton_01.hkb</SkeletonPath>
<AnimationPack>MaleSovereignAnimationPack</AnimationPack>
<BattleAnimationBehavior>Melee</BattleAnimationBehavior>
<Color_Skin>180,140,110,255</Color_Skin>
<Color_Clothing1>60,40,30,255</Color_Clothing1>
<SoundPack>SoundPack_Generic_Male</SoundPack>
</UnitType>
</UnitTypes>
Spells
<Spells>
<SpellDef InternalName="MyFireball">
<DisplayName>Fireball</DisplayName>
<Description>Hurls a ball of fire at the target.</Description>
<Image>T_Fireball_Painting.png</Image>
<IconFG>T_Fireball_Icon.png</IconFG>
<SpellType>Tactical</SpellType>
<SpellClass>Offensive</SpellClass>
<SpellSubClass>Damage</SpellSubClass>
<SpellTargetType>EnemyUnit</SpellTargetType>
<SpellBookSortCategory>Attack</SpellBookSortCategory>
<!-- Prerequisites -->
<Prereq>
<Type>AbilityBonusOption</Type>
<Attribute>FireAdept1</Attribute>
</Prereq>
<!-- Casting cost -->
<SpellResourceCost>
<Resource>Mana</Resource>
<Amount>12</Amount>
</SpellResourceCost>
<!-- Damage effect (see GameModifier section) -->
<GameModifier>
<ModType>Unit</ModType>
<Attribute>AdjustUnitStat</Attribute>
<StrVal>CurHealth</StrVal>
<Value>-15</Value>
</GameModifier>
<!-- Visual effect -->
<SpellDefEffect>
<EffectName>T_Fireball_Particle</EffectName>
<EffectScale>1.0</EffectScale>
<SnapToTerrain>1</SnapToTerrain>
</SpellDefEffect>
<HitSoundFX>Spell_Fire_01</HitSoundFX>
</SpellDef>
</Spells>
Improvements (City Buildings)
<ImprovementTypes>
<ImprovementType InternalName="MyLibrary">
<DisplayName>Grand Library</DisplayName>
<Description>A center of learning.</Description>
<RequiresCity>1</RequiresCity>
<RequiresForceUnlock>1</RequiresForceUnlock>
<LaborToBuild>0</LaborToBuild>
<!-- Required tech or building -->
<RequiredImprovement>Conclave</RequiredImprovement>
<!-- Terrain restrictions -->
<BarredTerrain>River</BarredTerrain>
<BarredTerrain>SwampTerrain</BarredTerrain>
<PreferredTerrain>City</PreferredTerrain>
<!-- Effects -->
<GameModifier>
<ModType>Player</ModType>
<Attribute>AbilityBonus</Attribute>
<StrVal>A_Research</StrVal>
<Value>15</Value>
<Provides>+15 Research</Provides>
</GameModifier>
<!-- AI priority -->
<AIData AIPersonality="AI_General">
<AIPriority>14</AIPriority>
<AITag>Study</AITag>
</AIData>
<ArtDef>Art_Academy</ArtDef>
</ImprovementType>
</ImprovementTypes>
Resources
<ResourceTypes>
<ResourceType InternalName="MyResource">
<DisplayName>Moonstone</DisplayName>
<Description>A rare crystalline mineral.</Description>
<Type>Material</Type>
<Icon>Gfx//Icons//Res_Icon_Moonstone.png</Icon>
<Worth>5</Worth>
<Global>0</Global>
<Rarity>0.3</Rarity>
<Shared>0</Shared>
<TradedByCaravans>1</TradedByCaravans>
<ShownInGlobalDisplay>1</ShownInGlobalDisplay>
<IconColor>180,200,255</IconColor>
<ModelColor>180,200,255</ModelColor>
</ResourceType>
</ResourceTypes>
Terrain Types
<TerrainTypes>
<TerrainType InternalName="MyTerrain">
<DisplayName>Crystalline Wastes</DisplayName>
<MaxHeight>60</MaxHeight>
<MinHeight>50</MinHeight>
<MovementCost>12</MovementCost>
<Category>Land</Category>
<IsBaseTerrain>0</IsBaseTerrain>
<IsTerrainFeature>1</IsTerrainFeature>
<PassableByLandUnits>1</PassableByLandUnits>
<PassableByWaterUnits>0</PassableByWaterUnits>
<PassableByAirUnits>1</PassableByAirUnits>
<Indestructable>0</Indestructable>
<!-- Yield bonus -->
<GameModifier InternalName="CrystalYield">
<ModType>Resource</ModType>
<Attribute>TileYieldMaterial</Attribute>
<Value>2</Value>
<PerTurn>1</PerTurn>
</GameModifier>
</TerrainType>
</TerrainTypes>
4. The GameModifier System
GameModifiers are the backbone of effects in Elemental. They're used everywhere: spells, items, improvements, terrain, abilities, and more. A single definition can contain multiple GameModifier blocks.
Basic Structure
<GameModifier InternalName="OptionalName">
<ModType>Unit</ModType>
<Attribute>AdjustUnitStat</Attribute>
<StrVal>CurHealth</StrVal>
<Value>10</Value>
<Provides>+10 HP</Provides>
</GameModifier>
ModType Values
ModType | | Applies to |
|---|
Unit
| | Individual units (stats, abilities) |
Player
| | Player-wide bonuses (research, gold income) |
Resource
| | Resource yields and production |
Map
| | Terrain and tile effects |
Common Attributes
XML Tag | | Description |
|---|
ModType
| | What the modifier targets |
Attribute
| | The specific attribute to modify |
Value
| | Numeric value of the effect |
StrVal / StrVal2
| | String parameters (e.g., stat name, unit class) |
Provides
| | Player-visible description of the effect |
Duration
| | How many turns the effect lasts |
DurationOnTile
| | Duration while on a specific tile |
Radius
| | Area of effect radius |
Multiplier
| | Multiplicative factor (default: 1.0) |
BonusValue
| | Additional bonus amount |
MinValue / MaxValue
| | Random range (if both set, value is randomized between them). |
Conditional Modifiers
XML Tag | | Description |
|---|
PerTurn
| | Apply every turn (boolean) |
PerLevel
| | Scale with unit level (boolean) |
PerStamina
| | Scale with stamina (boolean) |
Cumulative
| | Stacks with itself (boolean) |
vsDamaged
| | Only applies vs damaged targets |
vsLower
| | Only applies vs lower-stat targets |
vsHigher
| | Only applies vs higher-stat targets |
vsOtherAllegiance
| | Only applies vs different allegiance |
WhenUnderPercentHitPoints
| | Activates when HP below threshold (0-100) |
WhenUnderArmySize
| | Activates when army size is under N |
WhenOverArmySize
| | Activates when army size is over N |
Application Timing
XML Tag | | Description |
|---|
xActions
| | Apply at battle start |
ApplyAtBattleEnd
| | Apply when battle ends |
ApplyDuringConstruction
| | Apply while building is under construction |
ApplyFromTileAtTacticalTurnStart
| | Apply from tile at each tactical turn |
RemoveWhenTargetLeavesTile
| | Remove effect when unit leaves the tile |
IsPreHitSpellModifier
| | Apply before hit resolution |
ApplyIfSpellTargetKilled
| | Apply only if the spell kills the target |
Targeting
XML Tag | | Description |
|---|
AffectedUnits
| | Filter which units are affected |
UnitClass
| | Filter by unit class |
TerrainType
| | Filter by terrain type |
ApplyToCaster
| | Apply to the caster instead of the target |
ApplyToPlayer
| | Apply to the player instead of a unit |
ApplyToTile
| | Apply to the tile instead of a unit |
ApplyToSpellRadiusCenterOnly
| | Only affect center tile of AoE |
5. The Calculate System (Variable Expressions)
For dynamic values that depend on game state (unit stats, shard counts, etc.), use Calculate blocks inside a GameModifier:
<GameModifier>
<ModType>Unit</ModType>
<Attribute>CurHealth</Attribute>
<Calculate InternalName="ShardBonus" ValueOwner="CastingUnit">
<Expression><![CDATA[[UnitOwner_GetNumLifeShards] * 2]]></Expression>
</Calculate>
<Calculate InternalName="BaseHeal" ValueOwner="CastingUnit">
<Expression><![CDATA[[ShardBonus] + 8]]></Expression>
</Calculate>
<Calculate InternalName="Value">
<Expression><![CDATA[[BaseHeal]]]></Expression>
</Calculate>
</GameModifier>
How It Works
Each Calculate block has an InternalName and an <Expression>
Variables are referenced with square brackets: [VariableName]
Variables can reference other Calculate blocks by InternalName, or properties from the ValueOwner
The system links calculators together: child calculators feed into parent calculators
The final result must be in a calculator named Value
Use ValueForFormattedDescription for the value shown in UI descriptions
Supported Operators
Operator | | Description |
|---|
+
| | Addition |
-
| | Subtraction |
*
| | Multiplication |
/
| | Division |
%
| | Modulo |
^
| | Exponentiation |
<
| | Less than (returns 0 or 1) |
>
| | Greater than (returns 0 or 1) |
Tag | | Description |
|---|
Expression
| | The math expression (wrap in <![CDATA[...]]> for safety) |
Min
| | Minimum value the result can be |
Max
| | Maximum value the result can be |
ValueOwner
| | Where to look up variable values (CastingUnit, TargetUnit, etc.) |
Common Variable Names
Variables available depend on the ValueOwner. Common ones include:
[UnitOwner_GetNumLifeShards], [UnitOwner_GetNumFireShards], etc.
[UnitStat_HitPoints], [UnitStat_Accuracy], [UnitStat_CombatSpeed]
[Unit_GetHPCurrent], [Unit_GetLevel]
[A_Diplomacy], [TradeIncome] (for treaty calculations)
Any float property exposed by the ValueOwner's GetFloatProperty() method
6. Overriding Existing Definitions
The IfExists Attribute
When your mod defines something with the same InternalName as a base game definition, you can control what happens using the IfExists attribute:
<UnitType InternalName="Champion_Craul" IfExists="ClearIfExists">
<!-- This completely replaces Craul's definition -->
</UnitType>
IfExists Value | | Behavior |
|---|
Update
| | Merge your values on top of the existing definition (partial override) |
ClearIfExists
| | Wipe the existing definition completely, then read your new values (full replacement) |
ClearChildren
| | Clear child collections (e.g., level milestones) but keep parent data |
Ignore
| | Skip this definition if it already exists |
Duplicate
| | Always create a new entry (no duplicate check) |
If you don't specify IfExists, each data type has a default behavior. Most types default to Update, meaning your values merge on top.
Practical Examples
Buff an existing unit's HP:
<!-- Update mode (default) - only changes what you specify -->
<UnitType InternalName="Champion_Craul">
<LevelMilestone InternalName="L1">
<UnitStat_HitPoints>50</UnitStat_HitPoints>
</LevelMilestone>
</UnitType>
Completely replace a spell:
<SpellDef InternalName="Aid" IfExists="ClearIfExists">
<!-- Your entire new spell definition here -->
<DisplayName>Greater Aid</DisplayName>
<!-- ... all fields must be specified ... -->
</SpellDef>
7. Removing Definitions (RemoveDef)
The Smart Modding system lets you surgically remove base game content. Place a <RemoveDef> block in any XML file in your mod:
Remove All Definitions of a Type
<RemoveDef>
<RemoveAllCoreDefsOfType>UnitType</RemoveAllCoreDefsOfType>
</RemoveDef>
This removes every core UnitType, letting your mod provide all units from scratch.
Remove Specific Definitions by Name
<RemoveDef>
<UnitType InternalName="Champion_Craul"/>
<SpellDef InternalName="Aid"/>
<ImprovementType InternalName="Academy"/>
</RemoveDef>
Skip Parsing Entire Files
<RemoveDef>
<SkipParsingFile>CoreUnitProps.xml</SkipParsingFile>
<SkipParsingFile>CoreMonsters.xml</SkipParsingFile>
</RemoveDef>
This prevents the game from loading those files at all, so your mod can provide complete replacements.
Combining Approaches
You can combine these in a single RemoveDef block:
<RemoveDef>
<!-- Remove all core factions -->
<RemoveAllCoreDefsOfType>RaceConfig</RemoveAllCoreDefsOfType>
<!-- Remove a specific spell -->
<SpellDef InternalName="Aid"/>
<!-- Skip loading the base monster file entirely -->
<SkipParsingFile>CoreMonsters.xml</SkipParsingFile>
</RemoveDef>
Important: RemoveDef only affects core definitions. It won't remove definitions added by other mods loaded before yours. Load order matters.
8. Load Order
When multiple mods are enabled, the game loads them in the order shown in the Mod Manager. This matters because:
Later mods win. If two mods define the same InternalName, the later one's values take precedence (in Update mode, the later mod's values overwrite the earlier mod's for any overlapping fields).
RemoveDef applies to core only. RemoveDef blocks remove base game definitions during the counting phase, before any mod definitions are parsed.
Recommended practice: If your mod depends on another mod, document that it should be loaded after the dependency.
9. AI Data
Most data types support an <AIData> block that tells the AI how to evaluate and use the definition:
<AIData AIPersonality="AI_General">
<AIPriority>15</AIPriority>
<AITag>Study</AITag>
<!-- Optional: calculated value for AI decisions -->
<ValueCalcWrapper>
<ValueType>IsTargetWorthy</ValueType>
<Calculate InternalName="Calc" ValueOwner="TargetUnit">
<Expression><![CDATA[[Unit_GetHPCurrent]]]></Expression>
</Calculate>
<Calculate InternalName="Value">
<Expression><![CDATA[[Calc] < 30]]></Expression>
</Calculate>
</ValueCalcWrapper>
</AIData>
Higher AIPriority values make the AI favor that option more. The ValueCalcWrapper provides dynamic evaluation for context-sensitive decisions.
10. Reference: Moddable Data Types
Here are the major data types you can define in XML. Use the corresponding tag name as your XML element:
XML Tag | | Description | | Example File |
|---|
UnitType
| | Units, champions, monsters | | CoreUnits.xml |
SpellDef
| | Spell definitions | | CoreSpells.xml |
ImprovementType
| | City buildings and improvements | | CoreImprovements.xml |
ResourceType
| | Resources (gold, mana, materials) | | CoreResources.xml |
TerrainType
| | Terrain types and features | | TerrainTypes.xml |
GameItemType
| | Equipment and items | | CoreItems.xml |
RaceConfig
| | Faction configurations | | CoreRaceConfigs.xml |
RaceType
| | Race type definitions | | CoreRaceTypes.xml |
TechDef
| | Technology definitions | | CoreTechs.xml |
TechTree
| | Technology tree layout | | TechTree_Amarian.xml |
QuestDef
| | Quest definitions | | CoreQuests.xml |
QuestLocation
| | Quest locations on the map | | CoreQuestLocations.xml |
AbilityBonus
| | Ability/trait definitions | | CoreAbilities.xml |
RecipeType
| | Crafting recipes | | CoreRecipes.xml |
DungeonType
| | Dungeon definitions | | (in GameCore) |
GoodieHut
| | Goodie hut encounters | | CoreGoodieHuts.xml |
GameTrigger
| | Event triggers | | CoreGameEvents.xml |
FlavorText
| | Random flavor text | | CoreFlavorText.xml |
NamePool
| | Name generation pools | | CoreNamePools.xml |
FactionConfig
| | Faction setup and colors | | CoreRaceConfigs.xml |
DifficultyLevel
| | Difficulty settings | | CoreDifficultyLevels.xml |
Treaty
| | Diplomacy treaty types | | Treaties.xml |
MapSettings
| | Map generation settings | | CoreMaps.xml |
RandomEvent
| | Random event definitions | | CoreRandomEvents.xml |
UnitStatType
| | Unit stat definitions | | CoreUnitStats.xml |
UnitQualityType
| | Unit quality tiers | | CoreUnitQualityTypes.xml |
MusicLayerGroup
| | Music definitions | | CoreLayeredMusic.xml |
SoundPack
| | Sound effect packs | | UnitSoundPacks.xml |
Tip: The best way to learn any data type's available fields is to look at the corresponding core XML file in Elemental-LH/Game/data/GameCore/.
11. Tips and Best Practices
Start small. Override one unit or one spell to make sure your mod folder is set up correctly before building something large.
Use Update mode (the default) for small tweaks. Only use ClearIfExists when you need to completely replace a definition.
Keep your InternalNames unique for new content. Prefix them with your mod name to avoid conflicts: MyMod_FireGolem instead of FireGolem.
Test with the Spawn Object tool in-game (Ctrl+Alt+S or tilde key) to quickly spawn and inspect your modded objects.
Back up your mod folder before making large changes.
Check load order if your changes aren't appearing -- your mod might be loading before another mod that overrides the same definitions.
Localization keys (e.g., TXT_MY_MOD_UNIT_NAME) can be defined in localization XML files, but plain text strings work fine for testing and small mods.