Veran Warp

From ZeldaHacking Wiki
Jump to navigation Jump to search

Cause

When a tile on the map is selected, it will usually just read a byte from a table, and tell the game to print the text corresponding to it. If out-of-bounds on the past map, the text index given may be invalid. (This won't be the case in the present, since it will just continue to read the past map's data.)

This isn't enough to make the game go haywire, even if the index is invalid. However, if the byte read has bit 7 set, the game performs some "special behaviour". This is meant for screens whose text can change (ie. moblin's keep).

In this code snippet from the _mapGetRoomTextOrReturn (02:619d) function, register 'c' is the aforementioned byte:

	ld c,(hl)		; $61c5
	bit 7,c			; $61c6
	ret z			; $61c8

	ld a,c			; $61c9
	and $07			; $61ca
	rst_jumpTable			; $61cc

.dw $61d7 ; 0
.dw $61f4 ; 1
.dw $6208 ; 2
.dw $6210 ; 3
.dw $6219 ; 4

Each ".dw" line is an address the game will jump to if 'c'&7 equals the corresponding value. There are exactly 5 special-behaviour functions defined (values 0-4). However, since 'c' was ANDed with 7, the possible values it may have are 0-7. Here's what it looks like if values 5-7 are interpreted as addresses:

	ld a,c			; $61c9
	and $07			; $61ca
	rst_jumpTable			; $61cc

.dw $61d7 ; 0
.dw $61f4 ; 1
.dw $6208 ; 2
.dw $6210 ; 3
.dw $6219 ; 4
.dw $fad5 ; 5
.dw $cc34 ; 6
.dw $1107 ; 7

So, if one of the invalid tiles in the past has bit 7 set, and has bits 0-2 equal a value between 5-7, the game will jump somewhere unexpected.

Here is a table of the values which come after the past map's last tile. Tiles with interesting behaviour are noted. (Note: tiles $ee and $ef reference the same data as $f0 and $f1.)

Index Value Behaviour
$e0 $48
$e1 $88
$e2 $8d Jump to $fad5
$e3 $88
$e4 $83
$e5 $88
$e6 $ba
$e7 $88
$e8 $03
$e9 $88
$ea $0a
$eb $88
$ec $3c
$ed $a8
$f0 $90
$f1 $98
$f2 $03
$f3 $88
$f4 $ac
$f5 $ff Jump to $1107
$f6 $13
$f7 $af Jump to $1107
$f8 $78
$f9 $ff Jump to $1107
$fa $c1
$fb $ff Jump to $1107
$fc $0b
$fd $aa
$fe $05
$ff $99

Unfortunately, the jump to $1107 is uninteresting. It lands in the middle of the "setDeathRespawnPoint" function, but it does not have the effect of changing Link's respawn point, since HL is still pointing to ROM. It ends up writing several values to ROM (also starting at $1107), which only has the effect of writing to the "SRAM Enable" register of the MBC5.

The japanese version is the same as the US version for this jump, but the EU version actually tends to crash on these tiles.

As speedrunners know, though, the jump to $fad5 is very interesting indeed.

Veran Warp tile (Index $e2)

As explained above, the game jumps to $fad5. This falls into the gameboy's WRAM mirror ($f000-$fdff mirrors the values of $d000-$ddff, which contains the game's object data). Since there tend to be very few objects on-screen when this glitch is done, the game runs NOP opcodes until it reaches $fe00, OAM memory.

OAM memory is inaccessible except at hblank and vblank. If it happens to be accessible at the time, the OAM can be manipulated to perform arbitrary code execution. This is extremely finicky since the OAM is usually inaccessible in this situation.

If the OAM is inaccessible, it will immediately read $ff, or the "rst $38" opcode, which is the same as "call $0038". For some reason, the game has this apparently unused code at address $38:

	nop			; $0038
	nop			; $0039
	nop			; $003a
	pop hl			; $003b
	pop de			; $003c
	pop bc			; $003d
	pop af			; $003e
	reti			; $003f

Here's what happens next:

  • After above pop opcodes run, it returns to 01f8 (getLogA_v2)
  • After that function, it returns to 02:5b6e (middle of _inventorySubmenu0_drawStoredItems function)
    • This is in the middle of a loop which overwrites a lot of memory. Contents of bc, de, hl are irrelevant; however, the value of $ff8d is abnormally high when it jumps here, and this causes unexpected memory overwriting to occur. The value of $ff8d is the value of a sprite's X-position when you first open the map.
