Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

COMBAT.INI

Combat system configuration defining attack moves, defense moves, and combat dialogue (taunts) for all combatants.

Shipped sample path: /Redguard/COMBAT.INI (e.g. .../GOG Galaxy/Redguard/Redguard/COMBAT.INI).

The file is 54 KB and 3,728 lines, the largest INI in the game. Every move, defense, and voice line for every combatant is defined here, making the combat system fully data-driven.

File Structure

The file contains 474 sections in four types:

Section typeCountIndex rangePurpose
[misc]1—Global combat parameters
[attackNN]8900–88Attack move definitions
[defendNN]500–04Defense move definitions
[tauntNN]37900–599 (with gaps)Combat dialogue and voice lines

The file opens with a block of commented-out constants defining animation group IDs and attack type enums, followed by the sections in the order listed above.

Section suffixes are numeric IDs. A missing section leaves a gap in the ID space; later sections keep their suffixes. Numeric fields contain decimal integers, including signed arc_center offsets. An omitted field is distinct from an explicit zero in the file. Taunt labels retain their RTX spelling, including leading & characters.

Animation Groups

The header comments define the animation group ID table used by animation fields throughout the file:

IDName
1anim_defend_low
2anim_defend_right
3anim_defend_left
4anim_defend_high
5anim_attack_1
6anim_attack_2
7anim_attack_3
8anim_attack_thrust
9anim_attack_lunge
10anim_attack_1_end
11anim_attack_2_end
12anim_fight_disarm
13anim_fight_low
14anim_fight_jump_start
15anim_fight_jump
16anim_fight_fall
17anim_fight_land
18anim_fight_fall_attack
19anim_fight_land_attack
20anim_fight_hurt_1
21anim_fight_hurt_2
22anim_death_fight_stab
23anim_death_fight_hard
24anim_sheath_sword
25anim_explore_hurt_1
26anim_explore_hurt_2
27anim_death_explore

[misc] Section

Global parameters for the combat system.

KeyValue (shipped)Description
sword_clank_157Sound effect ID for sword clash, variant 1
sword_clank_258Sound effect ID for sword clash, variant 2
non_engaged_dist100Distance threshold for non-engaged state
in_face_dist100Distance threshold for in-face proximity
non_engaged_spacing500Spacing between non-engaged combatants, in engine angles
in_combat_threshold200Strict horizontal distance threshold for isFighting, shifted left eight bits at load
player_can_die1Whether the player can be killed (1 = yes)
cyrus_defend_interval2Minimum frames between Cyrus defends
node_timer120Timer value for combat node transitions
max_taunts600Maximum taunt index (exclusive upper bound for taunt pool)

[attackNN] Sections

Each [attackNN] section defines one attack move. There are 89 sections (attack00 through attack88).

Attack Types

The type field selects the attack category:

ValueName
0melee
1missile
2combo
3stab
4finishing

Elevation Values

The elevation field controls the vertical targeting zone:

ValueMeaning
0regular (default when omitted)
1above
2below

Field Schema

Standard attack (type 0, 1, 3, 4):

FieldTypeDescription
typeintegerAttack category (see enum above)
arcintegerHorizontal hit arc width, in engine angle units
arc_centerintegerHorizontal offset of arc center from forward direction; omitted when centered (0)
elevationintegerVertical targeting zone (see enum above); omitted when regular (0)
min_rangeintegerMinimum distance to target for hit to register
max_rangeintegerMaximum distance to target for hit to register
first_collide_frameintegerAnimation frame on which collision detection begins
collide_durationintegerNumber of frames collision detection remains active
damageintegerHit point damage dealt on successful hit
forceintegerKnockback force applied to target
defenseintegerDefense animation group ID triggered on the target
first_defend_frameintegerAnimation frame on which the attacker can be defended against; omitted on some attacks
defend_durationintegerNumber of frames the attacker is vulnerable to defense; omitted on some attacks
animationintegerAnimation group ID (see animation group table above)
col_vertexintegerModel vertex index used as the collision sphere origin; present only on large creature attacks
col_sphere_sizeintegerRadius of the collision sphere; present only on large creature attacks

Combo attack (type 2):

Combo sections reference other attack sections by index rather than defining collision geometry directly.

FieldTypeDescription
typeintegerAlways 2 for combos
num_attacksintegerNumber of sub-attacks in the combo (2 or 3)
attack00integerIndex of the first sub-attack section
attack01integerIndex of the second sub-attack section
attack02integerIndex of the third sub-attack section; present only when num_attacks = 3

Attack Allocation by Combatant

The file comments identify which attack indices belong to each combatant:

CombatantAttack indices
Cyrus (early)00–14
Skeleton15–17
Golem18–22
Zombie23–25
Serpent26
Troll27–29
Guard (low attack)30
Goblin31–34
Dragon35–37
Richton38–47
Dram48–52
Ogre53
Pirate (initial, weaker)54–64
Cyrus (later)65–74
Vermai75–77
Tavern thugs (no damage)78–88

Large creature attacks (Golem, Serpent, Dragon) use col_vertex and col_sphere_size to attach the collision sphere to a specific model vertex rather than the combatant’s origin point.

[defendNN] Sections

Each [defendNN] section defines one defense move. There are 5 sections (defend00 through defend04), shared by Cyrus and guards.

Field Schema

FieldTypeDescription
arcintegerHorizontal arc width covered by the defense; omitted on defend00
min_rangeintegerMinimum distance at which the defense is effective
max_rangeintegerMaximum distance at which the defense is effective
first_collide_frameintegerAnimation frame on which the defense window opens
collide_durationintegerNumber of frames the defense window remains active
animationintegerAnimation group ID (see animation group table above)

