Evil Islands eXtender
Engine fixes and tweaks for Evil Islands: Curse of the Lost Soul.
eix implements most of the features provided by EI addon.dll, as well as SpellAddon, and adds fixes and features. Scripts can be written in the game’s own language (script reference) or in Lua (Lua reference).
- Mods and plugins work the same way: same
config.reg,ai.regandspelladdon.ini. - Game:
game.exeRU 1.06 (EI starter’s and GOG’s Russian builds). Other builds not supported yet.
Install
- Install EIStarter-UM from Universal Mod. Just the starter, not the mod.
- Download eix’s zip from releases.
- Replace the starter’s
dinput.dll(besidegame.exe) andaddon.dll(in the starter’s folder) with eix’s. Keep the starter’s two files to switch back. - Put
spelladdon.iniin the game folder. A mod’s ownspelladdon.ini, in its folder, takes precedence. - Put
eix.iniin the mod’s folder (Mods\<mod>): eix’s own settings, such as pausing on a party member’s low health.
To uninstall, put the starter’s dinput.dll and addon.dll back.
Reference
| Page | Content |
|---|---|
| Recipes | Common changes: which file, which keys, which values |
| Script reference | Every function and command of the game’s script language, the original’s and eix’s |
| Lua, Lua reference | The Lua host, and the functions and callbacks of a mod’s script |
| Addon and loader | Settings of config.reg and ai.reg, console commands, start-up behavior |
| SpellAddon options | Every spelladdon.ini option |
| Fixes and features | Fixes of game.exe defects that eix adds; its own features: game options, AutoPause, encumbrance, FLAC music, INI variables |
| eix.ini | eix’s own settings: engine fixes, AutoPause, encumbrance, FLAC music |
| Development | Building, testing, releasing and publishing this site |
Development
Building, testing and releasing: development.
Related projects
ei-rebuild | ei-universal-mod | CursedLands
Source and releases: github.com/BGforgeNet/eix.
Recipes
Common changes: which file to edit, which keys to set, and to what. Each key is described in full on its reference page.
The files
| File | Where | Reference |
|---|---|---|
spelladdon.ini | The mod’s folder (Mods\<mod>, beside its config.reg); without one there, the game folder’s. eix reads one of the two, without merging them. | SpellAddon options |
eix.ini | The mod’s folder | eix.ini |
- Edit them in any text editor, then restart the game.
- Write fractions with a decimal point:
0.25. - Updating or reinstalling a mod can replace its files: keep a note of the changes.
Running drain (stamina)
Running drains stamina at every game tick. The game takes the maximum stamina / 150 per tick, so a full bar always lasts
the same time, however large it is. [rebalanceengine] in spelladdon.ini changes that:
[rebalanceengine]
rewriterunabilitytime=1
newrunsystem=1
runconst=0.5
| Drain per tick | newrunsystem | runconst |
|---|---|---|
| A fixed amount: a larger bar runs longer | 1 | The amount |
| A share of the maximum, as in the game | 0 | The share; the game’s is 0.006666666666 (1/150) |
A share of the maximum plus a fixed amount, runconstex | 2 | The share |
rewriterunabilitytime=1 makes the game use runconst; keep it in every row.
With a fixed amount:
- Lower
runconstto run longer:0.25runs twice as long as0.5. runconst= M / 150 drains as the game does for a hero with a maximum of M stamina:0.5matches the game at 75. A smaller bar empties sooner than in the game, a larger one later.
Related:
- eix’s encumbrance (
[Encumbrance] Enabled=1ineix.ini) raises the drain with the load: 1.25 times at the maximum load with the defaults.RunDrain=0there removes that extra,50halves it. [gameplay] automaticruncontrol=1inspelladdon.inistops a unit from running when its stamina runs out.- Any other formula: the Lua callback CalcRunningManaCost.
- Every key: SpellAddon options, eix.ini.
Mod settings for map scripts
A mod can give players a setting in its own INI file and read it in its map scripts, through eix’s INI variables. Without eix the setting reads 0, so 0 should mean the game’s own behavior.
-
Ship the INI file in the mod’s folder, with the default value:
; mymod.ini [Companions] Travel=0 -
Read it in a map script with the game’s
GSGetVar, namingini.<file>.<section>.<key>:if ( IsEqual( GSGetVar( 0, "ini.mymod.Companions.Travel" ) , 1 ) ) then ( ... ) -
Players change the value in
mymod.iniand restart the game.
Notes:
- A
mymod.iniin the game folder serves when the mod’s folder has none. - A value is a number;
0.5and0,5both read as a half. A missing file, section or key reads 0. - The value is not stored in the game: changing the INI and restarting changes it in every save.
- The conditions of an
ifmust all hold. For “either of two” conditions with values 0 or 1, writeNot( IsGreater( Not( a ) , b ) ), or give each condition its ownifwith the same commands.
Script reference
The functions and commands of the game’s script language. Each signature is written as a TypeScript declaration. A
function returns a value; a command returns void. The types are number, string, object and group; name? is
an argument a call may leave out, and ...name may be given again and again. Names ignore ASCII case. A condition is a
number: 0 is false.
Entries tagged eix are added or changed by eix: the functions and commands that addon.dll adds, and the changes that SpellAddon options make to the game’s own. The others are the original game’s. A note headed Differs from the original says where eix behaves differently.
Sections:
- Script flow
- Numbers and logic
- Text and console
- Groups
- Objects and positions
- Units and statistics
- Orders and behaviour
- Spells
- Players, parties and diplomacy
- Items and money
- Quests
- Player variables
- World, effects and sound
- Game and system
Script flow
Waiting, stopping and looping over groups.
Any
function Any(variable: object, group: group, condition: number): number
Returns 1 if the condition is nonzero for at least one object of the group, with the variable set to each object in turn; otherwise 0.
Every
function Every(variable: object, group: group, condition: number): number
Returns 1 if the condition is nonzero for every object of the group, with the variable set to each object in turn; otherwise 0.
For
function For(variable: object, group: group): void
Runs the loop body once for every object of the group, with the global variable set to that object. The group can be a
diplomatic group, a game group, or the result of GroupAdd or GroupCross.
ForIf
function ForIf(variable: object, group: group, condition: number): void
Like For, but runs the body only for the objects for which the condition is nonzero.
KillScript
function KillScript(): void
Stops the running script. Map script modules only; the first command of a script body, as a rule.
Sleep
function Sleep(ticks: number): void
Pauses the script for the given time, in 1/15 s units. Works in map script modules only.
SleepUntil
function SleepUntil(condition: number): void
Pauses the script until the condition becomes nonzero.
SleepUntilIdle
function SleepUntilIdle(unit: object): void
Pauses the script until the unit has no order left.
Sum
function Sum(variable: object, group: group, expression: number): number
Evaluates the expression once for every object of the group, with the variable set to that object, and returns the sum of the results.
WaitSegment
function WaitSegment(segments: number): void
Pauses the called procedure for the given number of segments, 15 to the second. Map script modules only.
Numbers and logic
Arithmetic, comparisons and rounding. A condition is a number: 0 is false, any other value true.
Abs
function Abs(value: number): number
eix Added by addon.dll.
Returns the absolute value.
Add
function Add(a: number, ...b: number[]): number
eix Added by addon.dll.
Returns the sum of two or more numbers. Replaces the game’s function of two numbers.
And
function And(a: number, ...b: number[]): number
eix Added by addon.dll.
Returns the logical conjunction of two or more values.
Ceil
function Ceil(value: number): number
eix Added by addon.dll.
Rounds up.
Cos
function Cos(value: number): number
eix Added by addon.dll.
Returns the cosine of a value in radians.
DistancePointPoint
function DistancePointPoint(x: number, y: number): number
eix Added by addon.dll.
Returns the distance from the point (x, y) to the origin: the two implicit coordinates are zero.
Differs from the original: the last two values are 0 (the original reads past its arguments)
Div
function Div(a: number, b: number): number
Returns a divided by b.
Floor
function Floor(value: number): number
eix Added by addon.dll.
Rounds down.
IsEqual
function IsEqual(a: number, b: number): number
Returns 1 if the two numbers are equal, otherwise 0.
IsEqualString
function IsEqualString(a: string, b: string): number
Returns 1 if the two strings are equal, case included, otherwise 0.
IsGreater
function IsGreater(a: number, b: number): number
Returns 1 if a is greater than b, otherwise 0.
IsLess
function IsLess(a: number, b: number): number
Returns 1 if a is less than b, otherwise 0.
Max
function Max(a: number, ...b: number[]): number
eix Added by addon.dll.
Returns the largest of two or more numbers.
Min
function Min(a: number, ...b: number[]): number
eix Added by addon.dll.
Returns the smallest of two or more numbers.
Mul
function Mul(a: number, ...b: number[]): number
eix Added by addon.dll.
Returns the product of two or more numbers. Replaces the game’s function of two numbers.
Not
function Not(value: number): number
Returns 1 if the value is 0, otherwise 0.
Or
function Or(a: number, ...b: number[]): number
eix Added by addon.dll.
Returns the logical disjunction of two or more values.
Pow
function Pow(base: number, exponent: number): number
eix Added by addon.dll.
Returns the base raised to the exponent.
Random
function Random(a: number, b?: number): number
eix Added by addon.dll.
Random(max) is the game’s random function. Random(min, max) returns a random value in the range, or min if max
is not above min. Replaces the game’s function of one number.
Round
function Round(value: number): number
eix Added by addon.dll.
Rounds half away from zero.
Differs from the original: Round is exact (the original gives 8388610 for 8388609 and 1 for 0.49999997)
Sin
function Sin(value: number): number
eix Added by addon.dll.
Returns the sine of a value in radians.
Sub
function Sub(a: number, b: number): number
Returns a minus b.
Text and console
Strings, and output to the console and the chat.
ConsoleFloat
function ConsoleFloat(value: number): void
Prints a number to the console. Synonym: #.
ConsoleString
function ConsoleString(...text: string[]): void
eix Added by addon.dll.
Joins the strings and prints them as one console line. Replaces the game’s command of one string.
FloatToStr
function FloatToStr(value: number, precision?: number): string
eix Added by addon.dll.
Converts a number to text. precision defaults to 3 and is clamped to 0 to 8; the fraction’s trailing zeros are
removed.
Differs from the original: FloatToStr(100, 0) is 100 (the original removes the integer part’s zeros too, giving
1)
RandStr
function RandStr(text: string, ...more: string[]): string
eix Added by addon.dll.
Returns one of two or more strings at random.
Differs from the original: RandStr stops on a missing object (the original crashes)
Say
function Say(...text: string[]): void
eix Added by addon.dll.
Joins the strings and sends them to the multiplayer server chat.
SendEvent
function SendEvent(player: number, event: number): void
Debug command: broadcasts a number to the engine’s players.
SendStringEvent
function SendStringEvent(player: number, event: string): void
Sends a text command to the engine. say sNN Name starts an NPC line (the text say sNN of texts.res, with the sound
from the unit’s Acks field); say_block does the same and blocks the speaker. Other commands: tutorial zt1,
briefing, autosave, endofgame.
StrCat
function StrCat(text: string, ...more: string[]): string
eix Added by addon.dll.
Joins two or more strings.
StrHas
function StrHas(text: string, fragment: string): number
eix Added by addon.dll.
Returns 1 if the fragment occurs in the text, otherwise 0.
StrLen
function StrLen(text: string): number
eix Added by addon.dll.
Returns the length of a string in bytes.
StrLower
function StrLower(text: string): string
eix Added by addon.dll.
Converts a string to lowercase by the active code page.
StrMid
function StrMid(text: string, start: number, count: number): string
eix Added by addon.dll.
Returns part of a string, by the active code page. start counts bytes from 1, and from the end when negative; a
count of 0 takes the rest of the string.
StrToFloat
function StrToFloat(text: string): number
eix Added by addon.dll.
Converts text to a number.
StrUpper
function StrUpper(text: string): string
eix Added by addon.dll.
Converts a string to uppercase by the active code page.
Groups
Sets of objects: diplomatic groups, game groups and the results of group functions.
AddObject
function AddObject(group: group, unit: object): void
Adds a unit to a game group, a global variable of the script.
GetObjectsOnMap
function GetObjectsOnMap(...class: number[]): group
eix Added by addon.dll.
Returns the group of the objects of the listed classes. -1 selects all.
GetPlayerUnits
function GetPlayerUnits(diplomacyGroup: number): group
Returns the group of the units of a diplomatic group.
GroupAdd
function GroupAdd(a: group, b: group): group
Returns the group of the objects that are in either group.
GroupCross
function GroupCross(a: group, b: group): group
Returns the group of the objects that are in both groups.
GroupHas
function GroupHas(group: group, unit: object): number
Returns 1 if the group contains the unit, otherwise 0.
GroupSee
function GroupSee(group: group): group
Returns the group of the objects that the members of the group see at this moment. The members see each other.
GroupSee - SpellAddon groupseetrans
function GroupSee(group: group, mode: number): group
eix SpellAddon option [gameplay] groupseetrans.
Accepts an extra numeric mode argument. The group traversal itself stays the game’s.
GroupSize
function GroupSize(group: group): number
Returns the number of units in the group.
GroupSub
function GroupSub(a: group, b: group): group
Returns the group of the objects of the first group that are not in the second.
PlayerSee
function PlayerSee(player: number): group
Returns the group of the units that the units of the player’s party see.
RandObj
function RandObj(group: group): object
eix Added by addon.dll.
Returns a random member of the group.
RemoveObject
function RemoveObject(group: group, unit: object): void
Removes a unit from a game group. Not usable from the console.
UnitSee
function UnitSee(unit: object): group
Returns the group of the units the unit sees. A unit does not see itself.
UnitSee - SpellAddon unitseetrans
function UnitSee(unit: object, mode: number): group
eix SpellAddon option [gameplay] unitseetrans.
Selects the visibility list: positive zero is the visible living units, a negative sign bit (negative zero included) the second list, any other value the nearby-units list.
UnitsNearPoint
function UnitsNearPoint(x: number, y: number, radius: number, filter: number): group
eix Added by addon.dll.
Returns the group of the objects within the radius that pass the filter. Filter bits: 1 units, 2 other objects, 4 living named objects.
Objects and positions
Finding objects, reading their positions and placing them on the map.
AddMob
function AddMob(file: string): void
Loads a .mob file from the MAPS folder; the name includes the extension.
AddMob - SpellAddon infiniteaddmobspawn
function AddMob(file: string): void
eix SpellAddon option [gameplay] infiniteaddmobspawn.
Can load the same file repeatedly, except case-sensitive names that begin with Auto, which still load once. Active for
values 1 and up.
AddMobEx
function AddMobEx(file: string, skipScripts?: number): void
eix Added by addon.dll.
Adds the objects of a .mob file without a loading movie, and optionally skips its scripts.
AddUnitToServer
function AddUnitToServer(mapName: string, prototype: string, displayName: string, x: number, y: number, z: number): void
Places a unit of the given prototype on the map at (x, y, z). mapName is its internal name, case-sensitive;
displayName is the name shown in info windows.
DistanceUnitPoint
function DistanceUnitPoint(unit: object, x: number, y: number): number
Returns the straight distance between an object and a point.
DistanceUnitUnit
function DistanceUnitUnit(unitA: object, unitB: object): number
Returns the straight distance between two objects.
GetBSZValue
function GetBSZValue(x: number, y: number): number
Returns the height of the surface at the point: like GetZValue, except that an unfrozen pool of water or lava gives
the height of its surface, not of its bottom.
GetFutureX
function GetFutureX(object: object, ticks: number): number
Returns the x coordinate the object is predicted to have after the given time, in 1/15 s units. The shorter the time, the better the prediction.
GetFutureY
function GetFutureY(object: object, ticks: number): number
Returns the y coordinate the object is predicted to have after the given time, in 1/15 s units.
GetLeader
function GetLeader(): object
Returns the leader of the current party: Zak in single player, the player’s current character in multiplayer.
GetObject
function GetObject(id: number): object
Returns the object with the given ID. Does not work with ten-digit IDs: use GetObjectByID.
GetObjectByID
function GetObjectByID(id: string): object
Returns the object with the given ID, written as a string. Accepts ten-digit IDs.
GetObjectByName
function GetObjectByName(name: string): object
Returns the object with the given in-game name.
GetObjectID
function GetObjectID(object: object): number
Returns the ID of an object, a unit or any other object such as a chest.
GetObjectStringID
function GetObjectStringID(object: object): string
eix Added by addon.dll.
Returns the ID of an object as a decimal string.
GetObjectTypeID
function GetObjectTypeID(object: object): number
eix Added by addon.dll.
Returns the class ID of an object, or -1.
GetPrototype
function GetPrototype(unit: object): string
eix Added by addon.dll.
Returns the name of the unit’s prototype.
Differs from the original: stops on a missing object (the original crashes)
GetRace
function GetRace(unit: object): string
eix Added by addon.dll.
Returns the model name of the unit.
Differs from the original: stops on a missing object (the original crashes)
GetX
function GetX(object: object): number
Returns the x coordinate of an object.
GetY
function GetY(object: object): number
Returns the y coordinate of an object.
GetZ
function GetZ(object: object): number
Returns the z coordinate of an object.
GetZValue
function GetZValue(x: number, y: number): number
Returns the height of the solid ground at the point, whatever water or lava lies over it.
HideObject
function HideObject(object: object, hide: number): void
Hides the object if hide is nonzero, shows it if 0. Works in briefing zones only.
IsInArea
function IsInArea(area: number, x: number, y: number): number
Returns 1 if the point (x, y) lies in a part of the quest area, otherwise 0.
IsInSquare
function IsInSquare(x: number, y: number, x1: number, y1: number, x2: number, y2: number): number
Returns 1 if the point (x, y) lies in the rectangle (x1, y1)-(x2, y2), otherwise 0.
IsUnitInWater
function IsUnitInWater(unit: object): number
Returns 1 if the unit is in water, otherwise 0.
IsUnitVisible
function IsUnitVisible(unit: object): number
Returns 1 if the player can see the unit in the zone, otherwise 0. HideObject does not change the result.
NearestUnit
function NearestUnit(x: number, y: number, radius: number, filter: number): object
eix Added by addon.dll.
Returns the nearest object within the radius that passes the filter, or no object. Filter bits: 1 units, 2 other objects, 4 living named objects.
RemoveObjectFromServer
function RemoveObjectFromServer(object: object): void
Removes the object from the server. Same as RemoveUnitFromServer.
RemoveUnitFromServer
function RemoveUnitFromServer(unit: object): void
Removes the object from the server. Same as RemoveObjectFromServer.
SetCP
function SetCP(object: object, x: number, y: number, z: number): void
Moves any map object, not only a unit, to (x, y). A unit loses its orders, and the passability graph is recalculated,
which is slower than SetCPFast.
SetCPFast
function SetCPFast(object: object, x: number, y: number, z: number): void
Like SetCP, but the AI passability graph is not recalculated.
UnitInSquare
function UnitInSquare(unit: object, x1: number, y1: number, x2: number, y2: number): number
Returns 1 if the unit stands in the rectangle (x1, y1)-(x2, y2), otherwise 0.
Units and statistics
Health, mana, attributes, skills and experience.
BlockUnit
function BlockUnit(unit: object, block: number): void
Blocks the player’s control of a unit if block is nonzero, gives it back if 0. A unit can be controlled from the
moment it joins a party.
GetActions
function GetActions(unit: object): number
eix Added by addon.dll.
Returns the current action count of a unit.
GetActionsBase
function GetActionsBase(unit: object): number
eix Added by addon.dll.
Returns the base action count of a unit.
GetAIClass
function GetAIClass(unit: object): number
Returns what the unit is doing: 0 calm, 1 moving, 2 turning, 3 attacking, 4 casting, 5 using a skill, 6 following.
GetAIClass - SpellAddon getaiclasstrans
function GetAIClass(unit: object): number
eix SpellAddon option [gameplay] getaiclasstrans.
Reads the AI class field of the unit’s server controller.
GetArmor
function GetArmor(unit: object, kind: number, part: number): number
eix Added by addon.dll.
Returns the protection of a unit. kind 0 to 5 selects a body slot’s layers and part 0 to 6 a damage type; a negative
kind uses the computed protection.
GetDexterity
function GetDexterity(unit: object): number
eix Added by addon.dll.
Returns the dexterity of a unit.
GetEncumbrance
function GetEncumbrance(unit: object): number
eix Added by addon.dll.
Returns the load a unit carries.
GetIntelligence
function GetIntelligence(unit: object): number
eix Added by addon.dll.
Returns the intelligence of a unit.
GetMaxEncumbrance
function GetMaxEncumbrance(unit: object): number
eix Added by addon.dll.
Returns the load a unit can carry.
GetPerk
function GetPerk(unit: object, name: string): number
eix Added by addon.dll.
Returns the level of a perk of a unit. Names: sword, axe, dagger, spear, hammer, bow, crossbow, fire,
lightning, acid, illusion, divination, enchantments, healing, domination, infra, health, mana,
vitality, spirit, quickness, lift, backstab, strength, dexterity, intelligence.
GetSkill
function GetSkill(unit: object, name: string): number
eix Added by addon.dll.
Returns a skill or attribute of a unit: science, melee, archery, elemental, sense or astral.
GetStrength
function GetStrength(unit: object): number
eix Added by addon.dll.
Returns the strength of a unit.
GetUnitExp
function GetUnitExp(unit: object, what?: string): number
eix Added by addon.dll.
Returns the experience of a unit: max (the default), spent, penalty (the experience not yet added) or real
(experience plus penalty).
GiveDexterity
function GiveDexterity(unit: object, amount: number): void
Adds dexterity points to a unit. Zones only; works on enemies as well.
GiveExp
function GiveExp(player: number, amount: number): void
eix Added by addon.dll.
Awards experience to a player’s party.
GiveIntelligence
function GiveIntelligence(unit: object, amount: number): void
Adds intelligence points to a unit. Zones only; works on enemies as well.
GiveSkill
function GiveSkill(unit: object, skill: string, amount: number): void
Raises a skill (science, melee, archery, and so on) by amount points. The experience needed is added to the
unit, not to the party, and spent on the skill, so health and stamina follow.
GiveStrength
function GiveStrength(unit: object, amount: number): void
Adds strength points to a unit. Zones only; works on enemies as well.
GiveUnitExp
function GiveUnitExp(unit: object, amount: number): void
eix Added by addon.dll.
Awards experience to one unit.
Differs from the original: GiveUnitExp stops on a missing object (the original crashes)
HP
function HP(unit: object): number
Returns the unit’s current health, with the effects of weakening and strengthening spells.
HP - SpellAddon hptrans
function HP(unit: object, index: number): number
eix SpellAddon option [gameplay] hptrans.
Reads a float by index from the unit’s vitals. Valid indices are 0 to 29; the fields are listed under indexed stat readers.
InflictDamage
function InflictDamage(unit: object, amount: number): void
Deals damage to the unit, ignoring its armor. Experience is granted for a kill.
IsAlive
function IsAlive(unit: object): number
eix Added by addon.dll.
Returns 1 if the unit is alive. Returns 0 for a missing object or a non-unit. Replaces the game’s function.
IsDead
function IsDead(unit: object): number
eix Added by addon.dll.
Returns 1 if the unit is dead. Returns 0 for a missing object or a non-unit. Replaces the game’s function.
IsUnitBlocked
function IsUnitBlocked(unit: object): number
Returns 1 if the player’s control of the unit is blocked, otherwise 0.
KillUnit
function KillUnit(unit: object): void
Kills the unit. The party gets no experience for it.
Mana
function Mana(unit: object): number
Returns the unit’s current mana.
Mana - SpellAddon mptrans
function Mana(unit: object, index: number): number
eix SpellAddon option [gameplay] mptrans.
Reads a float from the unit’s stats, indices 0 to 448; an invalid object, controller or index returns 0. The fields are
listed under indexed stat readers. Also adds the index argument to HP, which
keeps its reader unless hptrans is 1.
MaxHP
function MaxHP(unit: object): number
Returns the unit’s maximum health, with the effects of weakening and strengthening spells.
MaxHP - SpellAddon legendaryspellsystem
function MaxHP(unit: object, index: number): number
eix SpellAddon option [gameplay] legendaryspellsystem.
Reads a byte, starting at the skill-byte area of the unit, indices 0 to 631; outside it returns 0.
Differs from the original: stays inside the unit (the original reads any address)
MaxMana
function MaxMana(unit: object): number
Returns the unit’s maximum mana.
MaxMana - SpellAddon legendaryspellsystem
function MaxMana(x1: number, y1: number, z1: number, x2: number, y2: number, z2: number, extra: number): number
eix SpellAddon option [gameplay] legendaryspellsystem.
Takes seven numeric arguments, but the option supplies no working path-query implementation.
WasLooted
function WasLooted(unit: object): number
Returns whether the unit was robbed or its corpse searched: 0 if not. Stealing a quest item does not change the result.
WasLooted - SpellAddon waslootedtrans
function WasLooted(unit: object, bit?: number): number
eix SpellAddon option [gameplay] waslootedtrans.
Value 1: returns the full flag word. Value 2: WasLooted(unit, bit) returns the selected bit. Known bits: 15 moving, 19
knocked out, 20 looted, 24 stunned, 28 feebleminded.
Orders and behaviour
Orders to units, their stances, and the behaviours of the AI.
AlarmPosX
function AlarmPosX(alarm: number): number
Returns the x coordinate of the point set for the alarm number by InvokeAlarm.
AlarmPosY
function AlarmPosY(alarm: number): number
Returns the y coordinate of the point set for the alarm number by InvokeAlarm.
AlarmTime
function AlarmTime(alarm: number): number
Returns the time counter of the alarm number, in 1/15 s units. The counter runs while the alarm is the active one.
Attack
function Attack(unit: object, target: object): void
Orders the unit to attack the target.
Crawl
function Crawl(unit: object): void
Sets the unit’s stance to crouching.
Crawl - SpellAddon crawltrans
function Crawl(unit: object, slot: number): void
eix SpellAddon option [gameplay] crawltrans.
Requests a weapon slot instead of setting the crawl style.
Follow
function Follow(unit: object, target: object): void
Orders the unit to follow the target once. The order ends after a fight. See UMFollow.
Guard
function Guard(unit: object, x: number, y: number, radius: number): void
Orders the unit to guard the area of the given radius around (x, y), moving about in it.
Idle
function Idle(unit: object): void
Drops all behaviours and the current order of the unit: it stands and does nothing.
InvokeAlarm
function InvokeAlarm(alarm: number, x: number, y: number): void
Raises the alarm with the given number at the point (x, y). Only one alarm is active at a time: a new number replaces
the previous one. Enemies with that alarm number in their .mob go to the point and guard it. InvokeAlarm(0, 0, 0)
clears the alarm, and they return to their places.
IsAlarm
function IsAlarm(alarm: number): number
Returns 1 if the alarm number has been raised, otherwise 0.
Lie
function Lie(unit: object): void
Sets the unit’s stance to lying down.
MoveToObject
function MoveToObject(unit: object, target: object): void
Orders the unit to walk, in its current stance, to the place where the target stands at this moment. The unit does not follow the target.
MoveToObject - SpellAddon movetoobjecttrans
function MoveToObject(unit: object, target: object, skill?: number, unused?: number, run?: number, slot?: number): void
eix SpellAddon option [gameplay] movetoobjecttrans.
Value 1: MoveToObject(unit, target) performs thieving while walking. Value 2: runs instead. Value 3 and up: the four
numbers after the target supply the thieving order.
MoveToPoint
function MoveToPoint(unit: object, x: number, y: number): void
Orders the unit to move to the point (x, y).
PlayAnimation
function PlayAnimation(unit: object, animation: string): void
Plays an animation from the unit’s .adb file (res/database.res/<mask name>.adb; the mask is in RaceModels.txt).
The first letter of the name sets the kind: u plays once, then back to normal; c loops, and the unit ignores
everything until the next order; s is one step of a movement. Families: uattack01..09, udeath01..31,
cidle01..09, ucast01..04, uhit01..21, crun01..02, cwalk01..09, ccrawl01, ucross01..09, scross01..09,
crest; humans also have ubriefing##, uspecial## and cspecial##. An unknown name does nothing.
ResetTarget
function ResetTarget(unit: object): void
eix Added by addon.dll.
Resets the unit’s perception and reapplies its alarm state. Resets all guard, patrol and aggression behaviours: call it before building a patrol or guard list. Replaces the game’s command.
Differs from the original: refuses a negative slot or a unit without a controller
Rest
function Rest(unit: object): void
Orders the unit to rest. It sits down when it can.
RotateTo
function RotateTo(unit: object, x: number, y: number): void
Turns the unit to face the point (x, y). Does nothing right after AddUnitToServer: the unit has to exist on the map
first.
Run
function Run(unit: object): void
Sets the unit’s stance to running.
Run - SpellAddon runtrans
function Run(unit: object, style: number): void
eix SpellAddon option [gameplay] runtrans.
Sets the requested movement style instead of always selecting run.
Sentry
function Sentry(unit: object, x: number, y: number): void
Orders the unit to guard the point (x, y) and attack the enemies it sees. It returns to the point afterwards.
SetEnemy
function SetEnemy(unit: object, diplomacyGroup: number): void
Makes the diplomatic group hostile to the unit, as if one of its members had attacked it. Units only.
SetPlayerAggression
function SetPlayerAggression(a: number, b: number): void
Does nothing.
SetSpellAggression
function SetSpellAggression(unit: object, aggression: number): void
Does nothing.
Stand
function Stand(unit: object): void
Sets the unit’s stance to walking, as Walk.
Stand - SpellAddon standtrans
function Stand(unit: object): void
eix SpellAddon option [gameplay] standtrans.
Also revives the unit. A non-unit argument causes no revival.
Differs from the original: does nothing for an argument that is not a unit (the original crashes)
StartAnimation
function StartAnimation(unit: object, path: string): void
Not implemented in game.exe: does nothing. Use PlayAnimation.
UMAg
function UMAg(unit: object, preset: number): void
Replaces the unit’s fear, aggression and suspicion behaviours with a preset: 0 always afraid (flees), 1 afraid (fear without the “always” flag), 2 revenge plus fear. Each preset also adds suspicion and corpse watching.
UMAggression
function UMAggression(unit: object): void
Adds aggression: the unit attacks the enemies it sees.
UMClear
function UMClear(unit: object): void
Removes all independent behaviours of the unit. The current order stays.
UMCorpseWatcher
function UMCorpseWatcher(unit: object): void
Adds corpse watching: the unit reacts to dead bodies.
UMFear
function UMFear(unit: object, always: number): void
Makes the unit never attack and try to hide from enemies, the default of neutral beasts. If always is nonzero, the
unit fears the player for good.
UMFollow
function UMFollow(unit: object, target: object): void
Orders the unit to follow the target for good. The order survives a fight. See Follow.
UMGuard
function UMGuard(unit: object, x: number, y: number, radius: number): void
Makes the unit guard the point (x, y) within the radius.
UMGuardEx
function UMGuardEx(unit: object, x: number, y: number, radius: number, delay: number): void
Makes the unit guard the point (x, y) within the radius, pausing for delay at random stopping points.
UMPatrol
function UMPatrol(unit: object): void
Adds a patrol behaviour. The command raises an error in the game. To make a unit patrol, call ResetTarget, then
UMPatrolAddPoint.
UMPatrolAddPoint
function UMPatrolAddPoint(unit: object, x: number, y: number): void
Adds the patrol point (x, y). Does nothing when the unit has no patrol behaviour. Add UMPatrolAddPointLook after it to
make the unit wait there.
UMPatrolAddPointLook
function UMPatrolAddPointLook(unit: object, x: number, y: number, delay: number): void
Sets the point (x, y) the unit looks at, and the time delay it stays, at the last patrol point.
UMPatrolClear
function UMPatrolClear(unit: object): void
Removes all patrol points of the unit. ResetTarget also resets the other behaviours.
UMPlayer
function UMPlayer(unit: object): void
Makes the unit obey the rules of a player’s unit, which gives sensible behaviour. Briefing zones use it for scripted NPCs. Clears the unit’s other behaviours and orders.
UMRevenge
function UMRevenge(unit: object): void
Gives the unit conditional fear: it runs away from everyone hostile and fights only when wounded or cornered.
UMSentry
function UMSentry(unit: object, x: number, y: number): void
Makes the unit guard the point (x, y) and attack the enemies it sees. It returns to the point afterwards.
UMStandard
function UMStandard(unit: object): void
Gives the unit the behaviour of a standard enemy: aggression, suspicion and corpse watching.
UMSuspection
function UMSuspection(unit: object): void
Adds suspicion: the unit goes to the nearest enemy it sees.
WaitEndAnimation
function WaitEndAnimation(): void
Not implemented in game.exe: does nothing.
Walk
function Walk(unit: object): void
Sets the unit’s stance to walking.
Spells
Casting spells and giving them to units.
Cast
function Cast(unit: object, x: number, y: number): void
Makes the unit cast its active area spell at the point (x, y). The spell must be one meant for a place, not for targets.
Cast - SpellAddon castscripttrans
function Cast(unit: object, x: number, y: number, spell: number, target?: object): void
eix SpellAddon option [gameplay] castscripttrans.
Value 1: Cast(unit, x, y, spell) uses the numbered spell. Value 2: with target, casts on the target if there is one,
otherwise at the point.
Differs from the original: value 2 reads its target from the running command (the original: a stale value)
CastSpellPoint
function CastSpellPoint(spell: string, x1: number, y1: number, x2: number, y2: number): void
Casts a terrain spell by its name: the effect starts at (x1, y1) and lands at (x2, y2). Area spells only.
CastSpellPoint - SpellAddon castspellpointtrans
function CastSpellPoint(spell: string, x1: number, y1: number, x2: number, y2: number, caster: object): void
eix SpellAddon option [gameplay] castspellpointtrans.
Adds a caster unit to the named-spell command.
CastSpellUnit
function CastSpellUnit(spell: string, x: number, y: number, unit: object): void
Casts a spell on a unit. The visual effect starts at (x, y).
CastSpellUnit - SpellAddon castspellunittrans
function CastSpellUnit(spell: string, x: number, y: number, target: object, caster: object): void
eix SpellAddon option [gameplay] castspellunittrans.
Adds a caster unit to the named-spell command.
GiveUnitSpell
function GiveUnitSpell(unit: object, spell: string): void
Puts the spell into the unit’s set of active spells. Nothing happens when the set is full. Does not work in the shop; in a zone the spell is given, but the panel does not refresh.
GiveUnitSpell - SpellAddon giveunitspelltrans
function GiveUnitSpell(unit: object, name: string): void
eix SpellAddon option [gameplay] giveunitspelltrans.
Creates and adds a quick item instead of a spell, from the same unit and name arguments.
Players, parties and diplomacy
Players, their parties, and the relations between diplomatic groups.
AddUnitToParty
function AddUnitToParty(player: number, name: string, unit: string): void
Adds a localized character to a party; name is PartyName::NamePersRes.
AddUnitUnderControl
function AddUnitUnderControl(player: number, unit: object): void
Adds the unit’s icon to the player’s control panel. Diplomacy does not change.
CopyItems
function CopyItems(player: number, from: string, to: string): void
Copies the equipment (not the wagon, not the backpack) of a member of the current party to a member of another party of
the same player. to is PartyName::Name.
CopyStats
function CopyStats(player: number, from: string, to: string): void
Copies the skills, abilities and parameters of a member of the current party to a member of another party of the same
player. to is PartyName::Name.
CreateParty
function CreateParty(player: number, name: string): void
Creates a party for the player. A party of the same name is replaced. The name is case-sensitive.
GetDiplomacy
function GetDiplomacy(groupA: number, groupB: number): number
Returns what group A is to group B: 1 ally, 0 neutral, -1 enemy.
GetMercsNumber
function GetMercsNumber(player: number): number
Returns the number of mercenaries in the player’s current party, the leader not counted.
GetPlayer
function GetPlayer(unit: object): number
Returns the diplomatic group of the unit.
GetPlayer - SpellAddon getplayertrans
function GetPlayer(unit: object, index: number): number
eix SpellAddon option [gameplay] getplayertrans.
Reads a 32-bit integer at four times the index within the unit (0 to 310); returns 0 outside it.
Differs from the original: returns 0 outside the unit (the original reads any address)
GetPlayerOfUnit
function GetPlayerOfUnit(unit: object): number
eix Added by addon.dll.
Returns the number of the player the unit belongs to, or -1.
GetUnitOfPlayer
function GetUnitOfPlayer(player: number, index: number): object
Returns the unit at position index in the player’s current party, in the order the units joined.
IsEnemy
function IsEnemy(unit: object, diplomacyGroup: number): number
Returns 1 if the unit is an enemy of the diplomatic group, otherwise 0.
IsPlayer
function IsPlayer(unit: object): number
eix Added by addon.dll.
Returns 1 if the named unit belongs to a player, otherwise 0.
IsPlayerInDanger
function IsPlayerInDanger(player: number): number
Returns 1 if the player’s danger state is “in danger”, otherwise 0 (also for a player that does not exist). The state
has three values: safe, an in-between value, and in danger; at the in-between value both this and IsPlayerInSafety
return 0.
IsPlayerInSafety
function IsPlayerInSafety(player: number): number
Returns 1 if the player’s danger state is “safe”, otherwise 0 (also for a player that does not exist). Not the opposite
of IsPlayerInDanger: at the state’s in-between value both return 0.
PlayerExists
function PlayerExists(player: number): number
eix Added by addon.dll.
Returns 1 if the player exists, otherwise 0.
RedeployParty
function RedeployParty(player: number): void
Finishes the change of the current party.
RemoveParty
function RemoveParty(player: number, name: string): void
Removes the party.
RemoveUnitFromControl
function RemoveUnitFromControl(player: number, unit: object): void
Removes the unit’s icon from the player’s control panel.
RemoveUnitFromParty
function RemoveUnitFromParty(player: number, name: string): void
Removes a character from its party. PartyName::Name reaches a party other than the current one.
SendCurrentParty
function SendCurrentParty(player: number): void
eix Added by addon.dll.
Resends the player’s party state.
Differs from the original: SendCurrentParty stops on a missing object (the original crashes)
SetCurrentParty
function SetCurrentParty(player: number, name: string): void
Makes the party the player’s current one.
SetDiplomacy
function SetDiplomacy(groupA: number, groupB: number, relation: number): void
Sets the relation between two diplomatic groups: 1 ally, 0 neutral, -1 enemy. The player’s party is always group 0.
SetPlayer
function SetPlayer(unit: object, diplomacyGroup: number): void
Assigns the unit to a diplomatic group.
SetPlayer - SpellAddon setplayertrans
function SetPlayer(unit: object, value: number, field: number): void
eix SpellAddon option [gameplay] setplayertrans.
Writes a rounded 32-bit integer at four times field within the unit (0 to 310). Fields 132 to 148 keep the game’s
normal player-setting path; a write outside the unit is ignored.
Differs from the original: stores nothing outside the unit (the original writes any address)
Items and money
Items, quest items, wagons and money.
AddLoot
function AddLoot(player: number, from: string, to: string): void
Moves all items and gold from the wagon of a party to the wagon of another party of the same player.
CopyLoot
function CopyLoot(player: number, from: string, to: string): void
Copies the wagon (items and gold) of a party to the wagon of another party, which is emptied first. Do not confuse wagon
and backpack: RedeployParty empties the sender’s backpack, and the new party’s one stays empty, though its items still
show in the window.
EraseQuestItem
function EraseQuestItem(player: number, id: number): void
Removes a quest item from the player’s wagon.
FixItems
function FixItems(): void
Repairs every item of the current party: wagon, backpack, worn equipment and weapons.
GetLootItemsCount
function GetLootItemsCount(player: number): number
Returns how many item lines the current party has picked up in the zone, found, stolen or taken from enemies and corpses, quest items included. Money does not count, and identical items picked up one at a time each count.
GetMoney
function GetMoney(player: number): number
Returns the money of the player’s current party.
GiveItem
function GiveItem(player: number, item: string): void
Gives a regular item to the player’s backpack.
GiveMoney
function GiveMoney(player: number, amount: number): void
Adds money to the player’s party. Does not work in a shop.
GiveQuestItem
function GiveQuestItem(player: number, item: string): void
Gives a quest item to the player.
GiveQuestItem - SpellAddon legendaryspellsystem
function GiveQuestItem(unit: object, value: number): void
eix SpellAddon option [gameplay] legendaryspellsystem.
Writes byte 10 of the unit’s skill-byte area.
GiveUnitArmor
function GiveUnitArmor(unit: object, name: string, override: number): void
eix Added by addon.dll.
Creates an armor and equips the unit with it. override 1 also updates a non-named unit’s natural protection.
Differs from the original: stops on a missing object (the original crashes)
GiveUnitQuestItem
function GiveUnitQuestItem(unit: object, item: string): void
Puts a quest item into the unit’s backpack, such as a chest’s contents. For a member of the player’s party it goes to the party’s wagon.
GiveUnitWeapon
function GiveUnitWeapon(unit: object, name: string, override: number): void
eix Added by addon.dll.
Creates a weapon and equips the unit with it. override 1 also updates a non-named unit’s natural attack.
Differs from the original: stops on a missing object (the original crashes)
HaveItem
function HaveItem(player: number, id: number): number
Returns 1 if the player has the quest item in the wagon or the backpack, otherwise 0.
Loot
function Loot(player: number, unit: object): void
eix Added by addon.dll.
Loots the dead unit and removes it.
RemoveQuestItem
function RemoveQuestItem(unit: object, id: number): void
Removes a quest item from the unit’s backpack. Only items given by GiveUnitQuestItem or listed in the .mob file’s
QuestItems are removed.
Quests
Dynamic quests of multiplayer zones.
QFinish
function QFinish(): void
Completes the quest started by QStart. In single player the quest’s experience is paid too.
QObjArea
function QObjArea(area: number): void
Quest objective: enter the area. The area is a virtual object made of all the parts with that ID, usually area 1.
QObjGetItem
function QObjGetItem(id: number): void
Quest objective: get the quest item with the ID. A macro for ordinary commands.
QObjKillGroup
function QObjKillGroup(group: string): void
Quest objective: kill the whole game group, given by the name of its global variable.
QObjKillUnit
function QObjKillUnit(unitName: string): void
Quest objective: kill the named unit. A macro for ordinary commands.
QObjSeeObject
function QObjSeeObject(objectName: string): void
Quest objective: see the named object, a chest and not a unit. A macro for ordinary commands.
QObjSeeUnit
function QObjSeeUnit(unitName: string): void
Quest objective: see the named unit. A macro for ordinary commands.
QObjUse
function QObjUse(lever: string, state: number): void
Quest objective: put the lever into the state. A macro for ordinary commands.
QStart
function QStart(name: string): void
Starts a dynamic multiplayer quest and opens its list of objectives, which ends with QFinish.
QuestComplete
function QuestComplete(player: number, name: string): void
Completes the quest and pays its experience, like QFinish but without the message in the info window.
Player variables
Named numeric variables that belong to a player.
GSDelVar
function GSDelVar(player: number, name: string): void
Deletes a variable of the player.
GSGetPlayerVar
function GSGetPlayerVar(player: number, name: string): number
eix Added by addon.dll.
Returns a numeric variable of a player.
GSGetVar
function GSGetVar(player: number, name: string): number
Returns the value of a variable of the player. Works differently in single and multiplayer.
Differs from the original: a name ini.<file>.<section>.<key> reads that value of <file>.ini in the mod or game
folder, 0 when missing (INI variables)
GSGetVar - SpellAddon gsgetvar
function GSGetVar(player: number, name: string): number
eix SpellAddon option [speed] gsgetvar.
Returns the difficulty for names that begin with Diff, and the update period for names whose characters 4 to 7
(zero-based) are peed, such as SetSpeed.
Differs from the original: reads the variable’s name before freeing it
GSListPlayerVars
function GSListPlayerVars(player: number): void
eix Added by addon.dll.
Prints the variables of a player.
Differs from the original: stops on a missing object (the original crashes)
GSSetPlayerVar
function GSSetPlayerVar(player: number, name: string, value: number): void
eix Added by addon.dll.
Sets a numeric variable of a player.
Differs from the original: GSSetPlayerVar stops on a missing object (the original crashes)
GSSetVar
function GSSetVar(player: number, name: string, value: number): void
Sets a variable of the player. Works differently in single and multiplayer.
GSSetVar - SpellAddon gssetvar
function GSSetVar(player: number, name: string, value: number): void
eix SpellAddon option [speed] gssetvar.
Also sets the update period for names with peed at characters 4 to 7. The variable is still stored normally.
GSSetVarMax
function GSSetVarMax(player: number, name: string, value: number): void
Sets a variable of the player only when the new value is higher than the stored one.
World, effects and sound
Levers, areas, time, weather, lights, particles, sound, music, movies and the camera.
ActivateTrap
function ActivateTrap(trap: object, activate: number): void
Activates a trap on the map if activate is nonzero, deactivates it if 0. Traps attack only diplomatic group 0.
AddRectToArea
function AddRectToArea(area: number, x1: number, y1: number, x2: number, y2: number): void
Adds a rectangle, given by two opposite corners, to a quest area.
AddRoundToArea
function AddRoundToArea(area: number, x: number, y: number, radius: number): void
Adds a circle to a quest area.
AttachParticles
function AttachParticles(id: number, unit: object): void
Attaches the particle source to the unit. It follows the unit with the offset given in CreateParticleSource.
AttachParticleSource
function AttachParticleSource(id: number, unitId: number): void
Attaches the particle source to the unit with the ID unitId. It follows the unit with the offset given in
CreateParticleSource.
CreateFX
function CreateFX(x: number, y: number, z: number, volume: number, radius: number, wav: string): void
Plays a WAV file once at (x, y, z), audible within the radius.
CreateFXSource
function CreateFXSource(id: number, x: number, y: number, z: number, volume: number, radius: number, wav: string): void
Creates a looping sound source at (x, y, z).
CreateLightning
function CreateLightning(id: number, x1: number, y1: number, z1: number, x2: number, y2: number, z2: number, intensity: number): void
Creates a lightning that stays, from (x1, y1, z1) to (x2, y2, z2). A positive intensity ends the bolt in a ball, as if it hit an object.
CreateParticleSource
function CreateParticleSource(id: number, x: number, y: number, z: number, radius: number, type: string): void
Creates a particle source of the given type at (x, y, z). A negative radius flips the source upside down.
CreatePointLight
function CreatePointLight(id: number, x: number, y: number, z: number, radius: number, r: number, g: number, b: number): void
Creates a point light of the given color at (x, y, z). A torch or a campfire at night is a light; a dim one darkens a dense forest by day.
CreateRandomizedFXSource
function CreateRandomizedFXSource(id: number, x1: number, x2: number, y1: number, y2: number, z1: number, z2: number, volume: number, radius: number, wav: string): void
Creates a looping sound source placed at random inside the box x1..x2, y1..y2, z1..z2. Remove it with DeleteFXSource.
DeleteArea
function DeleteArea(area: number): void
Deletes every part of the quest area.
DeleteFXSource
function DeleteFXSource(id: number): void
Deletes all sound sources with the ID.
DeleteLightning
function DeleteLightning(id: number): void
Deletes all lightnings with the ID.
DeleteParticleSource
function DeleteParticleSource(id: number): void
Deletes all particle sources with the ID.
DeletePointLight
function DeletePointLight(id: number): void
Deletes all point lights with the ID.
EnableLever
function EnableLever(lever: object, enable: number): void
Lets the player use a lever (1) or not (0). A usable lever shows the grabbing-hand cursor.
FixWorldTime
function FixWorldTime(time: number): void
Sets the time of day and stops the clock.
FixWorldTime - SpellAddon fixworldtimetrans
function FixWorldTime(time: number, speed: number): void
eix SpellAddon option [gameplay] fixworldtimetrans.
Adds an explicit time-speed argument.
GetLeverState
function GetLeverState(lever: object): number
Returns 1 if the lever is on, 0 if it is off.
GetWorldTime
function GetWorldTime(): number
Returns the time of day, in hours.
IsCameraPlaying
function IsCameraPlaying(): number
Returns 1 if a camera path file is playing now, otherwise 0.
IsNight
function IsNight(): number
Returns how dark it is, from 0 to 1, by the game’s hour of day: 0 from 8:00 to 20:00, rising evenly from 0 at 20:00 to 1 at 24:00, and 1 from 0:00 until 8:00, when it drops to 0 at once. The server updates it every tick.
MoveParticleSource
function MoveParticleSource(id: number, x: number, y: number, z: number, time: number, remove: number): void
Moves the particle source to (x, y, z) over the time, in 1/15 s units. If remove is nonzero, the source is deleted on
arrival.
MovePointLight
function MovePointLight(id: number, x: number, y: number, z: number, time: number, remove: number): void
Moves the point light to (x, y, z) over the time, in 1/15 s units. If remove is nonzero, the light is deleted on
arrival.
PlayCamera
function PlayCamera(name: string): void
Starts the automatic camera path in the file CAMERA\<name>.
PlayFX
function PlayFX(x: number, y: number, z: number, radius: number, wav: string): void
Not implemented in game.exe: does nothing.
PlayMovie
function PlayMovie(name: string): void
Plays the video MOVIES\<name>, the name with its extension.
PlayMusic
function PlayMusic(player: number, name: string): void
Plays the piece STREAM\<name> for the player, the name without its extension. The name 0 turns the zone’s music off,
1 on.
PlayMusic - SpellAddon playmusictrans
function PlayMusic(player: number, name: string): void
eix SpellAddon option [gameplay] playmusictrans.
Values 1 and 2: the name "0" or "1" re-selects the local map’s music theme and sets the music system’s level to the
digit. The first character selects this behavior. Value 1 uses the map’s theme, value 2 its alternative name field.
Other text, or no map or music system, uses normal handling.
Differs from the original: without a map or a music system, does what the game does (the original crashes)
RunWorldTime
function RunWorldTime(hour: number): void
Sets the time of day and lets the clock run at normal speed.
SetBackGroundColor
function SetBackGroundColor(r: number, g: number, b: number): void
Sets the color the screen is cleared to, which is the sky behind everything. Each value is 0 to 255.
SetCameraOrientation
function SetCameraOrientation(angle: number): void
Not implemented in game.exe: does nothing.
SetCameraPosition
function SetCameraPosition(x: number, y: number, z: number): void
Not implemented in game.exe: does nothing.
SetDirectionToObject
function SetDirectionToObject(unit: number): void
Not implemented in game.exe: does nothing.
SetParticleSourceSize
function SetParticleSourceSize(id: number, radius: number): void
Changes the radius of the particle source.
SetScience
function SetScience(lever: object, questItem: number, skill: number, hands: number, lockpick: number, crowbar: number, key: number): void
Sets how a lever can be switched: with the quest item, with that much Sleight of hand, and by hands, lockpick, crowbar or key (1 allowed, 0 not).
SetSunLight
function SetSunLight(sunR: number, sunG: number, sunB: number, ambientR: number, ambientG: number, ambientB: number, skyR: number, skyG: number, skyB: number): void
Not implemented in game.exe: does nothing.
SetWaterLevel
function SetWaterLevel(basin: number, level: number, delay: number): void
Sets the water level of a basin, relative to its bottom, after the delay. Does not change where the party can wade.
SetWeather
function SetWeather(name: string): void
eix Added by addon.dll.
Sets the weather: rain or snow, exact and lowercase. Any other text clears the weather.
SetWind
function SetWind(x: number, y: number, z: number, force: number): void
Makes a gust of wind blow toward the point (x, y, z) with the given force.
ShowBitmap
function ShowBitmap(id: number, bitmap: string): void
Not implemented in game.exe: does nothing.
ShowCredits
function ShowCredits(text: string): void
Does nothing.
SwitchLeverState
function SwitchLeverState(lever: object, state: number): void
Puts the lever into the off (0) or on (1) position. GetLeverState reads it.
SwitchLeverStateEx
function SwitchLeverStateEx(lever: object, state: number, delay: number): void
Like SwitchLeverState, with a delay before the animation.
Game and system
Zone changes, game modes, game end and files.
GameOver
function GameOver(): void
eix Added by addon.dll.
Ends player 0’s game with the default title and text, the text keys game_over and game_over_msg.
GameOverMSG
function GameOverMSG(title: string, text: string): void
eix Added by addon.dll.
Ends player 0’s game with the given text keys for title and text.
GodMode
function GodMode(player: number, mode: number): void
Sets the mode of the player’s current party: 0 normal, 1 invulnerable when running and mana is free, 2 like 1, and every hit kills.
IsFileExists
function IsFileExists(path: string): number
eix Added by addon.dll.
Tests whether a file exists under the mod folder. A path that climbs to a parent folder is refused.
GSGetIniNumber
function GSGetIniNumber(file: string, section: string, key: string, default: number): number
eix Added by addon.dll.
Reads a value from an INI file of the mod folder, at the call, as a number; default when the file, section or key is
missing or the value is not a number. The file is a path below the mod folder, with / or \ as separators; an
absolute path, a drive letter or a .. component is refused and gives default. The decimal point is . or ,. File,
section and key are matched without regard to case. A missing value or a refusal is logged once per file, section and
key.
GSGetIniString
function GSGetIniString(file: string, section: string, key: string, default: string): string
eix Added by addon.dll.
Reads a value from an INI file of the mod folder, at the call, as text; default when the file, section or key is
missing. The path and matching rules are those of GSGetIniNumber. A key with an empty value gives an empty string.
KillUnit - SpellAddon killunittrans
function KillUnit(kind: number, strength: number): void
eix SpellAddon option [gameplay] killunittrans.
Sets the weather with two rounded numbers instead of killing a unit.
LeaveToZone
function LeaveToZone(player: number, zone: string, entry: number): void
Moves the player, every party and the wagon, to the zone, at its entry place entry (the numbers are in
Res/texts.res/map.txt).
PauseGame
function PauseGame(value: number): void
eix Added by addon.dll.
Outside multiplayer, 0 requests a pause and any other value unpauses.
RecalcMercBriefings
function RecalcMercBriefings(): void
Single player: recalculates which dialogues the companions and candidates offer.
ShowAllUnits
function ShowAllUnits(value: number): void
eix Added by addon.dll.
0 draws all units; any other value restores normal visibility.
StartCameraSave
function StartCameraSave(file: string): void
eix Added by addon.dll.
Starts recording a camera path to a file.
StopCameraSave
function StopCameraSave(): void
eix Added by addon.dll.
Stops recording the camera path.
Lua
With [Addon] EnableLuaScripts set in the mod’s ai.reg, addon.dll runs the mod’s Lua script and calls it from nine
patch groups. The other ai.reg settings are under addon and loader.
The last column of the table below gives eix’s difference from addon.dll 0.12.4.2, with what the original does in parentheses.
Host
Set [Addon] EnableLuaScripts nonzero and supply LuaMainScriptPath (default main.lua). The host is LuaJIT 2.1,
with bit and jit loaded as globals; load ffi with require("ffi"). Module search paths include the mod root
and its lua folder. Define only the callbacks the mod changes: once the main script has run, each group hooks the
game where the script defines a callback, and the game’s own code runs for the rest. A callback defined later is
not hooked. addon.log lists the callbacks found. A reported Lua error shows a message, logs its traceback, and exits.
Pointers are passed as signed 32-bit integers; raw memory operations require valid game memory.
| Behaviour | eix |
|---|---|
| LuaJIT build | a newer LuaJIT 2.1 (the original: 2.1.0-beta3) |
| A callback the script does not define | the game’s own code runs there (the original hooks every site of the nine groups and stops with a Lua error at the first call) |
| A Lua error | the message is shown as text (the original treats it as a printf format, so %d is consumed); the box is titled addon.dll; the message and its traceback also go to addon.log (the original logs nothing) |
| Lua state at exit | not closed at exit, since a fatal error box exits from inside a Lua call |
Callbacks and functions
The Lua reference lists the callbacks the mod defines, with the patch group that calls each, and the functions eix supplies. Each entry has its LuaLS signature and its difference from addon.dll 0.12.4.2. The same declarations ship as the definitions file eix.lua for the Lua language server.
Editor setup
With the definitions file, an editor running the Lua language server (LuaLS) completes eix’s functions, shows their documentation on hover and checks the arguments of each call.
- Install the language server’s plugin: in VS Code, the Lua extension (
sumneko.lua); other editors runlua-language-server. - From the
docsfolder of the release package, puteix.luain the game folder, besidegame.exe, and.luarc.jsonin the mod folder (Mods\<mod>). Open the mod folder in the editor. The site has eix.lua too.
The .luarc.json names the definitions file relative to the mod folder:
{
"$schema": "https://raw.githubusercontent.com/LuaLS/vscode-lua/master/setting/schema.json",
"runtime.version": "LuaJIT",
"workspace.library": ["../../eix.lua"]
}
A mod folder outside the game’s Mods folder names the file by its full path instead. A mod that has a .luarc.json
already takes the two settings into it. After an eix update, replace eix.lua with the one from the new release.
Lua reference
The Lua API of a mod’s main script: the functions addon.dll registers before the script runs, and the callbacks the
script defines. Lua says how the host runs the script. The declarations below are annotations for the Lua
language server (LuaLS); the same text is the definitions file eix.lua, in the docs folder of the release
package: editor setup says how to give it to the server for completion and type checks.
Types
The one type of this API that is not a Lua built-in.
Pointer
---@alias Pointer integer
A game address, passed as the 32 bits of the address read as a signed integer: an address above 2 GB is negative. Raw memory functions need an address that holds valid game memory. A record or slot index is zero-based and must lie inside the table or the slots.
Functions supplied by eix
Global functions that addon.dll registers before the main script runs. A signed 32-bit integer argument is read as Lua’s
luaL_checkinteger reads it: a number or a numeric string, truncated. A bad argument raises LuaJIT’s usual argument
error.
Round
---@param value number
---@return number
function Round(value) end
Rounds half away from zero.
IDiv
---@param a integer
---@param b integer
---@return integer
function IDiv(a, b) end
Signed integer quotient. A zero divisor or an overflow ends the game.
IMod
---@param a integer
---@param b integer
---@return integer
function IMod(a, b) end
Signed integer remainder. A zero divisor or an overflow ends the game.
GetEffectValue
---@param unit Pointer
---@param effect integer
---@return number
function GetEffectValue(unit, effect) end
The strength of an effect on a unit.
GetPerkModifierForServer
---@param stats Pointer
---@param perk integer
---@return number
function GetPerkModifierForServer(stats, perk) end
The modifier of a perk, read from a unit’s stats on the server.
GetPerkModifierForClient
---@param params Pointer
---@param perk integer
---@return number
function GetPerkModifierForClient(params, perk) end
The modifier of a perk, read from a unit’s parameters on a client.
Heal
---@param stats Pointer
---@param vitals Pointer
---@param amount number
function Heal(stats, vitals, amount) end
Heals the body slots and recomputes the total health.
RegenMp
---@param vitals Pointer
---@param fraction number
function RegenMp(vitals, fraction) end
Adds the maximum mana times fraction, capped at the maximum mana.
DistributeHp
---@param stats Pointer
---@param maxHp number
function DistributeHp(stats, maxHp) end
Sets the body slots’ maxima from maxHp and clamps their current health.
CollectHp
---@param stats Pointer
---@param maxHp number
---@return number
function CollectHp(stats, maxHp) end
Computes the total health from the body slots.
GetPerkRecord
---@param index integer
---@return Pointer
function GetPerkRecord(index) end
The perk record at index, or 0 past the table.
GetWeaponRecord
---@param index integer
---@return Pointer
function GetWeaponRecord(index) end
The weapon record at index, or 0 past the table.
GetArmorRecord
---@param index integer
---@return Pointer
function GetArmorRecord(index) end
The armor record at index, or 0 past the table.
GetMaterialRecord
---@param index integer
---@return Pointer
function GetMaterialRecord(index) end
The material record at index, or 0 past the table.
GetQuickRecord
---@param index integer
---@return Pointer
function GetQuickRecord(index) end
The quick-item record at index, or 0 past the table.
GetSpellRecord
---@param index integer
---@return Pointer
function GetSpellRecord(index) end
The spell record at index, or 0 past the table.
GetRuneRecord
---@param index integer
---@return Pointer
function GetRuneRecord(index) end
The rune record at index, or 0 past the table.
GetPerksTableSize
---@return integer
function GetPerksTableSize() end
The number of perk records.
GetWeaponsTableSize
---@return integer
function GetWeaponsTableSize() end
The number of weapon records.
GetArmorsTableSize
---@return integer
function GetArmorsTableSize() end
The number of armor records.
GetMaterialsTableSize
---@return integer
function GetMaterialsTableSize() end
The number of material records.
GetQuicksTableSize
---@return integer
function GetQuicksTableSize() end
The number of quick-item records.
GetSpellsTableSize
---@return integer
function GetSpellsTableSize() end
The number of spell records.
GetRunesTableSize
---@return integer
function GetRunesTableSize() end
The number of rune records.
GetPerkIndex
---@param record Pointer
---@return integer
function GetPerkIndex(record) end
The index of a perk record, or -1 if it is not found.
GetSpellIndex
---@param record Pointer
---@return integer
function GetSpellIndex(record) end
The index of a spell record, or -1 if it is not found.
GetRuneIndex
---@param record Pointer
---@return integer
function GetRuneIndex(record) end
The index of a rune record, or -1 if it is not found.
GetClassId
---@param object Pointer
---@return integer
function GetClassId(object) end
The class ID of an object.
GetItemsWeight
---@param unit Pointer
---@return number
function GetItemsWeight(unit) end
The total weight of a unit’s equipped items.
GetItemShapeEntry
---@param item Pointer
---@return Pointer
function GetItemShapeEntry(item) end
The prototype record of an item.
GetWeapon
---@param unit Pointer
---@param slot integer
---@return Pointer
function GetWeapon(unit, slot) end
The weapon in a slot (0 to 3) of a unit, or 0 if the slot is empty or out of range.
GetArmor
---@param unit Pointer
---@param slot integer
---@return Pointer
function GetArmor(unit, slot) end
The armor in a slot (0 to 6) of a unit, or 0 if the slot is empty or out of range.
GetQuick
---@param unit Pointer
---@param slot integer
---@return Pointer
function GetQuick(unit, slot) end
The quick item in a slot (0 to 3) of a unit, or 0 if the slot is empty or out of range.
GetSpell
---@param unit Pointer
---@param slot integer
---@return Pointer
function GetSpell(unit, slot) end
The spell in a slot (0 to 7) of a unit, or 0 if the slot is empty or out of range.
ConsoleWriteLine
---@param text string
function ConsoleWriteLine(text) end
Writes a line to the console.
GetGSVar
---@param unit Pointer
---@param name string
---@return number? value `nil` if the unit has no player or the variable does not exist.
function GetGSVar(unit, name) end
Reads a variable of the unit’s player. Names are case-sensitive.
SetGSVar
---@param unit Pointer
---@param name string
---@param value number
function SetGSVar(unit, name, value) end
Writes a variable of the unit’s player. Names are case-sensitive.
UnitIsHost
---@param unit Pointer
---@return boolean
function UnitIsHost(unit) end
Tests whether the unit belongs to the hosting player.
TempDumpVars
---@param unit Pointer
function TempDumpVars(unit) end
Prints every variable of the unit’s player to the console.
FloatFromMem
---@param address Pointer
---@return number
function FloatFromMem(address) end
Reads a 32-bit float.
DoubleFromMem
---@param address Pointer
---@return number
function DoubleFromMem(address) end
Reads a 64-bit float.
Int8FromMem
---@param address Pointer
---@return integer
function Int8FromMem(address) end
Reads a signed 8-bit integer.
Int16FromMem
---@param address Pointer
---@return integer
function Int16FromMem(address) end
Reads a signed 16-bit integer.
Int32FromMem
---@param address Pointer
---@return integer
function Int32FromMem(address) end
Reads a signed 32-bit integer.
UInt8FromMem
---@param address Pointer
---@return integer
function UInt8FromMem(address) end
Reads an unsigned 8-bit integer.
UInt16FromMem
---@param address Pointer
---@return integer
function UInt16FromMem(address) end
Reads an unsigned 16-bit integer.
UInt32FromMem
---@param address Pointer
---@return integer
function UInt32FromMem(address) end
Reads a 32-bit integer. The result is the signed reading, as for Int32FromMem.
FloatToMem
---@param address Pointer
---@param value number
function FloatToMem(address, value) end
Writes a 32-bit float.
DoubleToMem
---@param address Pointer
---@param value number
function DoubleToMem(address, value) end
Writes a 64-bit float.
Int8ToMem
---@param address Pointer
---@param value integer
function Int8ToMem(address, value) end
Writes the low 8 bits of an integer.
Int16ToMem
---@param address Pointer
---@param value integer
function Int16ToMem(address, value) end
Writes the low 16 bits of an integer.
Int32ToMem
---@param address Pointer
---@param value integer
function Int32ToMem(address, value) end
Writes a 32-bit integer.
UInt8ToMem
---@param address Pointer
---@param value integer
function UInt8ToMem(address, value) end
Writes the low 8 bits of an integer.
UInt16ToMem
---@param address Pointer
---@param value integer
function UInt16ToMem(address, value) end
Writes the low 16 bits of an integer.
UInt32ToMem
---@param address Pointer
---@param value integer
function UInt32ToMem(address, value) end
Writes the 32 bits of an integer, converted as Int32ToMem converts it.
StrFromMem
---@param address Pointer
---@return string? text `nil` if the stored pointer is null.
function StrFromMem(address) end
Reads the string pointer stored at address, then the NUL-terminated text it points to.
GetIniValue
---@param file string
---@param section string
---@param key string
---@return string? value `nil` if the path is refused or the file, section or key is missing.
function GetIniValue(file, section, key) end
Reads a value from an INI file of the mod folder, at the call. File, section and key are matched without regard to case.
The file is a path below the mod folder, with / or \ as separators; an absolute path, a drive letter or a ..
component is refused with a warning in addon.log, as is a missing value (once per file, section and key). Convert a
number with tonumber, which wants a . as the decimal point.
Callbacks supplied by the mod
Global functions that the main script defines, each called by the patch group named in its description. Every callback is optional: where the script defines none, the game’s own code runs. A callback that returns nothing updates the structures it receives through their addresses.
GetSkillPriceDiff
---@param from integer
---@param to integer
---@return integer cost
function GetSkillPriceDiff(from, to) end
Group LuaGetPerkPrice. The experience cost of a skill step.
GetPerkPrice
---@param stats Pointer
---@param perkRecord Pointer
---@return integer cost
function GetPerkPrice(stats, perkRecord) end
Group LuaGetPerkPrice. The experience cost of a perk.
GetModifiedDamageOnServer
---@param stats Pointer
---@param unit Pointer
---@param damage number
---@return number damage
function GetModifiedDamageOnServer(stats, unit, damage) end
Group LuaGetModifiedDamage. The damage a unit takes on the server, without the game’s floor of 1.
GetModifiedDamageOnClient
---@param stats Pointer
---@param unit Pointer
---@param damage number
---@return number damage
function GetModifiedDamageOnClient(stats, unit, damage) end
Group LuaGetModifiedDamage. The damage a unit takes on a client, without the game’s floor of 1.
CalcBaseHealth
---@param stats Pointer
---@return number health
function CalcBaseHealth(stats) end
Group LuaRecalcUnitStats. The base health of a unit.
CalcBaseMana
---@param stats Pointer
---@return number mana
function CalcBaseMana(stats) end
Group LuaRecalcUnitStats. The base mana of a unit.
GetModifiedHealth
---@param stats Pointer
---@param unit Pointer
---@param hp number
---@return number health
function GetModifiedHealth(stats, unit, hp) end
Group LuaRecalcUnitStats. The health of a unit after its effects.
RecalcUnitStats
---@param stats Pointer
---@param vitals Pointer
---@param unit Pointer
---@param effectMaxima Pointer
function RecalcUnitStats(stats, vitals, unit, effectMaxima) end
Group LuaRecalcUnitStats. Recomputes a unit’s statistics; effectMaxima points to 40 floats.
Differs from addon.dll 0.12.4.2: sets the alive bit in the stats’ flags (the original sets it in the build flags); an intelligence raise marks the unit changed (the original does not); a strength raise widens the unit by 0.2, as the game does (the original narrows it by mistake); a unit without vitals is skipped (the original crashes).
RecalcInternalHeroStats
---@param stats Pointer
---@param newLoad number
function RecalcInternalHeroStats(stats, newLoad) end
Group LuaRecalcUnitStats. Resets a hero’s statistics to their base values.
Differs from addon.dll 0.12.4.2: sets the alive bit in the stats’ flags (the original sets it in the build flags); an intelligence raise marks the unit changed (the original does not); a strength raise widens the unit by 0.2, as the game does (the original narrows it by mistake); a unit without vitals is skipped (the original crashes).
RegenerateHpAndMp
---@param vitals Pointer
---@param stats Pointer
---@param unit Pointer
---@param inCombat boolean
---@return boolean changed Whether something changed.
function RegenerateHpAndMp(vitals, stats, unit, inCombat) end
Group LuaRegenerateHpAndMp. Regenerates health and mana.
CalcRunningManaCost
---@param stats Pointer
---@param unit Pointer
---@param vitals Pointer
function CalcRunningManaCost(stats, unit, vitals) end
Group LuaCalcRunningManaCost. The mana a running unit pays; subtract it from the mana in the callback.
CalcAttackParamsOnServer
---@param stats Pointer
---@param unit Pointer
---@param params Pointer
---@param effectMaxima Pointer
function CalcAttackParamsOnServer(stats, unit, params, effectMaxima) end
Group LuaCalcAttackParams. Computes an attack’s parameters on the server; effectMaxima points to 40 floats.
Differs from addon.dll 0.12.4.2: a hit from another player’s unit is ignored unless SpellAddon’s enablekillsinmulti is
on, as without the group (the original lets players’ units always hurt each other).
CalcAttackParamsOnClient
---@param unitParams Pointer
---@param unit Pointer
---@param params Pointer
---@param effectMaxima Pointer
function CalcAttackParamsOnClient(unitParams, unit, params, effectMaxima) end
Group LuaCalcAttackParams. Computes an attack’s parameters on a client; effectMaxima points to 40 floats.
Differs from addon.dll 0.12.4.2: a hit from another player’s unit is ignored unless SpellAddon’s enablekillsinmulti is
on, as without the group (the original lets players’ units always hurt each other).
GetManaBonusOnServer
---@param stats Pointer
---@return number factor
function GetManaBonusOnServer(stats) end
Group LuaGetExpModifiers. The mana factor of a unit on the server.
GetManaBonusOnClient
---@param params Pointer
---@return number factor
function GetManaBonusOnClient(params) end
Group LuaGetExpModifiers. The mana factor of a unit on a client.
GetExpMultiplierOnServer
---@param stats Pointer
---@return number multiplier
function GetExpMultiplierOnServer(stats) end
Group LuaGetExpModifiers. The experience multiplier of a unit on the server.
GetExpMultiplierOnClient
---@param params Pointer
---@return number multiplier
function GetExpMultiplierOnClient(params) end
Group LuaGetExpModifiers. The experience multiplier of a unit on a client.
Differs from addon.dll 0.12.4.2: experience for a unit the client does not have shows unchanged, without a call (the original passes the script a pointer into nothing).
RecalcShopsPriceMultipliers
---@param multipliers Pointer
---@param isLmp boolean
function RecalcShopsPriceMultipliers(multipliers, isLmp) end
Group LuaRecalcShopsPriceMultipliers. Sets the price multipliers of the shops; multipliers points to nine floats per
shop.
DistributeLmpExp
---@param exp number
---@param players integer
---@return number share
function DistributeLmpExp(exp, players) end
Group LuaLmpExpDistribution. The share of a kill’s experience for each player.
Differs from addon.dll 0.12.4.2: no value is left on the FPU stack per call (the original’s leftovers corrupt later results).
Addon and loader
dinput.dll loads addon.dll, which loads the selected mod, applies fixes and extensions, and writes addon.log.
For installation and supported game builds, see the overview. SpellAddon has its own
option reference, and mod scripts in Lua have the Lua reference; additional eix fixes
are under fixes.
The last column of each table gives eix’s difference from addon.dll 0.12.4.2 and Addon Loader 1.1.0.0, with what
the original does in parentheses. same means the original’s behavior;
fixed: marks a difference that only fixes a defect of the original. A name in
parentheses after a key is its patch group’s name in addon.log.
Configuration
Settings come from:
| Source | Contents |
|---|---|
HKCU\Software\Gipat.Ru\EI_Starter\Settings | Launcher preferences; values below are DWORDs unless stated otherwise |
Mod folder’s config.reg | Mod paths, resource archives, menus and plugins |
File named by config.reg’s [CONFIG] ai.reg | Gameplay settings, experience, skill caps and Lua |
The .reg files use the game’s registry format, not Windows Registry Editor syntax. A missing key takes its
default, and so does a string where a number is expected or a single value where an array is expected. An integer
is accepted where a float is expected, and a float where an integer is expected (truncated). A negative integer
keeps its sign where a float is expected (the original reads -1 as 4294967296). Gameplay groups require a selected
mod and a nonempty [CONFIG] ai.reg path. Configure multiplayer participants consistently for gameplay changes.
Groups apply in a fixed order, and later groups can replace earlier changes. A failed byte check skips the whole
group and logs why.
Launcher settings
| Value | Default | Effect | eix |
|---|---|---|---|
WideScreen | 1 | Adapt the interface to a wide resolution; 0 disables. VideoResolution is a WxH string under EI_Starter\EvilIslands\General Settings | fixed: an out-of-range scaling value wraps instead of crashing; a failed curtain window or text size is skipped (the original writes through null) |
ObjectsDrawRadius | 100 | Object draw radius; 100 leaves the game’s value | same |
LandscapeDrawRadius | 100 | Terrain draw radius; 100 leaves the game’s value | same |
AntiCrash (FixCreateItem, DisableExitOnCrashReport) | 1 | Report invalid item creation and fatal game errors without the game’s forced exit; mod [Addon] AntiCrash overrides when present | same |
AutoRecover | 1 | Back up the hosting player’s party on a crash; 0 disables | fixed: with all 1000 backup names taken, nothing is backed up (the original writes into the drive’s root) |
FullDump | 0 | Nonzero includes the process’s full memory in crash dumps | same |
LogLevel, ConsoleLogLevel | 1, 3 | Minimum log/console severity: 0 debug, 1 information, 2 warning, 3 error, 4 off | same |
Rate (SetDefaultRate) | 5000 | Only 2500 enables the group, which writes 2500, the value the game already holds; no visible effect on RU 1.06 | same |
Console AutoExec (AutoExec) | Empty | REG_MULTI_SZ console commands, executed before 2utoexec.cfg and the game’s autoexec.cfg | same |
MQ client (MQClient) | 0 | Nonzero prevents writing files received from the server | same |
MP Speed-control (MPSpeedControl) | 0 | Nonzero allows speed keys and clock buttons in multiplayer | same |
MP console (MPConsole) | 0 | Nonzero allows console commands in multiplayer | same |
eix’s own settings are in the mod folder’s eix.ini, not in the registry.
Settings\AddonPath is a string naming the selected mod folder. The loader searches for addon.dll using the
starter root’s AddonPath (full DLL path), then Settings\AddonPath\addon.dll, then the starter root’s
Path\addon.dll; the first existing file wins.
Mod configuration: config.reg
Paths under [CONFIG] and plugin paths are relative to the mod folder. An empty [CONFIG] path other than
lights<X>.ini disables its override.
| Section and key | Default | Effect | eix |
|---|---|---|---|
[MOD] Title, Author | Empty | Mod identification | same |
[MOD] Multi, Single (MenuMultiDisable, MenuSingleDisable) | 1 each | 0 disables the respective main-menu entry | same |
[MOD] GameSaves (SavesPath) | 1 | Nonzero puts saves and multiplayer heroes under the mod folder | same |
[MOD] PreventZone1Animation | 0 | Nonzero skips the opening zone animation | same |
[MOD] ForceShowTutorial | 0 | Nonzero prevents saved preferences and the options window from disabling tutorials | same |
[MOD] ShowTutorialDefault | None | The “Show tutorial” option’s value while none is stored; the player’s later choice wins | eix’s own (fixes) |
[MOD] AddonVersion | Empty | Required addon version as text. The game stops with a message when it is not a dotted version of at most four numbers, or names a version newer than 0.12.4.2 | same |
[CONFIG] ai.reg (ConfigAiReg) | Empty | Replace the game’s AI settings and enable the gameplay groups | fixed: a path of 260 bytes or more is refused and the game’s own ai.reg loads (the original ends the process) |
[CONFIG] movie.ini, tutorial.ini (ConfigMovieIni, ConfigTutorialIni) | Empty | Replace the respective configuration | fixed: a path of 260 bytes or more fails the group (the original ends the process) |
[CONFIG] music.reg, streamsn.reg (ConfigMusicReg, ConfigStreamSNReg) | Empty | Replace music and streamed-sound configuration | fixed: a path of 260 bytes or more fails the group (the original ends the process) |
[CONFIG] lights<X>.ini (ConfigLightsIni) | None | Replace a matching lights file; use lowercase key names. The key’s presence enables it: an empty value names the mod folder itself | same |
[DEV] GameDebugFile (GameExeDebug) | Empty | Write game debug messages to this file, relative to the game working folder | same |
[DEV] ChatHtmlFile (ChatLog) | Empty | Append server chat to this HTML file, relative to the game working folder | fixed: names and messages are escaped, and the speakers’ colours show (the original writes them raw, and its colour classes are not valid CSS) |
[DEV] Plugin | Empty | Load a plugin DLL, a filename pattern, or a folder’s *.plg files; empty or missing loads the mod folder’s *.plg files | plugins are called in load order (the original: by module handle, which the system chooses) |
[MPZone] Gipath, Ingos, Suslanger (MpZone) | Missing | Replace multiplayer zone lists; provide all three as strings or string arrays; duplicate names are rejected ignoring case | same |
[RES] <archive> (ResOverride) | None | String or string array of replacement archive paths, in file order; a path starting with - suppresses the game’s archive | fixed: archive paths of 260 bytes and more work (the original ends the process); an archive that fails to open is left out and logged |
[RES] replacement keys: aiinfo.res, database.res, databaselmp.res, gfx.res, materials.res, outro.res,
redress.res, sfx.res, speech.res, texts.res, textslmp.res, textures.res.
figures.res and menus.res also add figure archives;
textures.res, redress.res and menus.res add texture archives.
The listed mod archives are searched before the game’s archive, in the supplied order.
Loose files in the mod folder override matching game files:
| Mod file | Effect | eix |
|---|---|---|
Maps folder (Maps) | Maps | fixed: no length limit (the original overruns its buffers at 260 bytes and more) |
Movies folder (MoviesPatch) | Movies | fixed: movie paths of 260 bytes and more work (the original ends the process) |
Camera folder (CameraPatch) | Camera paths | fixed: camera paths of 260 bytes and more work (the original overruns its buffer) |
Stream folder (StreamPatch) | Streamed sound | fixed: stream paths of 260 bytes and more work (the original ends the process) |
binkw32.dll (BinkPatch) | Replace the game’s movie decoder | fixed: a binkw32.dll without BinkSetVolume: the volume call does nothing, with a warning (the original crashes) |
A Stream folder can also hold .flac tracks: FLAC music.
Gameplay: ai.reg
Unless stated otherwise, these [Addon] keys default to 0: 0 leaves the option off; any nonzero integer enables it.
| Key | Effect | eix |
|---|---|---|
ShowAllQuests (MPShowAllQuests) | Offer every multiplayer zone separately instead of grouping quests | same |
DisableRunaway | Keep an action when its target moves out of reach | same |
ArchersDefence (EnableArchersDefence) | Retain defence while wielding a bow or crossbow | same |
DistanceModifier (DisableDistanceModifier) | Remove the distance penalty from attack rolls | same |
WeightBonus (DisableWeightBonus) | Remove the weapon-weight bonus from attack rolls | same |
MagicRandom (RandomMagicDamage) | Float, default -1 (off); nonnegative values scale spell damage by 1 + MagicRandom * u, with random u in [-1, 1) | same |
AllowMagicNegative (NegativeMagicEffect) | Allow negative spell effects; choose the strongest overlapping effect by magnitude | same |
DeagrPlayerOnLoose | Stop tracking an unseen enemy merely because it is on guard; clear a player’s target when sight of another player’s unit is lost | fixed: releases the target reference it clears (the original leaks it) |
AttackAnimSpeed | Match attack and cast animation speed to their action duration | fixed: a cast of no time plays at normal speed, as an attack of no time does (the original’s speed is then infinite) |
NewRunes (NewRuneCodes) | Rune code xa adds its whole strength to cast time, with a minimum of one tick | same |
UsePrototypeActionsForMobAttack | Use the natural attack interval for non-named units, scaled by their action rate | same |
UsePrototypeActionsForMobCast | Use the natural attack interval for non-named units’ casts, scaled by their action rate | same |
FastTeleport | Reduce the extra teleport delay from 30 ticks to one | same |
DisableCrippledHL | Disable crippling a hit location on a severing hit | same |
UnlockExperimentalSpells | Allow Possession, Link and Charm through the spell-casting restriction | same |
LoadSpellAnimationFromSlotsField | Select cast animations from the spell record’s slots field | same |
ImproveInfoWindows | Show spell damage to one decimal, cast time in seconds, and the unit rate percentage | fixed: info windows keep their text alive while it is drawn (the original draws freed memory); same text shown |
RemoveSpellConstructReqs | Remove mana and skill requirements for spell construction and equipping | same |
SendSpellEffectValueToPlayers | Add effect strengths to network state; enable on both host and clients because it changes the record format | same |
AddWeaponsFromDbToAllUnits | Give all units their prototype’s starting weapons and armor, not just heroes | same |
UnlockCorpses | Allow searching a corpse already owned or searched by another unit | same |
AntiCrash | Default: launcher value; override the two AntiCrash groups | same |
LogErrorsInFile, LogErrorsInConsole, LogErrorsInChat | Send game-data error reports to errors.log, the console, or multiplayer chat | same |
EnableShowingScriptErrors | Enable the script error display | same |
EnableLuaScripts | Load the main Lua script and enable the nine Lua groups | a group hooks only where the script defines a callback; the game’s own code runs for the rest (the original hooks everything and stops with a Lua error at the first call of a missing callback) |
LuaMainScriptPath | String, default main.lua; path relative to the mod folder | same |
UsePerkLimit | Enables and disables nothing | same |
| Section and key | Default | Effect | eix |
|---|---|---|---|
[AddonExp] ChargeMethod (ExpCalc) | 0 | Share awarded experience among heroes: 1 multiplies by hero count, 2 gives each hero the whole amount, all other values divide by count | fixed: 2 gives the whole amount (the original adds the hero count to it) |
[AddonExp] MulFactor (ExpCalc) | 1.0 | Multiply the resulting experience share | same |
[AddonExp] Limit (ExpLimit) | -1 | Negative disables the cap; otherwise cap experience at this value times the hero’s intelligence factor | fixed: no stray FPU pop on an empty stack |
[AddonPerk] Melee, Archery, Elemental, Sense, Astral (PerkLimit) | 100 each | Training caps for the five skills; any value other than 100 enables the cap group; Backstab is a perk, not a sixth skill | same |
[DifficultyLevels] Absorption, Attack, Defence | Empty | Float arrays of difficulty modifiers, one entry per level | same |
Lua experience modifiers replace the earlier experience-cap calculation. SpellAddon may replace overlapping gameplay rules when it applies later; select one implementation of a rule when configuring a mod.
Automatic groups
These need no individual switch. Mod-file overrides and the settings above supply the remaining group controls.
MultipleLoadingMobs also needs a selected mod and a nonempty [CONFIG] ai.reg. SetEiPluginMode,
PlayerNumbers, AddNewScriptCommands and PersistentGlobalVars run only when no incompatible EI_Plugin build
(*.asi) is in the game folder; a mod whose AddonVersion is 0.10 or newer then stops the game with a message.
| Group | Effect | eix |
|---|---|---|
AllowScriptArgsInLoops | Make enclosing script locals available inside For and ForIf | same |
AllowScriptsInMainMenu | Run the main-menu zone’s script | same |
FixLeversActivate | Correct signed lock/key level comparison and locks that require no skill | same |
FixSpellEffectsOverflow | Limit accumulated effects, replace renewed effects, and expire effects on sleeping objects | fixed: a missing object in the sleep count-down is skipped (the original crashes); every renewed effect goes (the original keeps the second of two in a row) |
FixProgressNames | Use the separate loading movies for the allods gipat2 and jigran | same |
AddNewConsoleCommands, ImproveConsole | Add commands below, clipboard shortcuts, and suppress consecutive duplicate history lines | fixed: execs without a file name does nothing (the original reads a stale argument); a paste over a selection puts the caret after the pasted text (the original puts it past the selection’s end, less one); a repeated line leaves no selection (the original may leave one) |
NewStringEvents | Add gameover [title [text]]; defaults are text keys game_over and game_over_msg | fixed: a failed allocation pushes no window (the original pushes null) |
FixSpellSelfCasting | Correct offensive-spell classification and clicked-unit targeting | same |
FixProcessLogin | Initialize the joining player’s age field | same |
FixMoveObject | Reject negative or invalid map coordinates instead of indexing an invalid sector | the refusal message goes to addon.log; coordinates round half to even, NaN prints NaN |
FixAddMapObject | Report a missing unit prototype and use the fallback record | same |
FixPlaingBattleMusicFromAntimagic | Stop Antimagic alone from triggering combat music | same |
FixRepairPrice | Bound wear to 0..1 and include repair cost correctly when taking an item apart | fixed: an item with no maximum condition has no wear (the original’s price is then not a number) |
FixRemoveMapObject | Report an unknown object instead of crashing on removal | same |
ExtendedServerName | Enlarge the multiplayer server-name field and wrap or shorten display text | fixed: a name of 90 bytes or more is cut to 89 (the original ends the process) |
NivalRegistry | Use the starter’s game-settings registry branch | same |
SetEiPluginMode | Disable the EI plugin’s duplicate script commands; eix supplies their replacements | same |
PlayerNumbers | Give each new session player the next number after the highest existing player | same |
AddNewScriptCommands | Add the script interface below and log script-load errors | same |
PersistentGlobalVars | Preserve party variables with the case-sensitive gvar. prefix across network resets and saved-party reloads | same |
MultipleLoadingMobs | When adding a mob to a populated zone, skip duplicate object IDs and assign unused IDs from 100 to anonymous objects | fixed: frees the entries it skips (the original leaks them); anonymous objects of one file each get their own ID (the original gives them one, so only the last appears) |
Console and command line
The console supports Ctrl+A/C/X/V for selection, copy, cut and first-line paste.
Enter the game’s cheat password before addon, execs, listgvar or drawall; nogui needs none.
| Console command | Effect |
|---|---|
addon info | Show addon compatibility version and current mod |
addon debug log [level], addon debug console [level] | Read or set verbosity: 0 debug, 1 information, 2 warning, 3 error, 4 off |
execs <file> | Load and run a script in the current zone; report a load error with its line |
listgvar | List the zone script’s globals, including strings, objects and groups |
drawall <value> | 0 draws all objects; other values restore normal visibility |
nogui <mode> | 0 shows panels and cursor, 1 hides panels, 2 hides panels and cursor |
Run these from the game folder (CommandLine; aigraph also GraphGenPatches):
| Command | Effect |
|---|---|
game.exe addon help | Print command help |
game.exe addon version | Print the addon compatibility version |
game.exe addon run | Start the game |
game.exe addon check <path>... | Check script text, .mob files, or directories of .mob files |
game.exe addon aigraph single <mob> [mpr] | Generate the single-player AI graph |
game.exe addon aigraph multi <mob> [mpr] | Generate the multiplayer AI graph |
Place --moddir <name> before the command to select a mod under the starter’s Mods folder.
Without an mpr argument, the map name is derived from the mob name, dropping -lmp.
Script-check exit codes: 0 success, 2 unreadable file, 3 nothing checked, 4 script error or failed batch.
Game script interface
addon.dll adds functions and commands to the game’s script language, and replaces some of the game’s own. The
script reference lists them with the rest of the language, tagged eix, with the differences from
addon.dll 0.12.4.2.
Loader and start-up behavior
Only the differences; everything else behaves as the original.
| Behaviour | eix |
|---|---|
DirectInputCreateA, DirectInputCreateW, DirectInputCreateEx | fixed: a missing system dinput.dll or export: a message box and E_FAIL (the original returns success with no interface and the game crashes) |
| Game build check | checks image base, size, time stamp and entry point (the original: the entry point alone); the box names the build found. The patches fit RU 1.06 byte for byte and would corrupt another build |
| Old-loader mode | not supported: an old loader reaching addon.dll gets an error box and the game exits. eix ships both DLLs, so the mode is never reached |
| Unknown game.exe in addon.dll | addon.dll checks the build again, logs it and stops with a box (the original addon.dll checks none) |
| Patch writes are verified | a site that does not hold the expected bytes skips the whole group, logged with site, expected and found bytes (the original logs and writes anyway) |
| config.reg and ai.reg | fixed: a file with a valid header and a broken body reads as empty, with an addon.log error (the original reads garbage or crashes); a section with no keys reads as empty (the original’s lookup there crashes start-up) |
| addon.log: opening | an addon.log that cannot be opened gets a message box, and the game goes on (the original runs silently without it) |
| addon.log: when a line is written | fixed: each line is written at once (the original buffers, so a crash loses the last lines) |
| Exit of a command | fixed: ends with the same exit code and no box (the original stops on an R6025 - pure virtual function call box) |
| addon.log: what it records | also the eix build and commit, the Windows and Wine versions, the game.exe build, and the loaded modules (the original logs none of these) |
| Crash handler: a filter set later | fixed: a plugin that replaces the crash handler (Universal Mod’s um.dll) no longer disables it: eix’s handler runs the others first, then its own. A crash within a quarter of a second of the plugin setting its filter reaches only the plugin’s |
| Crash handler: the record | addon.log gets the crash’s code, address, access, registers and return addresses, each address with the patch group, fix or SpellAddon feature that put code there, and the loaded modules (the original writes only the dump) |
| Crash handler: the box | asks for a report at eix’s issue tracker, naming addon.log and the dump (the original asks for the dump at its author’s address) |
Tracer | not reproduced: the original’s per-patch hit counter reports wrong names and traps every hit |
| When built-in SpellAddon runs | applies when the sound system starts, where the original module loads; a separate SpellAddon*.asi is not loaded |
| spelladdon.ini choice | fixed: the mod folder’s file, else the game folder’s, else SpellAddon is off (the original reads AddonPath’s file unchecked, and with some registry setups a garbage path, so every key takes its default) |
| spelladdon.ini numeric parameters | fixed: parammin, parammax, balance, exred, exgreen, exblue, hitdistmul and hitdistadd keep fractions (the original truncates to integers); framex and framey keep their integer reading |
| spelladdon.ini digit parser | fixed: runconst, runconstex, pow and expforint without a decimal point read as whole numbers (the original divides by ten for each digit); points and commas keep their meaning |
| spelladdon.ini switches | keeps the signed low byte, with a warning for an out-of-range value naming the key, written value and used value (the original truncates silently) |
| spelladdon.ini aliases | accepts avrgarmors for avgarmors, and the gameplay-section spell AI, spell construction and multiplayer quest keys for their speed-section keys, with an info line; a canonical key wins, with a warning naming the ignored alias (the original ignores these aliases) |
| spelladdon.ini duplicate keys | the first value wins, with a warning naming the section, key, used and ignored values (the original keeps the first silently) |
| The fixed patch | the spell-name patch that the original always writes is written only when an INI is found |
SpellAddonInfo.txt | not written (the original writes its documentation to the working folder) |
| Sites that do not hold | a feature whose sites do not hold the expected bytes, or whose original crashes, is logged and left out; the others apply (the original writes anyway, and a crash stops every later feature) |
SpellAddon options
The built-in SpellAddon supports SPELLADDON.INI. It uses the mod-folder file first, then the game-folder file.
It reads one file, without merging them. Without either file, SpellAddon is off. The built-in version takes
precedence over separate SpellAddon*.asi files.
Loader and INI compatibility details: addon start-up behavior.
The last column of each feature table gives eix’s difference from SpellAddon 20.6 (SpellAddonXa.asi), with what the
original does in parentheses. same means the original’s behavior;
fixed: marks a difference that only fixes a defect of the original.
Configuration
All feature switches default to 0 (off), including when an INI file exists. Parameter defaults below apply only when their feature uses them; they are not the sample values from older guides. Restart the game after edits. An INI file also enables the spell-construction diagnostic correction, independently of its feature switches.
Section and key names are case-insensitive. Spaces around names are ignored; disablepausekey works without the
historical trailing space. Duplicate keys use the first value and produce a warning. Canonical keys take precedence
over aliases: [gameplay] avrgarmors aliases avgarmors; [gameplay] showallquestsinmulti, spellsaimod and
spellsarealwaysconstructable alias their [speed] counterparts.
The tables give active values. Other values make no change unless marked skipped. A skipped value is logged
and left out, and every other feature still applies. Switches retain a signed byte: use the listed values within
-128..127; larger values wrap and warn. 1+ below means 1..127. Byte parameters retain the low byte (0..255), and
other values warn; 32-bit parameters retain 32 bits. Floating-point parameters accept decimal text with a sign and
an exponent; use a decimal point. runconst, runconstex, pow and expforint read only their first 21
characters, take a leading -, ignore any other character that is not a digit, point or comma, and also accept a
decimal comma (the original ignores the sign too). Other numeric text holds at most 31 bytes; font text holds at
most 47 bytes.
Parameters have no general range validation. Limits stated below describe their use, not an extra validator.
Features apply in a fixed order, independent of INI order. Where two features change the same code, the later one builds on the earlier, or the earlier is skipped with a warning when the later replaces all it does; the tables call out those interactions. A conflicting or unexpected game patch causes the affected feature to be skipped and logged. If writing the merged patches fails, no feature applies. See the addon options for the other built-in settings.
Combat - [gameplay]
| Key | Active values and effect | eix |
|---|---|---|
archersdefence | 1+: bows and crossbows retain defence. | same |
unbreakablebodyparts | 1+: prevent limb breaking; also use bodypartbreakmodifier for the limb-damage floor. | same |
enablekillsinmulti | 1: remove player damage immunity so players can hurt other players. | fixed: god mode still holds (the original drops it too) |
rangedweaponbackstabs | 1: allow ranged backstabs. | fixed: with newrangedweapontypes, its change to how orders are carried out stays (the original’s newrangedweapontypes replaces it) |
backstabsforall | 1: allow units without a player to backstab. | same |
newattackdefence | 1, 2: physical damage after armour uses attack minus defence divided by divmod, plus submod and the speed term; 1 also includes the distance/weight term. 3, 4: use max((attack - defence) * divmod + 1, submod); backstabs ignore defence. 4 also disables misses. | same |
damageboost | 1: scale weapon damage by strength/dexterity above 25 and spell effects by intelligence above 25, dividing by str, dex, int. 2: multiply by those parameters instead. 3: bypass the normal effect scaling and its client display adjustment. 4: boost after weapon-effect scaling and at cast completion, using multiplication. 5: boost after scaling and mark casts so only their spell effects get the intelligence boost. | same |
changeweightrangebonuses | 1+: use weight and range in hit calculations; 2 also bypasses the conditional range test. | same |
strengthstats | 1: set strength’s health, damage and carrying-capacity coefficients with strhp, strdmg, strweight. | same |
allowheroesarmors | 1: retain heroes’ natural armour. | same |
newrangedweapontypes | 1: weapon types 11 and 15 count as ranged, alongside bows (5) and crossbows (6), throughout combat checks. | same |
randomlessaimedhits | 1-4: choose a vulnerable body part using the last hit. 5-9: estimate damage from the weapon’s damage range and target resistance. 2, 6, 7, 9 compare the target’s reach minus the attacker’s reach with rangeddistance; other modes use attack reach. Highest score wins; bodypart is the fallback. 10 is skipped. | 10 skipped (calls code the original never wrote); 5 and 8 keep the game’s minimum of distance and reach |
increasinghitchance | 1: after more than tohitcheck misses, add misses * tohitmul - tohitsub to the hit threshold. The defender holds the counter; a hit resets it. | fixed: with newattackdefence 1, 2 or 4, both apply (the original undoes part of newattackdefence) |
runawaydistcontrol | 1: attack reach becomes weapon range * hitdistmul + hitdistadd. | fixed: keeps fractional hitdistmul and hitdistadd (the original truncates them to integers) |
nightpower | 2: multiply attack and defence by nightmeleeadd - P * nightmeleemul + vision * P * nightmeleemul / 100, where P is night level (0..1). 1 is skipped. | 1 skipped (every attack and defence value becomes garbage); fixed: with damageboost=3, the unit panel keeps that feature’s change (the original drops it) |
duels | 1: suppress diplomacy reactions to damage when player 0’s und<victim id> variable rounds to nonzero. | same |
acidattack | 1, 2: unfinished acid-effect variants; neither changes the visible effect. | same |
armorspell | 1 is skipped. | 1 skipped (corrupts the stats refresh) |
Progression and movement
| Section | Key | Active values and effect | eix |
|---|---|---|---|
skills | extendedskills | 1: replace the non-stealing skill cap with [skills] skills. | fixed: uses [skills] skills as its cap (the original uses [stealing] stealing) |
stealing | extendedstealing | 1: replace the Sleight of Hand cap with [stealing] stealing. | fixed: uses [stealing] stealing as its cap (the original uses [skills] skills) |
rebalanceengine | rewriteskillscounting | 1: next skill level costs pow ^ level * mul + add. | fixed: pow without a decimal point reads as a whole number (the original divides by ten for each digit) |
rebalanceengine | rewriteherolevelcounting | 1: level is round(mullvla * log2(exp / divlvla + addlvla) + addlvlb) on server and client. 2 is skipped. | 2 skipped (returns a stale level) |
rebalanceengine | rewriterunabilitytime | 1: use runconst as the running stamina coefficient; also supply runconstex for newrunsystem=2. | fixed: runconst and runconstex without a decimal point read as whole numbers (the original divides by ten for each digit) |
rebalanceengine | newrunsystem | 1: drain a fixed amount instead of maximum stamina times the coefficient. 2: drain maximum stamina times the coefficient, plus runconstex. rewriterunabilitytime controls the coefficient; otherwise the game uses 1/150. | fixed: runconstex without a decimal point reads as a whole number (the original divides by ten for each digit) |
rebalanceengine | useonlymindamage | 1: use minimum weapon/unit damage instead of rolling within its range. | same |
rebalanceengine | backstabvisualbase | 1: show bsbase as the base backstab percentage; display only. | same |
rebalanceengine | difficultyreset | 1: apply difficulty scaling to all units, including heroes. 2: also add difficulty-table values instead of multiplying by them. | same |
rebalanceengine | meleesum_low | 1: non-hero server attack/defence add the first skill and dexterity minus 25. Skipped unless meleesum_1 or meleesum_2 is exactly 1; meleesum_1=1 satisfies this although that feature is itself skipped. | 1 skipped without meleesum_1 or meleesum_2 (the original’s game hangs at the first attack) |
rebalanceengine | meleesum_1 | 1 is skipped. | 1 skipped (the original crashes at the first attack) |
rebalanceengine | meleesum_2 | 1: client attack/defence add the first skill and dexterity minus 25, retaining the low byte: the client side of meleesum_low’s sum. | same |
animationsspeed | rewriteactionsspeed | 1: set six animation factors from this section’s parameters; also adjust client animation timing. | same |
gameplay | changeexpforint | 1: use expforint as the experience multiplier per intelligence point. | fixed: expforint without a decimal point reads as a whole number (the original divides by ten for each digit) |
gameplay | heroalwayscanrun | 1: remove the load-based restriction on running. | same |
gameplay | automaticruncontrol | 1: stop running at zero stamina. | same |
gameplay | speedboost | 1: multiply movement speed by ((action counter + speedadd) / 15) ^ speedbase. | same |
gameplay | actionspatch | 1: actions become dexterity * actionsmul + actionsadd. | same |
gameplay | actionsdexteritymovespeed | 1+: actions and dexterity contribute to movement speed through actmovemul and dexmovemul. | same |
gameplay | cleveranimationsspeedup | 1: set casting animation speed from cast duration and send animation speed in unit network state; also adjust client animation timing. Peers need compatible settings. | same |
gameplay | nhits | 1: use a fixed count of five hits for the special multi-hit animations. | same |
gameplay | diffchange | 1: ignore clicks on the difficulty spinner in game options. | same |
gameplay | newdifficultylevels | 1: add normal between easy and hard in the new-game choice, default to normal, and use a difficulty slider in options. | fixed: the box grows for the new row and the explanation moves below it; a click on the hard box selects hard (the original’s overlaps and ignores the click) |
Items, shops and camp - [gameplay]
| Key | Active values and effect | eix |
|---|---|---|
unlockmoney | 1: keep money unencoded in memory. | same |
saveall | 1+: use the game’s persistent-zone save/load handling for every zone. Value 32 also participates in extendedmerc’s draw-range extension. | same |
extendedmerc | 1+: set the briefing mercenary limit to the low byte of maxcountofmerc. With value 16+, saveall=32 and maxcountofmerc>50, extend the client draw range from 100 to 4096. | same |
shopschanges | 1+: change trader templates’ price/count fields; the final template uses price/count factors 1.0, 0.2 and 0.1. shopsnewnormalchanges=1 supplies jigran for its shared factor. | same |
shopsnewnormalchanges | 1: set stock ranges for weapons, armour, wands, potions, prototypes and runes, plus four traders’ sell-price factors and jigran for shopschanges. | same |
copystatscut | 1: CopyStats skips portions of the stats copy, retaining the recipient’s racial traits rather than making a complete clone. | same |
liftchanges | 1: unfinished carry-weight check; no game-state change. | same |
liftdebuffs | 1: packed stats are scaled by 1.01 - q / (q + liftkey), q = load / maximum load, while load is nonzero. | same |
encumbrancemovespeed | 1: subtract r^3 * encumbrancemovemul from movement factor, r = load / (load + maximum load). With speedslowremaster=2, also apply its Speed/Slow contribution, defaultspeedmul, minimumspeedmul, and the overload factor. | same |
encumbranceattackspeed | 1: load slows attack animations using (animation factor - r^3) * encumbranceattackmul. 2: load reduces the stats’ attack rate using speed factor - r^3 * encumbranceattackmul. r is as above. | fixed: 1 slows rewriteactionsspeed’s attack factor and 2 actionspatch‘s actions (the original uses the game’s values there, dropping those features’ changes) |
improvedstealing | 1: separate theft from corpse loot. A living hero retains equipped armour/weapons; a previously robbed hero’s corpse yields those, without repeating gold or stolen items. An already robbed living unit yields nothing. | same |
dmgtypes | 1: list dmgtypescount damage types in camp panels. | same |
avgarmors | 1: show average rather than maximum armour, including Endurance’s bonus. Requires newperks>=1; otherwise skipped. The divisor follows dmgtypescount when dmgtypes is active. | also accepts [gameplay] avrgarmors when absent (the original ignores it); 1 skipped without newperks (the original crashes entering the camp) |
itemslightchanges | 1: replace eight item-highlight RGBA colours with light00 through light31. | same |
heroscanhideweapons | 1: press the selected weapon’s key again, or click its selected slot, to sheathe it. | same |
camp | 1+: SendStringEvent(0, "constr") enters camp. 2+: the camera-track key (Home by default) also enters when player 0’s Camp is nonzero, then sets Camp=2. With newoptions>=1, modes 2-12 omit Home; newoptions=1 adds the camp binding and ability button. Each of 3, 4 and 13+ adds only its own extra: 3 tracks/removes quest items; 4 limits quick quest-item slots by QuIs; 13+ restore zone music on return and retain Home. | fixed: the Home key without player 0 does nothing (the original runs into the next action); value 3’s quest-item handling keeps the game’s own steps |
newoptions | 1: add camp (action 60) and kick bindings (61, 62). Camp’s action requires camp>=2; actions 60/61 otherwise end safely, with no kick behavior added. | fixed: actions 60 and 61 end the battle screen’s handling (the original jumps into garbage), unless camp defines 60 |
newperks | 1+: add Endurance (armour against all seven damage types) and Ghostliness (less visibility), and separate the magic-school skills. 2 also changes the school field used by spell descriptions. | fixed: Ghostliness lowers loudness as well as visibility, and visibility stops at 0 (the original’s loudness change is overwritten, and visibility can go below 0) |
For camp=3, quest-item creation sets player 0’s q<item id>=2; taking the item sets it to 0, except while camp
entry strips items. Set QuIs to the active quest-item count when using camp=4.
Spells - [gameplay] unless specified
| Key | Active values and effect | eix |
|---|---|---|
possessioncharmlink | 1: allow casting Possession, Charm and Link. | same |
possessionpatch | 1: Possession retains the caster’s sight and registers both caster and target for script visibility. | same |
batterycharge | 1+: reject spells containing modifier codes ic or it when placing them in wands. Invalid rune-table references are skipped. | fixed: a modifier past the rune table is skipped (the original crashes) |
nonstopmanaregen | 1+: continue stamina/mana regeneration through the state that normally stops it. | same |
npcsmana | 1: charge NPCs mana on cast completion. 2: require enough mana before casting. 3: both. 4: make both exemptions depend on AI class 16 instead of player ownership. | same |
splashdamageonair | 1: area spells can hit flying units. 2: only Invoke Lightning gains this ability, including AI targeting. | same |
newspells | 1-3: extend spell dispatch, enable Ensorcell (42), Inspiration (43), script spells (44-48), and the Fireball-based spell 49. 1 also marks spell 49’s caster; 1/2 load the autorun mob. 3 adds lasting-effect cases and Ensorcell’s damage type. See script variables below. New spell records/scripts must come from the mod. | fixed: the original’s crashes left out: Charm on a spawned wolf, the effect types that crash the effect loop, Charm and Healing with a broken stack; legendaryspellsystem and changefont keep their data |
lastspellsdamagetype | 1: use astralbeam, destroyray, lightningbeam, firearrow as damage-type IDs. | same |
[speed] spellsaimod | 1: extend the AI offensive/friendly spell table to 54 types. | also accepts [gameplay] spellsaimod when absent (the original ignores it) |
[speed] spellsarealwaysconstructable | 1: bypass level checks when assembling spells or giving them to heroes. | also accepts [gameplay] spellsarealwaysconstructable when absent (the original ignores it) |
offensivespells | 1: mark Stench and Shrink as friendly in missile hostility checks. | same |
inspirationintelligence | 1: item Inspiration waits until mana is below maximum, as Healing waits for missing health; limit repeated item casts within the tick. 2/3 are skipped. | 2 and 3 skipped (Healing items crash) |
teleportboost | 1: teleport duration becomes round(900 / (effect strength / 2 + 22)) + 2. 2: use delay 8 instead of 30. 3: use delay 1. | same |
shrinkenlargerebalance | 1, 2: Shrink and Enlarge no longer change unit size. 1 also changes the scale multiplier used by the size calculation. | same |
hidefireworks | 1: omit Fireworks’ drawing setup. | same |
wallsfrequency | 1: wall spells deal damage every frequencyvalue ticks. | same |
wallspercentage | 1: per-type wall fractions are percentagevalue * period / 150. 2: use each configured fraction directly. | same |
controlmagic | 1: Stun-like spells, Weaken and Slow meet target resistance; the latter two use weaknessmultiplier/slownessmultiplier. 2, 5, 7: add the 22 configured spell bonuses. 3: add bonuses only for spell switches with odd values. Duration/intelligence formulas from older guides do not run. 4/6 are skipped. | 4 and 6 skipped (corrupt durations) |
effectredraws | 1: show all configured b<spell> bonuses as value+bonus in item descriptions, and their sum in the HUD, independently of the controlmagic switches. | same |
stenchremaster | 1: Stench increases visibility, loudness and two further perception stats by its strength times stenchmul. | same |
regenerationremaster | 1: add Regeneration strength times regenerationmul to natural regeneration. | same |
speedslowremaster | 1, 2: multiply Speed minus Slow by speedslowmul. 2 also affects movement when encumbrancemovespeed=1. | same |
strengthweakrebalance | 1: Strengthen minus Weaken, times strengthweakmul, scales strength. | same |
linkremaster | 1: every 32 ticks, transfer mana from the proportionally fuller linked unit towards equal fill ratios, limited by spell strength. 2/3 are skipped. | 2 and 3 skipped (the original crashes) |
allowcastsonbriefings | 1: allow casting in briefing zones. | same |
fakesrcrune | 1: modifier code f starts a spell from its target point instead of its caster. | same |
filtersarealwaysusing | 1, 2: apply target filters to every spell. | same |
tornadochanges | 1+: use tordmg for tornado damage. 2+: also remove the unit exclusion, so it can hurt every unit. | same |
changesounds | 1: use fireboom as the Fireball volume factor. | same |
vampirism | 1 is skipped. | 1 skipped (the original runs unfinished code) |
maxmanatrans | 1 is skipped. Do not use it for the advertised path-query interface. | 1 skipped (breaks every spell type but one) |
fhrunetrans | 1 is skipped. | 1 skipped (the original crashes and stops every later feature) |
AI and perception - [gameplay]
| Key | Active values and effect | eix |
|---|---|---|
rewritenpcvisionarc | 1+: set NPC sight-arc value to visionarc. | skipped with a warning when removenpcsblock is 1 or 2, which removes the value it sets (the original writes it unused) |
visionfix | 1: bypass two lost-sight exits; with aggrmod>5, bypass only the first shared exit. | same |
aggrmod | 1: record lost-sight state, without changing the loss calculation. 2: distance-dependent random loss using losehardcore. 4/5: distance-dependent loss based on clock ticks, losefactor1/2. 6/7: per-viewer aggression counter using losehardcore, losefactor1/2/3, difffactor, maxadd. follow affects all these modes; loseallyfast affects 6/7. 3 is skipped; 6/7 omit the faulty improve alarm hook and warn if requested. | 3 skipped (corrupts the AI’s state); 6 and 7 with improve nonzero leave out the alarm hook (it acts on the wrong unit), with a warning; 2, 4-7 handle a zero divisor |
spellsprioritys | 1: replace seven AI target-rating constants with the priority parameters below. | same |
otherspellcastingai | 1: permit area spells even with allies nearby. | same |
npcsspellcastingtactics | 1: NPCs lacking mana switch to weapons and return to spells once mana recovers. | same |
removenpcsblock | 1, 2: remove NPC-specific stats, AI and naming branches. 1 also removes the NPC difficulty-scaling exception. | same |
everyoneishero | 1: broaden the shared hero-ID test to nonnegative IDs below two billion. 2: selected game systems treat all units as heroes. 3: as 2 but retain difficulty scaling for enemy heroes. | same |
allysseeseachothers | 1: sight treats all units as player-owned. 2/3: also use the player branch during visibility updates. 4: sight uses hero IDs from one billion to below two billion as the ownership test. | fixed: 4: looting works with or without improvedstealing (the original crashes without it at the first scripted loot) |
newplayersafetyconditions | 1: use safetymuldist in party-safety distance checks and maxvisibilitymul for the visibility factor. | same |
fearpatch | 1: use fearsafetydist for retreat distance and legsdamagedmul for the leg-damage cutoff. | same |
stupidenemies | 1: witnessing a murder no longer invokes the diplomacy attack reaction. | same |
hyperreactions | 1: react to seen units/corpses without the own-side-only restriction. | same |
hearingreactionspatch | 1: fix the unit/target used in reactions to sounds. 2: also offset and scatter the destination with runtosoundsmul and randsoundfactor. | same |
visioninweather | 1: use visionweathermul in bad weather. | same |
nightvisionincaves | 1+: dark zones always use night vision, without daytime growth. | same |
nightpowervisionpatch | 1: ramp night level between visionevening/visionnight and visionmorning/visionday, with slope visionmulpowbetween. | same |
newbigtables | 1: alter the rebuilt AI tables’ positions/bounds. Requires the corresponding rebuild switches; it supplies no extra entries. The caster lookup shifts beyond the written table, and the offensive bound grows beyond its 38 entries. | same |
allvisible | 1 is skipped. | 1 skipped (corrupts the options load) |
sizerebalance | 1-3 are skipped. | 1-3 skipped (corrupts the unit) |
unitsrunfromdangers | 1 is skipped. | 1 skipped (passes a point as a unit) |
| Section | Key | Active values and effect | eix |
|---|---|---|---|
aicastertable | rebuildedaicastertable | 1: replace the 54 spell AI classes with keys 0 through 53 in this section. | same |
aioffendtable | rebuildedaioffendtable | 1: replace the 38 offensive/friendly entries with keys 0 through 37 in this section. No effect while spellsaimod=1, whose own 54-entry table the game reads instead. | same |
Multiplayer and speed
| Section | Key | Active values and effect | eix |
|---|---|---|---|
gameplay | fullexpforall | 1: every recipient gets the full experience award; do not divide it among recipients. | same |
gameplay | manygameexe | 1: allow multiple game processes. | same |
gameplay | enablecheatsinmulti | 1: allow the console’s restricted commands in multiplayer. | same |
gameplay | extendedparams | 1: character creation uses attribute bounds 5..45 and required sum 20000. 2: use parammin, parammax, balance and bypass the sum check. | fixed: keeps fractional parammin, parammax and balance (the original truncates them to integers) |
gameplay | longnick | 1: remove the character-name edit field’s length checks. | same |
gameplay | disableexppenalty | 1+: add experience directly to totals, bypass pending experience in training/trade, and remove its loss on respawn. | same |
speed | allowmpspeed | 1+: enable multiplayer speed keys and clock-button speed changes. | same |
speed | rewritespeed | 1: clock-button normal/fast periods use normal and fast. | same |
speed | rewritespeedkey | 1: keyboard normal/fast periods use normalkey and fastkey. | same |
speed | rewriteotherspeed | 1: apply both following changes. 2: reset to normal1 on battle-screen close. 3: initial clock period uses normal2/fast2. | same |
speed | disablepause | 1: clock pause sets period pause instead of pausing. | same |
speed | disablepausekey | 1: pause key sets period pausekey instead of pausing. | same |
speed | showallquestsinmulti | 1: bypass the multiplayer restriction on selectable quest zones. | also accepts [gameplay] showallquestsinmulti when absent (the original ignores it) |
speedrun | timervars | 1-3: publish a timer state, 0 during mission/zone/save loading and 1 when the game interface appears. 1/3 differ in battle-screen paths; 2 uses 3D-interface activation instead of briefing creation. Requires an external timer that reads this interface. | same |
Speed periods are milliseconds per update: smaller means faster. Speed and network-format changes must be compatible
between multiplayer peers. bigmapspatch and cleveranimationsspeedup change network data handling.
Interface and world - [gameplay] unless specified
| Key | Active values and effect | eix |
|---|---|---|
rewriteperssize | 1: use perssize for the hero preview scale. | same |
[fonts] changefont | 1+: use newfont1 through newfont4. 2 also loads the font file newfont5 from the INI folder for this process. | fixed: with newspells on, value 1 keeps the second and third font names (the original’s newspells overwrites them) |
infowindowschanges | 1: compact the unit-info layout. | same |
infowindowremake | 1: combine attack/defence with hearing on one line and add two panel rows. | same |
showtype | 1: show the movement-type line in unit information. | same |
showmanaforeveryone | 1: show mana bars for non-heroes too. | same |
meterscale | 1: use meter for the information ruler scale. | same |
allodsinfo | 1: display the adesc <allod> text from texts.res in a frame sized by framex/framey. | same |
exploredcolors | 1: set explored-zone colour with exred, exgreen, exblue. | fixed: keeps fractional exred, exgreen and exblue (the original truncates them to integers) |
lightsboost | 1: replace the light-strength constant with newlightsvalue. | same |
mainmenuweather | 1: set weather type 2 at strength 40. 2: skip menu weather. 0 leaves the game’s weather unchanged. | same |
drawvisiblepatch | 1: zone entry no longer resets the draw-visible setting. | same |
playingnewloadingscreens | 1: name loading movies after the zone. 2: also use gz1g in the special initial-zone movie selection. Requires matching movie assets. | same |
notrash | 1: share the speech resource path instead of requiring separate s and t folders; also change the client animation-mode timing test. | same |
musictimings | 1: wait minmusictime + random % (maxmusictime - minmusictime) between music tracks. | fixed: with maxmusictime not above minmusictime, the pause is minmusictime (the original divides by zero at the first track change, or waits far too long) |
newzonescpecificmusic | 1: zone gz12d2 uses music named gz12d2. 2: use the alternative music-name field in zones, briefings and camp and shorten music-mode setup. 3: as 2, but retain camp’s original field. | same |
disabledragon | 1: disable the quest-variable dragon response and the related flying-insect effect updates. | same |
noruinszoneanimation | 1: omit zone1’s built-in introduction script. | same |
dontmergegipathzones | 1: keep Gipat zones separate on the global map. | same |
newallodsacks | 1: add environment flags for zones named jigran, neloya, eyn, bebesh, kvatokh, nokks, umoir, yazes, yiul. | same |
newcounters | 1: narrow the regeneration counter to one byte. | same |
nogameoveronleadersdeath | 1: the leader’s death does not end the game; revival must be supplied by scripts. | same |
hiddenzonesexits | 1: subtract player 0’s Exits from exit count. 2+: replace exit count with Exits; absent/zero means no exits. | same |
segmentsonexitenter | 1: cap zone-transition segments at maxsegments, add addsegments, and use exitenteractivityradius for activity radius. | same |
bigmapspatch | 1: change network position scaling for larger maps; all peers need compatible encoding. | same |
ultrafixes | 1: skip network objects without the companion needed to send them. | same |
expirementalfxes | 1: change unit sorting. 2: mask loaded IDs to 16 bits and fix load-loop initialization. 3: combine 1/2. 4: mask IDs, change sorting, bypass the first load-section count check. 5: change sorting and zero load-loop initialization. 6: bypass three load-section checks. 7: bound load-loop iterations. 8: combine 1/7. 9: no change. 10: bound the loop, change unit sorting, add null guards in hostility/sight, and change drawing/removal paths. | same |
importantalerts | 1+: show the starter’s configured mod path in a modal box; without it, the fallback box has no useful path. | same |
versionalerts | 1: warn about unknown lowercase .asi files in the game folder. Known names: EI_Plugin.asi, mp3dec.asi, SpellAddonX.asi, SpellAddonXa.asi. Does not warn about the built-in SpellAddon. | does not warn about the built-in SpellAddon itself |
Script interfaces
These options change existing commands/functions, including their argument lists. Update the mod’s scripts together
with its INI. Defaults are 0. Except where shown otherwise, the active value is 1 and the section is [gameplay].
Numbers used as integer indices, styles or IDs are rounded with the game’s floating-point rounding mode.
| Key | Interface and effect | eix |
|---|---|---|
[speed] gsgetvar | GSGetVar(player, name) returns difficulty for names beginning Diff, and update period when characters 4-7 (zero-based) are peed, such as SetSpeed. | fixed: reads the variable’s name before freeing it |
[speed] gssetvar | GSSetVar(player, name, value) also sets update period for names with peed at characters 4-7. The named variable is still stored normally. | same |
[saves] savecontrol | 1, 2: player 0’s Save!=0 blocks escape-menu and keyboard saves. GSSetVar(0, "Save", 0) allows them. | fixed: reads player 0’s “Save” without corrupting the stack |
autorunmobfile | 1+: append loading of Maps/AutoRunSpellAddon123.mob to each zone’s start script. newspells=1/2 also enables this. | skipped with a warning when newspells is 1 or 2 (the original writes the same change twice) |
infiniteaddmobspawn | 1+: AddMob can load the same file repeatedly, except case-sensitive names beginning Auto, which still load once. | same |
standtrans | Stand(unit) also revives it. A non-unit argument causes no revival. | fixed: does nothing for an argument that is not a unit (the original crashes) |
waslootedtrans | 1: WasLooted(unit) returns the full flag word. 2: WasLooted(unit, bit) returns the selected bit. Known bits: 15 moving, 19 knocked out, 20 looted, 24 stunned, 28 feebleminded. | same |
castscripttrans | 1: Cast(unit, x, y, spell) uses the numbered spell. 2: Cast(unit, x, y, spell, target) casts on target if present, otherwise at the point. | fixed: 2 reads its target from the running command (the original: a stale value) |
castspellunittrans | CastSpellUnit(spell, x, y, target, caster) adds a caster unit to the named-spell command. | same |
castspellpointtrans | CastSpellPoint(spell, x, y, x2, y2, caster) adds a caster unit to the named-spell command. | same |
giveunitspelltrans | GiveUnitSpell creates/adds a quick item instead of a spell, using the existing unit/name arguments. | same |
hptrans | HP(unit, index) reads a float by index from the unit’s vitals companion; valid indices 0..29. The useful fields are listed below. | same |
mptrans | Mana(unit, index) reads a float from unit stats, indices 0..448; invalid objects/controllers/indices return 0. Also adds the index argument to HP, without changing its reader unless hptrans=1. | same |
legendaryspellsystem | MaxHP(unit, index) reads a byte starting at the skill-byte area, indices 0..631; outside it returns 0. GiveQuestItem(unit, value) writes byte 10 of that area. Also changes MaxMana to seven numeric arguments, but supplies no working path-query implementation. | fixed: MaxHP stays inside the unit (the original reads any address) |
getplayertrans | GetPlayer(unit, index) reads a 32-bit integer at four times the index within the unit (0..310); returns 0 outside it. | fixed: returns 0 outside the unit (the original reads any address) |
setplayertrans | SetPlayer(unit, value, field) writes a rounded 32-bit integer at four times field within the unit (0..310). Fields 132..148 retain the game’s normal player-setting path; out-of-unit writes are ignored. | fixed: stores nothing outside the unit (the original writes any address) |
groupseetrans | GroupSee(group, mode) accepts an extra numeric mode argument; group traversal itself remains the game’s. | same |
unitseetrans | UnitSee(unit, mode) selects the visibility list: positive zero = visible living units; negative sign bit (including negative zero) = the second list; other values = the nearby-units list. | same |
getaiclasstrans | GetAIClass(unit) reads the server controller’s AI-class field. | same |
runtrans | Run(unit, style) sets the requested movement style instead of always selecting run. | same |
crawltrans | Crawl(unit, slot) requests a weapon slot instead of setting crawl style. | same |
killunittrans | KillUnit(type, strength) sets weather with two rounded numbers instead of killing a unit. | same |
fixworldtimetrans | FixWorldTime(time, speed) adds an explicit time-speed argument. | same |
movetoobjecttrans | 1: MoveToObject(unit, target) performs thieving while walking. 2: run instead. 3+: MoveToObject(unit, target, skill, unused, run, slot) supplies four numbers for the thieving order. | same |
playmusictrans | 1, 2: PlayMusic(player, "0") or "1" re-selects the local map’s music theme and sets the music system’s level to the digit. The first character selects this behavior. 1 uses the map’s theme, 2 its alternative name field. Other text, or no map/music system, uses normal handling. | fixed: without a map or a music system, does what the game does (the original crashes) |
notifydeaths | 1: a death sets player 0’s variable named by the victim ID to 1. 2: set 2 for a hero killer, otherwise 1. | same |
notifylootings | 1: increase the corpse-ID variable by 20 for a hero looter, 10 otherwise. 2: a hero looter’s ID goes into the corpse-ID variable. 3: the corpse ID goes into the hero looter’s ID variable. Variables belong to player 0. | same |
genocideincvars | 1, 3: player 0’s Hits counts hero hits on non-heroes. 2 is skipped; 1/3 are skipped with genocidedipvars set. | 2 skipped, and 1 or 3 with genocidedipvars=2 (reads garbage as objects); 1 or 3 skipped with a warning when genocidedipvars is 1, 3, 4 or 5, which replaces its change (the original writes it unused) |
genocidedipvars | 1: Hits holds the last non-hero victim’s side when hit by a hero. 2: Kils holds that side on a hero kill. 3: both. 4: Hits records any ownerless victim’s side; Kils records ownerless victims killed by owned units. 5: both require an owned attacker and ownerless victim. Replaces genocideincvars. | same |
removefrozenvar | Zone 6 ignores its frozen/unique-zone restriction on entry. | same |
freemultiplayervars | Skip the built-in multiplayer variables in trader creation and journal refresh. | same |
setspellaggressiontrans | No change for any value; the command itself remains inactive. | same |
[tech] scriptchecking | 1-7: append script errors to SAlog.txt. 2, 4-7 also log mob loads. 1/2 do not record errors in the script. 3/4/6/7 return nonzero from error handling. 5 permits eight script-load errors to pass. 8+ are skipped. | 8 and up skipped (calls code the original never wrote); 1 and 2 write the line where the original crashes at the first script error |
[tech] drawunitsids | Prefix the unit-info name with its ID; truncate to 255 bytes. Safe with no selected unit. | fixed: works without a unit (the original crashes); lines cut at 255 bytes |
Loot and death notifications and genocide take IDs of at least one billion as heroes and lower IDs as non-heroes (the original’s death and genocide tests take IDs strictly above one billion).
With newspells=1..3, spell types 44-48 publish S0e (strength), S1d (duration), S2t (type), S3x/S4y
(point) on the first server player; scripts can read them with GSGetVar. They give the caster hostile mask 29 and
side round(strength * 32). Mode 1 also gives spell 49’s caster mask/side 29. These hooks expose script inputs;
they do not supply a summoning script or mod assets.
Indexed stat readers
HP indices: 10 current HP, 11 maximum HP; 13 current mana, 14 maximum mana, 15 mana regeneration.
Resistance uses base/current pairs: 16/17 piercing, 18/19 slashing, 20/21 crushing, 22/23 fire, 24/25 acid,
26/27 lightning, 28/29 general.
Mana reads the underlying float fields. Do not treat packed flags or skill bytes as ordinary numeric stats.
| Indices | Mana(unit, index) field |
|---|---|
| 1, 2 | Total and spent experience. |
| 3/4, 5/6, 7/8 | Natural/total strength, dexterity, intelligence. |
| 9/10, 11/12 | Natural/total movement and action coefficients. |
| 13-16 | Run, walk, crawl, lie speeds. |
| 17 | Vision arc. |
| 20/21 | Current/maximum load. |
| 28-32 | Natural reach, attack, attack spread, defence, speed. |
| 33/34/35 | Natural damage, damage spread, attack interval. |
| 36-42 | Natural damage weights, in damage-type order 0..6. |
| 44/45 | Base/current sight range. |
| 56/57, 62/63 | Base/current visibility and loudness. |
| 125/126/127/128 | Head HP/max HP/HP share/damage scale. |
| 186/187/188/189 | Body HP/max HP/HP share/damage scale. |
| 247/248/249/250, 308/309/310/311 | Left/right arm HP/max HP/HP share/damage scale. |
| 369/370/371/372, 430/431/432/433 | Left/right leg HP/max HP/HP share/damage scale. |
71 + 61*p + 18*l + t | Armour absorption: part p = 0..5, layer l = 0..2, damage type t = 0..6. |
| 447, 448 | Fixed maximum HP and pending experience. |
Parameters
Each row gives the default and the feature that uses it. F = floating-point; I = 32-bit integer; B = byte.
Unless stated otherwise, these are [gameplay] keys. Bounds and spell-ID lists below describe meaningful values;
values outside them can select unrelated fields or unsupported game data.
Progression, speed and presentation
| Section | Key(s) | Default(s) | Type | Use |
|---|---|---|---|---|
skills | skills | 0 | B | extendedskills: non-stealing skill cap. |
stealing | stealing | 0 | B | extendedstealing: stealing cap. |
rebalanceengine | pow, mul, add | 1.1, 4.5, 0.5 | F | rewriteskillscounting: exponential base, multiplier, addition. |
rebalanceengine | mullvla, addlvla, divlvla, addlvlb | 4.5, 1.5, 245.5, 0.5 | F | rewriteherolevelcounting: level formula. |
rebalanceengine | runconst, runconstex | 0.006666666666, 0.5 | F | rewriterunabilitytime/newrunsystem: drain coefficient and extra drain. |
rebalanceengine | bsbase | 300 | I | backstabvisualbase: displayed percent. |
speed | normal, fast | 55, 27 | I | rewritespeed: clock periods. |
speed | normalkey, fastkey | 55, 27 | I | rewritespeedkey: keyboard periods; the game’s own are 55 and 27 (the original’s built-in normalkey is 5). |
speed | normal1 | 55 | I | rewriteotherspeed 1/2: close/reset period. |
speed | normal2, fast2 | 55, 27 | B | rewriteotherspeed 1/3: initial clock periods. |
speed | pause, pausekey | 0, 0 | I | disablepause/disablepausekey: replacement periods. |
animationsspeed | attackspeed, castspeed, hitspeed, deathspeed, specialspeed, idlespeed | All 1 | F | rewriteactionsspeed: attack, cast, hit reaction, death, special, idle animation factors. |
gameplay | expforint | 1.0245 | F | changeexpforint: experience factor per intelligence point. |
gameplay | actionsmul, actionsadd | 0.2, 10.0 | F | actionspatch: dexterity multiplier and action addition. |
gameplay | actmovemul, dexmovemul | 0.5, 0.01 | F | actionsdexteritymovespeed: actions/dexterity contributions. |
gameplay | speedbase, speedadd | 0.3, 5.0 | F | speedboost: exponent and counter addition. |
gameplay | parammin, parammax, balance | 15.0, 35.0, 75.0 | F | extendedparams=2: attribute bounds and displayed balance; sum enforcement is bypassed. |
gameplay | perssize | 1.2 | F | rewriteperssize: hero preview scale. |
gameplay | framex, framey | 75.0, 175.0 | F | allodsinfo: frame width/height; integer parts also size text rectangles. |
gameplay | meter | 15.0 | F | meterscale: ruler factor. |
gameplay | newlightsvalue | 0.001 | F | lightsboost: light strength. |
gameplay | exred, exgreen, exblue | All 0.5 | F | exploredcolors: RGB components; normally 0..1. |
fonts | newfont1, newfont2, newfont3, newfont4 | All Times New Roman | Text | changefont: four interface font families. |
fonts | newfont5 | Times New Roman | Text | changefont=2: font-file name relative to the INI folder, not a family name. |
Combat, shops and load
| Key(s) | Default(s) | Type | Use |
|---|---|---|---|
divmod, submod | 100, 1 | F | newattackdefence: divisor/base for modes 1/2; multiplier/floor for 3/4. |
str, dex, int | 100.0012, 100.0013, 100.0014 | F | damageboost: strength/dexterity/intelligence scaling; divisors in mode 1, multipliers in 2/4/5, unused in 3. |
strhp, strdmg, strweight | 0.005, 0.003, 12.0 | F | strengthstats: strength coefficients. |
weight, range | 20.0, 10.0 | F | changeweightrangebonuses: weapon-weight and distance constants. |
bodypartbreakmodifier | 4 | F | unbreakablebodyparts: replace the limb-damage floor constant (normally -5). |
headmod, legmod, handmod | 3, 1, 1 | F | randomlessaimedhits: head/leg/arm score weights. |
criticalmod | 2 | F | randomlessaimedhits: boost a head score reaching full head HP, and leg scores at ranged reach. |
healthdowntoignore | 10.25 | F | randomlessaimedhits: ignore non-body parts when current HP times this value is below maximum HP. |
rangeddistance | 5.65 | F | randomlessaimedhits: reach threshold for boosting leg scores. |
bodypart | 1 | I | randomlessaimedhits: fallback part; 0 head, 1 body, 2/3 arms, 4/5 legs. |
checkhero | 1 | I | randomlessaimedhits 5-9: nonzero makes player-owned attackers use bodypart instead of the chooser. |
tohitcheck | 1 | B | increasinghitchance: miss count must exceed this. |
tohitsub, tohitmul | 0.0, 5.5 | F | increasinghitchance: subtraction and counter multiplier. |
hitdistmul, hitdistadd | 2.0, 5.0 | F | runawaydistcontrol: reach multiplier/addition. |
nightmeleeadd, nightmeleemul | 1.0, 1.0 | F | nightpower=2: night-factor base and slope. |
maxcountofmerc | 27 | I | extendedmerc: limit uses the low byte; full value controls the >50 draw-range condition (with extendedmerc 16+ and saveall=32). |
minsweapons, maxsweapons | 1, 10 | B | shopsnewnormalchanges: weapon stock range. |
minsarmors, maxsarmors | 1, 10 | B | shopsnewnormalchanges: armour stock range. |
minswands, maxswands | 1, 10 | B | shopsnewnormalchanges: wand stock range. |
minspotions, maxspotions | 20, 65 | B | shopsnewnormalchanges: potion stock range. |
minsprototypes, maxsprototypes | 1, 10 | B | shopsnewnormalchanges: prototype stock range. |
minsrunes, maxsrunes | 20, 56 | B | shopsnewnormalchanges: rune stock range. Use stock counts 0..127 because the game sign-extends these bytes. |
ingos, gipatz, gipatb, suslanger, jigran | All 0.5 | F | shopsnewnormalchanges: sell-price factors for Ingos, Gipat healer, Babur, Suslanger and Jigran. shopschanges also reads jigran when shopsnewnormalchanges=1. |
liftkey | 1.0 | F | liftdebuffs: load-ratio divisor term. |
encumbrancemovemul, encumbranceattackmul | 1.0, 1.0 | F | encumbrancemovespeed, encumbranceattackspeed: load penalties for movement and attack. |
speedslowmovemul, defaultspeedmul, minimumspeedmul | All 1.0 | F | encumbrancemovespeed with speedslowremaster=2: effect multiplier, overall multiplier, minimum factor. |
dmgtypescount | 6 | I | dmgtypes: displayed count; the game has seven damage types (0..6). |
light00 through light31 | All 1 | F | itemslightchanges: eight RGBA groups in order; 00-03 first colour, 04-07 second, through 28-31 eighth. Normally 0..1. |
AI, spells and zones
| Key(s) | Default(s) | Type | Use |
|---|---|---|---|
visionarc | -2 | F | rewritenpcvisionarc: NPC sight-arc value. |
visiondependence | 1.05 | F | aggrmod 2/4/5/6/7: NPC vision-distance factor. |
aggrrangemulmodifier | 4 | F | aggrmod=1 stores it but does not use it. |
losehardcore | 100000 | I | aggrmod=2: random modulus. 6/7: counter limit uses only 16 bits (default becomes 34464). |
losefactor1, losefactor2 | 15, 5 | I | aggrmod 4/5: time divisor multiplier and right-shift count. 6/7: distance multiplier and level-divisor addition. |
losefactor3, difffactor, maxadd | 5, 2, 2 | I | aggrmod 6/7: distance addition, difficulty addition, quotient threshold. These and losefactor1/2 use signed low bytes in 6/7. |
follow | 0 | I | Nonzero lets units continue towards a lost enemy’s position in active aggrmod modes. |
improve | 0 | I | Nonzero requests the faulty alarm hook in aggrmod 6/7; eix omits it and warns. |
loseallyfast | 0 | I | Nonzero in aggrmod 6/7 bypasses the counter for units not classed as enemies. |
sametarget, magicattack, damagemult, magicdamagemult, savedamagemult, rangecost, kickprice | All 10.0 | F | spellsprioritys: same-target bias, magic bias, weapon/spell/healing priorities, casting-distance cost, quick-kill target factor. |
safetymuldist, maxvisibilitymul | 2.0, 3.0 | F | newplayersafetyconditions: safety distance and visibility factors. |
fearsafetydist, legsdamagedmul | 10.0, 0.6 | F | fearpatch: retreat distance and damaged-leg threshold. |
runtosoundsmul, randsoundfactor | 1.0, 1.0 | F | hearingreactionspatch=2: extrapolation from sound position and random scatter factor. |
visionweathermul | 0.9 | F | visioninweather: bad-weather vision factor. |
visionevening, visionnight, visionmorning, visionday | 18.0, 22.0, 4.0, 8.0 | F | nightpowervisionpatch: hours for dusk/full night/dawn/full day. |
visionmulpowbetween | 0.250 | F | nightpowervisionpatch: night-level ramp slope per hour. |
astralbeam, destroyray, firearrow, lightningbeam | 5, 3, 3, 5 | B | lastspellsdamagetype: 0 piercing, 1 slashing, 2 crushing, 3 fire, 4 acid, 5 lightning, 6 general. |
slownessmultiplier, weaknessmultiplier | 12, 0.5 | F | controlmagic=1: resistance scaling for Slow and Weaken. |
durcoeff, effcoeff, lvldurcoeff | All 0.03 | F | Read but no active duration/effect formula consumes them; lvldurcoeff is stored by some controlmagic modes. |
mul3, pow3 | 1.0, 1.0 | F | Read but unused by the built-in features. |
frequencyvalue | 0 | B | wallsfrequency: ticks per damage event; set a meaningful positive period. |
firepercentagevalue, lightningpercentagevalue, acidpercentagevalue | All 0.1 | F | wallspercentage: fire, lightning and acid wall fractions. |
stenchmul, regenerationmul, speedslowmul, strengthweakmul | All 0.1 | F | Respective Stench, Regeneration, Speed/Slow and Strengthen/Weaken remasters. |
tordmg | 5.0 | F | tornadochanges: damage per tornado hit. |
fireboom | 5.0 | F | changesounds: Fireball volume factor. |
minmusictime, maxmusictime | 120000, 180000 | I | musictimings: minimum and exclusive upper delay in milliseconds. |
maxsegments, addsegments | 1000, 0 | I | segmentsonexitenter: segment cap and addition. |
exitenteractivityradius | 70.0 | F | segmentsonexitenter: transition activity radius. |
Per-spell bonuses - [gameplay]
Each switch defaults to 0 (B); each bonus defaults to 0.0 (F). controlmagic=3 applies the bonus only when the
switch is odd. Modes 2/5/7 apply all bonuses. effectredraws=1 displays all bonuses regardless of these switches.
| Spell | Switch | Bonus |
|---|---|---|
| Protection from Fire | prot_fire | bprot_fire |
| Protection from Lightning | prot_electro | bprot_electro |
| Protection from Acid | prot_acid | bprot_acid |
| Eagle Sight | eagle_sight | beagle_sight |
| Night Vision | infravision | binfravision |
| Detect Life | detect_life | bdetect_life |
| Invisibility | invisibility | binvisibility |
| Silence | silence | bsilence |
| Lichdom | lichdom | blichdom |
| Stench | stench | bstench |
| Stun | stun | bstun |
| Antimagic | antimagic | bantimagic |
| Strengthen | strength | bstrength |
| Weaken | weak | bweak |
| Regeneration | regeneration | bregeneration |
| Feeblemind | feeblemind | bfeeblemind |
| Speed | speed | bspeed |
| Slow | slow | bslow |
| Enlarge | enlarge | benlarge |
| Shrink | shrink | bshrink |
| Necro | necro | bnecro |
| Destroy | destroy | bdestroy |
Spell AI table entries
| Section | Keys | Default | Accepted meaning |
|---|---|---|---|
aicastertable | 0 through 53 | All 8 | B; 0 missile, 1 area attack, 2 lasting area attack, 3 out-of-combat buff, 4 combat buff, 5 unused, 6 healing, 7 debuff, 8 unused. Used with rebuildedaicastertable=1; with newbigtables=1, key n no longer classifies spell type n. |
aioffendtable | 0 through 37 | All 8 | B; 0 harmful, 1 friendly. Set meaningful entries before enabling rebuildedaioffendtable=1; the default 8 is not a normal classification. |
Read-only placeholders - [gameplay]
These switches default to 0 and have no feature of their own. Changing them has no effect in the built-in version.
| Key(s) | Status |
|---|---|
enemysmana | Read only; use npcsmana for the implemented mana rules. |
newspells_fireraze, newspells_inspircharm, newspells_spellsmachine, newspells_invislichd | Read only; newspells controls the implemented spell extensions. |
hideobjecttrans, stableaggrmod, helloworld, castspellpatch | Read only; no command/AI change. |
newallodsinmulti, autocasts | Read only; no allod-selection or automatic-casting feature. |
walktrans, lietrans, resttrans, getleadertrans, inflictdamagetrans, isunitblockedtrans, setplayeraggressiontrans | Read only; the named script interfaces retain their existing behavior. |
Fixes and features
eix’s own changes to game.exe RU 1.06, beside the originals’ features: fixes of defects that the original addon.dll and SpellAddon leave, and features. Each is set in eix.ini.
Fixes
Code: crates/addon/src/fixes/, one module per fix, applied in table order after the patch groups.
- A fix changes nothing a player sees, except the mod setting below. The changes a player sees are game options, switched in the same section.
- No fix writes a place a SpellAddon feature patches, or changes what a multiplayer peer computes.
- addon.log lists each fix under
fixes: applied, failed with the reason, or off. WithEnabled0 one line says no fix applied, and only the mod setting is listed.
The switches are in eix.ini’s [EngineFixes] section.
A mod’s config.reg can set [MOD] ShowTutorialDefault: the “Show tutorial” option’s value while the game has
none stored, as on a first start. The game stores the option at exit, so the player’s later choice wins. Without the
key the game’s default (on) stands. Enabled 0 does not turn it off.
| Fix | Before | After |
|---|---|---|
| HeapPadding | heap overruns crash under Wine (lobby, shops, looting) | blocks padded (about 14 % more heap) |
| TimerResolution | frame times snap to 15.6 ms on Windows 10 2004+ | 1 ms timer |
| CastTargetGone | a cast whose target leaves the world crashes the server | the order ends |
| KillScriptOutside | KillScript outside a script writes through null (AntiCrash on) | reported, game goes on |
| LowercaseTable | slow per-character lower-case conversion in parsing and lookups | cached; zone loads about 30 % faster |
| ViewDepthInit | uninitialised depth can crash the draw sort on a first zone load | depth starts at 0 |
| MappedFileMessage | a failed-open message over 210 bytes overflows its buffer | path cut at 210 |
| PresentFailure | a screen lock or UAC prompt in full screen ends the game | flip waits, frame skipped |
| FullScreenFallback | a refused full-screen mode crashes | next larger mode, game in its top left corner |
| ScreenshotRowPadding | screenshots at some widths read past their buffer | buffer sized right |
| BriefingText | a guest joining during a briefing crashes the host | dialogue goes on |
| UnitPanelText | the unit panel stalls the frame for its text | drawn in memory, copied on change |
| StreamWait | a music change spins the main thread | the wait sleeps |
| QuestSort | quests without a #quest entry crash or hang the journal | sorted first |
| ExitIndex | a zone with unloaded exits crashes the briefing screen | empty exit, warning |
| FatalErrorExit | a fatal error with AntiCrash off crashes on shutdown | clean exit, same code |
| UnknownScreen | an unknown game state from the host crashes the client | logged, ignored |
| DiplomacySides | a side outside 0..31 reads and writes past the tables | hostile, unchanged, warning |
| MissingPlayerMode | a party member with cleared modes crashes the party check | skipped |
| NoAudioDevice | no audio device: movies crash | runs silent, warning |
| EmptyMusicTheme | an empty theme track list divides by zero | plays nothing, warning |
| ZoneModeText | % in a theme name read as a format | printed as text |
| StreamFadeLock | a fade races the stream thread | takes its lock |
| PointLightOverflow | the 257th script light overruns the table | refused, warning |
| EmptyItemStrip | a missing constructor record crashes a camp or shop strip | empty list, warning |
| UnregisteredLight | a light removed twice or moved before added corrupts memory | ignored, warning |
| FindHandleLeak | each music track leaks a file search handle | closed |
| LoadFailureLeaks | a failed read and two failed texture loads leak | freed |
| TruncatedScript | a script ending mid-statement crashes or hangs the game | “Unexpected end of file” |
| VertexLighting | 3DfpFPU.dll lights vertices in slow x87 code | SSE, four at a time, same colours bit for bit, also with Universal Mod’s um-engine.dll |
Features
AutoPause and encumbrance are off by default, FLAC music and INI variables on; the game options each have their own default.
Game options
Window, display and start-up changes. Each has its own key in eix.ini’s [EngineFixes];
UnitShadowResolution, KeepRunningOnFocusLoss and ClipCursorToWindow are off by default, the others on. The
focus options change the window only, never full screen. Enabled 0 there turns all of them off. addon.log lists each
under fixes.
| Option | Before | After |
|---|---|---|
| KeepWindowOnFocusLoss | in a window, the game minimises on focus loss | stays on screen, paused |
| KeepRunningOnFocusLoss | in a window, the game pauses (tick, sound, input) and minimises on focus loss; a multiplayer client falls out of step | keeps running and playing, not minimised |
| ClipCursorToWindow | in a window, the cursor leaves it | confined to the client area while the window has the focus; let go on focus loss, minimising and closing |
| UnitShadowResolution | unit shadows are 64 by 64 pixels | 128 or 256: a sharper edge, more video memory and work per shadowed unit; rendering only |
| SmoothCamera | panning stutters: a tick’s camera step lands in one frame | spread over frames, same speed |
| PlayerListOnJoin | a client may see an empty player list until players change | refreshed when its player arrives |
| SkipDiscCheck | the starter’s game.exe asks for the game disc | starts without it, as GOG’s exe |
| UnitPanelSpells | the unit panel’s values page shows no spells of a unit outside the party | each spell below the values: its icon and “Effect:” with its value, as the spell windows show it; a page taller than the panel gets the game’s scroll bar (arrows, thumb, and the mouse wheel over the page instead of the camera’s zoom); single player and the host only |
| SpellsNeedAcceptedSkills | the camp’s spell constructor counts skills bought on the skills page before the purchase is accepted, so undoing the purchase keeps the spells made with them | counts each hero’s skills as last accepted |
KeepRunningOnFocusLoss covers KeepWindowOnFocusLoss in a window: with both on, the game never sees the focus loss,
so nothing pauses and nothing minimises. With KeepRunningOnFocusLoss 0 the second still keeps the window on the
screen, paused. Minimising the window yourself stays the game’s: it pauses, and resumes when the window is restored.
AutoPause
In single player, the game pauses when a party member’s health drops low, an enemy comes into view, an enemy turns on the party, or an enemy in view dies; each event has its own setting. A network game never pauses. addon.log names what paused the game.
- Health: a party member’s health drops below
HealthorHealthPercent; with both set, either limit pauses the game. It pauses once per drop: the member’s health must rise to the limit again before the next drop pauses the game. A member that is already low when it comes into view (a zone loads, a new member joins) does not pause the game. - An enemy is a living unit without a player that is hostile to the party’s side. The party’s view is what its
members see, as the script
PlayerSeegives it. EnemySightedandEnemyAggropause once per encounter: the next pause comes after no enemy is left in view, or aggressive, and one appears again. Enemies already in view, or aggressive, when a game loads pause it at once.
Encumbrance
The load a hero carries slows running, and makes running cost more stamina; above the hero’s maximum load it slows walking too. Load and maximum load are the encumbrance figures of the hero panel; their ratio is the encumbrance below (1.0 at the maximum). The rates are settings.
- Running speed is 100% -
RunSlopex encumbrance: with the defaults 80% at the maximum load, 60% at twice it. - Walking, sneaking and crawling keep the game’s speed up to the maximum load, then lose
WalkSlopeper extra maximum load: 80% at twice the maximum. - Turning while walking or standing slows with the running speed: the game turns a walking or standing unit at its running pace.
- Running drains the stamina the game’s run system takes, divided by the load’s running speed: at 80%, 1.25 times as
much. Wounded legs slow the hero without raising the drain.
RunDrainscales the extra: 0 keeps the game’s drain, 50 halves the extra. - No load stops a hero from running; wounded legs still slow every movement and stop running, as in the game.
- The speeds follow the load when the game recomputes a hero’s statistics (regeneration, damage, healing, effects), not at the moment an item is equipped.
- With SpellAddon’s
encumbrancemovespeedalso on, both slow movement; addon.log warns. SpellAddon’sheroalwayscanrunchanges the same byte as this feature. Its run settings (newrunsystem,runconst) decide the drain thatRunDrainscales.
FLAC music
eix plays a music or streamed-sound track from Stream\<name>.flac when there is one, in place of <name>.mp3: the
mod’s Stream folder first, then the game’s. The order is the mod’s .flac, the mod’s .mp3, the game’s .flac,
the game’s .mp3.
- The track keeps its
.mp3name in the game:music.regnames andstreamsn.regsections (<name>.mp3) stay. - Mono or stereo, any sample rate, up to 32 bits a sample (played as 16 bits). Packs can mix FLAC and MP3 tracks.
- addon.log names each FLAC file played. A file that does not decode plays silence, with a warning.
- Briefing speech (
speech.res) stays MP3. - On by default; eix.ini’s
[Music] Flac=0turns it off.
INI variables
A script’s GSGetVar(0, "ini.<file>.<section>.<key>") reads key in [section] of <file>.ini as a number, so a
mod’s map scripts can take settings from an INI file. Mod settings for map scripts
shows the use.
- The file comes from the mod’s folder (
Mods\<mod>), else the game folder.<file>is a plain file name: a name with\,/or:reads the game’s variable. - Each file is read once, at the first variable that names it: a change applies at the next game start.
- A missing file, section or key, or a value that is not a number, reads 0; addon.log notes each such name once. The
decimal point is
.or,; names ignore case. The key is the rest of the name, dots included. - Nothing is stored: saves hold no INI values, and multiplayer clients are sent none. Each machine reads its own file.
- Without eix the game reads 0 for such a name, as for any variable never set.
- Always on; other variable names keep the game’s own lookup.
eix.ini
eix’s own settings, in eix.ini in the mod’s folder (Mods\<mod>, beside its config.reg). Without the file, or
with no mod selected, every key takes its default. The package’s copy holds every key at its default.
addon.log names the file read, and each value left out with the reason.
EngineFixes
The switches of the fixes and the game options:
| Key | Value |
|---|---|
Enabled | 0: all fixes off; else on (default 1) |
KeepWindowOnFocusLoss, SmoothCamera, PlayerListOnJoin, SkipDiscCheck, UnitPanelSpells, SpellsNeedAcceptedSkills | 0: the game’s behaviour for that option; else on (default 1) |
UnitShadowResolution | 64 (default): the game’s; 128 or 256: sharper unit shadows; another value is logged and stays 64 |
KeepRunningOnFocusLoss, ClipCursorToWindow | 0 (default): off; else on |
AutoPause
The events that pause single player (AutoPause), each off by default:
| Key | Value |
|---|---|
Health | Hit points; 0 (default): off |
HealthPercent | A percentage of the member’s maximum hit points, 1 to 100; 0 (default): off |
EnemySighted | 1: an enemy comes into the party’s view while none was in view |
EnemyAggro | 1: an enemy turns on a party member while no enemy was aggressive to the party |
EnemyDead | 1: an enemy in the party’s view dies, whoever killed it |
A negative Health, or a HealthPercent above 100, is logged and is off.
[AutoPause]
Health=0
HealthPercent=25
EnemySighted=1
EnemyAggro=0
EnemyDead=1
Encumbrance
The rates of encumbrance, off by default. Encumbrance is load over maximum load (1.0 at the maximum).
| Key | Value |
|---|---|
Enabled | 1: on; 0 (default): the game’s movement |
RunSlope | Running speed lost per maximum load, in percent, 0 to 100 (default 20) |
WalkSlope | Walking speed lost per maximum load above the maximum, in percent, 0 to 100 (default 20) |
MinSpeed | The lowest speed either reaches, in percent, 10 to 100 (default 50) |
RunDrain | How much of the extra running drain applies, in percent, 0 to 200 (default 100) |
A value out of its range is logged and takes its default.
[Encumbrance]
Enabled=1
RunSlope=20
WalkSlope=20
MinSpeed=50
RunDrain=100
Music
| Key | Value |
|---|---|
Flac | 1 (default): a track plays from its .flac when there is one (FLAC music); 0: only the game’s own stream code runs |
Development
Build
Install podman, then:
cargo xtask container
- Runs
cargo xtask checkin the image frombuild/Containerfile: format, clippy (host and Windows), tests (Windows ones under Wine), release build, docs, dependency checks, workflow checks, and the public-text check (cargo xtask public). - It also checks the generated reference pages (see Documentation site) and builds the site.
- Output:
target/container/i686-pc-windows-gnu/release/{dinput,addon}.dll. - Release package:
cargo xtask container distwritestarget/container/dist/eix-<version>.zip(the DLLs,dist/spelladdon.ini,dist/eix.ini, the README, the licence, the changelog, the third-party notices anddocs/) and the release notes. - Without podman: the toolchain from
rust-toolchain.toml,i686-w64-mingw32-gcconPATH, Wine, and the toolsbuild/Containerfileinstalls, thencargo xtask check. - Tests that need the game’s files are ignored by the gate. Run them with
EIX_GAME_DIRset to the game folder as a Windows path (under Wine,Z:\...):cargo test -p eix-addon --target i686-pc-windows-gnu -- --ignored. They check every expected byte of the fixes and SpellAddon’s features againstgame.exe, and the vertex lighting against3dfpfpu.dll.
Documentation site
The site is an mdBook book: book.toml at the repository root, docs/ as its
source, docs/SUMMARY.md as its table of contents. Every page of docs/ is listed there.
Two pages are generated, and each has one data file that holds every signature and description:
| Page | Data file |
|---|---|
docs/scripting.md | docs/scripting.yml: the game’s script functions and commands, with their source and eix’s differences |
docs/lua-reference.md | docs/eix.lua: the Lua API as LuaLS annotations; it ships as it is, for the Lua language server |
- Edit the data file, then run
cargo xtask docsand commit both. Never edit a generated page:cargo xtask checkfails when a page differs from a fresh generation. cargo xtask checkalso fails on a broken link between pages and on a page missing fromdocs/SUMMARY.md, then builds the book intotarget/book. The build image carries mdBook, pinned inbuild/install-mdbook.sh.- Tests compare the data files with the code: every function and callback that addon.dll registers appears in
docs/scripting.ymlordocs/eix.luawith the same name and signature. Run the test that compares the game’s own entries with the keyword table ofgame.exewithEIX_GAME_DIRset, as for the other game tests:cargo test -p eix-docs -- --ignored. - Build the book by hand with
mdbook buildand opentarget/book/index.html. - Publishing:
.github/workflows/pages.ymlbuilds the book and deploys it to GitHub Pages on every push tomain. The repository’s Pages source must be set to GitHub Actions once (Settings, Pages, Build and deployment).
Continuous integration
.github/workflows/ci.yml: the gate (cargo xtask container) on every push tomainand every pull request. The build image is cached under a hash ofbuild/andrust-toolchain.toml, and stored by pushes tomainonly;EIX_IMAGE_KEYmakes xtask use a loaded image carrying that key instead of building one..github/workflows/pages.yml: the documentation site, as above..github/workflows/release.yml: on av*tag, the gate, the package, and a draft GitHub release.
Release
- Set the version in
Cargo.tomland add its section toCHANGELOG.md. - Push a tag
v<version>. The release workflow runs the gate, builds the package, and drafts a GitHub release with it and the changelog section. - Check the draft and publish it.
Keep each release’s package: an address inside addon.dll in a crash record is read against that exact file, which keeps its symbols.
Layout
| Path | Content |
|---|---|
crates/core | platform-free logic: registry format, options, group conditions, spelladdon.ini keys |
crates/docs | the reference pages generated from docs/scripting.yml and docs/eix.lua, and the checks of those files |
crates/sites | game.exe addresses, one named constant each, per exe build |
crates/engine | game.exe access: memory, hooks, typed game structures, Win32 |
crates/lua | the Lua host (LuaJIT) |
crates/spelladdon | the built-in SpellAddon |
crates/loader | dinput.dll |
crates/addon | addon.dll: patch groups, command line, engine fixes |
xtask | project tasks |
build | the build image and the installers of its tools |
dist | the release package’s spelladdon.ini and licence-notice settings |