Stack contents at address $0038
Address Value Use in glitch Set from
c212 fe01 pop hl
c214 6192 pop de
c216 6124 pop bc
c218 1a62 pop af
c21a 01f8 reti (from 003f)
c21c 5b6e ret (from getLogA_v2) Call to "updateMenus" function. Supposed to return to bank 1, but returns to bank 2 instead.
c21e 33c4 ret (from _inventorySubmenu0_drawStoredItems) Call to "runGameLogic" function. If the game fails to return here, it will almost surely crash. (This is the end of the stack.)

Memory overwrite loop

The value of $ff8d - or, the first sprite's X position - will determine what memory gets overwritten. The function it ends up in was originally written to draw the items in your inventory. The original logic of the function works like this:

  • Prior to calling this function, wram bank 4 is expected to be loaded.
  • For values of ff8d from $10 to $01:
    • The item index equals the value of [wInventoryStorage + [$ff8d] - 1].
    • Load that item's "treasure display data" to $cec0 by calling loadTreasureDisplayData.
    • Read an address from $5b80+[$ff8d]*2. This is where to write the item's "graphics map" to.
    • It proceeds to call _drawTreasureDisplayDataToBg, with parameters 'de' (the address from the last step) and 'hl' ($cec1, where the tresure display data was loaded).
      • This writes to 'de', which is expected to reference w4TileMap. It also ORs de with $400 and writes there, under the assumption that this will write to w4AttributeMap.

The details are rather complicated, but in summary: the addresses it writes to depend solely on $ff8d and no other variables. The values it writes depends on what "item" it thinks it's writing there.

Second A-press (re-opened map)

$ff8d cycles from about $50 to $3d, then loops back to $64 up to $5e. Then it turns to $00 and the player gains control.

Third A-press (immediately after 2nd without re-opening map)

$ff8d cycles from $00 to $f3, then control returns to the player. After pressing A again, it then cycles from $f3 to $bc. Along the way, it hits $c9, which may spawn Veran.

Memory overwrite table

The list of addresses it writes to in the below table is not necessarily exhaustive. It usually also writes to the bytes proceeding the ones listed. It should not deviate far from the given values, though (unless they cause other effects like changing the rom bank, then anything goes).

The memory-overwriting loop would be stable, if it weren't for the fact that it sometimes overwrites the ROM bank number. This causes the code being executed to change the moment it's written to. This can cause crashes and other abnormal effects, but sometimes this just has the effect of ending the loop and returning control to the player.

From $ff8d's starting value, the game keeps decrementing it until it reaches 0, or the ROM bank gets overwritten. If this happens, with some luck, the game will manage to return to the main thread and not crash.

FF8D value "Inventory slot" (source of data) Writes to addresses Notes
$01 $c68a (wInventoryStorage+$0) $d063,$d083,$d463,$d483
$02 $c68b (wInventoryStorage+$1) $d067,$d087,$d467,$d487
$03 $c68c (wInventoryStorage+$2) $d06b,$d08b,$d46b,$d48b
$04 $c68d (wInventoryStorage+$3) $d06f,$d08f,$d46f,$d48f
$05 $c68e (wInventoryStorage+$4) $d0c3,$d0e3,$d4c3,$d4e3
$06 $c68f (wInventoryStorage+$5) $d0c7,$d0e7,$d4c7,$d4e7
$07 $c690 (wInventoryStorage+$6) $d0cb,$d0eb,$d4cb,$d4eb
$08 $c691 (wInventoryStorage+$7) $d0cf,$d0ef,$d4cf,$d4ef
$09 $c692 (wInventoryStorage+$8) $d123,$d143,$d523,$d543
$0a $c693 (wInventoryStorage+$9) $d127,$d147,$d527,$d547
$0b $c694 (wInventoryStorage+$a) $d12b,$d14b,$d52b,$d54b
$0c $c695 (wInventoryStorage+$b) $d12f,$d14f,$d52f,$d54f
$0d $c696 (wInventoryStorage+$c) $d183,$d1a3,$d583,$d5a3
$0e $c697 (wInventoryStorage+$d) $d187,$d1a7,$d587,$d5a7
$0f $c698 (wInventoryStorage+$e) $d18b,$d1ab,$d58b,$d5ab
$10 $c699 (wInventoryStorage+$f) $d18f,$d1af,$d58f,$d5af
$11 $c69a (wObtainedTreasureFlags+$0) $9221,$9241,$9621,$9641
$12 $c69b (wObtainedTreasureFlags+$1) $2a5e,$2a7e,$2e5e,$2e7e
$13 $c69c (wObtainedTreasureFlags+$2) $28b7,$28d7,$2cb7,$2cd7
$14 $c69d (wObtainedTreasureFlags+$3) $e026,$e046,$e426,$e446 Possible music corruption here
$15 $c69e (wObtainedTreasureFlags+$4) $c9ac,$cd8c,$cdac

