-
Notifications
You must be signed in to change notification settings - Fork 0
Combat System
Navigation: Home - Combat - Combat System
Trace of the encounter/battle engine in mm2.capstone.asm. All addresses are
code-hunk load addresses (base 0). A4 = data_base + 0x7FFE, so an A4
displacement -d maps to data-hunk offset 0x7FFE - d (see doc 16). Confidence
is high for control flow and data layout; the exact HP/to-hit/damage arithmetic
is only partially reduced (noted inline).
[TOC]
encounter start
-> 0x11C82 build battle arrays (per monster slot: 0x11C2C)
-> 0x12A22 COMBAT ROUND LOOP (repeats each round)
-> per round: 0x135BE / 0x11D0C / 0x11C82 (display + recompute)
-> initiative select (highest speed not-yet-acted)
-> 0x119C2 PLAYER turn (character -$4F5)
-> 0x1064C MONSTER turn (monster slot -$4F7)
-> 0x13282 round/over check
-> 0x12430 VICTORY + rewards (when -$77BE monster count == 0)
-> 0x11646 party defeat / retreat
The encounter holds up to ~11 active monsters. Per-instance state is kept in
parallel A4 arrays keyed by slot; full stats are re-derived from the type id
by the unpacker at 0x4C8E when needed (see doc 16).
| Array (A4) | Element | Meaning |
|---|---|---|
-$11DE[i] |
byte | monster type id (record index into monsters.dat) |
-$53A[i] |
word | current HP (set from unpacked -$11A0) |
-$519[i] |
byte |
status flags (bit0 = awake/active; &0xFE = afflictions) |
-$50E[i] |
byte |
speed / initiative (set from unpacked -$11B1, record byte 0x18) |
-$503[i] |
byte | secondary stat (from unpacked -$11BA, record byte 0x14 hi nibble) |
-$77BE |
byte | live monster count |
-$524 |
byte | active party count (clamped to 10 for menus) |
-$5E4A[i] |
byte | monster "has acted this round" flag |
-$5E40[i] |
byte | party "has acted this round" flag |
0x11C2C instantiates one slot from the scratch unpack globals; 0x11C82
loops it over all monsters at battle/round start.
Characters are heap objects fetched by index via JSR -$7F20(A4) (-$4F5 =
current character, -$7959 = party size, -$5E4D = front-rank cutoff). Field
offsets observed in combat:
| Off | Field |
|---|---|
$0F |
class (2 gets a ranged option) |
$26 |
status bits (bit1 = silenced) |
$4E |
has bow / ranged weapon |
$58 |
spell points (word) |
$6E |
speed (initiative) |
$72 |
spellcaster flag |
- Reset round flags; clear
-$5E4A[0..9]and-$5E40[0..7](acted flags). - For each monster, roll RNG and update
-$519[i](wake/initiative bit). -
Initiative: scan monsters for the highest
-$50E[i]among not-acted ->-$5E38(best monster speed) /-$4F7(slot); scan party for highestchar.$6Eamong not-acted ->-$5E37/-$4F5. - If best character speed > best monster speed (and nonzero) ->
0x119C2(player turn). Else if a monster can act ->0x1064C(monster turn). Else nobody left -> advance. -
0x13282decides whether the round/combat continues. - End:
-$77BE==0->0x12430victory; else defeat/retreat via0x11646.
RNG helper: JSR -$7BB4(A4) with (1, max) returns a roll in [1,max].
-
0x11866draws the command bar and sets capability flags for the active character:-
-$5E36melee/attack: character is within front-rank cutoff-$5E4D. -
-$5E35shoot: class$0F==2or front rank, and$4E(bow) set. -
-$5E34cast: not silenced ($26bit1) and caster ($72) and spell points$58 > 0. - Each available command is printed via
0x1181E(string pointer table atA4-$6F9C: "A-Attack F-Fight S-Shoot C-Cast U-Use B-Block R-Run E-Exch V-View", colors/labels at-$6F4B/-$6F54).
-
-
0x1175Creads a key and accepts it only if valid (B D P Q V U E Ralways,A/Fif-$5E36,Sif-$5E35,Cif-$5E34). - Dispatch (jump table at
0x11BD0, key normalised by-0x41):
| Key | Action | Handler |
|---|---|---|
| A | Attack (single target) | 0xCD90 |
| F | Fight (auto/melee) | 0xCFD0 |
| C | Cast spell | spell select -> dispatch table 0xD000..0xD256
|
| S | Shoot (ranged) | (ranged path) |
| B | Block |
0x11B0A (-$7D5E/-$7C3E) |
| R | Run / retreat |
0x11B1A (-$7CC2 party reorder) |
| U | Use item |
0x11B62 (0x133EC) |
| V | View character |
0x11B6E (-$7E00) |
Target selection: 0x111DA ("which (A - x)?"), -$5E32 selects monster-side
(-$77BE) vs party-side (-$524) targeting; chosen index -> -$51D. The
Attack command has its own selector at 0xD43C/0xD390 (auto-targets when only
one monster remains).
0xD000..0xD256 is a jump table of per-spell handlers (JSR $bc3a, $bc7a, …
in the 0xBC00..0xC800 block), indexed by spell number; entries 0xD186+ are
the .w offsets.
For monster slot -$4F7 (status -$519[i]):
- Status byte
>= 0x80(special/disabled) -> handled separately. -
Flee:
-$11B6(Oabil bits 5-6) indexes probability tableA4-$6F1A; on a successful roll the monster runs (0x10DFCprints " runs"). - Otherwise it acts:
-
Archer (
-$11AE, Sabil bit6): ranged attack (0x10584). -
Group/party attack when the Pabil effect
-$11BCis in range:0x10002prints " " from the verb table atA4-$6E56(index 29 = "frenzies"); see doc 16. -
Melee otherwise:
0x10118, applying the single-target status effect-$11B9(Sabil low5) to a party member.
-
Archer (
-
Multiplies/breeds (
-$11A1, Oabil bit7):0x100B0roughly doubles the on-screen count. -
Adds friends (
-$11B7, Oabil low nibble):0x11F0Aappends reinforcement monster ids to-$11DE[](" adds friends!").
Battle status uses the -$519[] byte plus per-character bits. UI abbreviations
(table at A4-$6FBC): Enca Mdls Held Aslp Afrd Weak Siln Hurt
(encased / mindless / held / asleep / afraid / weak / silenced / hurt). Full
victim-effect names are the single-attack message table (doc 16, master[10..39]).
On -$77BE==0, 0x12430 ends combat. Per defeated monster, the reward routine
0x10B74 decodes record byte 0x10:
- bit2 -> add RNG(1..10) to
-$3F12(gems); - bits3-4 -> gold tier into
-$3F10(with/16or/2scaling + RNG); - bits0-1 -> item-drop level (
-$5E28/-$5E29); - accumulated XP
-$119Eadded to party total-$6FC6. "Experience has multiplied three-fold." (string0x14300) handles the bonus case.
| Addr | Routine |
|---|---|
0x12A22 |
round loop |
0x119C2 |
player turn |
0x11866 |
build command bar + capability flags |
0x1175C |
read valid command key |
0x1181E |
print one command-bar entry |
0x111DA |
target selector ("which (A - x)?") |
0x1064C / 0x106A0
|
monster turn / AI dispatch |
0x10002 |
monster group attack (verb table A4-$6E56) |
0xFEEA |
monster single attack |
0x10118 |
melee resolution |
0x10DFC |
flee ("runs") |
0x100B0 |
multiply / breed |
0x11F0A |
adds friends (reinforcements) |
0x10B74 |
per-monster reward decode |
0x12430 |
victory / end combat |
0x11646 |
defeat / retreat |
0x11C2C / 0x11C82
|
instantiate monster slot / all slots |
0x4C8E |
monster stat unpacker (doc 16) |
0xD000 |
spell-effect jump table |
From FAQ §2-5 / §3-8 — detail in 32-character-mechanics.md:
-
Extra attacks:
floor(level / divisor)— divisor 4 (Knight/Paladin/Barbarian), 5 (Archer/Robber/Ninja), 7 (Cleric), 10 (Sorcerer). ASM divisor table TBD. - HP per level at End 11–12: Barbarian 15 … Sorcerer 6 (see doc 32 table).
Extra attacks per round = floor(level / x) where x is class-dependent:
Divisor x
|
Classes |
|---|---|
| 4 | Knight, Paladin, Barbarian |
| 5 | Archer, Robber, Ninja |
| 7 | Cleric |
| 10 | Sorcerer |
Status: FAQ-sourced. ASM computation site not yet located in the current trace.
See also 32-character-mechanics.md §4 for HP/level baseline.
At Endurance 11–12 (no bonus): Knight 12, Paladin/Archer/Ninja 10, Cleric/Robber 8, Sorcerer 6, Barbarian 15 HP/level.
Endurance above 12 adds a bonus (see 32-character-mechanics.md §3).
Training at Atlantium vs Middlegate is ~6 HP/level difference. [FAQ §4-2]
- Unconscious party members: receive XP for the fight.
- Stoned / dead party members: do not receive XP.
- Characters who flee during combat: do not receive their share (but their share is not forfeited — it is distributed to the remaining party).
- Monsters that frenzy or explode: party does receive treasure + XP.
- Monsters that flee: party does NOT receive treasure/XP.
- Friend summon cap: only one friend-summon per fight; summon doubles the count of monsters not in the first 10; hard cap at 255 monsters total (>122 in back → summon impossible). [FAQ §3-8]
XP accumulation: 0x10B74 per-monster reward decode; accumulated in -$119E, added to party total -$6FC6 at victory 0x12430. [ASM confirmed]
- Exact to-hit / AC interaction and physical damage formula inside
0xCD90/0xCFD0/0x10118. - HP/XP code -> value tables (
A4-$746C,A4-$7464) numeric contents. - Full per-spell handler semantics (
0xBC00..0xC800).
The following notes are FAQ-sourced (lines 1841-1864) and have not been independently traced in ASM — treat as player-visible behaviour pending code confirmation.
-
Frenzy / explode: the party does receive XP and treasure (FAQ line
1841). Frenzy and explode are Pabil group-attack verbs (doc 16, verb table
A4-$6E56). -
Flee: monsters that flee yield no treasure and no XP share (FAQ line
1842-1843).
0x10DFCprints " runs". - Fleeing party members: a party member who flees combat does not receive XP for that encounter. However, their XP share is not forfeited to the remaining party — it is simply lost (FAQ line 1843-1844).
- Unconscious characters: receive XP (FAQ line 1845).
- Stoned / dead characters: do not receive XP (FAQ line 1845).
- When a monster uses "adds friends" (
Oabillow nibble via0x11F0A): the count of monsters not in the front 10 doubles (FAQ line 1846-1848). Example: 6 woodsmen in back → 12 after summon. - Maximum total monsters: 255. If there are > 122 monsters already in the back ranks, no more can be summoned (FAQ line 1848-1849).
- There is only one "adds friends" event per fight (FAQ line 1850).
The monster list in FAQ §3-8 includes a U (undead) column (Y/N). This
corresponds to Sabil bit 7 in monsters.dat byte 0x12 (doc 16). Undead
flag Y means: the monster is classified undead and can be affected by Turn
Undead (C1-7) and Holy Word (C9-2). Cross-reference: Sabil bit7
ASM-confirmed via 0xFEEA / 0x4C8E (doc 16).
| Page | Why |
|---|---|
| Combat Overview | Summary + mermaid |
| Spells and Item Use | Combat spell flags |
| 3D View and Game Screen | Encounter sprites |
- Docs Wiki Hub ← full doc index
- Getting Started ← read this first
- Overview
- Workspace Notes
- Open Questions
- Full Analysis
- Game Remake
- Startup and Init
- Runtime Memory Map
- Main Loop and Map
- Exploration Input and Options
- Party and Session
- Game State Struct
- Data Hunk mm2 data 00
- Time Era Calendar
- GFX Loading
- ANM TV Format
- PC DOS graphics
- SNES graphics
- 3D View and Game Screen
- Amiga 3D Render Process
- Scripted Scene Graphics
- Event Graphics Opcodes
- Title Screen Assets
- Title Screen Animation
- Format inventory
- items.dat
- monsters.dat
- roster.dat
- attrib.dat
- map.dat
- spells & item use
- event.dat
- Events by location ← 71 maps
- Events hub (numbered)
- Event Script Opcodes
-
Event Script DSL ←
.mm2evtauthoring - Event Text Rendering
- Event Graphics Opcodes
- Combat Overview
- Combat System
- Encounter Tables
- Spell Cast ASM
- monsters.dat abilities
- Spells and item use
- Amiga audio in exe ← Paula / DATA / remake
- Controls: Sounds / Walk Beep
- MM2 music format (superseded)
- Title/death audio paths (superseded)
- Known songs catalog (superseded)
- Town Services
- Spell Sources
- Character Mechanics
- Skills and Hirelings
- Commerce Formulas
- Commerce World Services
- Mount Farview Class Quest
- Class Quest HP Bug
- Event Runtime
- Event to String Path
- Embedded Exe Strings
- Copy Protection
- Time Era Calendar
- Game State Struct
- MM1 Overview ← hub + decode status
- MM1 MAZEDATA format
- MM1 to MM2 outdoor
- MM1 WALLPIX by sector
- MM1 art & graphics
- MM1 items / monsters (status)
- MM1 map walker ↗
- MM1 2D maps gallery
- MM1 WALLPIX gallery