Data Modding Guide

From Elemental - Official Wiki
Revision as of 18:32, 7 April 2026 by Jsan (talk | contribs) (Created page with "{{DISPLAYTITLE:<span style="position: absolute; clip: rect(1px 1px 1px 1px); clip: rect(1px, 1px, 1px, 1px);">{{FULLPAGENAME}}</span>}} {{HeaderTemplate |welcome=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. {{SectionTemplate |h=h1 |title=Getting Started |content= ===Mod Folder Location=== All mods l...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search
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.

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

  1. Launch the game
  2. From the main menu, open the Mod Manager
  3. Enable the User folder (or your custom mod folder)
  4. Adjust load order if you have multiple mods (later mods override earlier ones)
  5. Restart or start a new game


XML File Format

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)


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>


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

ModTypeApplies to
UnitIndividual units (stats, abilities)
PlayerPlayer-wide bonuses (research, gold income)
ResourceResource yields and production
MapTerrain and tile effects

Common Attributes

XML TagDescription
ModTypeWhat the modifier targets
AttributeThe specific attribute to modify
ValueNumeric value of the effect
StrVal / StrVal2String parameters (e.g., stat name, unit class)
ProvidesPlayer-visible description of the effect
DurationHow many turns the effect lasts
DurationOnTileDuration while on a specific tile
RadiusArea of effect radius
MultiplierMultiplicative factor (default: 1.0)
BonusValueAdditional bonus amount
MinValue / MaxValueRandom range (if both set, value is randomized between them)

Conditional Modifiers

XML TagDescription
PerTurnApply every turn (boolean)
PerLevelScale with unit level (boolean)
PerStaminaScale with stamina (boolean)
CumulativeStacks with itself (boolean)
vsDamagedOnly applies vs damaged targets
vsLowerOnly applies vs lower-stat targets
vsHigherOnly applies vs higher-stat targets
vsOtherAllegianceOnly applies vs different allegiance
WhenUnderPercentHitPointsActivates when HP below threshold (0-100)
WhenUnderArmySizeActivates when army size is under N
WhenOverArmySizeActivates when army size is over N

Application Timing

XML TagDescription
xActionsApply at battle start
ApplyAtBattleEndApply when battle ends
ApplyDuringConstructionApply while building is under construction
ApplyFromTileAtTacticalTurnStartApply from tile at each tactical turn
RemoveWhenTargetLeavesTileRemove effect when unit leaves the tile
IsPreHitSpellModifierApply before hit resolution
ApplyIfSpellTargetKilledApply only if the spell kills the target

Targeting

XML TagDescription
AffectedUnitsFilter which units are affected
UnitClassFilter by unit class
TerrainTypeFilter by terrain type
ApplyToCasterApply to the caster instead of the target
ApplyToPlayerApply to the player instead of a unit
ApplyToTileApply to the tile instead of a unit
ApplyToSpellRadiusCenterOnlyOnly affect center tile of AoE


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

OperatorDescription
+Addition
-Subtraction
*Multiplication
/Division
%Modulo
^Exponentiation
<Less than (returns 0 or 1)
>Greater than (returns 0 or 1)

Calculate Tags

TagDescription
ExpressionThe math expression (wrap in <![CDATA[...]]> for safety)
MinMinimum value the result can be
MaxMaximum value the result can be
ValueOwnerWhere 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


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 ValueBehavior
UpdateMerge your values on top of the existing definition (partial override)
ClearIfExistsWipe the existing definition completely, then read your new values (full replacement)
ClearChildrenClear child collections (e.g., level milestones) but keep parent data
IgnoreSkip this definition if it already exists
DuplicateAlways 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>


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.


Load Order

When multiple mods are enabled, the game loads them in the order shown in the Mod Manager. This matters because:

  1. 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).
  2. RemoveDef applies to core only. RemoveDef blocks remove base game definitions during the counting phase, before any mod definitions are parsed.
  3. Recommended practice: If your mod depends on another mod, document that it should be loaded after the dependency.


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.


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 TagDescriptionExample File
UnitTypeUnits, champions, monstersCoreUnits.xml
SpellDefSpell definitionsCoreSpells.xml
ImprovementTypeCity buildings and improvementsCoreImprovements.xml
ResourceTypeResources (gold, mana, materials)CoreResources.xml
TerrainTypeTerrain types and featuresTerrainTypes.xml
GameItemTypeEquipment and itemsCoreItems.xml
RaceConfigFaction configurationsCoreRaceConfigs.xml
RaceTypeRace type definitionsCoreRaceTypes.xml
TechDefTechnology definitionsCoreTechs.xml
TechTreeTechnology tree layoutTechTree_Amarian.xml
QuestDefQuest definitionsCoreQuests.xml
QuestLocationQuest locations on the mapCoreQuestLocations.xml
AbilityBonusAbility/trait definitionsCoreAbilities.xml
RecipeTypeCrafting recipesCoreRecipes.xml
DungeonTypeDungeon definitions(in GameCore)
GoodieHutGoodie hut encountersCoreGoodieHuts.xml
GameTriggerEvent triggersCoreGameEvents.xml
FlavorTextRandom flavor textCoreFlavorText.xml
NamePoolName generation poolsCoreNamePools.xml
FactionConfigFaction setup and colorsCoreRaceConfigs.xml
DifficultyLevelDifficulty settingsCoreDifficultyLevels.xml
TreatyDiplomacy treaty typesTreaties.xml
MapSettingsMap generation settingsCoreMaps.xml
RandomEventRandom event definitionsCoreRandomEvents.xml
UnitStatTypeUnit stat definitionsCoreUnitStats.xml
UnitQualityTypeUnit quality tiersCoreUnitQualityTypes.xml
MusicLayerGroupMusic definitionsCoreLayeredMusic.xml
SoundPackSound effect packsUnitSoundPacks.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/.


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.