$c9ac+: rooms in d5 (keyblock room, bridge room)

$cd8c+: wStaticObjects

$16 $c69f (wObtainedTreasureFlags+$5) $1368,$1748,$1768
$17 $c6a0 (wObtainedTreasureFlags+$6) $1b30,$1b50,$1f30,$1f50
$18 $c6a1 (wObtainedTreasureFlags+$7) $8be0,$8fe0,$9000
$19 $c6a2 (wObtainedTreasureFlags+$8) $c94a,$cd2a,$cd4a

$c94a+: Rooms in d3 (boss room and prior rooms)

$cd2a+: Area / tileset stuff

$1a $c6a3 (wObtainedTreasureFlags+$9) $583e,$5c1e,$5c3e
$1b $c6a4 (wObtainedTreasureFlags+$a) $f0e5,$f105,$f4e5,$f505
$1c $c6a5 (wObtainedTreasureFlags+$b) $c9ac,$cd8c,$cdac Same as $15
$1d $c6a6 (wObtainedTreasureFlags+$c) $12f6,$16d6,$16f6
$1e $c6a7 (wObtainedTreasureFlags+$d) $c943,$cd23,$cd43

$c943+: Early rooms in d2

$cd23+: Area / tileset stuff

$1f $c6a8 (wObtainedTreasureFlags+$e) $593c,$5d1c,$5d3c
$20 $c6a9 (wObtainedTreasureFlags+$f) $e14e,$e16e,$e54e,$e56e
$21 $c6aa (wLinkHealth) $113a,$115a,$153a,$155a
$22 $c6ab (wLinkMaxHealth) $d3e0,$d7e0,$d800
$23 $c6ac (wNumHeartPieces) $68cd,$68ed,$6ccd,$6ced
$24 $c6ad (wNumRupees) $7900,$7920,$7d00,$7d20
$25 $c6ae (wNumRupees+1) $2312,$2332,$2712,$2732
$26 $c6af (wShieldLevel) $1823,$1843,$1c23,$1c43
$27 $c6b0 (wNumBombs) $fad6,$faf6,$fed6,$fef6
$28 $c6b1 (wMaxBombs) $c2ec,$c6cc,$c6ec

$c6cc = wRingBoxLevel

$c6cd = wNumUnappraisedRingsBcd

$c6ce = wNumRingsAppraised

$c6ec = wPirateShipRoom

$c6ed = wPirateShipY

$29 $c6b2 (wSwordLevel) $03fe,$07fe,$081e
$2a $c6b3 (wNumBombchus) $0a48,$0e28,$0e48
$2b $c6b4 (wSeedSatchelLevel) $3341,$3721,$3741
$2c $c6b5 (wFluteIcon) $db7c,$df5c,$df7c
$2d $c6b6 (wSwitchHookLevel) $4a4a,$4e2a,$4e4a
$2e $c6b7 (wSelectedHarpSong) $0306,$0326,$0706,$0726
$2f $c6b8 (wBraceletLevel) $228f,$266f,$268f
$30 $c6b9 (wNumEmberSeeds) $c9f1,$cdd1,$cdf1

$c9f1+: Black tower rooms

$cdd1: wNumEnemies

$cdd2: wToggleBlocksState

$cdd3: wSwitchState

$31 $c6ba (wNumScentSeeds) $5925,$5d05,$5d25
$32 $c6bb (wNumPegasusSeeds) $f1ed,$f5cd,$f5ed
$33 $c6bc (wNumGaleSeeds) $c85c,$c87c,$cc5c,$cc7c

$c85c+: D8 entrance

$c87c+: Sea of no return entrance

$cc5c: wLinkInAir

$cc5d: wLinkSwimmingState

$cc5e: ?

$cc7c+: Part of wGrabbableObjectBuffer