The five shipped defenses correspond to: default (defend00), low (defend01), right (defend02), left (defend03), and high (defend04).

Runtime Attack Loading

The engine scans attack00, attack01, and subsequent numbered sections in order. A section is admitted when either damage or type has a nonempty value. The first section with neither value ends the scan; later sections are not loaded. This runtime rule differs from parsing the INI as a collection of sparse sections.

A non-combo attack loads one move. A combo reads its referenced moves in the order of attack00, attack01, and attack02, using num_attacks as the count. Each attack reserves three zero-initialized motion slots. Loading fills the authored motions and leaves unused slots zeroed. Each move’s numeric loader reads an omitted or empty value as zero. This applies to motion type, ranges, collision and defence timing, arc, damage, force, defence selector, collision vertex, collision sphere size, animation and elevation. Raw INI parsing still distinguishes omission from an explicit zero. The runtime motion record stores the converted value for every loaded field.

Each loaded move adds 97 with signed 32-bit wrapping to its configured animation value to obtain the actor animation group. An omitted animation therefore selects group 97. A single attack copies its move’s minimum and maximum ranges. A nonempty combo starts its minimum at 65,535 and maximum at -1, then lowers the minimum and raises the maximum for each referenced move.

Each attack also retains a damage total, initialized to zero. A single attack adds its move’s damage; a combo adds each referenced move’s damage in authored order. The additions wrap as signed 32-bit values. A combo with no moves retains zero damage. Defence pacing reads this accumulated total, rather than only the first motion’s damage.

Runtime Defense Loading

Defense loading scans defend00, defend01, and subsequent numbered sections in order. A section is admitted when its numeric max_range is nonzero. The first zero value ends the table; later sections are not loaded. Each admitted record loads its minimum and maximum ranges, first collision frame, collision duration, arc and animation. The configured animation value is increased by 97 to obtain the actor animation group.

Actor Move Selection

Combat initialization binds nine attack slots from actor attribute bytes 70 through 78. Each nonzero byte selects the attack record with that index; zero leaves the corresponding slot empty. An empty attack slot does not prevent later attack slots from being populated.

Four defense slots use an attribute cursor starting at byte 79. A nonzero byte selects the defense record with that index and advances the cursor. A zero byte leaves the slot empty without advancing the cursor, so all remaining defense slots also stay empty. Defense selection therefore uses only the nonzero prefix of attribute bytes 79 through 82. A zero selector does not select defend00.

Binding a nonzero defense slot marks its shared defense record available and stores the actor animation group’s signed frame count in that record. An absent animation group supplies zero. The four-slot availability query succeeds when one bound record has its availability marker equal to one.

[tauntNN] Sections

Each [tauntNN] section defines one combat voice line or audio cue. There are 379 sections with indices spanning 00–599, with large gaps between combatant blocks.

An actor’s taunt list begins at its RAEX taunt_id and contains attr_num_taunts consecutive entries. A zero count creates no list. The range is selected per actor; it is independent of which taunt sections are present elsewhere in the file. Without RAEX, the first index is zero. Each actor allocates exactly attr_num_taunts pointers and fills them from that range in order. The per-actor pointer list has no additional sentinel entry.

The loader creates an empty record for each absent section and an additional empty sentinel at max_taunts. Empty records have a zero label, type, and animation. Present records copy the first four rtx_label bytes directly, including a leading &. A nonzero animation value is increased by 152 before storage; zero remains zero and requests no accompanying animation.

Taunt Types

The type field identifies when the taunt fires:

ValueTrigger
0begin combat
1attack
2hurt by opponent
3hit opponent
4defend
5misc, during move
6death
7after kill opponent
8want to switch out
9want to switch in
10opponent is unarmed (male)
11opponent is unarmed (female)

Field Schema

FieldTypeDescription
typeintegerTrigger condition (see enum above)
rtx_labelstringFour-byte label key into ENGLISH.RTX, preserved literally including &NNN spellings
animationintegerCombat animation offset; nonzero values become group 152 + animation, while 0 disables accompanying animation

Combat taunt selection is skipped when the actor satisfies IsDead, including the selected player’s death override. Begin-combat writes lifecycle selector 6 before this check; the selected-player override remains independent.

Begin-combat, hurt, death, and opponent-unarmed selection scans the actor’s list in order. Only entries with the requested type and a nonzero RTX label participate. Each matching entry becomes the current selection and consumes one random draw. The scan stops when floor(4 * draw / 32767) == 1; otherwise the last matching entry wins. Death selection retries with the hurt type only when no death entry matched. The other four types have no such fallback.

Taunt Allocation by Combatant

The file comments define the index ranges reserved for each combatant:

Index rangeCombatant
0–49Cyrus
50–149Guards
150–154Skeletons
155–159Zombies
160–179Tavern Thug 1
180–199Tavern Thug 2
200–219Tavern Thug 3 (Dagoo)
220–228Brennan
229–234Golem
235–239Serpent / Vermai
240–249Troll
250–259Goblin
260–279Richton
280–299Dram
300–319Pirate 1
320–339Pirate 2
340–349Ngasta
350–359Urik
360–369Zombie
370–389Vander
390–409Island Thug 1
410–429Island Thug 2
430–449Island Thug 3
450–469Island Thug 4
470–489Island Thug 5
490–509Island Thug 6
510–529Pirate Hideout 1
530–549Pirate Hideout 2
550–569Pirate Hideout 3
570–589Pirate Hideout 4
580–587Dragon
591–599Jail interior (reuses guard lines)

Not all reserved slots are populated. Many combatants use only a subset of their allocated range, and some ranges overlap in the comments (Dragon at 580–587 falls inside Pirate Hideout 4 at 570–589).

External References