The current URL is datacrystal.tcrf.net.
Secret of Evermore/Alchemy RAM manipulation: Difference between revisions
No edit summary |
No edit summary |
||
Line 190: | Line 190: | ||
0d 00 00 00 10 00 27 00 03 00 74 02 ?? 4? ?? 0? | 0d 00 00 00 10 00 27 00 03 00 74 02 ?? 4? ?? 0? | ||
1? 00 0? 00 ?? 00 xx_xx 7f xx_xx xx_xx ?? ?? c7 | 1? 00 0? 00 ?? 00 xx_xx 7f xx_xx xx_xx ?? ?? c7 | ||
00 00 00 00 00 00 ?? ?? 10 ?? | 00 00 00 00 00 00 ?? ?? 10 ?? xx 10 50 36 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 00 00 00 | ||
fe ff | 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 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 8a 00 00 00 00 e4 81 a7 4f 93 a7 2e 13 7f | ||
Line 250: | Line 250: | ||
| ? | | ? | ||
| Unknown purpuse, but any moving entity changes this value deterministically (Therefore hard to manipulate) | | Unknown purpuse, but any moving entity changes this value deterministically (Therefore hard to manipulate) | ||
|- | |- | ||
| $0059-$005A | | $0059-$005A | ||
Line 260: | Line 259: | ||
| $0000-$0440 (Utopia map) | | $0000-$0440 (Utopia map) | ||
| Y (See $0059-$005A) | | Y (See $0059-$005A) | ||
Coordinates over $0FFF don't exist! | |||
|- | |||
| $006A | |||
| $00-$06f (Sandpits map) | |||
| Increases by 1 every 11 vertical | |||
Moving sprites influence that value | |||
|- | |- | ||
| $0082 | | $0082 |
Revision as of 19:13, 25 April 2020
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 14th and 15th byte of the first animation alchemy slot ($7E3364-$7E3563, 40 bytes per slot) |
$7E338c (16 bit) | A | Is the 28th and 29th 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 03 00 74 02 ?? 4? ?? 0? 1? 00 0? 00 ?? 00 xx_xx 7f xx_xx xx_xx ?? ?? c7 00 00 00 00 00 00 ?? ?? 10 ?? 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:
|
$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 |
---|---|---|
$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! |
$006A | $00-$06f (Sandpits map) | Increases by 1 every 11 vertical
Moving sprites influence that value |
$0082 | $00-$FF? | Lower half of the pointer to the most recent script ($83 and $84 get cleared) |
$0095 |
|
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 |
|
Inputs are heavily restricted | $4218-$421F |
|
The crash has to be cleared more efficiently | $3364-$337C |
|
TAS restrictions still apply | - |
|
Code Storage
Controllers
Problem | Memory | Comment |
---|---|---|
The copy of controller 1 cannot point at the controllers | $0104 |
|
Looping controllers as code seems to be instable | $4218-$421F |
|
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.