$34 $c6bd (wNumMysterySeeds) $7847,$7867,$7c47,$7c67
$35 $c6be (wNumGashaSeeds) $3121,$3141,$3521,$3541
$36 $c6bf (wEssencesObtained) $d37c,$d75c,$d77c
$37 $c6c0 (wTradeItem) $127e,$165e,$167e
$38 $c6c1 (wc6c1) $78d1,$78f1,$7cd1,$7cf1
$39 $c6c2 (wTuniNutState) $c141,$c521,$c541
$3a $c6c3 (wNumSlates) $d3e6,$d7c6,$d7e6
$3b $c6c4 (wSatchelSelectedSeeds) $fa9e,$fe7e,$fe9e
$3c $c6c5 (wShooterSelectedSeeds) $28ff,$291f,$2cff,$2d1f Changes the ROM bank, so this can crash. Equipping ember or pegasus seeds appears to prevent the crash. (Gambatte doesn't seem to crash at all, though.)
$3d $c6c6 (wRingBoxContents+0) $c130,$c510,$c530
$3e $c6c7 (wRingBoxContents+1) $784f,$786f,$7c4f,$7c6f
$3f $c6c8 (wRingBoxContents+2) $eb41,$ef21,$ef41
$40 $c6c9 (wRingBoxContents+3) $d3f3,$d7d3,$d7f3
$41 $c6ca (wRingBoxContents+4) $f299,$f679,$f699
$42 $c6cb (wActiveRing) $73e0,$77c0,$77e0
$43 $c6cc (wRingBoxLevel) $c999,$cd79,$cd99 $c999+: D5 rooms (Includes d5 boss keys room and others leading to it)
$44 $c6cd (wNumUnappraisedRingsBcd) $72fe,$731e,$76fe,$771e
$45 $c6ce (wc6ce) $01e1,$05c1,$05e1
$46 $c6cf (wc6cf) $db20,$db40,$df20,$df40
$47 $c6d0 (wGlobalFlags+0) $c91a,$ccfa,$cd1a

$c91a+: D1 rooms

$48 $c6d1 (wGlobalFlags+1) $c2e6,$c6c6,$c6e6 $c6c6 and $c6c7 are the first 2 rings in the ring box.

$c6e6: Maku tree text index

$49 $c6d2 (wGlobalFlags+2) $ea1c,$ea3c,$ee1c,$ee3c

$ca1c+: D6 BK room and others

$ca3c+: D6 past rooms

$4a $c6d3 (wGlobalFlags+3) $d3ef,$d7ef,$d80f
$4b $c6d4 (wGlobalFlags+4) $8211,$8231,$8611,$8631
$4c $c6d5 (wGlobalFlags+5) $3af1,$3ed1,$3ef1
$4d $c6d6 (wGlobalFlags+6) $c3fe,$c7fe,$c81e
$4e $c6d7 (wGlobalFlags+7) $72fe,$731e,$76fe,$771e
$4f $c6d8 (wGlobalFlags+8) $e277,$e657,$e677 Gives small keys for Dungeon 5, Dungeon 6 present, and (sometimes) Dungeon 7. See here for more information.
$50 $c6d9 (wGlobalFlags+9) $cbf0,$cff0,$d010
$51 $c6da (wGlobalFlags+10) $8357,$8737,$8757
$52 $c6db (wGlobalFlags+11) $a8ed,$accd,$aced Savefile corruption?
$53 $c6dc (wGlobalFlags+12) $7a01,$7a21,$7e01,$7e21
$54 $c6dd (wGlobalFlags+13) $0fe6,$1006
$55 $c6de (wGlobalFlags+14) $1181,$11a1,$1581,$15a1
$56 $c6df (wGlobalFlags+15) $d062,$d082,$d462,$d482
$57 $c6e0 (wc6e0) $68cd,$68ed,$6ccd,$6ced
$58 $c6e1 (wc6e1) $c900,$c920,$cd00,$cd20

$c900+: Maku path rooms

$c920+: D1 rooms

$59 $c6e2 (wc6e2) $83a4,$8784,$87a4
$5a $c6e3 (wc6e3) $89aa,$8d8a,$8daa
$5b $c6e4 (wc6e4) $8190,$81b0,$8590,$85b0
$5c $c6e5 (wc6e5) $8332,$8712,$8732
$5d $c6e6 (wc6e6) $892c,$8d0c,$8d2c
$5e $c6e7 (wc6e7) $2106,$2126,$2506,$2526
$5f $c6e8 (wMakuTreeState) $590a,$5cea,$5d0a
$60 $c6e9 (wJabuWaterLevel) $e011,$e031,$e411,$e431
$61 $c6ea (wc6ea) $02f3,$06d3,$06f3
$62 $c6eb (wc6eb) $c92b,$cd0b,$cd2b

$c92b = d2 boss room

$c92c = d2 room underneath swoop

$cd0b = wRoomHeight (but this is rarely used)

$cd0c = wScreenTransitionBoundaryX; this is what causes the glitch that makes Link oscillate and allows him to always screen transition.

$cd0d = wScreenTransitionBoundaryY

$cd2b = wLoadedAreaAnimation

$cd2c = wLastToggleBlocksState

$63 $c6ec (wPirateShipRoom) $00a6,$0486,$04a6
$64 $c6ed (wPirateShipY) $0806,$0826,$0c06,$0c26
$65 $c6ee (wPirateShipX) $3998,$3d78,$3d98
$66 $c6ef (wPirateShipAngle) $bb41,$bf21,$bf41 Savefile corruption?
$67 $c6f0 (wc6f0) $c9e6,$cdc6,$cde6

$c9e6+: Black tower rooms

$68 $c6f1 $0205,$0225,$0605,$0625
$69 $c6f2 $1a20,$1a40,$1e20,$1e40
$6a $c6f3 $78c5,$78e5,$7cc5,$7ce5
$6b $c6f4 $b221,$b241,$b621,$b641
$6c $c6f5 $db7c,$df5c,$df7c
$6d $c6f6 $624a,$662a,$664a
$6e $c6f7 $016f,$018f,$056f,$058f
$6f $c6f8 $0202,$0222,$0602,$0622
$70 $c6f9 $0331,$0711,$0731
$71 $c6fa $c920,$cd00,$cd20 Similar to $58
$72 $c6fb $5928,$5d08,$5d28
$73 $c6fc $78c1,$78e1,$7cc1,$7ce1
$74 $c6fd $db41,$df21,$df41
$75 $c6fe $d3f3,$d7d3,$d7f3
$76 $c6ff $0036,$0056,$0436,$0456
$77 $c700 (present map $00) $2005,$2025,$2405,$2425
$78 $c701 (present map $01) $fad9,$faf9,$fed9,$fef9
$79 $c702 (present map $02) $c2cc,$c6ac,$c6cc

$c2cc is part of a stack...

$c6ac = wNumHeartPieces

$c6ad = wNumRupees (low byte)

$c6cc = wRingBoxLevel

$c6cd = wNumUnappraisedRingsBcd

$c6ce = wNumRingsAppraised

$7a $c703 (present map $03) $214f,$216f,$254f,$256f
$7b $c704 (present map $04) $d3e9,$d7e9,$d809
$7c $c705 (present map $05) $73a6,$7786,$77a6
$7d $c706 (present map $06) $b399,$b779,$b799
$7e $c707 (present map $07) $1348,$1728,$1748
$7f $c708 (present map $08) $10c6,$10e6,$14c6,$14e6
$80 $c709 (present map $09) $4fea,$500a
$81 $c70a (present map $0a) $21d1,$21f1,$25d1,$25f1
$82 $c70b (present map $0b) $58f8,$5cd8,$5cf8
$83 $c70c (present map $0c) $2ac5,$2ae5,$2ec5,$2ee5
$84 $c70d (present map $0d) $ca31,$ce11,$ce31 $ca31+: D6 past underwater rooms
$85 $c70e (present map $0e) $c9f0,$cdd0,$cdf0 $c9f0+: Ganon's tower rooms

$cdd0: wEnemiesKilledListTail

$cdd1: wNumEnemiesKilles

$cdd2: wToggleBlocksState

$86 $c70f (present map $0f) $0068,$0088,$0468,$0488
$87 $c710 (present map $10) $18ed,$1ccd,$1ced
$88 $c711 (present map $11) $c15d,$c17d,$c55d,$c57d
$89 $c712 (present map $12) $200d,$202d,$240d,$242d
$8a $c713 (present map $13) $faf1,$fb11,$fef1,$ff11
$8b $c714 (present map $14) $c854,$cc34,$cc54 $c854+: Past overworld rooms

$cc34: wAreaFlags

$cc35: wActiveMusic

$cc36: wGrassAnimationModifier

$8c $c715 (present map $15) $80e6,$8106,$84e6,$8506
$8d $c716 (present map $16) $4b27,$4f07,$4f27
$8e $c717 (present map $17) $e821,$e841,$ec21,$ec41 $c821+: Past Talus Peaks rooms

$c841+: More Past Talus Peaks rooms

$cc21: wLinkLocalRespawnY

$cc22: wLinkLocalRespawnX

$cc23: wLinkLocalRespawnDir

$cc41+: Dungeon-related vars

$8f $c718 (present map $18) $82f3,$86d3,$86f3
$90 $c719 (present map $19) $7977,$7997,$7d77,$7d97
$91 $c71a (present map $1a) $83a7,$8787,$87a7
$92 $c71b (present map $1b) $2181,$21a1,$2581,$25a1
$93 $c71c (present map $1c) $58e4,$5cc4,$5ce4
$94 $c71d (present map $1d) $11df,$11ff,$15df,$15ff
$95 $c71e (present map $1e) $d06e,$d08e,$d46e,$d48e
$96 $c71f (present map $1f) $18ed,$1ccd,$1ced
$97 $c720 (present map $20) $1a7d,$1e5d,$1e7d
$98 $c721 (present map $21) $c370,$c390,$c770,$c790 $c770+: Fairy's woods screens
$99 $c722 (present map $22) $593c,$5d1c,$5d3c
$9a $c723 (present map $23) $d084,$d0a4,$d484,$d4a4
$9b $c724 (present map $24) $d087,$d0a7,$d487,$d4a7
$9c $c725 (present map $25) $d0c9,$d0e9,$d4c9,$d4e9
$9d $c726 (present map $26) $d129,$d149,$d529,$d549
$9e $c727 (present map $27) $d167,$d187,$d567,$d587
$9f $c728 (present map $28) $d164,$d184,$d564,$d584
$a0 $c729 (present map $29) $d122,$d142,$d522,$d542
$a1 $c72a (present map $2a) $d0c2,$d0e2,$d4c2,$d4e2
$a2 $c72b (present map $2b) $0118,$0138,$0518,$0538
$a3 $c72c (present map $2c) $0119,$0139,$0519,$0539
$a4 $c72d (present map $2d) $1aff,$1b1f,$1eff,$1f1f
$a5 $c72e (present map $2e) $1b01,$1b21,$1f01,$1f21
$a6 $c72f (present map $2f) $fb21,$ff01,$ff21
$a7 $c730 (present map $30) $031c,$033c,$071c,$073c
$a8 $c731 (present map $31) $031d,$033d,$071d,$073d
$a9 $c732 (present map $32) $1b1f,$1eff,$1f1f
$aa $c733 (present map $33) $1b23,$1f03,$1f23
$ab $c734 (present map $34) $fb23,$ff03,$ff23
$ac $c735 (present map $35) $7800,$7820,$7c00,$7c20
$ad $c736 (present map $36) $7905,$7925,$7d05,$7d25
$ae $c737 (present map $37) $fb25,$ff05,$ff25
$af $c738 (present map $38) $7a40,$7a60,$7e40,$7e60
$b0 $c739 (present map $39) $7b05,$7b25,$7f05,$7f25
$b1 $c73a (present map $3a) $fb25,$ff05,$ff25
$b2 $c73b (present map $3b) $7b42,$7b62,$7f42,$7f62
$b3 $c73c (present map $3c) $7a25,$7a45,$7e25,$7e45
$b4 $c73d (present map $3d) $fb45,$ff25,$ff45
$b5 $c73e (present map $3e) $0201,$0221,$0601,$0621
$b6 $c73f (present map $3f) $0023,$0403,$0423
$b7 $c740 (present map $40) $0225,$0605,$0625
$b8 $c741 (present map $41) $0807,$0827,$0c07,$0c27
$b9 $c742 (present map $42) $6165,$6185,$6565,$6585
$ba $c743 (present map $43) $e180,$e560,$e580
$bb $c744 (present map $44) $c91a,$ccfa,$cd1a Similar to $47
$bc $c745 (present map $45) $21c6,$21e6,$25c6,$25e6 Writes to ROM bank number. Veran Warp has a tendency to crash here.

This is typically where veran warp ends. When successful, the ROM bank number changes, but the game still manages to return properly.

Although veran warp does crash here sometimes, it seems that this doesn't actually cause the crash; the actual cause appears to be related to the timer interrupt being corrupted from when $ff8d=$da.

$bd $c746 (present map $46) $5921,$5d01,$5d21 Writes to RAM bank number.
$be $c747 (present map $47) $7af7,$7ed7,$7ef7
$bf $c748 (present map $48) $e1b7,$e1d7,$e5b7,$e5d7 Writes to thread 1's stack; could cause a crash? (not likely though, since it's pretty far down in the stack)

