-
Notifications
You must be signed in to change notification settings - Fork 0
Spell Cast ASM
Navigation: Home - Combat - Spell Cast ASM
Traced from EXTRACTED/mm2.asm (IRA + DC-gap decode) and cross-checked with
tools/_map_spell_handlers.py / tools/_trace_spell_picker.py.
Addresses are code-hunk load addresses (Capstone base 0). A4 is set to
LAB_7FFE at init (0x24948); game fields use negative d(A4) displacements.
flowchart TD
subgraph pick [Spell selection]
P1[JSR -$7E4E precast]
P2[JSR -$7E12 modal picker]
P3[JSR $6622 spell grid UI]
end
subgraph gate [School gate]
G1[JSR $13730]
G2{index in A4-$6D88?}
end
subgraph fx [Effect dispatch]
CDB8[$CDB8 + table $CDC6]
CFF8[$CFF8 + table $D002]
STUB[Per-spell stub $B900..$C800]
end
P1 --> P2
P2 --> P3
P3 --> G1
G1 --> G2
G2 -->|yes| CDB8
G2 -->|no| CFF8
CDB8 --> STUB
CFF8 --> STUB
Combat does not draw the spell-book grid. C goes straight to the level/number
prompt (-$7E12 / 0x79EE). The grid (LAB_6622) is only used from exploration
cast (0x6E30) and from combat character-sheet V (0x675A).
| Step | Address | IRA / gap line | Role |
|---|---|---|---|
| Player turn | 0x119C2 |
~13501 (DC) | Combat menu loop |
| Command bar | 0x11866 |
~13479 | Sets A4-$5E34 if caster, not silenced, SP>0 |
| Read key | 0x1175C |
~13463 |
CMPI #$43 accepts C
|
| Dispatch | 0x11BF8 |
~13538 |
'C' (#$43) → 0x11A90
|
| Precast | 0x11A90 |
~13515 | JSR -$7E4E(A4) |
| Picker | 0x11AAC |
~13517 |
JSR -$7E12(A4) → index in D0, $FFFF = cancel |
| School gate | 0x11AE8 |
— |
JSR $13730(PC) with index on stack |
| Cleric FX | 0x11AF6 |
— | if gate ≠ 0: JSR $CDB8(PC)
|
| Sorc FX | 0x11B02 |
— | if gate = 0: JSR $CFF8(PC)
|
| SP spend | 0x11B14 |
— | optional JSR $6DEE / refresh |
Readable IRA (not DC gap) — same picker, always uses $CDB8 after selection:
LINK.W A5,#-6 ;06e30
...
JSR LAB_6622(PC) ;06e8a ; spell grid
JSR -32274(A4) ;06e9a ; -$7E12 picker
...
JSR LAB_CDB8(PC) ;06ebc ; effect dispatch-
Call sites: only
0x06E9Aand0x11AAC. -
Not present as normal
LAB_code in the static image atA4-$7E12(that resolves to0x01EC, which is embedded string data in the hunk header). - Behaves like other MM2 UI entry points (
-$7BD2,-$7BE4, …): a runtime thunk in theA4workspace that opens the Intuition/list UI. - Nearby helper
0x6622builds the spell list grid before/around the modal:- Reads
A4-$85B0(active caster context). - Uses
A4-$8C22(9 level labels) andA4-$8C2B(spells-per-level counts). - Walks known spells via
LAB_65C2/ character field$51(A0)(spellbook bitmask on the live character object, sourced from roster$4C..$57at load).
- Reads
-
0x67C0(called from spell UI setup @0x65B8) usesJSR -$7BD2(A4)(same key-validation family as combat0x1175C) to step the highlight and return the chosen index.
013730 link.w a5,#$fffc
...
013744 lea.l -$6d88(a4),a0 ; 13 x uint16 table
013748 cmp.w (a0,d0.l), 8(a5) ; spell index from picker
...
; loop i = 0 .. 11
013766 addq.w #1,-$2(a5) ; if match before end → return 1
01376a move.w -$2(a5),d0 ; else return 0
rts
| Return | Combat branch | Meaning |
|---|---|---|
| 1 | JSR $CDB8 |
Picked index appears in A4-$6D88 (13 words) → cleric jump table |
| 0 | JSR $CFF8 |
No match → sorcerer jump table |
The table at A4-$6D88 is only read here (no static initializer found in
mm2.asm); it is filled at runtime when the caster/context is set up.
Dispatch is two-stage:
- A sparse-code executor validates/normalizes
D0and jumps by offset table. - The jump lands on a
jsr <stub> ; bra <return>pair.
00cdb8 link.w a5,#0
00cdbc move.w 8(a5),d0
00cdc2 bra.w $cfde
...
00cfde cmp.l #$60,d0 ; codes 0..95
00cfe8 lea.l $cf1e(pc),a0 ; sparse offset table
00cfec move.w (a0,d0.w),d0
00cff0 jmp $cff2(pc,d0.w)
- Stub pairs begin at
0xCDC6. - There are 43 direct spell stubs in this block (
0xCDC6..0xCF1A). - Offset table at
0xCF1Eis sparse; sentinel value+2maps to return/no-op.
00cff8 link.w a5,#0
00cffc move.w 8(a5),d0
00d002 bra.w $d266
...
00d266 subq.l #2,d0
00d268 cmp.l #$5c,d0 ; post-adjust range
00d272 lea.l $d1ae(pc),a0 ; sparse offset table
00d276 move.w (a0,d0.w),d0
00d27a jmp $d27c(pc,d0.w)
- Primary spell stub pairs at
0xD006..0xD182(48 Sorcerer entries). - Additional handlers at
0xD186..0xD1AA(5 extra entries) are reached via sparse table codes (these are part of the shared skill/spell engine, not a separate top-level cast menu). - Offset table at
0xD1AEis sparse;+2entries again mean return/no-op.
- The picker/gate does not pass a dense 0..47 school-local index directly.
- It passes a sparse spell code consumed by the executors above.
-
A4-$6D88in$13730acts as a 13-entry membership/gate list over that code space (currently read-only in static analysis).
Spell/skill handlers live in 0xB900–0xC800; common return points are
$CFF4 (CDB8 path) and $D27E (CFF8 path).
Typical combat spell stub pattern:
00b66c link.w a5,#$fffe
00b670 jsr $d464(pc) ; target picker ("which monster?")
00b678 cmpi.b #$1b,-$1(a5) ; cancel target?
00b680 ...
00b688 jsr $133b6(pc) ; apply effect (level, count, target)
00b69c jsr $108bc(pc) ; combat resolver / messaging
00b6a2 move.b #1,-$7958(a4) ; spell-acted flag
| Helper | Address | Role |
|---|---|---|
$D464 |
0xD464 |
Target selection UI; sets A4-$7958; 'A'..'J' monster slots |
$133B6 |
0x133B6 |
Effect applier: uses caster level $71(A0), RNG -7BB4, loops targets |
$108BC |
0x108BC |
Combat-side apply (monster count -77BE, party -524) |
$6DEE |
0x06DEE |
Deduct SP/gems from caster at A4-$B834 after cast |
- On-disk: 96 × 2 bytes cost/type (see
19-spells-and-item-use.md). -
0xE260and0x13772are equivalent spell-info render helpers:- both index
A4-$702A(lea -$702A(a4); move.l (a0,d0*4),...), - print labels via
-$7B84/-$7BE4, - optionally print suffix at
A4-$7026, - end with
jsr -$7E84(a4)(UI/audio cue path). This is strong evidence thatA4-$702A/$7026are spell metadata text pointers (cost/type fragments) loaded before cast UI.
- both index
- Stub handlers use
$133B6/$108BCfor behaviour; they do not readspells.datdirectly in the stub prologue.
Combat/spell code from 0x8000–0x248A5 is stored as DC.L in mm2.asm.
To read it:
- Generate
mm2.capstone.asm:python tools/disasm_m68k.py <mm2 executable> -o EXTRACTED - Or run:
python tools/_map_spell_handlers.py/tools/_trace_spell_picker.py
| Script | Purpose |
|---|---|
tools/_map_spell_handlers.py |
Full Sorc/Cleric jump table ↔ spell names |
tools/_trace_spell_picker.py |
Disassemble picker, gate, stubs |
tools/_trace_spell_cast.py |
Earlier combat-path trace |
tools/label_capstone.py |
Known labels @ combat addresses |
- Static body of
-$7E12(picker thunk) — needs runtime/workspace dump or second code hunk. - Exact producer of
A4-$6D88(13-word sparse-code membership table). - Per-stub semantics (damage formulas, status opcodes) in
0xB900–0xC800. - Confirm
A4-$702A↔spells.datload buffer with a loader trace @0x29868filename ref.
- 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
- 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