Enemies Balancer
This is a library for balancing enemies with Mods Communicator. Create rules that changes worlds enemies stats.
| Last updated | 3 weeks ago |
| Total downloads | 96 |
| Total rating | 0 |
| Categories | Balancing Libraries Utility |
| Dependency string | GymMed-Enemies_Balancer-0.0.1 |
| Dependants | 0 other packages depend on this package |
This mod requires the following mods to function
GymMed-Mods_Communicator
Outward Mods Communicator enables seamless communication between mods through shared events and configuration syncing. It also lets users override any changes made by other mods, giving them full control over their settings.
Preferred version: 1.2.0README
Outward Enemies Balancer
Outward mod that allows you to modify enemy stats (health, damage, resistances, etc.) and change enemy factions using Mods Communicator to send events.
Deeper Explanation
This mod hooks into theSL.OnSceneLoaded method and evaluates the
BalancingRules and FactionRules. These rules
determine whether your stat modifications should be applied to an enemy.
The mod acts as a central Enemies Balancer that stores simple, abstracted logic and handles more complex game mechanics internally. Its state can be saved or loaded using XML.
When you publish an event, the rules are applied immediately to all matching enemies in the current scene.
Multiple matching rules stack and are all applied to the same enemy.
By default (without specific targeting), rules apply to all regular enemies (non-boss,
non-unique). Use isForBosses, isForBossPawns,
isForStoryBosses, isForUniqueArenaBosses, or
isForUniqueEnemies to target special enemy types.
Other mods can inspect, modify, or react to the BalancingRuleRegistryManager's
dynamic state and see how different mods interact with it.
How to use it
Firstly, install Mods
Communicator
After that, you can publish and subscribe to Enemies Balancer events.
All events are registered and visible in Mods Communicator's logging system. However, it is still recommended to read the event descriptions below and review the examples. Many event fields are optional and give you extra control, but they are not required.
Value Modifier Types
ValueModifierType determines how the stat modification is applied:
Direct- Sets stat to exact valueScale- Multiplies stat (1.5 = 150%)Add- Adds value to current stat
Default: Scale when using dictionary approach
Stat Types
Vital Stats
| Stat Name | Description |
|---|---|
| MaxHealth | Maximum health |
| MaxStamina | Maximum stamina |
| MaxMana | Maximum mana |
| HealthRegen | Health regeneration rate |
| StaminaRegen | Stamina regeneration rate |
| ManaRegen | Mana regeneration rate |
Damage Types
| Stat Name | Description |
|---|---|
| PhysicalDamage | Physical damage output |
| EtherealDamage | Ethereal damage output |
| DecayDamage | Decay damage output |
| ElectricDamage | Electric damage output |
| FrostDamage | Frost damage output |
| FireDamage | Fire damage output |
| RawDamage | Raw damage output |
Resistances
| Stat Name | Description |
|---|---|
| PhysicalResistance | Physical resistance (%) |
| EtherealResistance | Ethereal resistance (%) |
| DecayResistance | Decay resistance (%) |
| ElectricResistance | Electric resistance (%) |
| FrostResistance | Frost resistance (%) |
| FireResistance | Fire resistance (%) |
Protections
| Stat Name | Description |
|---|---|
| PhysicalProtection | Physical protection (flat) |
| EtherealProtection | Ethereal protection (flat) |
| DecayProtection | Decay protection (flat) |
| ElectricProtection | Electric protection (flat) |
| FrostProtection | Frost protection (flat) |
| FireProtection | Fire protection (flat) |
Environmental Stats
| Stat Name | Description |
|---|---|
| ColdProtection | Cold temperature protection |
| HeatProtection | Heat temperature protection |
| ColdRegenRate | Cold regeneration rate |
| HeatRegenRate | Heat regeneration rate |
| CorruptionProtection | Corruption protection |
| Waterproof | Waterproof rating |
Combat Stats
| Stat Name | Description |
|---|---|
| Impact | Impact damage |
| ImpactResistance | Impact resistance |
| MovementSpeed | Movement speed |
| AttackSpeed | Attack speed |
| SkillCooldownModifier | Skill cooldown modifier |
| DodgeInvulnerabilityModifier | Dodge invulnerability modifier |
| GlobalStatusResistance | Global status resistance |
Events
Check the parameter tables to understand which values are required. Event descriptions below are intentionally abstract — always refer to the tables for the exact field requirements.
Publish
Mod Namespace:gymmed.enemies_balancer_*
Make sure to publish only after Enemies Balancer has initialized. I
recommend adding it as a dependency in your mod, or publishing it before/after
ResourcesPrefabManager.Load has finished.
Add Balance Rule
Event Name:AddBalanceRule
Full balancing rule with all targeting options and stat modifications.
Requires at least one targeting parameter and one stat modification.
Example - Dictionary Approach
using OutwardModsCommunicator;
...
var payload = new EventPayload
{
["enemyName"] = "Hyena",
["statModifications"] = new Dictionary<string, float?>
{
{ "MaxHealth", 2.0f },
{ "PhysicalResistance", 15.0f }
},
["modifierType"] = ValueModifierType.Scale,
};
EventBus.Publish("gymmed.enemies_balancer_*", "AddBalanceRule", payload);
Example - Individual Parameters
using OutwardModsCommunicator;
...
var payload = new EventPayload
{
["enemyName"] = "Hyena",
["statType"] = "MaxHealth",
["value"] = 2.0f,
["modifierType"] = ValueModifierType.Scale,
};
EventBus.Publish("gymmed.enemies_balancer_*", "AddBalanceRule", payload);
Add Balance Rule By Enemy Name
Event Name:AddBalanceRuleByEnemyNameCompares Character.Name to your provided string.
Example
using OutwardModsCommunicator;
...
var payload = new EventPayload
{
["enemyName"] = "Hyena",
["statModifications"] = new Dictionary<string, float?>
{
{ "MaxHealth", 500f }
},
["modifierType"] = ValueModifierType.Direct,
};
EventBus.Publish("gymmed.enemies_balancer_*", "AddBalanceRuleByEnemyName", payload);
Add Balance Rule By Enemy Id
Event Name:AddBalanceRuleByEnemyIdMatches enemy by UID.
Example
using OutwardModsCommunicator;
...
var payload = new EventPayload
{
["enemyId"] = "eCz766tEIEOWfK81om19wg",
["statModifications"] = new Dictionary<string, float?>
{
{ "MaxHealth", 2.0f }
},
["modifierType"] = ValueModifierType.Scale,
};
EventBus.Publish("gymmed.enemies_balancer_*", "AddBalanceRuleByEnemyId", payload);
Add Balance Rule For Bosses
Event Name:AddBalanceRuleForBossesApply to boss types using isForBosses, isForBossPawns, isForStoryBosses, isForUniqueArenaBosses, isForUniqueEnemies.
Example
using OutwardModsCommunicator;
...
var payload = new EventPayload
{
["isForBosses"] = true,
["statModifications"] = new Dictionary<string, float?>
{
{ "MaxHealth", 1.5f }
},
["modifierType"] = ValueModifierType.Scale,
};
EventBus.Publish("gymmed.enemies_balancer_*", "AddBalanceRuleForBosses", payload);
Add Balance Rule For Uniques
Event Name:AddBalanceRuleForUniquesApply to unique enemies.
Example
using OutwardModsCommunicator;
...
var payload = new EventPayload
{
["isForUniqueEnemies"] = true,
["statModifications"] = new Dictionary<string, float?>
{
{ "MaxHealth", 2.0f }
},
["modifierType"] = ValueModifierType.Scale,
};
EventBus.Publish("gymmed.enemies_balancer_*", "AddBalanceRuleForUniques", payload);
Add Balance Rule For Area
Event Name:AddBalanceRuleForAreaApply to enemies in specific area or area family.
Example
using OutwardModsCommunicator;
...
var payload = new EventPayload
{
["area"] = AreaManager.AreaEnum.Abrassar,
["statModifications"] = new Dictionary<string, float?>
{
{ "MaxHealth", 1.2f }
},
["modifierType"] = ValueModifierType.Scale,
};
EventBus.Publish("gymmed.enemies_balancer_*", "AddBalanceRuleForArea", payload);
Modify Vital Stats
Event Name:ModifyVitalStatsModify health, stamina, mana, and regeneration stats.
Example
using OutwardModsCommunicator;
...
var payload = new EventPayload
{
["maxHealth"] = 1.5f,
["healthRegen"] = 1.2f,
["isForBosses"] = true,
["modifierType"] = ValueModifierType.Scale,
};
EventBus.Publish("gymmed.enemies_balancer_*", "ModifyVitalStats", payload);
Modify Environmental Stats
Event Name:ModifyEnvironmentalStatsModify cold/heat protection, corruption resistance, waterproof.
Example
using OutwardModsCommunicator;
...
var payload = new EventPayload
{
["coldProtection"] = 30f,
["heatProtection"] = 30f,
["modifierType"] = ValueModifierType.Direct,
};
EventBus.Publish("gymmed.enemies_balancer_*", "ModifyEnvironmentalStats", payload);
Modify Combat Stats
Event Name:ModifyCombatStatsModify impact, movement speed, attack speed.
Example
using OutwardModsCommunicator;
...
var payload = new EventPayload
{
["impact"] = 20f,
["movementSpeed"] = 1.1f,
["modifierType"] = ValueModifierType.Add,
};
EventBus.Publish("gymmed.enemies_balancer_*", "ModifyCombatStats", payload);
Load Balance Rules XML
Loads your custom balance-rules XML document into the mod.Event Name:
LoadBalanceRulesFromXmlRequires the full path to the XML file, provided as the
filePath parameter.Note: You must publish this event via Mods Communicator to load rules.
Recommended workflow: Add rules with Mods Communicator events → Save to XML → Load XML on next session (ensures correct syntax).
Example
using OutwardModsCommunicator;
...
var payload = new EventPayload
{
["filePath"] = "assemblyLocation/filePath.xml",
};
EventBus.Publish("gymmed.enemies_balancer_*", "LoadBalanceRulesFromXml", payload);
Store Balance Rules to XML
Stores the currentBalancingRuleRegistryManager balance rules into an XML document.Event Name:
SaveBalanceRulesToXmlOptional: you may provide a full XML file path using the
filePath
parameter. If omitted, the file will be stored at:
BepInEx/config/gymmed.Mods_Communicator/Enemies_Balancer/BalanceRules-date.xml
Example
using OutwardModsCommunicator;
...
var payload = new EventPayload
{
//["filePath"] = "",
};
EventBus.Publish("gymmed.enemies_balancer_*", "SaveBalanceRulesToXml", payload);
Add Faction Rule
Event Name:AddFactionRuleChange enemy factions. Useful for making enemies friendly or hostile. Requires
newFaction parameter with the target faction.
Example - Make Enemy Friendly
using OutwardModsCommunicator;
...
var payload = new EventPayload
{
["enemyName"] = "Hyena",
["newFaction"] = Character.Factions.Player,
};
EventBus.Publish("gymmed.enemies_balancer_*", "AddFactionRule", payload);
Example - Make Bosses Friendly
using OutwardModsCommunicator;
...
var payload = new EventPayload
{
["isForBosses"] = true,
["newFaction"] = Character.Factions.Player,
};
EventBus.Publish("gymmed.enemies_balancer_*", "AddFactionRule", payload);
Available Factions
Character.Factions.NONE- No factionCharacter.Factions.Player- Player factionCharacter.Factions.Bandits- BanditsCharacter.Factions.Mercs- MercenariesCharacter.Factions.Tuanosaurs- TuanosaursCharacter.Factions.Deer- Deer/WildlifeCharacter.Factions.Hounds- HoundsCharacter.Factions.Merchants- MerchantsCharacter.Factions.Golden- Golden OrderCharacter.Factions.CorruptionSpirit- Corruption Spirits
Subscribe
Mod Namespace:gymmed.enemies_balancerYou can listen when mod methods are triggered.
Balance Rule Appended
Event Name:BalanceRuleAppendedPublished when a balancing rule is added.
Example
using OutwardModsCommunicator;
...
public awake()
{
...
EventBus.Subscribe(
"gymmed.enemies_balancer",
"BalanceRuleAppended",
YourMethod
);
}
...
public static void YourMethod(EventPayload payload)
{
if (payload == null) return;
string balanceRuleId = payload.Get<string>("balanceRuleId", null);
// Your code...
}
Balance Rule Removed
Event Name:BalanceRuleRemovedPublished when a balancing rule is removed.
Example
using OutwardModsCommunicator;
...
public awake()
{
...
EventBus.Subscribe(
"gymmed.enemies_balancer",
"BalanceRuleRemoved",
YourMethod
);
}
...
public static void YourMethod(EventPayload payload)
{
if (payload == null) return;
string balanceRuleId = payload.Get<string>("balanceRuleId", null);
// Your code...
}
Faction Rule Appended
Event Name:FactionRuleAppendedPublished when a faction rule is added.
Example
using OutwardModsCommunicator;
...
public awake()
{
...
EventBus.Subscribe(
"gymmed.enemies_balancer",
"FactionRuleAppended",
YourMethod
);
}
...
public static void YourMethod(EventPayload payload)
{
if (payload == null) return;
string factionRuleId = payload.Get<string>("factionRuleId", null);
// Your code...
}
Faction Rule Removed
Event Name:FactionRuleRemovedPublished when a faction rule is removed.
Example
using OutwardModsCommunicator;
...
public awake()
{
...
EventBus.Subscribe(
"gymmed.enemies_balancer",
"FactionRuleRemoved",
YourMethod
);
}
...
public static void YourMethod(EventPayload payload)
{
if (payload == null) return;
string factionRuleId = payload.Get<string>("factionRuleId", null);
// Your code...
}
Unique Enemies
If you going to provide onlyenemyName and that enemy is unique
make sure to provide one of isForBosses,
isForBossPawns, isForStoryBosses,
isForUniqueArenaBosses, isForUniqueEnemies parameters.Enemies internally are compared by
UID + _ + Area.GetName().Trim().Replace(' ', '_')
because even UID repeat(is not truly unique) in different scenes and adding
location prevents collision.Data collected using Outward Scene Tester
Bosses
Below are all included inisForBosses parameter.
Story Bosses
All enemies included inisForStoryBosses. They are all compared by UID. Djinn has dummy data and is not tested, but he never enters the state to be looted?
Boss Pawns
All enemies included inisForBossPawns. They are all compared by UID.
Unique Arena Bosses
All enemies included inisForUniqueArenaBosses. They are all compared by UID.
Definitive Edition Unique Enemies
All enemies included inisForUniqueEnemies. They are all compared by UID.
Installation
- Install BepInEx
- Install SideLoader
- Install Mods Communicator
- Copy
OutwardEnemiesBalancer.dlltoBepInEx/plugins/OutwardEnemiesBalancer/
Configuration
XML configuration file is NOT loaded automatically. You must publish the LoadBalanceRulesFromXml event via Mods Communicator to load rules.
Recommended Workflow
1. Add rules programmatically using Mods Communicator events (ensures valid syntax) 2. Save rules to XML usingSaveBalanceRulesToXml event
3. On next session, load the XML using LoadBalanceRulesFromXml event
This approach ensures your XML syntax is always correct.
XML configuration file is located at:
BepInEx/config/gymmed.Mods_Communicator/Enemies_Balancer/BalanceRules.xml
XML Format
<?xml version="1.0" encoding="utf-8"?>
<BalanceRules>
<Rule>
<Id>unique-rule-id</Id>
<EnemyName>Hyena</EnemyName>
<StatModifications>
<Stat StatName="MaxHealth" Value="2.0" ModifierType="Scale"/>
<Stat StatName="PhysicalResistance" Value="15"/>
</StatModifications>
</Rule>
<FactionRule>
<Id>faction-rule-id</Id>
<EnemyName>Hyena</EnemyName>
<NewFaction>Player</NewFaction>
</FactionRule>
</BalanceRules>