$c5b7+ = wSavefileString; corruption shouldn't matter since it's rewritten upon saving

$c5d7+ = wUnappraisedRings

$c0 $c749 (present map $49) $00c9,$00e9,$04c9,$04e9
$c1 $c74a (present map $4a) $0301,$0321,$0701,$0721
$c2 $c74b (present map $4b) $1105,$1125,$1505,$1525
$c3 $c74c (present map $4c) $e321,$e701,$e721 $c701+ = Talus Peaks screens (Note: $c702 is used as an address for ring box corruption)

$c721+ = Talus Peaks present screens

$c4 $c74d (present map $4d) $79e5,$7a05,$7de5,$7e05
$c5 $c74e (present map $4e) $cb72,$cb92,$cf72,$cf92
$c6 $c74f (present map $4f) $73d4,$73f4,$77d4,$77f4
$c7 $c750 (present map $50) $90eb,$94cb,$94eb
$c8 $c751 (present map $51) $3943,$3d23,$3d43 Writes to high bit of ROM bank number. Veran warp has a tendency to crash here.
$c9 $c752 (present map $52) $f240,$f620,$f640 Spawns an interaction.
$ca $c753 (present map $53) $3b01,$3ee1,$3f01 Writes to high bit of ROM bank number. I'm not sure if this is an issue or not, since Ages doesn't have enough ROM space for this to matter normally?
$cb $c754 (present map $54) $d340,$d720,$d740

