Secret of Evermore/Alchemy RAM manipulation

From Data Crystal
Jump to navigation Jump to search

This is a sub-page of Secret of Evermore.

Affects of the Alchemy Crash to a Player

Details

Usually there are only up to 2-3 spells active, because the game limits how many can be cast:

  • The boy has an internal cooldown on opening the ring menu after using alchemy
  • Bosses have some kind of internal cooldown
  • Only 8 alchemy spells per type can be active at any given moment
    • Particle type alchemy (like Flash and Fireball)
    • Animation type alchemy (like Crush and Acid Rain)

But there are known ways to circumvent these limitations:

  • Opening the boys ring menu as the dog can be done once per frame (Also known as 8cast, because the same spell can be cast up to 8 times)
  • Bosses cast their spells regardless of the limit (See Enemies Casting Spells)
    • Magmar casts at a certain damage threshold Heat Wave, which is an animation spell
    • Aquagoth randomly casts Lightning Storm and other spells, which are animation spells
    • Verminator randomly casts Acid Rain and other spells, which is are animation spells

Additional facts:

  • The 2x8 alchemy slots aren't cleared once the spell has been resolved, they are just flagged as inactive (Leaving the game overrides most memory with zeros, though)

Crash

Once the game tries to put the 9th alchemy spell in a slot the game somewhat freezes:

  • The game no longer progresses states
    • User inputs are blocked
    • Spell projectiles stop moving
    • Enemies stop moving
  • The music keeps playing the most recent loop (because it's not linked to the hardware)

In very rare cases the game does not crash and the following effects may occur based on what memory is being executed:

  • Severe visual glitches
    • Black screen
    • Repeating patterns
    • Corrupted HUD
    • Corrupted background
  • Side effects to the projectile
    • Animation alchemy like healing is randomly applied (E.g. Healing)
    • The projectile might fly in random directions (E.g. orbiting the boy, or flying outside the screen)

Reproducing the Crash

  • Cast a projectile alchemy spell near the exit of a map
  • Leave the screen instantly (before the projectile has been processed)
  • Unfinished projectiles are being flagged as "currently active" and cannot be reused anymore
    • This also circumvents the "only 8 per school" limitation, because it uses a separated stack
  • Once the 9th projectile is being cast the game "freezes"

Manipulating Memory

Details on the Crash

Casting 6 Hard Balls in the transition leads to the game crashing on the next 3+cast, which in almost all cases looks the same:

9198f7 ldx $0014,y   [7e3378] A:000a X:0000 Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 72 H:226 F:48
9198fa beq $9907     [919907] A:000a X:d22c Y:3364 S:1ff1 D:0000 DB:7e NvmxdizC V: 72 H:236 F:48
9198fc lda $0028,y   [7e338c] A:000a X:d22c Y:3364 S:1ff1 D:0000 DB:7e NvmxdizC V: 72 H:239 F:48
9198ff sta $4c       [00004c] A:4e89 X:d22c Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 72 H:249 F:48
919901 jsl $919750   [919750] A:4e89 X:d22c Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 72 H:256 F:48
919750 lda $910000,x [91d22c] A:4e89 X:d22c Y:3364 S:1fee D:0000 DB:7e nvmxdizC V: 72 H:270 F:48
919754 tax                    A:800a X:d22c Y:3364 S:1fee D:0000 DB:7e NvmxdizC V: 72 H:279 F:48
919755 jsr ($8000,x) [91000a] A:800a X:800a Y:3364 S:1fee D:0000 DB:7e NvmxdizC V: 72 H:282 F:48

00885f stp                    A:800a X:800a Y:3364 S:1fe8 D:0000 DB:7e NvmxdIzC V: 72 H:312 F:48
Address/Value Register/Usage Comment
$7E3378 (16 bit) X Is the 20th and 21st byte of the first animation alchemy slot ($7E3364-$7E3563, 40 bytes per slot)
$7E338c (16 bit) A Is the 40th and 41st byte of the first animation alchemy slot ($7E3364-$7E3563, 40 bytes per slot)
$910000 Base jump address for both X values Bank $91 mirrors bank $11 ($0000-$1FFF refer to LowRAM)
$8000 Final jump offset -

Which means that the jump address can be altered, by altering the first animation alchemy slot.

  • Store 2 bytes from $7E3378 in X_alchemy
    • $7E3378 happens to be the 14th and 15th byte of the first animation alchemy slot
    • MSB: $7E3379 (Seems to be some kind of timer which advances after $7E3378 overflows)
    • LSB: $7E3378 (Seems to be some kind of timer which advances after each partial animation)
  • Read 2 bytes from $910000+X_alchemy
    • X_alchemy=$0000-$1FFF happens to be LowRAM
    • MSB: $910000+X_alchemy+1 refers to $7E000+X_alchemy+1
    • LSB: $910000+X_alchemyrefers to $7E000+X_alchemy
  • Store that new value in X_ram
  • Jump to $918000+X_ram

This leads to the following formula: (Random value for X_alchemy)

[$7E3378] = $002B = X_alchemy
Jump
[$91002B] = $8080 = X_ram (Has an offset of $8000)
Jump with offset
[$910080] = $FFFE
Jump
Execute code

Or shorter:

[7E_3378]=0x002B -> [91_002B]=0x8080 -8k-> [91_0080]=0xFFFE -> [91_FFFE]=??? (Execute code)

Therefore the code can be manipulated by altering the indirect, indirect (with offset) jump.

Manipulating X_alchemy

To this point it's not known if X_alchemy can be overwritten at the right moment. Therefore it has to be routed with RNG first.

Examples: Seed=$0003:

[7E_3378]=0x0003 -> [91_0003]=0xC900 -8k-> [91_5900]="???" (In Unused)
9198f7 ldx $0014,y   [7e3378] A:000a X:0000 Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 45 H:176 F:31
9198fa beq $9907     [919907] A:000a X:0003 Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 45 H:186 F:31
9198fc lda $0028,y   [7e338c] A:000a X:0003 Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 45 H:189 F:31
9198ff sta $4c       [00004c] A:4e89 X:0003 Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 45 H:199 F:31
919901 jsl $919750   [919750] A:4e89 X:0003 Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 45 H:206 F:31
919750 lda $910000,x [910003] A:4e89 X:0003 Y:3364 S:1fee D:0000 DB:7e nvmxdizC V: 45 H:220 F:31
919754 tax                    A:c900 X:0003 Y:3364 S:1fee D:0000 DB:7e NvmxdizC V: 45 H:230 F:31
919755 jsr ($8000,x) [914900] A:c900 X:c900 Y:3364 S:1fee D:0000 DB:7e NvmxdizC V: 45 H:233 F:31

918080 iny                    A:c900 X:c900 Y:3364 S:1fec D:0000 DB:7e NvmxdizC V: 45 H:246 F:31
918081 sta $a841,y   [7edba6] A:c900 X:c900 Y:3365 S:1fec D:0000 DB:7e nvmxdizC V: 45 H:249 F:31
918084 stx $a7       [0000a7] A:c900 X:c900 Y:3365 S:1fec D:0000 DB:7e nvmxdizC V: 45 H:259 F:31
918086 ora ($ab),y   [7edaf8] A:c900 X:c900 Y:3365 S:1fec D:0000 DB:7e nvmxdizC V: 45 H:266 F:31
918088 rti                    A:c900 X:c900 Y:3365 S:1fec D:0000 DB:7e NvmxdizC V: 45 H:278 F:31
00885f stp                    A:c900 X:0000 Y:0065 S:1fec D:0000 DB:7e nVmXdIZC V: 45 H:307 F:31

Seed=$D22C:

[7E_3378]=0xD22C -> [91_D22C]=0x800A -8k-> [91_000A]="???" (In LowRAM)
9198f7 ldx $0014,y   [7e3378] A:000a X:0000 Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 72 H:226 F:48
9198fa beq $9907     [919907] A:000a X:d22c Y:3364 S:1ff1 D:0000 DB:7e NvmxdizC V: 72 H:236 F:48
9198fc lda $0028,y   [7e338c] A:000a X:d22c Y:3364 S:1ff1 D:0000 DB:7e NvmxdizC V: 72 H:239 F:48
9198ff sta $4c       [00004c] A:4e89 X:d22c Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 72 H:249 F:48
919901 jsl $919750   [919750] A:4e89 X:d22c Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 72 H:256 F:48
919750 lda $910000,x [91d22c] A:4e89 X:d22c Y:3364 S:1fee D:0000 DB:7e nvmxdizC V: 72 H:270 F:48
919754 tax                    A:800a X:d22c Y:3364 S:1fee D:0000 DB:7e NvmxdizC V: 72 H:279 F:48
919755 jsr ($8000,x) [91000a] A:800a X:800a Y:3364 S:1fee D:0000 DB:7e NvmxdizC V: 72 H:282 F:48

00885f stp                    A:800a X:800a Y:3364 S:1fe8 D:0000 DB:7e NvmxdIzC V: 72 H:312 F:48

With RNG

Based on yet unknown factors seemingly random values between $0000 and $FFFF are being used. That leads to different jumps for every X_alchemy value, unless the RNG has been locked.

Observed patterns:

  • $7E3379 seems to be either $00 or $FF, most of the time
    • $00-$1F are LowRAM ($01-1F contain relevant values)
  • $7E3378
    • Seems to be rather random

This leads to mostly to two specific memory blocks:

Memory Values Comment
$9100xx
00 00 ?? 00 ?? ?? ?? ?0 0? 00 00 00 ?? ?? 0? 00
64 35 ?? 01 ?? 51 e8 00 c9 00 3? 00 ?? ?? 00 00
00 00 f? ?? ?? 00 ?? ?? c? 8e ?? 80 ?? 00 ?? 0?
e2 00 00 00 60 01 a7 80 a7 00 00 c3 7f 00 12 00
0d 00 00 00 10 00 27 00 xx 00 74 02 ?? 4? ?? 0?
1? 00 0? 00 ?? 00 xx_xx 7f xx_xx xx_xx ?? ?? c7
00 00 00 00 00 00 1x ?? yx ?? xx 10 50 36 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
fe ff xx_00_00 00 00 00 00 00 01 00 80 a7 09 04
00 00 02 0c c4 34 08 xx 99 8e ff 00 00 00 85 14
00 00 8a 00 00 00 00 e4 81 a7 4f 93 a7 2e 13 7f
00 00 a7 00 00 00 00 00 00 00 00 00 00 00 00 70
02 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 ff 01 40 96 0? 00 ?? 00 ?? 0? ??
00 ?? 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
LowRAM contains a lot of volatile values:
  • x can be manipulated
  • ? is pseudo random (Current script)
$9101xx
xx_xx_xx_xx xx_xx 0f 00 00 00 00 00 04 00 b8 02
17 01 2d 02 df 00 00 00 ff ff 00 00 ff 00 ff 00
ff 00 00 00 00 8b 85 80 00 00 80 8b 85 80 00 00
00 00 00 93 50 46 91 fe 92 23 1b 78 00 78 00 80
64 a0 7f 32 0c 1a 00 80 64 a0 7f 32 0c 1a 00 80
64 a0 7f 32 0c 1a 00 80 64 a0 7f 32 0c 1a 00 80
64 a0 7f 32 0c 1a 00 80 64 a0 7f 32 0c 1a 00 80
...
Slightly out of range for $9100xx
$91ffxx
00 01 00 c0 00 00 00 00 00 00 00 80 00 00 07 00
1f 00 01 00 c0 00 00 00 00 00 00 00 80 80 00 e0
00 80 00 00 00 00 00 03 00 00 00 00 00 00 80 00
e0 00 80 00 00 00 00 00 03 00 00 00 00 e0 00 80
00 00 00 00 00 07 00 00 00 00 00 00 00 00 e0 00
80 00 00 00 00 00 07 00 00 00 00 00 00 00 00 00
00 00 00 e0 00 f0 00 00 00 00 00 00 00 00 00 00
00 00 00 00 e0 00 f0 00 00 00 00 00 00 3f 03 00
00 00 00 00 00 00 03 00 1f 00 01 00 00 00 00 03
00 00 00 00 00 00 00 03 00 1f 00 01 00 00 80 00
00 00 00 00 00 00 c0 00 f0 00 c0 00 00 00 00 80
00 00 00 00 00 00 00 c0 00 f0 00 c0 00 00 00 00
00 00 00 00 00 00 80 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 80 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 1c 00 70 00 00 00 00 00
00 00 00 00 00 00 00 00 00 1c 00 70 00 00 00 08
ROM

Bytes that can be manipulated:

Address Values Comment
$0048 $00-$?? Increases by 1 every 11 vertical pixels camera movement

Moving sprites influence that value

$0056-$0057 ? Unknown purpuse, but any moving entity changes this value deterministically (Therefore hard to manipulate)
$0059-$005A $0000-$0620 (Utopia map) Copy of the camera offset X (Can be pause buffered)

Coordinates over $0FFF don't exist!

$005B-$005C $0000-$0440 (Utopia map) Y (See $0059-$005A)

Coordinates over $0FFF don't exist!

$0066 $00-$10 Increases by 1 every 1 vertical pixel movement

Moving sprites influence that value

$006A $00-$06f (Sandpits map) Increases by 1 every 11 vertical pixels movement

Moving sprites influence that value

$0082 $00-$FF? Lower half of the pointer to the most recent script ($83 and $84 get cleared)
$0095
  • Can be used:
    • $8C (Boy)
    • $98 (Dog)
    • $C2 (Call Beads - Choose spell)
  • Can't be used:
    • $AC (Buy ingredients)
    • $B0 (Call Beads - Choose person)
    • $9C (Buy consumables)
    • $A4 (Sell consumables)
Most recent ring menu ($93 and $94 get cleared)

Other menus can't be closed without entering the boys or dogs ring menu

Slightly outside $9100FF
$0100-$0103 $00000000-$FFFFFFFF Frame counter
$0104-$0105 $00-$FF Controller inputs (Player 1)

X_alchemy values that load specific values as X_ram:

X_alchemy X_ram Comment
$0081 $xxFF See $0082
$0082 $00xx $82 can be manipulated by triggering scripts
$0094 $(8C,98,C2)00 See $0095
$0095 $00(8C,98,C2) $95 can be manipulated by closing ring menus
? $8100 Frame counter ($0100)
$0002, $0018, $001C, $0054, $00DB, $00E1, etc. $xx00 Wildcards (Very hard to manipulate)

Example: Enforce $0100 with the table

Possible X_alchemy values: $910089, $91ff00, $91ff11, $91ff89, $91ff9A

Seed=$FF89:

[7E_3378]=0xFF89 -> [91_FF89]=0x0100 -8k-> [91_8100]="???" (In ??)
; missing ldx line
9198fa beq $9907     [919907] A:000a X:ff89 Y:3364 S:1ff1 D:0000 DB:7e NvmxdizC V: 60 H: 26 F:48
9198fc lda $0028,y   [7e338c] A:000a X:ff89 Y:3364 S:1ff1 D:0000 DB:7e NvmxdizC V: 60 H: 29 F:48
9198ff sta $4c       [00004c] A:4e89 X:ff89 Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 60 H: 39 F:48
919901 jsl $919750   [919750] A:4e89 X:ff89 Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 60 H: 46 F:48
919750 lda $910000,x [91ff89] A:4e89 X:ff89 Y:3364 S:1fee D:0000 DB:7e nvmxdizC V: 60 H: 60 F:48
919754 tax                    A:0100 X:ff89 Y:3364 S:1fee D:0000 DB:7e nvmxdizC V: 60 H: 69 F:48
919755 jsr ($8000,x) [918100] A:0100 X:0100 Y:3364 S:1fee D:0000 DB:7e nvmxdizC V: 60 H: 72 F:48

918416 bit $00,x     [000100] A:0100 X:0100 Y:3364 S:1fec D:0000 DB:7e nvmxdizC V: 60 H: 85 F:48
918418 eor ($00)     [7e0000] A:0100 X:0100 Y:3364 S:1fec D:0000 DB:7e nvmxdiZC V: 60 H: 93 F:48
91841a bpl $841c     [91841c] A:0100 X:0100 Y:3364 S:1fec D:0000 DB:7e nvmxdizC V: 60 H:104 F:48
91841c cop #$00               A:0100 X:0100 Y:3364 S:1fec D:0000 DB:7e nvmxdizC V: 60 H:109 F:48
00885e stp                    A:0100 X:0100 Y:3364 S:1fe8 D:0000 DB:7e nvmxdIzC V: 60 H:124 F:48

With Alchemy

Usually X can be altered by casting animation based alchemy, but not during the crash.

There is no proof yet, but the memory behind X_alchemy can also be set by casting an animation. Items are also included in this list, because they are treated as animation spell.

This is done by casting them and waiting for the sub animation of interest to set the memory value:

Alchemy Possible X_alchemy Values Comment
Acid Rain $86F0, $86F2, $86F8, $8716, $871C, $871E, $8722, $8726 -
Atlas $8B2A, $8B2C, $8B32, $8B44, $8B48, $8B4A, $8B50, $8B52 -
Barrier $944C, $944E, $9452, $9462, $9466, $9474 -
Cure $85D8, $85DA, $85DC, $85E2, $85F2, $86C6, $86CC, $86CE, $86D2, $86E2 -
Crush $8A9C, $8A9E, $8AA4, $8AAE, $8ABA, $8B04, $8B0C -
Corrosion $8F20, $8F22, $8F2C, $8F42, $8F48, $8F4A, $8F54, $8F5A, $8F5C, $8F46, $8F6A, $8F78, $8F7E, $8F80, $8F8A -
Defend $872A, $872C, $8732, $8740, $8744 -
Double Drain $9362, $9364, $9376, $937E, $9380, $9382, $938E, $9390, $9446 -
Drain $89B4, $89B6, $89C8, $89D0, $89D2, $89D4, $89E0, $89E2 -
Energize $9610, $9612, $9616, $961C -
Escape $8E22, $8E24, $8E2C -
Explosion $90D2, $90D4, $90DA, $90EA, $90FE, $91BE, $91C0, $91C4, $91CA -
Fireball - -
Fire Power $8F8E, $8F90, $8F92, $8F9A, $8FA6, $8FA8, $8FAA $9068, $9070 -
Flash - -
Force Field $962A, $962C, $9630, $9636 -
Heal $886C, $886E, $8872, $8880 $894E, $895E, $8960, $8964, $8968 -
Lance $8E36, $8E38, $8E3A, $8E40, $8E4E $8F14, $8F1E -
Levitate $896E, $8970, $8974, $897E, $8982, $8984 Can only be cast once per rock
Lightning Storm $91CC, $91CE, $91D4, $91Da, $91E4 -
Miracle Cure $920C, $920E, $9212, $9226, $9230, $9240, $9242, $9246, $9254, $925A, $925C, $9268 -
Nitro $94F6, $94F8, $94FE, $9508, $9522, $95D8 -
One Up $9072, $9074, $907A, $9080, $909E, $90A0, $90A4 -
Reflect $95DC, $95DE, $95E4, $95EA -
Regrowth $90AE, $90B0, $90B4, $90C2 -
Reveal ? Can only be cast in act 2
Revive $8B60, $8B62, $8B66, $8C34, $8C4A Requires the dog to be dead
Slow Burn $91E6, $91E8, $91F2, $9202 -
Speed $8988, $898A, $898E, $899C, $89A4 -
Sting $8B10, $8B12, $8B18, $8B1E, $8B26 -
Stop $94D6, $94D8, $94DE, $94E8 -
Super Heal $947E, $9480, $9484, $9492, $9494, $949E, $94A8, $94BE, $94C8, $94CA, $94CE -
Storm $81C0, $81C2, $81C8, $81CE, $81D8 -
Life Spark $81DA, $81DC, $81E2, $81EE, $81F0, $81F8 -
Flare - -
Heat Wave $8164, $8166, $816C, $817E, $818A, $818C, $8198, $819A, $81A4, $81AA, $81AC, $81B6, $81CB -
Time Warp $8200, $8202, $8208, $823E, $8244, $8246, $825C -
First Aid $8270, $8272, $8278, $8284, $828A, $8294, $829E, $82B4, $82BE, $82C0, $82C4, $82CA -
Confound $82CE, $82D0, $82D6, $82E0, $82F4, $82FE, $8300, $8304 -
Plague $8416, $8418, $8420, $842A, $8440, $8432, $845C, $8474, $847E, $8480, $8484, $849C, $84A2, $84A4 -
Hypnotize $84AC, $84AE, $84B4, $84E8, $84EA, $8500 -
Shock Wave $8374, $8376, $837C, $8390, $8392, $839C, $839E, $83A8, $83AA, $83B4, $83B6, $83C0, $83C2, $83CC, $83CE, $83D8, $83DA, $83E4, $83E6, $83F0, $83F2, $83F6 -
Electra-Bolt $85B0, $85B2, $85B8, $85C6, $85D0, $85D2, $85D8 -
Disrupt $8512, $8514, $851A, $8524, $8538, $8542, $8544, $8548, $854E -
Dog Biscuit $96D8, $96DA, $96DE, $9718, $972E Requires the dog to be dead
Essence $9644, $9646, $964A, $965C, $9674, $967A, $967C, $9680 -
Honey $9690, $9692, $9696, $96A4, $96B8, $96C8, $96CA, $96CE, $96D2 -
Nectar (See Honey) -
Petal (See Honey) -
Pixie Dust $830E, $8310, $8314, $8324, $8328, $8336, $8344 -
Wings $8E22, $8E24, $8E2C -

Desired Values for X_ram

X_alchemy just has to find a good X_ram value. (It's hard to make a list of #FFFF values, which are partially dynamic)

The offset of $918000 leads to the following jumps for X_ram:

X_ram Value Bank Addresses Comment
$0000-$7FFF $11 $8000-$FFFF HiROM section (program memory)
$8000-$9FFF $12 $0000-$1FFF LowRAM, shadowed from bank $7E
$A000-$A0FF $12 $2000–$20FF Unused
$A100–$A1FF $12 $2100–$21FF PPU1, APU, hardware registers
$A200–$AFFF $12 $2200–$2FFF Unused
$B000–$BFFF $12 $3000–$3FFF DSP, SuperFX, hardware registers
$C000–$C0FF $12 $4000–$40FF Old Style Joypad Registers
$C100–$C1FF $12 $4100–$41FF Unused
$C200–$C4FF $12 $4200–$44FF DMA, PPU2, hardware registers
$C500–$DFFF $12 $4500–$5FFF Unused
$E000–$FFFF $12 $6000–$7FFF RESERVED

LowRAM is the easiest memory to manipulate and contains promising values:

X_ram Value LowRAM Address Comment
$8A3F-$8A40 $0A3F-$0A40 Boy - Attack (Roughly $0000-$00FF and $FF00-$FFFF)
$8A41-$8A42 $0A41-$0A42 Boy - Defense (Roughly $0000-$00FF and $FF00-$FFFF)
$8AC6-$8AC8 $0AC6-$0AC8 Money - Talons
$8AC9-$8ACB $0AC9-$0ACB Money - Jewels
$8ACC-$8ACE $0ACC-$0ACE Money - Gold Coins
$8ACF-$8AD1 $0ACF-$0AD1 Money - Credits
$B218-? $4218-? Controller inputs

Executing Code

Code that shall be executed:

  • 5 bytes of arbitrary code and 3 bytes to loop back to controller 1
  • $CB waits till the next interrupt (Which happens to be once per frame)
  • The last 3 bytes cannot be changed, because it'd desync the process
Instruction Comment
EA EA EA EA EA CB 80 F8 Do nothing (Also synchronizes the ACE)
A9 XX XX EA EA CB 80 F8 Store value in accumulator
8D XX XX EA EA CB 80 F8 Store accumulator in memory
8F XX XX XX EA CB 80 F8 Store accumulator in memory (long)
60 60 60 60 60 60 60 60 Exit ACE

First Controller Copy

The by far easiest address to reach address, that can still be manipulated, is the 2 Byte copy of the first controller:

7E0059 to 7E005A = Copy of camera x offset (Mask: 0FFF)
7E005B to 7E005C = Copy of camera y offset (Mask: 0FFF)

7E0104 to 7E0105 = Copy of the first controller
Address Alias Value Comment
$7E3378 $AnimationAlchemySlot0Byte14 $SemiRandomNumber Somewhat based on the animation of the 9th particle
$7E005A $CameraXY (XX) 04 81 (XX) Camera offset X=$01XX and Y=$XX81 pixels: (Can be pause buffered)

$FrameCounter with an offset of $8000

$7E0104 $FirstControllerCopy 1A 42 Can be altered by pressing buttons

Jump to controller inputs ($421A)

$914218 $ControllerInputs $ArbitraryCode Can be altered by pressing buttons and is usually used for Arbitrary Code Execution

Seed=$005A (No RAM manipulation, no code example)

[7E_3378]=0x005A -> [91_005A]=0x8104 -8k-> [91_0104]=0x421A -> [91_421A]="arbitrary code"

Frame Counter

Close second is the 4 Byte frame counter, which was utilized for the first ACE attempts:

7E0059 to 7E005A = Copy of camera x offset (Mask: 0FFF)
7E005B to 7E005C = Copy of camera y offset (Mask: 0FFF)

7E0100 to 7E0103 = Frame counter

It can be accessed in various ways...

By manipulating the camera offset:

[7E_3378]=$005A -> [91_005A]=$8100 -8k-> [91_0100]=$4218 -> [91_4218]="arbitrary code" (Frame counter Byte 0-2)
[7E_3378]=$005A -> [91_005A]=$8101 -8k-> [91_0101]=$4218 -> [91_4218]="arbitrary code" (Frame counter Byte 1-3)
Address Alias Value Comment
$7E3378 $AnimationAlchemySlot0Byte14 $SemiRandomNumber Somewhat based on the animation of the 9th particle
$7E005A $CameraXY (XX) 01 81 (XX) Camera offset X=$01XX and Y=$XX81 pixels: (Can be pause buffered)

$FrameCounter with an offset of $8000

$7E0101 $FrameCounter (XX) 18 42 (XX) 4,331,520 Frames: (Roughly 20 hours, but valid for $FF frames)

Jump to controller inputs ($4218)

$914218 $ControllerInputs $ArbitraryCode Can be altered by pressing buttons and is usually used for Arbitrary Code Execution

Seed=$005A (No RAM manipulation, random frame count)

[7E_3378]=0x005A -> [91_005A]=0x8101 -8k-> [91_0101]=0x0AEA -> [91_0AEA]="random code"
; x_alchemy=$SemiRandomNumber ([AnimationAlchemySlot0Byte14])
; missing ldx ("read $7E3378=$5A" triggers the break point)
9198fa beq $9907     [919907] A:000a X:005a Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 37 H:275 F:57
9198fc lda $0028,y   [7e338c] A:000a X:005a Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 37 H:278 F:57
9198ff sta $4c       [00004c] A:4e89 X:005a Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 37 H:288 F:57
919901 jsl $919750   [919750] A:4e89 X:005a Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 37 H:295 F:57

; A=$FrameCounter ([$CameraXY], including an 8k offset)
919750 lda $910000,x [91005a] A:4e89 X:005a Y:3364 S:1fee D:0000 DB:7e nvmxdizC V: 37 H:308 F:57
; x_ram=A
919754 tax                    A:8101 X:005a Y:3364 S:1fee D:0000 DB:7e NvmxdizC V: 37 H:318 F:57
; jump to $RandomFrameCount ($CameraXY)
919755 jsr ($8000,x) [910101] A:8101 X:8101 Y:3364 S:1fee D:0000 DB:7e NvmxdizC V: 37 H:321 F:57

; frame count = $00000AEA00xx ([$RandomFrameCount] Contains no useful code, but can be easily manipulated)
910aea ora ($00,x)   [7e0a9c] A:8101 X:8101 Y:3364 S:1fec D:0000 DB:7e NvmxdizC V: 37 H:334 F:57
910aec ora ($00,x)   [7e0a9c] A:8501 X:8101 Y:3364 S:1fec D:0000 DB:7e NvmxdizC V: 38 H:  8 F:57
910aee ora ($00,x)   [7e0a9c] A:8501 X:8101 Y:3364 S:1fec D:0000 DB:7e NvmxdizC V: 38 H: 21 F:57
910af0 ora ($00,x)   [7e0a9c] A:8501 X:8101 Y:3364 S:1fec D:0000 DB:7e NvmxdizC V: 38 H: 35 F:57
910af2 ora ($00,x)   [7e0a9c] A:8501 X:8101 Y:3364 S:1fec D:0000 DB:7e NvmxdizC V: 38 H: 48 F:57
910af4 ora ($00,x)   [7e0a9c] A:8501 X:8101 Y:3364 S:1fec D:0000 DB:7e NvmxdizC V: 38 H: 62 F:57
910af6 ora ($00,x)   [7e0a9c] A:8501 X:8101 Y:3364 S:1fec D:0000 DB:7e NvmxdizC V: 38 H: 75 F:57
910af8 brk #$00               A:8501 X:8101 Y:3364 S:1fec D:0000 DB:7e NvmxdizC V: 38 H: 89 F:57
00885f stp                    A:8501 X:8101 Y:3364 S:1fe8 D:0000 DB:7e NvmxdIzC V: 38 H:105 F:57

Seed=$005A (Injected frame count)

[7E_3378]=0x005A -> [91_005A]=0x8101 -8k-> [91_0101]=0x4218 -> [91_4218]="arbitrary code"
; missing ldx ("read $7E3378=$5A" triggers the break point)
; missing beq
; missing lda
9198ff sta $4c       [00004c] A:4e89 X:005a Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 65 H:287 F:35
919901 jsl $919750   [919750] A:4e89 X:005a Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 65 H:294 F:35
919750 lda $910000,x [91005a] A:4e89 X:005a Y:3364 S:1fee D:0000 DB:7e nvmxdizC V: 65 H:307 F:35
919754 tax                    A:8101 X:005a Y:3364 S:1fee D:0000 DB:7e NvmxdizC V: 65 H:317 F:35
919755 jsr ($8000,x) [910101] A:8101 X:8101 Y:3364 S:1fee D:0000 DB:7e NvmxdizC V: 65 H:320 F:35

914218 brk #$00               A:8101 X:8101 Y:3364 S:1fec D:0000 DB:7e NvmxdizC V: 65 H:333 F:35
00885f stp                    A:8101 X:8101 Y:3364 S:1fe8 D:0000 DB:7e NvmxdIzC V: 66 H:  8 F:35

Currencies

The currencies contain 12 Bytes, which can be manipulated by killing enemies and buying items:

7E0AC6 to 7E0AC8 = Money - Talons
7E0AC9 to 7E0ACB = Money - Jewels
7E0ACC to 7E0ACE = Money - Gold Coins
7E0ACF to 7E0AD1 = Money - Credits
Address Alias Value Comment
$7E3378 $AnimationAlchemySlot0Byte14 $SemiRandomNumber Somewhat based on the animation of the 9th particle
$7E0AC6 $Talon C9 8A (XX) 35,529 Talons:

$Jewels with an offset of $8000

$7E0AC9 $Jewels CC 0A (XX) 2,764 Jewels:

$GoldCoins

$7E0ACC $GoldCoins 5C 18 42 4,331,612 Gold Coins:

Arbitrary code 1: Long jump ($5C) to controller inputs ($4218)

$7E0ACF $Credits 00 (XX XX) 0 Credits:

Arbitrary code 2: The chosen example requires a 4th Byte

$004218 $ControllerInputs $ArbitraryCode Can be altered by pressing buttons and is usually used for Arbitrary Code Execution

Seed=$0AC6: (Manually injected)

[7E_FF89]=0x0AC6 -> [91_0AC6]=0x8AC9 -8k-> [91_0AC9]= 0x0ACC -> [91_0ACC]="JML 004218" (Long jump to $004218)
; x_alchemy=$SemiRandomNumber ([AnimationAlchemySlot0Byte14])
9198f7 ldx $0014,y   [7e3378] A:000a X:0000 Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 60 H:167 F: 9

; x_alchemy=$Talon (Injected $Talon, for testing)
9198fa beq $9907     [919907] A:000a X:ffb8 Y:3364 S:1ff1 D:0000 DB:7e NvmxdizC V: 60 H:177 F: 9

9198fc lda $0028,y   [7e338c] A:000a X:0ac6 Y:3364 S:1ff1 D:0000 DB:7e NvmxdizC V: 60 H:180 F: 9
9198ff sta $4c       [00004c] A:4e89 X:0ac6 Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 60 H:190 F: 9
919901 jsl $919750   [919750] A:4e89 X:0ac6 Y:3364 S:1ff1 D:0000 DB:7e nvmxdizC V: 60 H:197 F: 9

; A=$Jewels ([$Talon], including an 8k offset)
919750 lda $910000,x [910ac6] A:4e89 X:0ac6 Y:3364 S:1fee D:0000 DB:7e nvmxdizC V: 60 H:210 F: 9

; x_ram=A
919754 tax                    A:8ac9 X:0ac6 Y:3364 S:1fee D:0000 DB:7e NvmxdizC V: 60 H:220 F: 9

; jump to $GoldCoins ([$Jewels])
919755 jsr ($8000,x) [910ac9] A:8ac9 X:8ac9 Y:3364 S:1fee D:0000 DB:7e NvmxdizC V: 60 H:223 F: 9

; jump to $ControllerInputs ([$GoldCoins])
910acc jml $004218   [004218] A:8ac9 X:8ac9 Y:3364 S:1fec D:0000 DB:7e NvmxdizC V: 60 H:237 F: 9

004218 brk #$00               A:8ac9 X:8ac9 Y:3364 S:1fec D:0000 DB:7e NvmxdizC V: 60 H:245 F: 9
00885f stp                    A:8ac9 X:8ac9 Y:3364 S:1fe8 D:0000 DB:7e NvmxdIzC V: 60 H:260 F: 9

Routing the Exploit

Software

  • Secret of Evermore
    • US
  • lsnes
    • Arbitrary 64 bit inputs
    • LUA scripts (Which help with the ACE)

Route

Setup

  • Start a new game
  • Intro (Cannot be skipped in a TAS, because having a preexisting save file would be treated as "dirty SRAM")
  • Raptor Fight skip
  • Fireeyes cutscene skip
  • Get Hard Ball Formula (This would also work with Flash, but it should take longer since it costs 2 oil)
    • Gather 9 clay and 9 crystals on the way (Crystals can also be purchased for 60 Talons)
  • Cast 8 Hard Balls into a transition
    • Can be verified by probing if the 9th crashes the game

Manipulation

  • Camera Offset
    • Move to a map that has beneficial coordinates (E.g. Bugmuck is good, Eastern Jungle with another weapon is good, Sandpits less)
    • X is pixel perfect (LSB), Y has to be $FF pixel precise (MSB)
    • Can be pause buffered (Pixel perfect)
    • Map coordinates are masked with $0FFF (The MSB is mostly $00 or $01)
    • The camera can be moved between Boy and Dog by swapping the active character (Which makes the RNG manipulation way harder)
  • First Controller Copy
    • The crash happens exactly 37 bytes after B has been pressed
    • Due to the way the bits are being cleared, the inputs have to be close to frame perfect
  • 9cast Crash
    • The RNG locks when the menu is open up until the crash happens
    • Sometimes the RNG seems to rapidly increase, sometimes it seems rapidly decrease
    • Letting the Dog sniff removes a moving unit
    • Sometimes the RNG is linked to the buttons pressed

Code Execution

  • Remove the 9th projectile from the first animation alchemy slot
    • If an invalid byte remains in this memory the game will crash in the next frame
    • In theory it should be possible to "deactivate" it instead
  • Optional:
    • Set credits flag ($22EB=$FF)
    • Switch active weapon to a spear ($22DA=$18)
    • Activate Toaster Dog ($2363=$0C)
    • etc.

LUA script snippet:

send_lda(0xFFFF)
send_sta(0x22EB) --credit_active

send_lda(0x0000)
send_sta(0x3364) --clear_crashing_alchemy ($3364-$337C)
send_sta(0x3366)
send_sta(0x3368)
send_sta(0x336A)
send_sta(0x336C)
send_sta(0x336D)
send_sta(0x336F)
send_sta(0x3371)
send_sta(0x3373)
send_sta(0x3375)
send_sta(0x3377)
send_sta(0x3379)
send_sta(0x337B)

set_frame(0x60) --exit_crashing_alchemy
; sync loop with nops
; controller1 is busy
; controller1 is busy
91421a nop                    A:8100 X:8100 Y:3364 S:1fe9 D:0000 DB:7e NvmxdizC V: 92 H: 620
91421b nop                    A:8100 X:8100 Y:3364 S:1fe9 D:0000 DB:7e NvmxdizC V: 92 H: 632
91421c nop                    A:8100 X:8100 Y:3364 S:1fe9 D:0000 DB:7e NvmxdizC V: 92 H: 644
91421d wai                    A:8100 X:8100 Y:3364 S:1fe9 D:0000 DB:7e NvmxdizC V: 92 H: 656
-- NMI occured --
91421e bra $4218     [914218] A:8100 X:8100 Y:3364 S:1fe9 D:0000 DB:7e NvmxdizC V:228 H: 942

; load $FFFF
914218 lda #$ffff             A:8100 X:8100 Y:3364 S:1fe9 D:0000 DB:7e NvmxdizC V:228 H: 960
91421b nop                    A:ffff X:8100 Y:3364 S:1fe9 D:0000 DB:7e NvmxdizC V:228 H: 978
91421c nop                    A:ffff X:8100 Y:3364 S:1fe9 D:0000 DB:7e NvmxdizC V:228 H: 990
91421d wai                    A:ffff X:8100 Y:3364 S:1fe9 D:0000 DB:7e NvmxdizC V:228 H:1002
-- NMI occured --
91421e bra $4218     [914218] A:ffff X:8100 Y:3364 S:1fe9 D:0000 DB:7e NvmxdizC V:228 H: 984

; override credit flags and the following byte
914218 sta $22eb     [7e22eb] A:ffff X:8100 Y:3364 S:1fe9 D:0000 DB:7e NvmxdizC V:228 H:1002
91421b nop                    A:ffff X:8100 Y:3364 S:1fe9 D:0000 DB:7e NvmxdizC V:228 H:1036
91421c nop                    A:ffff X:8100 Y:3364 S:1fe9 D:0000 DB:7e NvmxdizC V:228 H:1048
91421d wai                    A:ffff X:8100 Y:3364 S:1fe9 D:0000 DB:7e NvmxdizC V:228 H:1060
-- NMI occured --
91421e bra $4218     [914218] A:ffff X:8100 Y:3364 S:1fe9 D:0000 DB:7e NvmxdizC V:228 H: 984

; load $0000
914218 lda #$0000             A:ffff X:8100 Y:3364 S:1fe9 D:0000 DB:7e NvmxdizC V:228 H:1002
91421b nop                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1020
91421c nop                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1032
91421d wai                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1044
-- NMI occured --
91421e bra $4218     [914218] A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H: 984

; clear alchemy slot 0 from the crash ($3364-$337C)
914218 sta $3364     [7e3364] A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1002
91421b nop                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1036
91421c nop                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1048
91421d wai                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1060
-- NMI occured --
91421e bra $4218     [914218] A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H: 984

914218 sta $3366     [7e3366] A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1002
91421b nop                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1036
91421c nop                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1048
91421d wai                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1060
-- NMI occured --
91421e bra $4218     [914218] A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1024

914218 sta $3368     [7e3368] A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1042
91421b nop                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1076
91421c nop                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1088
91421d wai                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1100
-- NMI occured --
91421e bra $4218     [914218] A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1024

914218 sta $336a     [7e336a] A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1042
91421b nop                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1076
91421c nop                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1088
91421d wai                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1100
-- NMI occured --
91421e bra $4218     [914218] A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1028

914218 sta $336c     [7e336c] A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1046
91421b nop                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1080
91421c nop                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1092
91421d wai                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1104
91421e bra $4218     [914218] A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1028

914218 sta $336d     [7e336d] A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1046
91421b nop                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1080
91421c nop                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1092
91421d wai                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1104
91421e bra $4218     [914218] A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1028

914218 sta $336d     [7e336d] A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1046
91421b nop                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1080
91421c nop                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1092
91421d wai                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1104
-- NMI occured --
91421e bra $4218     [914218] A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1068

914218 sta $336f     [7e336f] A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1086
91421b nop                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1120
91421c nop                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1132
91421d wai                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1144
-- NMI occured --
91421e bra $4218     [914218] A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1068

914218 sta $3371     [7e3371] A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1086
91421b nop                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1120
91421c nop                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1132
91421d wai                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1144
-- NMI occured --
91421e bra $4218     [914218] A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1066

914218 sta $3373     [7e3373] A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1084
91421b nop                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1118
91421c nop                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1130
91421d wai                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1142
-- NMI occured --
91421e bra $4218     [914218] A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1070

914218 sta $3377     [7e3377] A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1088
91421b nop                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1122
91421c nop                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1134
91421d wai                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1146
-- NMI occured --
91421e bra $4218     [914218] A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1112

914218 sta $3379     [7e3379] A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1130
91421b nop                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1164
91421c nop                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1176
91421d wai                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1188
-- NMI occured --
91421e bra $4218     [914218] A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1110

914218 sta $337b     [7e337b] A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1128
91421b nop                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1162
91421c nop                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1174
91421d wai                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1186
-- NMI occured --
; no need to branch

; exit ACE
91421e rts                    A:0000 X:8100 Y:3364 S:1fe9 D:0000 DB:7e nvmxdiZC V:228 H:1110

Payoff

  • Move to a map that has an outro event trigger (Which triggers a specific script)
    • Landing Place ($08, requires a weapon that can cut grass)
    • Village (Should have a similar flag)

RTA Strategies

The RTA route has to get the same results as the TAS route, without the assistance of tools.

Problem Memory Comment
The crash is only semi reliable $3378-$3379
  • Getting the desired outcome is 1:256
  • There are no known manipulations for the game
Inputs are heavily restricted $4218-$421F
  • 64 bit inputs would require 1-2 Multi Taps and 4 custom controllers
    • TAS: BYsS ↑↓←→ AXLR 0123
    • RTA: BYsS (Only one)↑↓←→ AXLR $0 (Without wobbling and device identifier code 0)
  • Frame perfect inputs are not reliable
  • This limits both reachable addresses, as well as code that can be executed
The crash has to be cleared more efficiently $3364-$337C
  • This can be tested easily with an emulator
  • Instead of filling the memory with zeros, only the relevant bytes should be changed
TAS restrictions still apply -
  • 9cast crash is required and has to be cleared with the executed code
  • A credit related screen has to be entered with the glitched progress flags

Code Storage

Controllers

Problem Memory Comment
The copy of controller 1 cannot point at the controllers $0104
  • It's not possible to hold these buttons: -Y-- --←- ---R 0-2-
  • There is no known controller with hardware ID code $A [1]
  • Building a 16 button custom controller is possible
  • Using the other routes is possible, but way more difficult
Looping controllers as code seems to be instable $4218-$421F
  • The first controller has to hold -Y-- --←- ---R 0-2-
  • Code can be executed by controlling the other 3 controllers
  • Looping seems to be impossible:
    • WAI ($CB) crashes after 1 frame
    • BRA-1 ($x0FF) crashes after the NMI interrupt incorrectly expects the next instruction to be after the branch
    • RTS ($60) crashes after an unknown amount amount of frames, because the randomness of the crash begins changing

Inventory

TODO

7E2517 to 7E2518 = Trade good amount - Annihilation Amulet
7E2519 to 7E251A = Trade good amount - Bead
7E251B to 7E251C = Trade good amount - Ceramic Pot
7E251D to 7E251E = Trade good amount - Chicken
7E251F to 7E2520 = Trade good amount - Golden Jackal
7E2521 to 7E2522 = Trade good amount - Jeweled Scarab
7E2523 to 7E2524 = Trade good amount - Limestone Tablet
7E2525 to 7E2526 = Trade good amount - Perfume
7E2527 to 7E2528 = Trade good amount - Rice
7E2529 to 7E252A = Trade good amount - Spice
7E252B to 7E252C = Trade good amount - Spoon
7E252D to 7E252E = Trade good amount - Tapestry
7E252F to 7E2530 = Trade good amount - Ticket for Exhibition

Similar Crashes

Enemies Casting Alchemy Spells

Reproducing the Crash:

  • Damage Magmar if neccessary (Heat Wave is triggered by a damage threshold)
  • Cast 8 animation spells via 8cast (E.g. Storm from Fire Eyes Call Beads)
  • Magmar will cast Heat Wave in response to the damage
  • The game tries to adds a 9th animation spell in a slot (Sometimes refereed to as 9cast)
  • The game "freezes"

Executed code:

8cd01f ldy $2f28,x   [7e2f2c] A:b912 X:0004 Y:0002 S:1ff1 D:0000 DB:7e nvmxdizc V:  0 H:311 F: 7
8cd022 bne $d011     [8cd011] A:b912 X:0004 Y:29e9 S:1ff1 D:0000 DB:7e nvmxdizc V:  0 H:321 F: 7
8cd011 stx $80       [000080] A:b912 X:0004 Y:29e9 S:1ff1 D:0000 DB:7e nvmxdizc V:  0 H:325 F: 7
8cd013 sty $7e       [00007e] A:b912 X:0004 Y:29e9 S:1ff1 D:0000 DB:7e nvmxdizc V:  0 H:332 F: 7
8cd015 ldx $0003,y   [7e29ec] A:b912 X:0004 Y:29e9 S:1ff1 D:0000 DB:7e nvmxdizc V:  0 H:339 F: 7
8cd018 jsr ($d029,x) [8cd02b] A:b912 X:0002 Y:29e9 S:1ff1 D:0000 DB:7e nvmxdizc V:  1 H:  9 F: 7
8cd09c lda $0000,y   [7e29e9] A:b912 X:0002 Y:29e9 S:1fef D:0000 DB:7e nvmxdizc V:  1 H: 22 F: 7
8cd09f sta $82       [000082] A:f404 X:0002 Y:29e9 S:1fef D:0000 DB:7e Nvmxdizc V:  1 H: 32 F: 7
8cd0a1 lda $0001,y   [7e29ea] A:f404 X:0002 Y:29e9 S:1fef D:0000 DB:7e Nvmxdizc V:  1 H: 39 F: 7
8cd0a4 sta $83       [000083] A:95f4 X:0002 Y:29e9 S:1fef D:0000 DB:7e Nvmxdizc V:  1 H: 49 F: 7
8cd0a6 lda [$82]     [95f404] A:95f4 X:0002 Y:29e9 S:1fef D:0000 DB:7e Nvmxdizc V:  1 H: 56 F: 7
8cd0a8 inc $82       [000082] A:f4d6 X:0002 Y:29e9 S:1fef D:0000 DB:7e Nvmxdizc V:  1 H: 68 F: 7
8cd0aa and #$00ff             A:f4d6 X:0002 Y:29e9 S:1fef D:0000 DB:7e Nvmxdizc V:  1 H: 80 F: 7
8cd0ad asl a                  A:00d6 X:0002 Y:29e9 S:1fef D:0000 DB:7e nvmxdizc V:  1 H: 85 F: 7
8cd0ae tax                    A:01ac X:0002 Y:29e9 S:1fef D:0000 DB:7e nvmxdizc V:  1 H: 88 F: 7
8cd0af jsr ($e8bd,x) [8cea69] A:01ac X:01ac Y:29e9 S:1fef D:0000 DB:7e nvmxdizc V:  1 H: 91 F: 7

8c0285 bpl $0287     [8c0287] A:01ac X:01ac Y:29e9 S:1fed D:0000 DB:7e nvmxdizc V:  1 H:104 F: 7
8c0287 bra $0307     [8c0307] A:01ac X:01ac Y:29e9 S:1fed D:0000 DB:7e nvmxdizc V:  1 H:109 F: 7
8c0307 bra $037d     [8c037d] A:01ac X:01ac Y:29e9 S:1fed D:0000 DB:7e nvmxdizc V:  1 H:115 F: 7
8c037d ora $00,s     [001fed] A:01ac X:01ac Y:29e9 S:1fed D:0000 DB:7e nvmxdizc V:  1 H:120 F: 7
8c037f ora ($00,x)   [7e4043] A:b1ad X:01ac Y:29e9 S:1fed D:0000 DB:7e Nvmxdizc V:  1 H:130 F: 7
8c0381 brk #$00               A:b1ad X:01ac Y:29e9 S:1fed D:0000 DB:7e Nvmxdizc V:  1 H:153 F: 7
00885f stp                    A:b1ad X:01ac Y:29e9 S:1fe9 D:0000 DB:7e NvmxdIzc V:  1 H:169 F: 7
8cea4f lda [$82]     [94b92a] A:0001 X:0062 Y:0089 S:1fea D:0000 DB:7e nvMXdizc V:254 H:216 F:29
8cea51 inc $82       [000082] A:0078 X:0062 Y:0089 S:1fea D:0000 DB:7e nvMXdizc V:254 H:227 F:29
8cea53 bne $ea57     [8cea57] A:0078 X:0062 Y:0089 S:1fea D:0000 DB:7e nvMXdizc V:254 H:235 F:29
8cea57 asl a                  A:0078 X:0062 Y:0089 S:1fea D:0000 DB:7e nvMXdizc V:254 H:240 F:29
8cea58 rol $8a       [00008a] A:00f0 X:0062 Y:0089 S:1fea D:0000 DB:7e NvMXdizc V:254 H:243 F:29
8cea5a tax                    A:00f0 X:0062 Y:0089 S:1fea D:0000 DB:7e nvMXdiZc V:254 H:251 F:29
8cea5b rep #$30               A:00f0 X:00f0 Y:0089 S:1fea D:0000 DB:7e NvMXdizc V:254 H:254 F:29
8cea5d jmp ($f041,x) [8cf131] A:00f0 X:00f0 Y:0089 S:1fea D:0000 DB:7e Nvmxdizc V:254 H:259 F:29
8cf03a sta $99a8,y   [7e9a31] A:00f0 X:00f0 Y:0089 S:1fea D:0000 DB:7e Nvmxdizc V:254 H:268 F:29

8cf03d brk #$00               A:00f0 X:00f0 Y:0089 S:1fea D:0000 DB:7e Nvmxdizc V:254 H:278 F:29
00885f stp                    A:00f0 X:00f0 Y:0089 S:1fe6 D:0000 DB:7e NvmxdIzc V:254 H:293 F:29

Layering Audio Tracks

TODO

Entity

TODO

FAQ

Q A
Is an ACE possible? Yes, it has been performed with lsnes: http://tasvideos.org/6617S.html
Is the run deterministic on real hardware? Unknown, but the game does not play music in between screen transitions, which is a good sign!
Is this strategy RTA viable? No, because the current variations can't be performed with just 2 regular controllers

TL;DR

It's possible to flag all 8 available particle alchemy slots as "being currently used" by casting them into a screen transition. The 9th cast overflows that logic and is being written into the first animation alchemy slot, which has an incompatible structure.

This wouldn't be harmful as is, but progressing the animations seems to execute code for each animation in every frame. So based on the properties of the projectile various memory addresses can be manipulated. If the crash is being executed in the very right moment it leads to executing RAM values, like the controller inputs, as code.

Example:

This can be exploited by having some very specific preconditions:

  • Casting the 9th projectile alchemy spell (1:256 chance)
  • A specific camera offset (Can be buffered)
  • Holding specific buttons on the first controller (Close to frame perfect)
  • TASBot like inputs with 4 controllers (TAS only)

Which makes the game run the controller inputs as code, which is useless in RTA but can be heavily abused in a TAS.