Writes to interaction slots. Spawns veran, possibly other objects under other circumstances.

In order for veran to appear, it must write: nonzero to $dx40, and $2d to $dx41. ($dx40 enables it, and $dx41 sets the "id" to "veran".)

$cc $c755 (present map $55) $2005,$2025,$2405,$2425 Writes to ROM bank number.
$cd $c756 (present map $56) $c9ed,$ca0d,$cded,$ce0d $c9ed+: Black Tower screens

$ca0d+: Unused screens

$ce $c757 (present map $57) $4b4a,$4f2a,$4f4a
$cf $c758 (present map $58) $434a,$472a,$474a
$d0 $c759 (present map $59) $39cd,$39ed,$3dcd,$3ded Writes to high bit of ROM bank.
$d1 $c75a (present map $5a) $187d,$1c5d,$1c7d
$d2 $c75b (present map $5b) $4b4a,$4f2a,$4f4a
$d3 $c75c (present map $5c) $434a,$472a,$474a
$d4 $c75d (present map $5d) $39cd,$39ed,$3dcd,$3ded Writes to high bit of ROM bank.
$d5 $c75e (present map $5e) $3a7d,$3e5d,$3e7d Writes to high bit of ROM bank.
$d6 $c75f (present map $5f) $c940,$cd20,$cd40 $c940+: D2 rooms

$cd20+: Area / tileset vars

$d7 $c760 (present map $60) $0068,$0088,$0468,$0488
$d8 $c761 (present map $61) $8bf0,$8ff0,$9010
$d9 $c762 (present map $62) $0a67,$0e47,$0e67
$da $c763 (present map $63) $2a07,$2a27,$2e07,$2e27 Writes to ROM bank. Has a tendency to crash veran warp.

On its first call to @writeTile, the ROM bank gets overwritten, but it manages to return.

On its second call, de has been changed from the previous ROM bank switch. In at least one crash case, de = $e00b; so the RAM values to be written to are $e00b, $e02b, $e40b, $e42b, and the bytes immediately after those. The write to $e00b and $e00c is particularly bad since this is a function in RAM; this can cause the timer interrupt to crash. (It almost certainly will, since that happens to be on the opcode which restores the ROM bank...)

In one non-crashing case, de = $8901; an innocent value pointing to vram.

$e42b ($c42b) is part of wVBlankFunctionQueue; this could also cause a crash if it overwrites something currently being queued. Not sure if this happens in practice.

$db $c764 (present map $64) $a0c3,$a0e3,$a4c3,$a4e3 Savefile corruption?
$dc $c765 (present map $65) $d173,$d553,$d573
$dd $c766 (present map $66) $b399,$b779,$b799 Savefile corruption?
$de $c767 (present map $67) $0948,$0d28,$0d48
$df $c768 (present map $68) $0024,$0404,$0424
$e0 $c769 (present map $69) $3087,$30a7,$3487,$34a7
$e1 $c76a (present map $6a) $cb02,$cb22,$cf02,$cf22
$e2 $c76b (present map $6b) $4bf8,$4fd8,$4ff8
$e3 $c76c (present map $6c) $60cd,$60ed,$64cd,$64ed
$e4 $c76d (present map $6d) $d15d,$d17d,$d55d,$d57d
$e5 $c76e (present map $6e) $3ae9,$3ec9,$3ee9
$e6 $c76f (present map $6f) $1202,$1222,$1602,$1622
$e7 $c770 (present map $70) $d2cb,$d2eb,$d6cb,$d6eb
$e8 $c771 (present map $71) $123d,$125d,$163d,$165d
$e9 $c772 (present map $72) $203e,$205e,$243e,$245e Writes to ROM bank.
$ea $c773 (present map $73) $68cd,$68ed,$6ccd,$6ced
$eb $c774 (present map $74) $3a20,$3e00,$3e20
$ec $c775 (present map $75) $1201,$1221,$1601,$1621
$ed $c776 (present map $76) $92cb,$92eb,$96cb,$96eb
$ee $c777 (present map $77) $123c,$125c,$163c,$165c
$ef $c778 (present map $78) $c9d1,$c9f1,$cdd1,$cdf1 $c9d1+: Black tower turret screens

The rest is similar to $30.

$f0 $c779 (present map $79) $1279,$1299,$1679,$1699
$f1 $c77a (present map $7a) $d2cb,$d2eb,$d6cb,$d6eb
$f2 $c77b (present map $7b) $1278,$1298,$1678,$1698
$f3 $c77c (present map $7c) $203e,$205e,$243e,$245e Writes to the ROM bank. Doesn't seem to cause crashes, but if you've traded to get the poe clock, control returns to the player here. You can just press A again to continue. (So, there are 3 A presses in total, instead of 2.)
$f4 $c77d (present map $7d) $68cd,$68ed,$6ccd,$6ced
$f5 $c77e (present map $7e) $7800,$7820,$7c00,$7c20
$f6 $c77f (present map $7f) $cb12,$cb32,$cf12,$cf32
$f7 $c780 (present map $80) $7992,$79b2,$7d92,$7db2
$f8 $c781 (present map $81) $123c,$125c,$163c,$165c
$f9 $c782 (present map $82) $c9e9,$cdc9,$cde9 $c9e9+: Black tower rooms (including the room where you present the essences)
$fa $c783 (present map $83) $59e0,$5dc0,$5de0
$fb $c784 (present map $84) $325e,$363e,$365e
$fc $c785 (present map $85) $48cd,$48ed,$4ccd,$4ced
$fd $c786 (present map $86) $d017,$d037,$d417,$d437
$fe $c787 (present map $87) $6801,$6821,$6c01,$6c21
$ff $c788 (present map $88) $fa20,$fa40,$fe20,$fe40

Crash cases

$ff8d = $bc,$cc,$da

These values for $ff8d all have a similar effect:

  • ROM bank switches to 1
  • Jumps to 03:6306 -> 03:6318
  • Jumps to "updateAllObjects"
    • Calls many functions including "updateAnimations"
  • Rets to 2a07 (or somewhere else depending on which index this is?), then to 5d23 (this resumes the memory-overwriting loop).

Now, it will proceed to overwrite the next few bytes, as normal. The value of 'de' after the above shenanigans will determine where it writes to. If de=$e00a, as sometimes occurs, this causes a crash later on due to corrupting code in RAM.

The value of 'de' is determined by the call to "updateAnimations". So, this very common cause of crashing is ultimately determined by the state of the animations on-screen. Note that animations reset when paused; so, it may be possible to avoid crashes by being very precise with timing the second pause during the veran warp setup.

Potential memory corruptions

  • The black tower entrance (address $c9ea) can be corrupted with veran warp. In theory it could cause the room's state to be set such that it thinks the essence cutscene was already done. However it doesn't appear possible to manipulate it in this particular way.

Ring boxes

There are two ways to corrupt the ring box level; either by standing at position $7a or $29 (triggering $79 or $28, respectively).

$79 depends on address $c702 (top-left of symmetry city).

  • Level 10: Don't visit symmetry top-left.
  • Level 15: Do visit symmetry top-left.

$28 depends on wMaxBombs.

  • Level 1: Have 10 or 30 max bombs.
  • Level 13: Have 50 max bombs.

$c702 can be written to with $ff8d=$c3. However, it seems only a value of $01 can be written, which is useless.

Sadly, all of these ring boxes crash when opening the ring list. Other levels may not crash and would allow us to overwrite memory past the ring list.

wRingBoxLevel is also close to wNumRingsAppraised. Corruption could be helpful for getting the 100th ring. Unfortunately, only the sequence for obtaining the level 10 ringbox corrupts this, in which case it becomes 7, which is not very useful.