diff options
author | PikalaxALT <PikalaxALT@gmail.com> | 2016-01-29 18:36:31 -0500 |
---|---|---|
committer | PikalaxALT <PikalaxALT@gmail.com> | 2016-01-29 18:36:31 -0500 |
commit | 2bf93c5905319e9181f87b3f83cd3bce7b9feeca (patch) | |
tree | 3ebf17c8879e5d6243d81aac8f1c36eb226fac26 /home | |
parent | ed3f9395f6d45f6554ed9d9c49c41ea86a8e2447 (diff) |
Import stuff from pokecrystal; diff gold and silver
Diffstat (limited to 'home')
38 files changed, 11473 insertions, 0 deletions
diff --git a/home/audio.asm b/home/audio.asm new file mode 100644 index 00000000..c7bb7fed --- /dev/null +++ b/home/audio.asm @@ -0,0 +1,596 @@ +; Audio interfaces. + +MapSetup_Sound_Off:: ; 3b4e + + push hl + push de + push bc + push af + + ld a, [hROMBank] + push af + ld a, BANK(_MapSetup_Sound_Off) + ld [hROMBank], a + ld [MBC3RomBank], a + + call _MapSetup_Sound_Off + + pop af + ld [hROMBank], a + ld [MBC3RomBank], a + + pop af + pop bc + pop de + pop hl + ret +; 3b6a + + +UpdateSound:: ; 3b6a + + push hl + push de + push bc + push af + + ld a, [hROMBank] + push af + ld a, BANK(_UpdateSound) + ld [hROMBank], a + ld [MBC3RomBank], a + + call _UpdateSound + + pop af + ld [hROMBank], a + ld [MBC3RomBank], a + + pop af + pop bc + pop de + pop hl + ret +; 3b86 + + +_LoadMusicByte:: ; 3b86 +; CurMusicByte = [a:de] +GLOBAL LoadMusicByte + + ld [hROMBank], a + ld [MBC3RomBank], a + + ld a, [de] + ld [CurMusicByte], a + ld a, BANK(LoadMusicByte) + + ld [hROMBank], a + ld [MBC3RomBank], a + ret +; 3b97 + + +PlayMusic:: ; 3b97 +; Play music de. + + push hl + push de + push bc + push af + + ld a, [hROMBank] + push af + ld a, BANK(_PlayMusic) ; and BANK(_MapSetup_Sound_Off) + ld [hROMBank], a + ld [MBC3RomBank], a + + ld a, e + and a + jr z, .nomusic + + call _PlayMusic + jr .end + +.nomusic + call _MapSetup_Sound_Off + +.end + pop af + ld [hROMBank], a + ld [MBC3RomBank], a + pop af + pop bc + pop de + pop hl + ret +; 3bbc + + +PlayMusic2:: ; 3bbc +; Stop playing music, then play music de. + + push hl + push de + push bc + push af + + ld a, [hROMBank] + push af + ld a, BANK(_PlayMusic) + ld [hROMBank], a + ld [MBC3RomBank], a + + push de + ld de, MUSIC_NONE + call _PlayMusic + call DelayFrame + pop de + call _PlayMusic + + pop af + ld [hROMBank], a + ld [MBC3RomBank], a + + pop af + pop bc + pop de + pop hl + ret + +; 3be3 + + +PlayCryHeader:: ; 3be3 +; Play cry header de. + + push hl + push de + push bc + push af + + ld a, [hROMBank] + push af + + ; Cry headers are stuck in one bank. + ld a, BANK(CryHeaders) + ld [hROMBank], a + ld [MBC3RomBank], a + + ld hl, CryHeaders +rept 6 + add hl, de +endr + + ld e, [hl] + inc hl + ld d, [hl] + inc hl + + ld a, [hli] + ld [CryPitch], a + ld a, [hli] + ld [CryPitch + 1], a + ld a, [hli] + ld [CryLength], a + ld a, [hl] + ld [CryLength + 1], a + + ld a, BANK(_PlayCryHeader) + ld [hROMBank], a + ld [MBC3RomBank], a + + call _PlayCryHeader + + pop af + ld [hROMBank], a + ld [MBC3RomBank], a + + pop af + pop bc + pop de + pop hl + ret +; 3c23 + + +PlaySFX:: ; 3c23 +; Play sound effect de. +; Sound effects are ordered by priority (lowest to highest) + + push hl + push de + push bc + push af + + ; Is something already playing? + call CheckSFX + jr nc, .play + + ; Does it have priority? + ld a, [CurSFX] + cp e + jr c, .done + +.play + ld a, [hROMBank] + push af + ld a, BANK(_PlaySFX) + ld [hROMBank], a + ld [MBC3RomBank], a + + ld a, e + ld [CurSFX], a + call _PlaySFX + + pop af + ld [hROMBank], a + ld [MBC3RomBank], a + +.done + pop af + pop bc + pop de + pop hl + ret +; 3c4e + + +WaitPlaySFX:: ; 3c4e + call WaitSFX + call PlaySFX + ret +; 3c55 + + +WaitSFX:: ; 3c55 +; infinite loop until sfx is done playing + + push hl + +.wait + ld hl, Channel5Flags + bit 0, [hl] + jr nz, .wait + ld hl, Channel6Flags + bit 0, [hl] + jr nz, .wait + ld hl, Channel7Flags + bit 0, [hl] + jr nz, .wait + ld hl, Channel8Flags + bit 0, [hl] + jr nz, .wait + + pop hl + ret +; 3c74 + +IsSFXPlaying:: ; 3c74 +; Return carry if no sound effect is playing. +; The inverse of CheckSFX. + push hl + + ld hl, Channel5Flags + bit 0, [hl] + jr nz, .playing + ld hl, Channel6Flags + bit 0, [hl] + jr nz, .playing + ld hl, Channel7Flags + bit 0, [hl] + jr nz, .playing + ld hl, Channel8Flags + bit 0, [hl] + jr nz, .playing + + pop hl + scf + ret + +.playing + pop hl + and a + ret +; 3c97 + +MaxVolume:: ; 3c97 + ld a, $77 ; max + ld [Volume], a + ret +; 3c9d + +LowVolume:: ; 3c9d + ld a, $33 ; 40% + ld [Volume], a + ret +; 3ca3 + +VolumeOff:: ; 3ca3 + xor a + ld [Volume], a + ret +; 3ca8 + +Unused_FadeOutMusic:: ; 3ca8 + ld a, 4 + ld [MusicFade], a + ret +; 3cae + +FadeInMusic:: ; 3cae + ld a, 4 | 1 << 7 + ld [MusicFade], a + ret +; 3cb4 + +SkipMusic:: ; 3cb4 +; Skip a frames of music. +.loop + and a + ret z + dec a + call UpdateSound + jr .loop +; 3cbc + +FadeToMapMusic:: ; 3cbc + push hl + push de + push bc + push af + + call GetMapMusic + ld a, [wMapMusic] + cp e + jr z, .done + + ld a, 8 + ld [MusicFade], a + ld a, e + ld [MusicFadeIDLo], a + ld a, d + ld [MusicFadeIDHi], a + ld a, e + ld [wMapMusic], a + +.done + pop af + pop bc + pop de + pop hl + ret +; 3cdf + +PlayMapMusic:: ; 3cdf + push hl + push de + push bc + push af + + call GetMapMusic + ld a, [wMapMusic] + cp e + jr z, .done + + push de + ld de, MUSIC_NONE + call PlayMusic + call DelayFrame + pop de + ld a, e + ld [wMapMusic], a + call PlayMusic + +.done + pop af + pop bc + pop de + pop hl + ret +; 3d03 + +EnterMapMusic:: ; 3d03 + push hl + push de + push bc + push af + + xor a + ld [wDontPlayMapMusicOnReload], a + ld de, MUSIC_BICYCLE + ld a, [PlayerState] + cp PLAYER_BIKE + jr z, .play + call GetMapMusic +.play + push de + ld de, MUSIC_NONE + call PlayMusic + call DelayFrame + pop de + + ld a, e + ld [wMapMusic], a + call PlayMusic + + pop af + pop bc + pop de + pop hl + ret +; 3d2f + +TryRestartMapMusic:: ; 3d2f + ld a, [wDontPlayMapMusicOnReload] + and a + jr z, RestartMapMusic + xor a + ld [wMapMusic], a + ld de, MUSIC_NONE + call PlayMusic + call DelayFrame + xor a + ld [wDontPlayMapMusicOnReload], a + ret +; 3d47 + +RestartMapMusic:: ; 3d47 + push hl + push de + push bc + push af + ld de, MUSIC_NONE + call PlayMusic + call DelayFrame + ld a, [wMapMusic] + ld e, a + ld d, 0 + call PlayMusic + pop af + pop bc + pop de + pop hl + ret +; 3d62 + +SpecialMapMusic:: ; 3d62 + ld a, [PlayerState] + cp PLAYER_SURF + jr z, .surf + cp PLAYER_SURF_PIKA + jr z, .surf + + ld a, [StatusFlags2] + bit 2, a + jr nz, .contest + +.no + and a + ret + +.bike + ld de, MUSIC_BICYCLE + scf + ret + +.surf + ld de, MUSIC_SURF + scf + ret + +.contest + ld a, [MapGroup] + cp GROUP_ROUTE_35_NATIONAL_PARK_GATE + jr nz, .no + ld a, [MapNumber] + cp MAP_ROUTE_35_NATIONAL_PARK_GATE + jr z, .ranking + cp MAP_ROUTE_36_NATIONAL_PARK_GATE + jr nz, .no + +.ranking + ld de, MUSIC_BUG_CATCHING_CONTEST_RANKING + scf + ret +; 3d97 + +GetMapMusic:: ; 3d97 + call SpecialMapMusic + ret c + call GetMapHeaderMusic + ret +; 3d9f + +Function3d9f:: ; 3d9f +; Places a BCD number at the +; upper center of the screen. +; Unreferenced. + ld a, 4 * 8 + ld [Sprites + 38 * 4], a + ld [Sprites + 39 * 4], a + ld a, 10 * 8 + ld [Sprites + 38 * 4 + 1], a + ld a, 11 * 8 + ld [Sprites + 39 * 4 + 1], a + xor a + ld [Sprites + 38 * 4 + 3], a + ld [Sprites + 39 * 4 + 3], a + ld a, [wc296] + cp 100 + jr nc, .max + add 1 + daa + ld b, a + swap a + and $f + add "0" + ld [Sprites + 38 * 4 + 2], a + ld a, b + and $f + add "0" + ld [Sprites + 39 * 4 + 2], a + ret + +.max + ld a, "9" + ld [Sprites + 38 * 4 + 2], a + ld [Sprites + 39 * 4 + 2], a + ret +; 3dde + +CheckSFX:: ; 3dde +; Return carry if any SFX channels are active. + ld a, [Channel5Flags] + bit 0, a + jr nz, .playing + ld a, [Channel6Flags] + bit 0, a + jr nz, .playing + ld a, [Channel7Flags] + bit 0, a + jr nz, .playing + ld a, [Channel8Flags] + bit 0, a + jr nz, .playing + and a + ret +.playing + scf + ret +; 3dfe + +TerminateExpBarSound:: ; 3dfe + xor a + ld [Channel5Flags], a + ld [SoundInput], a + ld [rNR10], a + ld [rNR11], a + ld [rNR12], a + ld [rNR13], a + ld [rNR14], a + ret +; 3e10 + + +ChannelsOff:: ; 3e10 +; Quickly turn off music channels + xor a + ld [Channel1Flags], a + ld [Channel2Flags], a + ld [Channel3Flags], a + ld [Channel4Flags], a + ld [SoundInput], a + ret +; 3e21 + +SFXChannelsOff:: ; 3e21 +; Quickly turn off sound effect channels + xor a + ld [Channel5Flags], a + ld [Channel6Flags], a + ld [Channel7Flags], a + ld [Channel8Flags], a + ld [SoundInput], a + ret +; 3e32 diff --git a/home/battle.asm b/home/battle.asm new file mode 100644 index 00000000..3fd59363 --- /dev/null +++ b/home/battle.asm @@ -0,0 +1,361 @@ +UserPartyAttr:: ; 3945 + push af + ld a, [hBattleTurn] + and a + jr nz, .ot + pop af + jr BattlePartyAttr +.ot + pop af + jr OTPartyAttr +; 3951 + + +OpponentPartyAttr:: ; 3951 + push af + ld a, [hBattleTurn] + and a + jr z, .ot + pop af + jr BattlePartyAttr +.ot + pop af + jr OTPartyAttr +; 395d + + +BattlePartyAttr:: ; 395d +; Get attribute a from the active BattleMon's party struct. + push bc + ld c, a + ld b, 0 + ld hl, PartyMons + add hl, bc + ld a, [CurBattleMon] + call GetPartyLocation + pop bc + ret +; 396d + + +OTPartyAttr:: ; 396d +; Get attribute a from the active EnemyMon's party struct. + push bc + ld c, a + ld b, 0 + ld hl, OTPartyMon1Species + add hl, bc + ld a, [CurOTMon] + call GetPartyLocation + pop bc + ret +; 397d + + +ResetDamage:: ; 397d + xor a + ld [CurDamage], a + ld [CurDamage + 1], a + ret +; 3985 + +SetPlayerTurn:: ; 3985 + xor a + ld [hBattleTurn], a + ret +; 3989 + +SetEnemyTurn:: ; 3989 + ld a, 1 + ld [hBattleTurn], a + ret +; 398e + + +UpdateOpponentInParty:: ; 398e + ld a, [hBattleTurn] + and a + jr z, UpdateEnemyMonInParty + jr UpdateBattleMonInParty +; 3995 + +UpdateUserInParty:: ; 3995 + ld a, [hBattleTurn] + and a + jr z, UpdateBattleMonInParty + jr UpdateEnemyMonInParty +; 399c + +UpdateBattleMonInParty:: ; 399c +; Update level, status, current HP + + ld a, [CurBattleMon] + +UpdateBattleMon:: ; 399f + ld hl, PartyMon1Level + call GetPartyLocation + + ld d, h + ld e, l + ld hl, BattleMonLevel + ld bc, BattleMonMaxHP - BattleMonLevel + jp CopyBytes +; 39b0 + +UpdateEnemyMonInParty:: ; 39b0 +; Update level, status, current HP + +; No wildmons. + ld a, [wBattleMode] + dec a + ret z + + ld a, [CurOTMon] + ld hl, OTPartyMon1Level + call GetPartyLocation + + ld d, h + ld e, l + ld hl, EnemyMonLevel + ld bc, EnemyMonMaxHP - EnemyMonLevel + jp CopyBytes +; 39c9 + + +RefreshBattleHuds:: ; 39c9 + call UpdateBattleHuds + ld c, 3 + call DelayFrames + jp WaitBGMap +; 39d4 + +UpdateBattleHuds:: ; 39d4 + callba UpdatePlayerHUD + callba UpdateEnemyHUD + ret +; 39e1 + + +GetBattleVar:: ; 39e1 +; Preserves hl. + push hl + call GetBattleVarAddr + pop hl + ret +; 39e7 + +GetBattleVarAddr:: ; 39e7 +; Get variable from pair a, depending on whose turn it is. +; There are 21 variable pairs. + + push bc + + ld hl, .battlevarpairs + ld c, a + ld b, 0 +rept 2 + add hl, bc +endr + + ld a, [hli] + ld h, [hl] + ld l, a + +; Enemy turn uses the second byte instead. +; This lets battle variable calls be side-neutral. + ld a, [hBattleTurn] + and a + jr z, .getvar + inc hl + +.getvar +; var id + ld a, [hl] + ld c, a + ld b, 0 + + ld hl, .vars +rept 2 + add hl, bc +endr + + ld a, [hli] + ld h, [hl] + ld l, a + + ld a, [hl] + + pop bc + ret + +.battlevarpairs + dw .substatus1, .substatus2, .substatus3, .substatus4, .substatus5 + dw .substatus1opp, .substatus2opp, .substatus3opp, .substatus4opp, .substatus5opp + dw .status, .statusopp, .animation, .effect, .power, .type + dw .curmove, .lastcounter, .lastcounteropp, .lastmove, .lastmoveopp + +; player enemy +.substatus1 db PLAYER_SUBSTATUS_1, ENEMY_SUBSTATUS_1 +.substatus1opp db ENEMY_SUBSTATUS_1, PLAYER_SUBSTATUS_1 +.substatus2 db PLAYER_SUBSTATUS_2, ENEMY_SUBSTATUS_2 +.substatus2opp db ENEMY_SUBSTATUS_2, PLAYER_SUBSTATUS_2 +.substatus3 db PLAYER_SUBSTATUS_3, ENEMY_SUBSTATUS_3 +.substatus3opp db ENEMY_SUBSTATUS_3, PLAYER_SUBSTATUS_3 +.substatus4 db PLAYER_SUBSTATUS_4, ENEMY_SUBSTATUS_4 +.substatus4opp db ENEMY_SUBSTATUS_4, PLAYER_SUBSTATUS_4 +.substatus5 db PLAYER_SUBSTATUS_5, ENEMY_SUBSTATUS_5 +.substatus5opp db ENEMY_SUBSTATUS_5, PLAYER_SUBSTATUS_5 +.status db PLAYER_STATUS, ENEMY_STATUS +.statusopp db ENEMY_STATUS, PLAYER_STATUS +.animation db PLAYER_MOVE_ANIMATION, ENEMY_MOVE_ANIMATION +.effect db PLAYER_MOVE_EFFECT, ENEMY_MOVE_EFFECT +.power db PLAYER_MOVE_POWER, ENEMY_MOVE_POWER +.type db PLAYER_MOVE_TYPE, ENEMY_MOVE_TYPE +.curmove db PLAYER_CUR_MOVE, ENEMY_CUR_MOVE +.lastcounter db PLAYER_COUNTER_MOVE, ENEMY_COUNTER_MOVE +.lastcounteropp db ENEMY_COUNTER_MOVE, PLAYER_COUNTER_MOVE +.lastmove db PLAYER_LAST_MOVE, ENEMY_LAST_MOVE +.lastmoveopp db ENEMY_LAST_MOVE, PLAYER_LAST_MOVE + +.vars + dw PlayerSubStatus1, EnemySubStatus1 + dw PlayerSubStatus2, EnemySubStatus2 + dw PlayerSubStatus3, EnemySubStatus3 + dw PlayerSubStatus4, EnemySubStatus4 + dw PlayerSubStatus5, EnemySubStatus5 + dw BattleMonStatus, EnemyMonStatus + dw wPlayerMoveStructAnimation, wEnemyMoveStructAnimation + dw wPlayerMoveStructEffect, wEnemyMoveStructEffect + dw wPlayerMoveStructPower, wEnemyMoveStructPower + dw wPlayerMoveStructType, wEnemyMoveStructType + dw CurPlayerMove, CurEnemyMove + dw LastEnemyCounterMove, LastPlayerCounterMove + dw LastPlayerMove, LastEnemyMove +; 3a90 + + +FarCopyRadioText:: ; 3a90 + inc hl + ld a, [hROMBank] + push af + ld a, [hli] + ld e, a + ld a, [hli] + ld d, a + ld a, [hli] + ld [hROMBank], a + ld [MBC3RomBank], a + ld a, e + ld l, a + ld a, d + ld h, a + ld de, wRadioText + ld bc, 2 * SCREEN_WIDTH + call CopyBytes + pop af + ld [hROMBank], a + ld [MBC3RomBank], a + ret +; 3ab2 + + +MobileTextBorder:: ; 3ab2 + +CELL_PHONE_TOP EQU $5e +CELL_PHONE_BOTTOM EQU $5f + + ; For mobile link battles only. + ld a, [wLinkMode] + cp LINK_MOBILE + ret c + + ; Draw a cell phone icon at the + ; top right corner of the border. + hlcoord 19, 12 + ld [hl], CELL_PHONE_TOP + hlcoord 19, 13 + ld [hl], CELL_PHONE_BOTTOM + ret +; 3ac3 + + +BattleTextBox:: ; 3ac3 +; Open a textbox and print text at hl. + push hl + call SpeechTextBox + call MobileTextBorder + call UpdateSprites + call ApplyTilemap + pop hl + call PrintTextBoxText + ret +; 3ad5 + + +StdBattleTextBox:: ; 3ad5 +; Open a textbox and print battle text at 20:hl. + +GLOBAL BattleText + + ld a, [hROMBank] + push af + + ld a, BANK(BattleText) + rst Bankswitch + + call BattleTextBox + + pop af + rst Bankswitch + ret +; 3ae1 + +GetBattleAnimPointer:: ; 3ae1 + +GLOBAL BattleAnimations +GLOBAL BattleAnimCommands + + ld a, BANK(BattleAnimations) + rst Bankswitch + + ld a, [hli] + ld [BattleAnimAddress], a + ld a, [hl] + ld [BattleAnimAddress + 1], a + + ld a, BANK(BattleAnimCommands) + rst Bankswitch + + ret +; 3af0 + +GetBattleAnimByte:: ; 3af0 + + push hl + push de + + ld hl, BattleAnimAddress + ld e, [hl] + inc hl + ld d, [hl] + + ld a, BANK(BattleAnimations) + rst Bankswitch + + ld a, [de] + ld [BattleAnimByte], a + inc de + + ld a, BANK(BattleAnimCommands) + rst Bankswitch + + ld [hl], d + dec hl + ld [hl], e + + pop de + pop hl + + ld a, [BattleAnimByte] + ret +; 3b0c diff --git a/home/copy.asm b/home/copy.asm new file mode 100644 index 00000000..08eb5c10 --- /dev/null +++ b/home/copy.asm @@ -0,0 +1,434 @@ +; Functions to copy data from ROM. + + +Get2bpp_2:: ; dc9 + ld a, [rLCDC] + bit 7, a + jp z, Copy2bpp + + ld a, [hROMBank] + push af + ld a, BANK(_Get2bpp) + rst Bankswitch + call _Get2bpp + pop af + rst Bankswitch + + ret +; ddc + +Get1bpp_2:: ; ddc + ld a, [rLCDC] + bit 7, a + jp z, Copy1bpp + + ld a, [hROMBank] + push af + ld a, BANK(_Get1bpp) + rst Bankswitch + call _Get1bpp + pop af + rst Bankswitch + + ret +; def + +FarCopyBytesDouble_DoubleBankSwitch:: ; def + ld [hBuffer], a + ld a, [hROMBank] + push af + ld a, [hBuffer] + rst Bankswitch + + call FarCopyBytesDouble + + pop af + rst Bankswitch + ret +; dfd + +OldDMATransfer:: ; dfd + dec c + ld a, [hBGMapMode] + push af + xor a + ld [hBGMapMode], a + ld a, [hROMBank] + push af + ld a, b + rst Bankswitch + +.loop +; load the source and target MSB and LSB + ld a, d + ld [rHDMA1], a ; source MSB + ld a, e + and $f0 + ld [rHDMA2], a ; source LSB + ld a, h + and $1f + ld [rHDMA3], a ; target MSB + ld a, l + and $f0 + ld [rHDMA4], a ; target LSB +; stop when c < 8 + ld a, c + cp $8 + jr c, .done +; decrease c by 8 + sub $8 + ld c, a +; DMA transfer state + ld a, $f + ld [hDMATransfer], a + call DelayFrame +; add $100 to hl and de + ld a, l + add $100 % $100 + ld l, a + ld a, h + adc $100 / $100 + ld h, a + ld a, e + add $100 % $100 + ld e, a + ld a, d + adc $100 / $100 + ld d, a + jr .loop + +.done + ld a, c + and $7f ; pretty silly, considering at most bits 0-2 would be set + ld [hDMATransfer], a + call DelayFrame + pop af + rst Bankswitch + + pop af + ld [hBGMapMode], a + ret +; e4a + + + +ReplaceKrisSprite:: ; e4a + callba _ReplaceKrisSprite + ret +; e51 + + + +LoadStandardFont:: ; e51 + callba _LoadStandardFont + ret +; e58 + +LoadFontsBattleExtra:: ; e58 + callba _LoadFontsBattleExtra + ret +; e5f + + + +LoadFontsExtra:: ; e5f + callba _LoadFontsExtra1 + callba _LoadFontsExtra2 + ret +; e6c + +LoadFontsExtra2:: ; e6c + callba _LoadFontsExtra2 + ret +; e73 + +DecompressRequest2bpp:: ; e73 + push de + ld a, BANK(sScratch) + call GetSRAMBank + push bc + + ld de, sScratch + ld a, b + call FarDecompress + + pop bc + pop hl + + ld de, sScratch + call Request2bpp + call CloseSRAM + ret +; e8d + + + +FarCopyBytes:: ; e8d +; copy bc bytes from a:hl to de + + ld [hBuffer], a + ld a, [hROMBank] + push af + ld a, [hBuffer] + rst Bankswitch + + call CopyBytes + + pop af + rst Bankswitch + ret +; 0xe9b + + +FarCopyBytesDouble:: ; e9b +; Copy bc bytes from a:hl to bc*2 bytes at de, +; doubling each byte in the process. + + ld [hBuffer], a + ld a, [hROMBank] + push af + ld a, [hBuffer] + rst Bankswitch + +; switcheroo, de <> hl + ld a, h + ld h, d + ld d, a + ld a, l + ld l, e + ld e, a + + inc b + inc c + jr .dec + +.loop + ld a, [de] + inc de +rept 2 + ld [hli], a +endr +.dec + dec c + jr nz, .loop + dec b + jr nz, .loop + + pop af + rst Bankswitch + ret +; 0xeba + + +Request2bpp:: ; eba +; Load 2bpp at b:de to occupy c tiles of hl. + ld a, [hBGMapMode] + push af + xor a + ld [hBGMapMode], a + + ld a, [hROMBank] + push af + ld a, b + rst Bankswitch + + ld a, [hTilesPerCycle] + push af + ld a, $8 + ld [hTilesPerCycle], a + + ld a, [wLinkMode] + cp LINK_MOBILE + jr nz, .NotMobile + ld a, [hMobile] + and a + jr nz, .NotMobile + ld a, $6 + ld [hTilesPerCycle], a + +.NotMobile + ld a, e + ld [Requested2bppSource], a + ld a, d + ld [Requested2bppSource + 1], a + ld a, l + ld [Requested2bppDest], a + ld a, h + ld [Requested2bppDest + 1], a +.loop + ld a, c + ld hl, hTilesPerCycle + cp [hl] + jr nc, .iterate + + ld [Requested2bpp], a +.wait + call DelayFrame + ld a, [Requested2bpp] + and a + jr nz, .wait + + pop af + ld [hTilesPerCycle], a + + pop af + rst Bankswitch + + pop af + ld [hBGMapMode], a + ret + +.iterate + ld a, [hTilesPerCycle] + ld [Requested2bpp], a + +.wait2 + call DelayFrame + ld a, [Requested2bpp] + and a + jr nz, .wait2 + + ld a, c + ld hl, hTilesPerCycle + sub [hl] + ld c, a + jr .loop +; f1e + + +Request1bpp:: ; f1e +; Load 1bpp at b:de to occupy c tiles of hl. + ld a, [hBGMapMode] + push af + xor a + ld [hBGMapMode], a + + ld a, [hROMBank] + push af + ld a, b + rst Bankswitch + + ld a, [hTilesPerCycle] + push af + + ld a, $8 + ld [hTilesPerCycle], a + ld a, [wLinkMode] + cp LINK_MOBILE + jr nz, .NotMobile + ld a, [hMobile] + and a + jr nz, .NotMobile + ld a, $6 + ld [hTilesPerCycle], a + +.NotMobile + ld a, e + ld [Requested1bppSource], a + ld a, d + ld [Requested1bppSource + 1], a + ld a, l + ld [Requested1bppDest], a + ld a, h + ld [Requested1bppDest + 1], a +.loop + ld a, c + ld hl, hTilesPerCycle + cp [hl] + jr nc, .iterate + + ld [Requested1bpp], a +.wait + call DelayFrame + ld a, [Requested1bpp] + and a + jr nz, .wait + + pop af + ld [hTilesPerCycle], a + + pop af + rst Bankswitch + + pop af + ld [hBGMapMode], a + ret + +.iterate + ld a, [hTilesPerCycle] + ld [Requested1bpp], a + +.wait2 + call DelayFrame + ld a, [Requested1bpp] + and a + jr nz, .wait2 + + ld a, c + ld hl, hTilesPerCycle + sub [hl] + ld c, a + jr .loop +; f82 + + +Get2bpp:: ; f82 + ld a, [rLCDC] + bit 7, a + jp nz, Request2bpp + +Copy2bpp:: ; f89 +; copy c 2bpp tiles from b:de to hl + + push hl + ld h, d + ld l, e + pop de + +; bank + ld a, b + +; bc = c * $10 + push af + swap c + ld a, $f + and c + ld b, a + ld a, $f0 + and c + ld c, a + pop af + + jp FarCopyBytes +; f9d + + +Get1bpp:: ; f9d + ld a, [rLCDC] + bit 7, a + jp nz, Request1bpp + +Copy1bpp:: ; fa4 +; copy c 1bpp tiles from b:de to hl + + push de + ld d, h + ld e, l + +; bank + ld a, b + +; bc = c * $10 / 2 + push af + ld h, 0 + ld l, c +rept 3 + add hl, hl +endr + ld b, h + ld c, l + pop af + + pop hl + jp FarCopyBytesDouble +; fb6 diff --git a/home/copy2.asm b/home/copy2.asm new file mode 100644 index 00000000..538be572 --- /dev/null +++ b/home/copy2.asm @@ -0,0 +1,135 @@ +CopyBytes:: ; 0x3026 +; copy bc bytes from hl to de + inc b ; we bail the moment b hits 0, so include the last run + inc c ; same thing; include last byte + jr .HandleLoop +.CopyByte + ld a, [hli] + ld [de], a + inc de +.HandleLoop + dec c + jr nz, .CopyByte + dec b + jr nz, .CopyByte + ret + +SwapBytes:: ; 0x3034 +; swap bc bytes between hl and de +.Loop + ; stash [hl] away on the stack + ld a, [hl] + push af + + ; copy a byte from [de] to [hl] + ld a, [de] + ld [hli], a + + ; retrieve the previous value of [hl]; put it in [de] + pop af + ld [de], a + inc de + + ; handle loop stuff + dec bc + ld a, b + or c + jr nz, .Loop + ret + +ByteFill:: ; 0x3041 +; fill bc bytes with the value of a, starting at hl + inc b ; we bail the moment b hits 0, so include the last run + inc c ; same thing; include last byte + jr .HandleLoop +.PutByte + ld [hli], a +.HandleLoop + dec c + jr nz, .PutByte + dec b + jr nz, .PutByte + ret + +GetFarByte:: ; 0x304d +; retrieve a single byte from a:hl, and return it in a. + ; bankswitch to new bank + ld [hBuffer], a + ld a, [hROMBank] + push af + ld a, [hBuffer] + rst Bankswitch + + ; get byte from new bank + ld a, [hl] + ld [hBuffer], a + + ; bankswitch to previous bank + pop af + rst Bankswitch + + ; return retrieved value in a + ld a, [hBuffer] + ret + +GetFarHalfword:: ; 0x305d +; retrieve a halfword from a:hl, and return it in hl. + ; bankswitch to new bank + ld [hBuffer], a + ld a, [hROMBank] + push af + ld a, [hBuffer] + rst Bankswitch + + ; get halfword from new bank, put it in hl + ld a, [hli] + ld h, [hl] + ld l, a + + ; bankswitch to previous bank and return + pop af + rst Bankswitch + ret +; 0x306b + +FarCopyWRAM:: ; 306b + ld [hBuffer], a + ld a, [rSVBK] + push af + ld a, [hBuffer] + ld [rSVBK], a + + call CopyBytes + + pop af + ld [rSVBK], a + ret +; 307b + +GetFarWRAMByte:: ; 307b + ld [hBuffer], a + ld a, [rSVBK] + push af + ld a, [hBuffer] + ld [rSVBK], a + ld a, [hl] + ld [hBuffer], a + pop af + ld [rSVBK], a + ld a, [hBuffer] + ret +; 308d + +GetFarWRAMWord:: ; 308d + ld [hBuffer], a + ld a, [rSVBK] + push af + ld a, [hBuffer] + ld [rSVBK], a + ld a, [hli] + ld h, [hl] + ld l, a + pop af + ld [rSVBK], a + ret +; 309d diff --git a/home/cry.asm b/home/cry.asm new file mode 100644 index 00000000..aea7af03 --- /dev/null +++ b/home/cry.asm @@ -0,0 +1,108 @@ +PlayStereoCry:: ; 37b6 + push af + ld a, 1 + ld [wStereoPanningMask], a + pop af + call _PlayCry + call WaitSFX + ret +; 37c4 + +PlayStereoCry2:: ; 37c4 +; Don't wait for the cry to end. +; Used during pic animations. + push af + ld a, 1 + ld [wStereoPanningMask], a + pop af + jp _PlayCry +; 37ce + +PlayCry:: ; 37ce + call PlayCry2 + call WaitSFX + ret +; 37d5 + +PlayCry2:: ; 37d5 +; Don't wait for the cry to end. + push af + xor a + ld [wStereoPanningMask], a + ld [CryTracks], a + pop af + call _PlayCry + ret +; 37e2 + +_PlayCry:: ; 37e2 + push hl + push de + push bc + + call GetCryIndex + jr c, .done + + ld e, c + ld d, b + call PlayCryHeader + +.done + pop bc + pop de + pop hl + ret +; 37f3 + +LoadCryHeader:: ; 37f3 +; Load cry header bc. + + call GetCryIndex + ret c + + ld a, [hROMBank] + push af + ld a, BANK(CryHeaders) + rst Bankswitch + + ld hl, CryHeaders +rept 6 + add hl, bc +endr + + ld e, [hl] + inc hl + ld d, [hl] + inc hl + + ld a, [hli] + ld [CryPitch], a + ld a, [hli] + ld [CryPitch + 1], a + ld a, [hli] + ld [CryLength], a + ld a, [hl] + ld [CryLength + 1], a + + pop af + rst Bankswitch + and a + ret +; 381e + +GetCryIndex:: ; 381e + and a + jr z, .no + cp NUM_POKEMON + 1 + jr nc, .no + + dec a + ld c, a + ld b, 0 + and a + ret + +.no + scf + ret +; 382d diff --git a/home/decompress.asm b/home/decompress.asm new file mode 100644 index 00000000..13613f64 --- /dev/null +++ b/home/decompress.asm @@ -0,0 +1,343 @@ +FarDecompress:: ; b40 +; Decompress graphics data from a:hl to de. + + ld [wLZBank], a + ld a, [hROMBank] + push af + ld a, [wLZBank] + rst Bankswitch + + call Decompress + + pop af + rst Bankswitch + ret +; b50 + + +Decompress:: ; b50 +; Pokemon Crystal uses an lz variant for compression. +; This is mainly (but not necessarily) used for graphics. + +; This function decompresses lz-compressed data from hl to de. + + +LZ_END EQU $ff ; Compressed data is terminated with $ff. + + +; A typical control command consists of: + +LZ_CMD EQU %11100000 ; command id (bits 5-7) +LZ_LEN EQU %00011111 ; length n (bits 0-4) + +; Additional parameters are read during command execution. + + +; Commands: + +LZ_LITERAL EQU 0 << 5 ; Read literal data for n bytes. +LZ_ITERATE EQU 1 << 5 ; Write the same byte for n bytes. +LZ_ALTERNATE EQU 2 << 5 ; Alternate two bytes for n bytes. +LZ_ZERO EQU 3 << 5 ; Write 0 for n bytes. + + +; Another class of commands reuses data from the decompressed output. +LZ_RW EQU 2 + 5 ; bit + +; These commands take a signed offset to start copying from. +; Wraparound is simulated. +; Positive offsets (15-bit) are added to the start address. +; Negative offsets (7-bit) are subtracted from the current position. + +LZ_REPEAT EQU 4 << 5 ; Repeat n bytes from the offset. +LZ_FLIP EQU 5 << 5 ; Repeat n bitflipped bytes. +LZ_REVERSE EQU 6 << 5 ; Repeat n bytes in reverse. + + +; If the value in the count needs to be larger than 5 bits, +; LZ_LONG can be used to expand the count to 10 bits. +LZ_LONG EQU 7 << 5 + +; A new control command is read in bits 2-4. +; The top two bits of the length are bits 0-1. +; Another byte is read containing the bottom 8 bits. +LZ_LONG_HI EQU %00000011 + +; In other words, the structure of the command becomes +; 111xxxyy yyyyyyyy +; x: the new control command +; y: the length + + +; For more information, refer to the code below and in extras/gfx.py. + + + ; Save the output address + ; for rewrite commands. + ld a, e + ld [wLZAddress], a + ld a, d + ld [wLZAddress + 1], a + +.Main + ld a, [hl] + cp LZ_END + ret z + + and LZ_CMD + + cp LZ_LONG + jr nz, .short + +.long +; The count is now 10 bits. + + ; Read the next 3 bits. + ; %00011100 -> %11100000 + ld a, [hl] + add a + add a ; << 3 + add a + + ; This is our new control code. + and LZ_CMD + push af + + ld a, [hli] + and LZ_LONG_HI + ld b, a + ld a, [hli] + ld c, a + + ; read at least 1 byte + inc bc + jr .command + + +.short + push af + + ld a, [hli] + and LZ_LEN + ld c, a + ld b, 0 + + ; read at least 1 byte + inc c + + +.command + ; Increment loop counts. + ; We bail the moment they hit 0. + inc b + inc c + + pop af + + bit LZ_RW, a + jr nz, .rewrite + + cp LZ_ITERATE + jr z, .Iter + cp LZ_ALTERNATE + jr z, .Alt + cp LZ_ZERO + jr z, .Zero + + +.Literal +; Read literal data for bc bytes. +.lloop + dec c + jr nz, .lnext + dec b + jp z, .Main + +.lnext + ld a, [hli] + ld [de], a + inc de + jr .lloop + + +.Iter +; Write the same byte for bc bytes. + ld a, [hli] + +.iloop + dec c + jr nz, .inext + dec b + jp z, .Main + +.inext + ld [de], a + inc de + jr .iloop + + +.Alt +; Alternate two bytes for bc bytes. + dec c + jr nz, .anext1 + dec b + jp z, .adone1 +.anext1 + ld a, [hli] + ld [de], a + inc de + + dec c + jr nz, .anext2 + dec b + jp z, .adone2 +.anext2 + ld a, [hld] + ld [de], a + inc de + + jr .Alt + + ; Skip past the bytes we were alternating. +.adone1 + inc hl +.adone2 + inc hl + jr .Main + + +.Zero +; Write 0 for bc bytes. + xor a + +.zloop + dec c + jr nz, .znext + dec b + jp z, .Main + +.znext + ld [de], a + inc de + jr .zloop + + +.rewrite +; Repeat decompressed data from output. + push hl + push af + + ld a, [hli] + bit 7, a ; sign + jr z, .positive + +.negative +; hl = de - a + ; Since we can't subtract a from de, + ; Make it negative and add de. + and %01111111 + cpl + add e + ld l, a + ld a, -1 + adc d + ld h, a + jr .ok + +.positive +; Positive offsets are two bytes. + ld l, [hl] + ld h, a + ; add to starting output address + ld a, [wLZAddress] + add l + ld l, a + ld a, [wLZAddress + 1] + adc h + ld h, a + +.ok + pop af + + cp LZ_REPEAT + jr z, .Repeat + cp LZ_FLIP + jr z, .Flip + cp LZ_REVERSE + jr z, .Reverse + +; Since LZ_LONG is command 7, +; only commands 0-6 are passed in. +; This leaves room for an extra command 7. +; However, lengths longer than 768 +; would be interpreted as LZ_END. + +; More practically, LZ_LONG is not recursive. +; For now, it defaults to LZ_REPEAT. + + +.Repeat +; Copy decompressed data for bc bytes. + dec c + jr nz, .rnext + dec b + jr z, .donerw + +.rnext + ld a, [hli] + ld [de], a + inc de + jr .Repeat + + +.Flip +; Copy bitflipped decompressed data for bc bytes. + dec c + jr nz, .fnext + dec b + jp z, .donerw + +.fnext + ld a, [hli] + push bc + lb bc, 0, 8 + +.floop + rra + rl b + dec c + jr nz, .floop + + ld a, b + pop bc + + ld [de], a + inc de + jr .Flip + + +.Reverse +; Copy reversed decompressed data for bc bytes. + dec c + jr nz, .rvnext + + dec b + jp z, .donerw + +.rvnext + ld a, [hld] + ld [de], a + inc de + jr .Reverse + + +.donerw + pop hl + + bit 7, [hl] + jr nz, .next + inc hl ; positive offset is two bytes +.next + inc hl + jp .Main +; c2f diff --git a/home/delay.asm b/home/delay.asm new file mode 100644 index 00000000..450b4190 --- /dev/null +++ b/home/delay.asm @@ -0,0 +1,22 @@ +DelayFrame:: ; 45a +; Wait for one frame + ld a, 1 + ld [VBlankOccurred], a + +; Wait for the next VBlank, halting to conserve battery +.halt + halt ; rgbasm adds a nop after this instruction by default + ld a, [VBlankOccurred] + and a + jr nz, .halt + ret +; 468 + + +DelayFrames:: ; 468 +; Wait c frames + call DelayFrame + dec c + jr nz, DelayFrames + ret +; 46f diff --git a/home/double_speed.asm b/home/double_speed.asm new file mode 100644 index 00000000..c07dc9ce --- /dev/null +++ b/home/double_speed.asm @@ -0,0 +1,30 @@ +; The CGB hardware introduces Double Speed Mode. +; While active, the clock speed is doubled. + +; The hardware can switch between normal speed +; and double speed at any time, but LCD output +; collapses during the switch. + +DoubleSpeed:: ; 2fef + ld hl, rKEY1 + bit 7, [hl] + jr z, SwitchSpeed + ret +; 2ff7 + +NormalSpeed:: ; 2ff7 + ld hl, rKEY1 + bit 7, [hl] + ret z +; 2ffd + +SwitchSpeed:: ; 2ffd + set 0, [hl] + xor a + ld [rIF], a + ld [rIE], a + ld a, $30 + ld [rJOYP], a + stop ; rgbasm adds a nop after this instruction by default + ret +; 300b diff --git a/home/fade.asm b/home/fade.asm new file mode 100644 index 00000000..579a4125 --- /dev/null +++ b/home/fade.asm @@ -0,0 +1,136 @@ +; Functions to fade the screen in and out. + + +Function48c:: ; 48c + ld a, [TimeOfDayPal] + ld b, a + ld hl, IncGradGBPalTable_11 + ld a, l + sub b + ld l, a + jr nc, .okay + dec h + +.okay + ld a, [hli] + ld [rBGP], a + ld a, [hli] + ld [rOBP0], a + ld a, [hli] + ld [rOBP1], a + ret +; 4a3 + + +RotateFourPalettesRight:: ; 4a3 + ld a, [hCGB] + and a + jr z, .dmg + ld hl, IncGradGBPalTable_00 + ld b, 4 + jr RotatePalettesRight + +.dmg + ld hl, IncGradGBPalTable_08 + ld b, 4 + jr RotatePalettesRight +; 4b6 + +RotateThreePalettesRight:: ; 4b6 + ld a, [hCGB] + and a + jr z, .dmg + ld hl, IncGradGBPalTable_05 + ld b, 3 + jr RotatePalettesRight + +.dmg + ld hl, IncGradGBPalTable_13 + ld b, 3 +RotatePalettesRight:: ; 4c7 +; Rotate palettes to the right and fill with loaded colors from the left +; If we're already at the leftmost color, fill with the leftmost color + push de + ld a, [hli] + call DmgToCgbBGPals + ld a, [hli] + ld e, a + ld a, [hli] + ld d, a + call DmgToCgbObjPals + ld c, 8 + call DelayFrames + pop de + dec b + jr nz, RotatePalettesRight + ret +; 4dd + +RotateFourPalettesLeft:: ; 4dd + ld a, [hCGB] + and a + jr z, .dmg + ld hl, IncGradGBPalTable_04 - 1 + ld b, 4 + jr RotatePalettesLeft + +.dmg + ld hl, IncGradGBPalTable_12 - 1 + ld b, 4 + jr RotatePalettesLeft +; 4f0 + +RotateThreePalettesLeft:: ; 4f0 + ld a, [hCGB] + and a + jr z, .dmg + ld hl, IncGradGBPalTable_07 - 1 + ld b, 3 + jr RotatePalettesLeft + +.dmg + ld hl, IncGradGBPalTable_15 - 1 + ld b, 3 +RotatePalettesLeft:: ; 501 +; Rotate palettes to the left and fill with loaded colors from the right +; If we're already at the rightmost color, fill with the rightmost color + push de + ld a, [hld] + ld d, a + ld a, [hld] + ld e, a + call DmgToCgbObjPals + ld a, [hld] + call DmgToCgbBGPals + ld c, 8 + call DelayFrames + pop de + dec b + jr nz, RotatePalettesLeft + ret +; 517 + + +; 517 +IncGradGBPalTable_00:: db %11111111, %11111111, %11111111 +IncGradGBPalTable_01:: db %11111110, %11111110, %11111110 +IncGradGBPalTable_02:: db %11111001, %11111001, %11111001 +IncGradGBPalTable_03:: db %11100100, %11100100, %11100100 + +IncGradGBPalTable_04:: db %11100100, %11100100, %11100100 +IncGradGBPalTable_05:: db %10010000, %10010000, %10010000 +IncGradGBPalTable_06:: db %01000000, %01000000, %01000000 + +IncGradGBPalTable_07:: db %00000000, %00000000, %00000000 +; bgp obp1 obp2 +IncGradGBPalTable_08:: db %11111111, %11111111, %11111111 +IncGradGBPalTable_09:: db %11111110, %11111110, %11111000 +IncGradGBPalTable_10:: db %11111001, %11100100, %11100100 +IncGradGBPalTable_11:: db %11100100, %11010000, %11100000 + +IncGradGBPalTable_12:: db %11100100, %11010000, %11100000 +IncGradGBPalTable_13:: db %10010000, %10000000, %10010000 +IncGradGBPalTable_14:: db %01000000, %01000000, %01000000 + +IncGradGBPalTable_15:: db %00000000, %00000000, %00000000 +; 547 diff --git a/home/farcall.asm b/home/farcall.asm new file mode 100644 index 00000000..7c9fe105 --- /dev/null +++ b/home/farcall.asm @@ -0,0 +1,54 @@ +FarCall_de:: ; 2d54 +; Call a:de. +; Preserves other registers. + + ld [hBuffer], a + ld a, [hROMBank] + push af + ld a, [hBuffer] + rst Bankswitch + call .de + jr ReturnFarCall + +.de + push de + ret +; 2d63 + + +FarCall_hl:: ; 2d63 +; Call a:hl. +; Preserves other registers. + + ld [hBuffer], a + ld a, [hROMBank] + push af + ld a, [hBuffer] + rst Bankswitch + call FarJump_hl +; 2d6e + +ReturnFarCall:: ; 2d6e +; We want to retain the contents of f. +; To do this, we can pop to bc instead of af. + + ld a, b + ld [wFarCallBCBuffer], a + ld a, c + ld [wFarCallBCBuffer + 1], a + +; Restore the working bank. + pop bc + ld a, b + rst Bankswitch + + ld a, [wFarCallBCBuffer] + ld b, a + ld a, [wFarCallBCBuffer + 1] + ld c, a + ret +; 2d82 + +FarJump_hl:: ; 2d82 + jp [hl] +; 2d83 diff --git a/home/flag.asm b/home/flag.asm new file mode 100644 index 00000000..099f4bf0 --- /dev/null +++ b/home/flag.asm @@ -0,0 +1,112 @@ +ResetMapBufferEventFlags:: ; 2e50 + xor a + ld hl, EventFlags + ld [hli], a + ret +; 2e56 + +ResetBikeFlags:: ; 2e56 + xor a + ld hl, BikeFlags + ld [hli], a + ld [hl], a + ret +; 2e5d + +ResetFlashIfOutOfCave:: ; 2e5d + ld a, [wPermission] + cp $2 + jr z, .asm_2e69 + cp $1 + jr z, .asm_2e69 + ret + +.asm_2e69 + ld hl, StatusFlags + res 2, [hl] + ret +; 2e6f + + +EventFlagAction:: ; 0x2e6f + ld hl, EventFlags + call FlagAction + ret + +FlagAction:: ; 0x2e76 +; Perform action b on bit de in flag array hl. + +; inputs: +; b: function +; 0 clear bit +; 1 set bit +; 2 check bit +; de: bit number +; hl: index within bit table + + ; get index within the byte + ld a, e + and 7 + + ; shift de right by three bits (get the index within memory) + srl d + rr e + srl d + rr e + srl d + rr e + add hl, de + + ; implement a decoder + ld c, 1 + rrca + jr nc, .one + rlc c +.one + rrca + jr nc, .two + rlc c + rlc c +.two + rrca + jr nc, .three + swap c +.three + + ; check b's value: 0, 1, 2 + ld a, b + cp 1 + jr c, .clearbit ; 0 + jr z, .setbit ; 1 + + ; check bit + ld a, [hl] + and c + ld c, a + ret + +.setbit + ; set bit + ld a, [hl] + or c + ld [hl], a + ret + +.clearbit + ; clear bit + ld a, c + cpl + and [hl] + ld [hl], a + ret +; 0x2ead + + +CheckReceivedDex:: ; 2ead + ld de, ENGINE_POKEDEX + ld b, CHECK_FLAG + callba EngineFlagAction + ld a, c + and a + ret +; 2ebb diff --git a/home/game_time.asm b/home/game_time.asm new file mode 100644 index 00000000..54cad89c --- /dev/null +++ b/home/game_time.asm @@ -0,0 +1,131 @@ +ResetGameTime:: ; 208a + xor a + ld [GameTimeCap], a + ld [GameTimeHours], a + ld [GameTimeHours + 1], a + ld [GameTimeMinutes], a + ld [GameTimeSeconds], a + ld [GameTimeFrames], a + ret +; 209e + + +GameTimer:: ; 209e + + nop + + ld a, [rSVBK] + push af + ld a, 1 + ld [rSVBK], a + + call UpdateGameTimer + + pop af + ld [rSVBK], a + ret +; 20ad + + +UpdateGameTimer:: ; 20ad +; Increment the game timer by one frame. +; The game timer is capped at 999:59:59.00. + + +; Don't update if game logic is paused. + ld a, [wc2cd] + and a + ret nz + +; Is the timer paused? + ld hl, GameTimerPause + bit 0, [hl] + ret z + +; Is the timer already capped? + ld hl, GameTimeCap + bit 0, [hl] + ret nz + + +; +1 frame + ld hl, GameTimeFrames + ld a, [hl] + inc a + + cp 60 ; frames/second + jr nc, .second + + ld [hl], a + ret + + +.second + xor a + ld [hl], a + +; +1 second + ld hl, GameTimeSeconds + ld a, [hl] + inc a + + cp 60 ; seconds/minute + jr nc, .minute + + ld [hl], a + ret + + +.minute + xor a + ld [hl], a + +; +1 minute + ld hl, GameTimeMinutes + ld a, [hl] + inc a + + cp 60 ; minutes/hour + jr nc, .hour + + ld [hl], a + ret + + +.hour + xor a + ld [hl], a + +; +1 hour + ld a, [GameTimeHours] + ld h, a + ld a, [GameTimeHours + 1] + ld l, a + inc hl + + +; Cap the timer after 1000 hours. + ld a, h + cp 1000 / $100 + jr c, .ok + + ld a, l + cp 1000 % $100 + jr c, .ok + + ld hl, GameTimeCap + set 0, [hl] + + ld a, 59 ; 999:59:59.00 + ld [GameTimeMinutes], a + ld [GameTimeSeconds], a + ret + + +.ok + ld a, h + ld [GameTimeHours], a + ld a, l + ld [GameTimeHours + 1], a + ret +; 210f diff --git a/home/handshake.asm b/home/handshake.asm new file mode 100644 index 00000000..e53e78a5 --- /dev/null +++ b/home/handshake.asm @@ -0,0 +1,50 @@ +PrinterReceive:: ; 2057 + ld a, [hROMBank] + push af + ld a, BANK(_PrinterReceive) + rst Bankswitch + + call _PrinterReceive + pop af + rst Bankswitch + + ret +; 2063 + +AskSerial:: ; 2063 +; send out a handshake while serial int is off + ld a, [wc2d4] + bit 0, a + ret z + + ld a, [wc2d5] + and a + ret nz + +; once every 6 frames + ld hl, wca8a + inc [hl] + ld a, [hl] + cp 6 + ret c + + xor a + ld [hl], a + + ld a, $c + ld [wc2d5], a + +; handshake + ld a, $88 + ld [rSB], a + +; switch to internal clock + ld a, %00000001 + ld [rSC], a + +; start transfer + ld a, %10000001 + ld [rSC], a + + ret +; 208a diff --git a/home/init.asm b/home/init.asm new file mode 100644 index 00000000..dacc5ff7 --- /dev/null +++ b/home/init.asm @@ -0,0 +1,222 @@ +Reset:: ; 150 + di + call MapSetup_Sound_Off + xor a + ld [hMapAnims], a + call ClearPalettes + xor a + ld [rIF], a + ld a, 1 ; VBlank int + ld [rIE], a + ei + + ld hl, wcfbe + set 7, [hl] + + ld c, 32 + call DelayFrames + + jr Init +; 16e + + +_Start:: ; 16e + cp $11 + jr z, .cgb + xor a + jr .load + +.cgb + ld a, $1 + +.load + ld [hCGB], a + ld a, $1 + ld [hFFEA], a +; 17d + + +Init:: ; 17d + + di + + xor a + ld [rIF], a + ld [rIE], a + ld [rRP], a + ld [rSCX], a + ld [rSCY], a + ld [rSB], a + ld [rSC], a + ld [rWX], a + ld [rWY], a + ld [rBGP], a + ld [rOBP0], a + ld [rOBP1], a + ld [rTMA], a + ld [rTAC], a + ld [$d000], a + + ld a, %100 ; Start timer at 4096Hz + ld [rTAC], a + +.wait + ld a, [rLY] + cp 145 + jr nz, .wait + + xor a + ld [rLCDC], a + +; Clear WRAM bank 0 + ld hl, wc000 + ld bc, wd000 - wc000 +.ByteFill + ld [hl], 0 + inc hl + dec bc + ld a, b + or c + jr nz, .ByteFill + + ld sp, Stack + +; Clear HRAM + ld a, [hCGB] + push af + ld a, [hFFEA] + push af + xor a + ld hl, HRAM_START + ld bc, HRAM_END - HRAM_START + call ByteFill + pop af + ld [hFFEA], a + pop af + ld [hCGB], a + + call ClearWRAM + ld a, 1 + ld [rSVBK], a + call ClearVRAM + call ClearSprites + call Function270 + + + ld a, BANK(LoadPushOAM) + rst Bankswitch + + call LoadPushOAM + + xor a + ld [hMapAnims], a + ld [hSCX], a + ld [hSCY], a + ld [rJOYP], a + + ld a, $8 ; HBlank int enable + ld [rSTAT], a + + ld a, $90 + ld [hWY], a + ld [rWY], a + + ld a, 7 + ld [hWX], a + ld [rWX], a + + ld a, %11100011 + ; LCD on + ; Win tilemap 1 + ; Win on + ; BG/Win tiledata 0 + ; BG Tilemap 0 + ; OBJ 8x8 + ; OBJ on + ; BG on + ld [rLCDC], a + + ld a, -1 + ld [hLinkPlayerNumber], a + + callba Function9890 + + ld a, VBGMap1 / $100 + ld [hBGMapAddress + 1], a + xor a ; VBGMap1 % $100 + ld [hBGMapAddress], a + + callba StartClock + + xor a + ld [MBC3LatchClock], a + ld [MBC3SRamEnable], a + + ld a, [hCGB] + and a + jr z, .asm_22b + call NormalSpeed +.asm_22b + + xor a + ld [rIF], a + ld a, %1111 ; VBlank, LCDStat, Timer, Serial interrupts + ld [rIE], a + ei + + call DelayFrame + + predef Function9853 + + call MapSetup_Sound_Off + xor a + ld [wMapMusic], a + jp GameInit +; 245 + + +ClearVRAM:: ; 245 +; Wipe VRAM banks 0 and 1 + + ld a, 1 + ld [rVBK], a + call .clear + + xor a + ld [rVBK], a +.clear + ld hl, VTiles0 + ld bc, $2000 + xor a + call ByteFill + ret +; 25a + +ClearWRAM:: ; 25a +; Wipe swappable WRAM banks (1-7) + + ld a, 1 +.asm_25c + push af + ld [rSVBK], a + xor a + ld hl, $d000 + ld bc, $1000 + call ByteFill + pop af + inc a + cp 8 + jr nc, .asm_25c + ret +; 270 + +Function270:: ; 270 + ld a, $0 + call GetSRAMBank + ld hl, $a000 + ld bc, $0020 + xor a + call ByteFill + call CloseSRAM + ret +; 283 diff --git a/home/item.asm b/home/item.asm new file mode 100644 index 00000000..92d74c35 --- /dev/null +++ b/home/item.asm @@ -0,0 +1,75 @@ +DoItemEffect:: ; 2f3f + callba _DoItemEffect + ret +; 2f46 + +CheckTossableItem:: ; 2f46 + push hl + push de + push bc + callba _CheckTossableItem + pop bc + pop de + pop hl + ret +; 2f53 + +TossItem:: ; 2f53 + push hl + push de + push bc + ld a, [hROMBank] + push af + ld a, BANK(_TossItem) + rst Bankswitch + + call _TossItem + + pop bc + ld a, b + rst Bankswitch + pop bc + pop de + pop hl + ret +; 2f66 + +ReceiveItem:: ; 2f66 + push bc + ld a, [hROMBank] + push af + ld a, BANK(_ReceiveItem) + rst Bankswitch + push hl + push de + + call _ReceiveItem + + pop de + pop hl + pop bc + ld a, b + rst Bankswitch + pop bc + ret +; 2f79 + +CheckItem:: ; 2f79 + push hl + push de + push bc + ld a, [hROMBank] + push af + ld a, BANK(_CheckItem) + rst Bankswitch + + call _CheckItem + + pop bc + ld a, b + rst Bankswitch + pop bc + pop de + pop hl + ret +; 2f8c diff --git a/home/joypad.asm b/home/joypad.asm new file mode 100644 index 00000000..390166be --- /dev/null +++ b/home/joypad.asm @@ -0,0 +1,496 @@ +JoypadInt:: ; 92e +; Replaced by Joypad, called from VBlank instead of the useless +; joypad interrupt. + +; This is a placeholder in case the interrupt is somehow enabled. + reti +; 92f + +ClearJoypad:: ; 92f + xor a +; Pressed this frame (delta) + ld [hJoyPressed], a +; Currently pressed + ld [hJoyDown], a + ret +; 935 + +Joypad:: ; 935 +; Read the joypad register and translate it to something more +; workable for use in-game. There are 8 buttons, so we can use +; one byte to contain all player input. + +; Updates: + +; hJoypadReleased: released this frame (delta) +; hJoypadPressed: pressed this frame (delta) +; hJoypadDown: currently pressed +; hJoypadSum: pressed so far + +; Any of these three bits can be used to disable input. + ld a, [wcfbe] + and %11010000 + ret nz + +; If we're saving, input is disabled. + ld a, [wc2cd] + and a + ret nz + +; We can only get four inputs at a time. +; We take d-pad first for no particular reason. + ld a, R_DPAD + ld [rJOYP], a +; Read twice to give the request time to take. +rept 2 + ld a, [rJOYP] +endr + +; The Joypad register output is in the lo nybble (inversed). +; We make the hi nybble of our new container d-pad input. + cpl + and $f + swap a + +; We'll keep this in b for now. + ld b, a + +; Buttons make 8 total inputs (A, B, Select, Start). +; We can fit this into one byte. + ld a, R_BUTTONS + ld [rJOYP], a +; Wait for input to stabilize. +rept 6 + ld a, [rJOYP] +endr +; Buttons take the lo nybble. + cpl + and $f + or b + ld b, a + +; Reset the joypad register since we're done with it. + ld a, $30 + ld [rJOYP], a + +; To get the delta we xor the last frame's input with the new one. + ld a, [hJoypadDown] ; last frame + ld e, a + xor b + ld d, a +; Released this frame: + and e + ld [hJoypadReleased], a +; Pressed this frame: + ld a, d + and b + ld [hJoypadPressed], a + +; Add any new presses to the list of collective presses: + ld c, a + ld a, [hJoypadSum] + or c + ld [hJoypadSum], a + +; Currently pressed: + ld a, b + ld [hJoypadDown], a + +; Now that we have the input, we can do stuff with it. + +; For example, soft reset: + and A_BUTTON | B_BUTTON | SELECT | START + cp A_BUTTON | B_BUTTON | SELECT | START + jp z, Reset + + ret +; 984 + + +GetJoypad:: ; 984 +; Update mirror joypad input from hJoypadDown (real input) + +; hJoyReleased: released this frame (delta) +; hJoyPressed: pressed this frame (delta) +; hJoyDown: currently pressed + +; bit 0 A +; 1 B +; 2 SELECT +; 3 START +; 4 RIGHT +; 5 LEFT +; 6 UP +; 7 DOWN + + push af + push hl + push de + push bc + +; The player input can be automated using an input stream. +; See more below. + ld a, [InputType] + cp a, AUTO_INPUT + jr z, .auto + +; To get deltas, take this and last frame's input. + ld a, [hJoypadDown] ; real input + ld b, a + ld a, [hJoyDown] ; last frame mirror + ld e, a + +; Released this frame: + xor b + ld d, a + and e + ld [hJoyReleased], a + +; Pressed this frame: + ld a, d + and b + ld [hJoyPressed], a + +; It looks like the collective presses got commented out here. + ld c, a + +; Currently pressed: + ld a, b + ld [hJoyDown], a ; frame input + +.quit + pop bc + pop de + pop hl + pop af + ret + +.auto +; Use a predetermined input stream (used in the catching tutorial). + +; Stream format: [input][duration] +; A value of $ff will immediately end the stream. + +; Read from the input stream. + ld a, [hROMBank] + push af + ld a, [AutoInputBank] + rst Bankswitch + + ld hl, AutoInputAddress + ld a, [hli] + ld h, [hl] + ld l, a + +; We only update when the input duration has expired. + ld a, [AutoInputLength] + and a + jr z, .updateauto + +; Until then, don't change anything. + dec a + ld [AutoInputLength], a + pop af + rst Bankswitch + jr .quit + + +.updateauto +; An input of $ff will end the stream. + ld a, [hli] + cp a, -1 + jr z, .stopauto + ld b, a + +; A duration of $ff will end the stream indefinitely. + ld a, [hli] + ld [AutoInputLength], a + cp a, -1 + jr nz, .next + +; The current input is overwritten. +rept 2 + dec hl +endr + ld b, NO_INPUT + jr .finishauto + +.next +; On to the next input... + ld a, l + ld [AutoInputAddress], a + ld a, h + ld [AutoInputAddress+1], a + jr .finishauto + +.stopauto + call StopAutoInput + ld b, NO_INPUT + +.finishauto + pop af + rst Bankswitch + ld a, b + ld [hJoyPressed], a ; pressed + ld [hJoyDown], a ; input + jr .quit +; 9ee + + +StartAutoInput:: ; 9ee +; Start reading automated input stream at a:hl. + + ld [AutoInputBank], a + ld a, l + ld [AutoInputAddress], a + ld a, h + ld [AutoInputAddress+1], a +; Start reading the stream immediately. + xor a + ld [AutoInputLength], a +; Reset input mirrors. + xor a + ld [hJoyPressed], a ; pressed this frame + ld [hJoyReleased], a ; released this frame + ld [hJoyDown], a ; currently pressed + + ld a, AUTO_INPUT + ld [InputType], a + ret +; a0a + + +StopAutoInput:: ; a0a +; Clear variables related to automated input. + xor a + ld [AutoInputBank], a + ld [AutoInputAddress], a + ld [AutoInputAddress+1], a + ld [AutoInputLength], a +; Back to normal input. + ld [InputType], a + ret +; a1b + + +JoyTitleScreenInput:: ; a1b +.loop + + call DelayFrame + + push bc + call JoyTextDelay + pop bc + + ld a, [hJoyDown] + cp D_UP | SELECT | B_BUTTON + jr z, .keycombo + + ld a, [hJoyLast] + and START | A_BUTTON + jr nz, .keycombo + + dec c + jr nz, .loop + + and a + ret + +.keycombo + scf + ret +; a36 + + +JoyWaitAorB:: ; a36 +.loop + call DelayFrame + call GetJoypad + ld a, [hJoyPressed] + and A_BUTTON | B_BUTTON + ret nz + call RTC + jr .loop +; a46 + +WaitButton:: ; a46 + ld a, [hOAMUpdate] + push af + ld a, 1 + ld [hOAMUpdate], a + call WaitBGMap + call JoyWaitAorB + pop af + ld [hOAMUpdate], a + ret +; a57 + +JoyTextDelay:: ; a57 + call GetJoypad + ld a, [hInMenu] + and a + ld a, [hJoyPressed] + jr z, .ok + ld a, [hJoyDown] +.ok + ld [hJoyLast], a + ld a, [hJoyPressed] + and a + jr z, .checkframedelay + ld a, 15 + ld [TextDelayFrames], a + ret + +.checkframedelay + ld a, [TextDelayFrames] + and a + jr z, .restartframedelay + xor a + ld [hJoyLast], a + ret + +.restartframedelay + ld a, 5 + ld [TextDelayFrames], a + ret +; a80 + +WaitPressAorB_BlinkCursor:: ; a80 + ld a, [hMapObjectIndexBuffer] + push af + ld a, [hObjectStructIndexBuffer] + push af + xor a + ld [hMapObjectIndexBuffer], a + ld a, 6 + ld [hObjectStructIndexBuffer], a + +.loop + push hl + hlcoord 18, 17 + call BlinkCursor + pop hl + + call JoyTextDelay + ld a, [hJoyLast] + and A_BUTTON | B_BUTTON + jr z, .loop + + pop af + ld [hObjectStructIndexBuffer], a + pop af + ld [hMapObjectIndexBuffer], a + ret +; aa5 + +SimpleWaitPressAorB:: ; aa5 +.loop + call JoyTextDelay + ld a, [hJoyLast] + and A_BUTTON | B_BUTTON + jr z, .loop + ret +; aaf + +ButtonSound:: ; aaf + ld a, [wLinkMode] + and a + jr nz, .link + call .wait_input + push de + ld de, SFX_READ_TEXT_2 + call PlaySFX + pop de + ret + +.link + ld c, 65 + jp DelayFrames +; ac6 + +.wait_input: ; ac6 + ld a, [hOAMUpdate] + push af + ld a, $1 + ld [hOAMUpdate], a + ld a, [InputType] + or a + jr z, .input_wait_loop + callba _DudeAutoInput_A + +.input_wait_loop + call .blink_cursor + call JoyTextDelay + ld a, [hJoyPressed] + and A_BUTTON | B_BUTTON + jr nz, .received_input + call RTC + ld a, $1 + ld [hBGMapMode], a + call DelayFrame + jr .input_wait_loop + +.received_input + pop af + ld [hOAMUpdate], a + ret +; af5 + +.blink_cursor: ; af5 + ld a, [hVBlankCounter] + and %00010000 ; bit 4, a + jr z, .cursor_off + ld a, "▼" + jr .load_cursor_state + +.cursor_off + ld a, [TileMap + 17 + 17 * SCREEN_WIDTH] + +.load_cursor_state + ld [TileMap + 18 + 17 * SCREEN_WIDTH], a + ret +; b06 + +BlinkCursor:: ; b06 + push bc + ld a, [hl] + ld b, a + ld a, "▼" + cp b + pop bc + jr nz, .place_arrow + ld a, [hMapObjectIndexBuffer] + dec a + ld [hMapObjectIndexBuffer], a + ret nz + ld a, [hObjectStructIndexBuffer] + dec a + ld [hObjectStructIndexBuffer], a + ret nz + ld a, "─" + ld [hl], a + ld a, -1 + ld [hMapObjectIndexBuffer], a + ld a, 6 + ld [hObjectStructIndexBuffer], a + ret + +.place_arrow + ld a, [hMapObjectIndexBuffer] + and a + ret z + dec a + ld [hMapObjectIndexBuffer], a + ret nz + dec a + ld [hMapObjectIndexBuffer], a + ld a, [hObjectStructIndexBuffer] + dec a + ld [hObjectStructIndexBuffer], a + ret nz + ld a, 6 + ld [hObjectStructIndexBuffer], a + ld a, "▼" + ld [hl], a + ret +; b40 diff --git a/home/lcd.asm b/home/lcd.asm new file mode 100644 index 00000000..875043bc --- /dev/null +++ b/home/lcd.asm @@ -0,0 +1,81 @@ +; LCD handling + + +Function547:: ; 547 +; Unreferenced + ld a, [hFFC6] + cp rSCX - $ff00 + ret nz + ld c, a + ld a, [LYOverrides] + ld [$ff00+c], a + ret +; 552 + + +LCD:: ; 552 + push af + ld a, [hFFC6] + and a + jr z, .done + +; At this point it's assumed we're in WRAM bank 5! + push bc + ld a, [rLY] + ld c, a + ld b, LYOverrides >> 8 + ld a, [bc] + ld b, a + ld a, [hFFC6] + ld c, a + ld a, b + ld [$ff00+c], a + pop bc + +.done + pop af + reti +; 568 + + +DisableLCD:: ; 568 +; Turn the LCD off + +; Don't need to do anything if the LCD is already off + ld a, [rLCDC] + bit 7, a ; lcd enable + ret z + + xor a + ld [rIF], a + ld a, [rIE] + ld b, a + +; Disable VBlank + res 0, a ; vblank + ld [rIE], a + +.wait +; Wait until VBlank would normally happen + ld a, [rLY] + cp 145 + jr nz, .wait + + ld a, [rLCDC] + and %01111111 ; lcd enable off + ld [rLCDC], a + + xor a + ld [rIF], a + ld a, b + ld [rIE], a + ret +; 58a + + +EnableLCD:: ; 58a + ld a, [rLCDC] + set 7, a ; lcd enable + ld [rLCDC], a + ret +; 591 diff --git a/home/map.asm b/home/map.asm new file mode 100644 index 00000000..c51f9c48 --- /dev/null +++ b/home/map.asm @@ -0,0 +1,2385 @@ +; Functions dealing with rendering and interacting with maps. + +Clearwc7e8:: ; 210f + ld hl, wc7e8 + ld bc, 24 + ld a, $0 + call ByteFill + ret +; 211b + +CheckTriggers:: ; 211b +; Checks wCurrentMapTriggerPointer. If it's empty, returns -1 in a. Otherwise, returns the active trigger ID in a. + push hl + ld hl, wCurrentMapTriggerPointer + ld a, [hli] + ld h, [hl] + ld l, a + or h + ld a, [hl] + jr nz, .triggerexists + ld a, -1 + +.triggerexists + pop hl + ret +; 212a + +GetCurrentMapTrigger:: ; 212a +; Grabs the wram map trigger pointer for the current map and loads it into wCurrentMapTriggerPointer. +; If there are no triggers, both bytes of wCurrentMapTriggerPointer are wiped clean. +; Copy the current map group and number into bc. This is needed for GetMapTrigger. + ld a, [MapGroup] + ld b, a + ld a, [MapNumber] + ld c, a +; Blank out wCurrentMapTriggerPointer; this is the default scenario. + xor a + ld [wCurrentMapTriggerPointer], a + ld [wCurrentMapTriggerPointer + 1], a + call GetMapTrigger + ret c ; The map is not in the trigger table +; Load the trigger table pointer from de into wCurrentMapTriggerPointer + ld a, e + ld [wCurrentMapTriggerPointer], a + ld a, d + ld [wCurrentMapTriggerPointer + 1], a + xor a + ret +; 2147 + +GetMapTrigger:: ; 2147 +; Searches the trigger table for the map group and number loaded in bc, and returns the wram pointer in de. +; If the map is not in the trigger table, returns carry. + push bc + ld a, [hROMBank] + push af + ld a, BANK(MapTriggers) + rst Bankswitch + + ld hl, MapTriggers +.loop + push hl + ld a, [hli] ; map group, or terminator + cp -1 + jr z, .end ; the current map is not in the trigger table + cp b + jr nz, .next ; map group did not match + ld a, [hli] ; map number + cp c + jr nz, .next ; map number did not match + jr .found ; we found our map + +.next + pop hl + ld de, 4 ; size of an entry in the trigger table + add hl, de + jr .loop + +.end + scf + jr .done + +.found + ld e, [hl] + inc hl + ld d, [hl] + +.done + pop hl + pop bc + ld a, b + rst Bankswitch + + pop bc + ret +; 2173 + +OverworldTextModeSwitch:: ; 2173 + call LoadMapPart + call FarCallSwapTextboxPalettes + ret +; 217a + +LoadMapPart:: ; 217a + ld a, [hROMBank] + push af + + ld a, [TilesetBlocksBank] + rst Bankswitch + + call LoadMetatiles + ld a, $60 + hlcoord 0, 0 + ld bc, SCREEN_WIDTH * SCREEN_HEIGHT + call ByteFill + + ld a, BANK(_LoadMapPart) + rst Bankswitch + call _LoadMapPart + + pop af + rst Bankswitch + ret +; 2198 + +LoadMetatiles:: ; 2198 + ; de <- wOverworldMapAnchor + ld a, [wOverworldMapAnchor] + ld e, a + ld a, [wOverworldMapAnchor + 1] + ld d, a + ld hl, wMisc + ld b, WMISC_HEIGHT / 4 ; 5 + +.row + push de + push hl + ld c, WMISC_WIDTH / 4 ; 6 + +.col + push de + push hl + ; Load the current map block. + ; If the current map block is a border block, load the border block. + ld a, [de] + and a + jr nz, .ok + ld a, [MapBorderBlock] + +.ok + ; Load the current wMisc address into de. + ld e, l + ld d, h + ; Set hl to the address of the current metatile data ([TilesetBlocksAddress] + (a) tiles). + add a + ld l, a + ld h, 0 +rept 3 + add hl, hl +endr + ld a, [TilesetBlocksAddress] + add l + ld l, a + ld a, [TilesetBlocksAddress + 1] + adc h + ld h, a + + ; copy the 4x4 metatile +rept 3 +rept 4 + ld a, [hli] + ld [de], a + inc de +endr + ld a, e + add WMISC_WIDTH - 4 + ld e, a + jr nc, .next\@ + inc d +.next\@ +endr +rept 4 + ld a, [hli] + ld [de], a + inc de +endr + ; Next metatile + pop hl + ld de, 4 + add hl, de + pop de + inc de + dec c + jp nz, .col + ; Next metarow + pop hl + ld de, WMISC_WIDTH * 4 + add hl, de + pop de + ld a, [MapWidth] + add 6 + add e + ld e, a + jr nc, .ok2 + inc d +.ok2 + dec b + jp nz, .row + ret +; 222a + +ReturnToMapFromSubmenu:: ; 222a + ld a, MAPSETUP_SUBMENU + ld [hMapEntryMethod], a + callba RunMapSetupScript + xor a + ld [hMapEntryMethod], a + ret +; 2238 + +CheckWarpTile:: ; 2238 + call GetDestinationWarpNumber + ret nc + + push bc + callba CheckDirectionalWarp + pop bc + ret nc + + call CopyWarpData + scf + ret +; 224a + +WarpCheck:: ; 224a + call GetDestinationWarpNumber + ret nc + call CopyWarpData + ret +; 2252 + +GetDestinationWarpNumber:: ; 2252 + callba CheckWarpCollision + ret nc + + ld a, [hROMBank] + push af + + call SwitchToMapScriptHeaderBank + call .GetDestinationWarpNumber + + pop de + ld a, d + rst Bankswitch + ret +; 2266 + +.GetDestinationWarpNumber ; 2266 + ld a, [PlayerStandingMapY] + sub $4 + ld e, a + ld a, [PlayerStandingMapX] + sub $4 + ld d, a + ld a, [wCurrMapWarpCount] + and a + ret z + + ld c, a + ld hl, wCurrMapWarpHeaderPointer + ld a, [hli] + ld h, [hl] + ld l, a +.loop + push hl + ld a, [hli] + cp e + jr nz, .next + ld a, [hli] + cp d + jr nz, .next + jr .found_warp + +.next + pop hl + ld a, 5 + add l + ld l, a + jr nc, .okay + inc h + +.okay + dec c + jr nz, .loop + xor a + ret + +.found_warp + pop hl + call .IncreaseHLTwice + ret nc ; never encountered + + ld a, [wCurrMapWarpCount] + inc a + sub c + ld c, a + scf + ret + +.IncreaseHLTwice + inc hl + inc hl + scf + ret +; 22a7 + +CopyWarpData:: ; 22a7 + ld a, [hROMBank] + push af + + call SwitchToMapScriptHeaderBank + call .CopyWarpData + + pop af + rst Bankswitch + scf + ret +; 22b4 + +.CopyWarpData ; 22b4 + push bc + ld hl, wCurrMapWarpHeaderPointer + ld a, [hli] + ld h, [hl] + ld l, a + ld a, c + dec a + ld bc, 5 ; warp size + call AddNTimes + ld bc, 2 ; warp number + add hl, bc + ld a, [hli] + cp $ff + jr nz, .skip + ld hl, BackupWarpNumber + ld a, [hli] + +.skip + pop bc + ld [wNextWarp], a + ld a, [hli] + ld [wNextMapGroup], a + ld a, [hli] + ld [wNextMapNumber], a + + ld a, c + ld [wPrevWarp], a + ld a, [MapGroup] + ld [wPrevMapGroup], a + ld a, [MapNumber] + ld [wPrevMapNumber], a + scf + ret +; 22ee + +CheckOutdoorMap:: ; 22ee + cp ROUTE + ret z + cp TOWN + ret +; 22f4 + +CheckIndoorMap:: ; 22f4 + cp INDOOR + ret z + cp CAVE + ret z + cp DUNGEON + ret z + cp GATE + ret +; 2300 + +; XXX + cp INDOOR + ret z + cp GATE + ret z + cp PERM_5 + ret +; 2309 + +LoadMapAttributes:: ; 2309 + call CopyMapHeaders + call SwitchToMapScriptHeaderBank + call ReadMapScripts + xor a + call ReadMapEventHeader + ret +; 2317 + +LoadMapAttributes_SkipPeople:: ; 2317 + call CopyMapHeaders + call SwitchToMapScriptHeaderBank + call ReadMapScripts + ld a, $1 + call ReadMapEventHeader + ret +; 2326 + +CopyMapHeaders:: ; 2326 + call PartiallyCopyMapHeader + call SwitchToMapBank + call GetSecondaryMapHeaderPointer + call CopySecondMapHeader + call GetMapConnections + ret +; 2336 + +ReadMapEventHeader:: ; 2336 + push af + ld hl, MapEventHeaderPointer + ld a, [hli] + ld h, [hl] + ld l, a + inc hl + inc hl + call ReadWarps + call ReadCoordEvents + call ReadSignposts + + pop af + and a + ret nz + + call ReadObjectEvents + ret +; 234f + +ReadMapScripts:: ; 234f + ld hl, MapScriptHeaderPointer + ld a, [hli] + ld h, [hl] + ld l, a + call ReadMapTriggers + call ReadMapCallbacks + ret +; 235c + +CopySecondMapHeader:: ; 235c + ld de, MapHeader + ld c, 12 ; size of the second map header +.loop + ld a, [hli] + ld [de], a + inc de + dec c + jr nz, .loop + ret +; 2368 + +GetMapConnections:: ; 2368 + ld a, $ff + ld [NorthConnectedMapGroup], a + ld [SouthConnectedMapGroup], a + ld [WestConnectedMapGroup], a + ld [EastConnectedMapGroup], a + + ld a, [MapConnections] + ld b, a + + bit NORTH_F, b + jr z, .no_north + ld de, NorthMapConnection + call GetMapConnection +.no_north + + bit SOUTH_F, b + jr z, .no_south + ld de, SouthMapConnection + call GetMapConnection +.no_south + + bit WEST_F, b + jr z, .no_west + ld de, WestMapConnection + call GetMapConnection +.no_west + + bit EAST_F, b + jr z, .no_east + ld de, EastMapConnection + call GetMapConnection +.no_east + + ret +; 23a3 + +GetMapConnection:: ; 23a3 +; Load map connection struct at hl into de. + ld c, SouthMapConnection - NorthMapConnection +.loop + ld a, [hli] + ld [de], a + inc de + dec c + jr nz, .loop + ret +; 23ac + +ReadMapTriggers:: ; 23ac + ld a, [hli] ; trigger count + ld c, a + ld [wCurrMapTriggerCount], a ; current map trigger count + ld a, l + ld [wCurrMapTriggerHeaderPointer], a ; map trigger pointer + ld a, h + ld [wCurrMapTriggerHeaderPointer + 1], a + ld a, c + and a + ret z + + ld bc, 4 ; size of a map trigger header entry + call AddNTimes + ret +; 23c3 + +ReadMapCallbacks:: ; 23c3 + ld a, [hli] + ld c, a + ld [wCurrMapCallbackCount], a + ld a, l + ld [wCurrMapCallbackHeaderPointer], a + ld a, h + ld [wCurrMapCallbackHeaderPointer + 1], a + ld a, c + and a + ret z + + ld bc, 3 + call AddNTimes + ret +; 23da + +ReadWarps:: ; 23da + ld a, [hli] + ld c, a + ld [wCurrMapWarpCount], a + ld a, l + ld [wCurrMapWarpHeaderPointer], a + ld a, h + ld [wCurrMapWarpHeaderPointer + 1], a + ld a, c + and a + ret z + ld bc, 5 + call AddNTimes + ret +; 23f1 + +ReadCoordEvents:: ; 23f1 + ld a, [hli] + ld c, a + ld [wCurrentMapXYTriggerCount], a + ld a, l + ld [wCurrentMapXYTriggerHeaderPointer], a + ld a, h + ld [wCurrentMapXYTriggerHeaderPointer + 1], a + + ld a, c + and a + ret z + + ld bc, 8 + call AddNTimes + ret +; 2408 + +ReadSignposts:: ; 2408 + ld a, [hli] + ld c, a + ld [wCurrentMapSignpostCount], a + ld a, l + ld [wCurrentMapSignpostHeaderPointer], a + ld a, h + ld [wCurrentMapSignpostHeaderPointer + 1], a + + ld a, c + and a + ret z + + ld bc, 5 + call AddNTimes + ret +; 241f + +ReadObjectEvents:: ; 241f + push hl + call ClearObjectStructs + pop de + ld hl, Map1Object + ld a, [de] + inc de + ld [wCurrentMapPersonEventCount], a + ld a, e + ld [wCurrentMapPersonEventHeaderPointer], a + ld a, d + ld [wCurrentMapPersonEventHeaderPointer + 1], a + + ld a, [wCurrentMapPersonEventCount] + call CopyMapObjectHeaders + +; get NUM_OBJECTS - [wCurrentMapPersonEventCount] + ld a, [wCurrentMapPersonEventCount] + ld c, a + ld a, NUM_OBJECTS ; - 1 + sub c + jr z, .skip + ; jr c, .skip + +; stupid waste of time and space + ld bc, 1 + add hl, bc +; Fill the remaining sprite IDs and y coords with 0 and -1, respectively. +; Bleeds into wObjectMasks due to a bug. Uncomment the above subtraction +; to fix. + ld bc, OBJECT_LENGTH +.loop + ld [hl], 0 + inc hl + ld [hl], -1 + dec hl + add hl, bc + dec a + jr nz, .loop + +.skip + ld h, d + ld l, e + ret +; 2457 + +CopyMapObjectHeaders:: ; 2457 + and a + ret z + + ld c, a +.loop + push bc + push hl + ld a, $ff + ld [hli], a + ld b, MAPOBJECT_E - MAPOBJECT_SPRITE +.loop2 + ld a, [de] + inc de + ld [hli], a + dec b + jr nz, .loop2 + + pop hl + ld bc, OBJECT_LENGTH + add hl, bc + pop bc + dec c + jr nz, .loop + ret +; 2471 + +ClearObjectStructs:: ; 2471 + ld hl, Object1Struct + ld bc, OBJECT_STRUCT_LENGTH * (NUM_OBJECT_STRUCTS - 1) + xor a + call ByteFill + +; Just to make sure (this is rather pointless) + ld hl, Object1Struct + ld de, OBJECT_STRUCT_LENGTH + ld c, NUM_OBJECT_STRUCTS - 1 + xor a +.loop + ld [hl], a + add hl, de + dec c + jr nz, .loop + ret +; 248a + +RestoreFacingAfterWarp:: ; 248a + call GetMapScriptHeaderBank + rst Bankswitch + + ld hl, MapEventHeaderPointer + ld a, [hli] + ld h, [hl] + ld l, a +rept 3 + inc hl ; get to the warp coords +endr + ld a, [WarpNumber] + dec a + ld c, a + ld b, 0 + ld a, 5 + call AddNTimes + ld a, [hli] + ld [YCoord], a + ld a, [hli] + ld [XCoord], a + ; destination warp number + ld a, [hli] + cp $ff + jr nz, .skip + call .backup + +.skip + callba GetCoordOfUpperLeftCorner + ret +; 24ba + +.backup + ld a, [wPrevWarp] + ld [BackupWarpNumber], a + ld a, [wPrevMapGroup] + ld [BackupMapGroup], a + ld a, [wPrevMapNumber] + ld [BackupMapNumber], a + ret +; 24cd + +LoadBlockData:: ; 24cd + ld hl, OverworldMap + ld bc, OverworldMapEnd - OverworldMap + ld a, 0 + call ByteFill + call ChangeMap + call FillMapConnections + ld a, MAPCALLBACK_TILES + call RunMapCallback + ret +; 24e4 + +ChangeMap:: ; 24e4 + ld a, [hROMBank] + push af + + ld hl, OverworldMap + ld a, [MapWidth] + ld [hConnectedMapWidth], a + add $6 + ld [hConnectionStripLength], a + ld c, a + ld b, 0 +rept 3 + add hl, bc +endr + ld c, 3 + add hl, bc + ld a, [MapBlockDataBank] + rst Bankswitch + + ld a, [MapBlockDataPointer] + ld e, a + ld a, [MapBlockDataPointer+1] + ld d, a + ld a, [MapHeight] + ld b, a +.row + push hl + ld a, [hConnectedMapWidth] + ld c, a +.col + ld a, [de] + inc de + ld [hli], a + dec c + jr nz, .col + pop hl + ld a, [hConnectionStripLength] + add l + ld l, a + jr nc, .okay + inc h +.okay + dec b + jr nz, .row + + pop af + rst Bankswitch + ret +; 2524 + +FillMapConnections:: ; 2524 + +; North + ld a, [NorthConnectedMapGroup] + cp $ff + jr z, .South + ld b, a + ld a, [NorthConnectedMapNumber] + ld c, a + call GetAnyMapBlockdataBank + + ld a, [NorthConnectionStripPointer] + ld l, a + ld a, [NorthConnectionStripPointer + 1] + ld h, a + ld a, [NorthConnectionStripLocation] + ld e, a + ld a, [NorthConnectionStripLocation + 1] + ld d, a + ld a, [NorthConnectionStripLength] + ld [hConnectionStripLength], a + ld a, [NorthConnectedMapWidth] + ld [hConnectedMapWidth], a + call FillNorthConnectionStrip + +.South + ld a, [SouthConnectedMapGroup] + cp $ff + jr z, .West + ld b, a + ld a, [SouthConnectedMapNumber] + ld c, a + call GetAnyMapBlockdataBank + + ld a, [SouthConnectionStripPointer] + ld l, a + ld a, [SouthConnectionStripPointer + 1] + ld h, a + ld a, [SouthConnectionStripLocation] + ld e, a + ld a, [SouthConnectionStripLocation + 1] + ld d, a + ld a, [SouthConnectionStripLength] + ld [hConnectionStripLength], a + ld a, [SouthConnectedMapWidth] + ld [hConnectedMapWidth], a + call FillSouthConnectionStrip + +.West + ld a, [WestConnectedMapGroup] + cp $ff + jr z, .East + ld b, a + ld a, [WestConnectedMapNumber] + ld c, a + call GetAnyMapBlockdataBank + + ld a, [WestConnectionStripPointer] + ld l, a + ld a, [WestConnectionStripPointer + 1] + ld h, a + ld a, [WestConnectionStripLocation] + ld e, a + ld a, [WestConnectionStripLocation + 1] + ld d, a + ld a, [WestConnectionStripLength] + ld b, a + ld a, [WestConnectedMapWidth] + ld [hConnectionStripLength], a + call FillWestConnectionStrip + +.East + ld a, [EastConnectedMapGroup] + cp $ff + jr z, .Done + ld b, a + ld a, [EastConnectedMapNumber] + ld c, a + call GetAnyMapBlockdataBank + + ld a, [EastConnectionStripPointer] + ld l, a + ld a, [EastConnectionStripPointer + 1] + ld h, a + ld a, [EastConnectionStripLocation] + ld e, a + ld a, [EastConnectionStripLocation + 1] + ld d, a + ld a, [EastConnectionStripLength] + ld b, a + ld a, [EastConnectedMapWidth] + ld [hConnectionStripLength], a + call FillEastConnectionStrip + +.Done + ret +; 25d3 + +FillNorthConnectionStrip:: +FillSouthConnectionStrip:: ; 25d3 + + ld c, 3 +.y + push de + + push hl + ld a, [hConnectionStripLength] + ld b, a +.x + ld a, [hli] + ld [de], a + inc de + dec b + jr nz, .x + pop hl + + ld a, [hConnectedMapWidth] + ld e, a + ld d, 0 + add hl, de + pop de + + ld a, [MapWidth] + add 6 + add e + ld e, a + jr nc, .okay + inc d +.okay + dec c + jr nz, .y + ret +; 25f6 + +FillWestConnectionStrip:: +FillEastConnectionStrip:: ; 25f6 + +.loop + ld a, [MapWidth] + add 6 + ld [hConnectedMapWidth], a + + push de + + push hl + ld a, [hli] + ld [de], a + inc de + ld a, [hli] + ld [de], a + inc de + ld a, [hli] + ld [de], a + inc de + pop hl + + ld a, [hConnectionStripLength] + ld e, a + ld d, 0 + add hl, de + pop de + + ld a, [hConnectedMapWidth] + add e + ld e, a + jr nc, .okay + inc d +.okay + dec b + jr nz, .loop + ret +; 261b + +LoadMapStatus:: ; 261b + ld [MapStatus], a + ret +; 261f + +CallScript:: ; 261f +; Call a script at a:hl. + + ld [ScriptBank], a + ld a, l + ld [ScriptPos], a + ld a, h + ld [ScriptPos + 1], a + + ld a, PLAYEREVENT_MAPSCRIPT + ld [ScriptRunning], a + + scf + ret +; 2631 + +CallMapScript:: ; 2631 +; Call a script at hl in the current bank if there isn't already a script running + ld a, [ScriptRunning] + and a + ret nz + call GetMapScriptHeaderBank + jr CallScript +; 263b + +RunMapCallback:: ; 263b +; Will run the first callback found in the map header with execution index equal to a. + ld b, a + ld a, [hROMBank] + push af + call SwitchToMapScriptHeaderBank + call .FindCallback + jr nc, .done + + call GetMapScriptHeaderBank + ld b, a + ld d, h + ld e, l + call ExecuteCallbackScript + +.done + pop af + rst Bankswitch + ret +; 2653 + +.FindCallback: ; 2653 + ld a, [wCurrMapCallbackCount] + ld c, a + and a + ret z + ld hl, wCurrMapCallbackHeaderPointer + ld a, [hli] + ld h, [hl] + ld l, a + or h + ret z + ld de, 3 +.loop + ld a, [hl] + cp b + jr z, .found + add hl, de + dec c + jr nz, .loop + xor a + ret + +.found + inc hl + ld a, [hli] + ld h, [hl] + ld l, a + scf + ret +; 2674 + +ExecuteCallbackScript:: ; 2674 +; Do map callback de and return to script bank b. + callba CallCallback + ld a, [ScriptMode] + push af + ld hl, ScriptFlags + ld a, [hl] + push af + set 1, [hl] + callba EnableScriptMode + callba ScriptEvents + pop af + ld [ScriptFlags], a + pop af + ld [ScriptMode], a + ret +; 269a + +MapTextbox:: ; 269a + ld a, [hROMBank] + push af + + ld a, b + rst Bankswitch + + push hl + call SpeechTextBox + call Function2e31 + ld a, 1 + ld [hOAMUpdate], a + call ApplyTilemap + pop hl + call PrintTextBoxText + xor a + ld [hOAMUpdate], a + + pop af + rst Bankswitch + ret +; 26b7 + +Call_a_de:: ; 26b7 +; Call a:de. + + ld [hBuffer], a + ld a, [hROMBank] + push af + ld a, [hBuffer] + rst Bankswitch + + call .de + + pop af + rst Bankswitch + ret + +.de + push de + ret +; 26c7 + +GetMovementData:: ; 26c7 +; Initialize the movement data for person c at b:hl + ld a, [hROMBank] + push af + ld a, b + rst Bankswitch + + ld a, c + call LoadMovementDataPointer + + pop hl + ld a, h + rst Bankswitch + ret +; 26d4 + +GetScriptByte:: ; 0x26d4 +; Return byte at ScriptBank:ScriptPos in a. + + push hl + push bc + ld a, [hROMBank] + push af + ld a, [ScriptBank] + rst Bankswitch + + ld hl, ScriptPos + ld c, [hl] + inc hl + ld b, [hl] + + ld a, [bc] + + inc bc + ld [hl], b + dec hl + ld [hl], c + + ld b, a + pop af + rst Bankswitch + ld a, b + pop bc + pop hl + ret +; 0x26ef + +ObjectEvent:: ; 0x26ef + jumptextfaceplayer ObjectEventText +; 0x26f2 + +ObjectEventText:: + text_jump _ObjectEventText + db "@" +; 0x26f7 + +BGEvent:: ; 26f7 + jumptext BGEventText +; 26fa + +BGEventText:: ; 26fa + text_jump UnknownText_0x1c46fc + db "@" +; 26ff + +CoordinatesEvent:: ; 26ff + jumptext CoordinatesEventText +; 2702 + +CoordinatesEventText:: ; 2702 + text_jump UnknownText_0x1c4706 + db "@" +; 2707 + +CheckObjectMask:: ; 2707 + ld a, [hMapObjectIndexBuffer] + ld e, a + ld d, $0 + ld hl, wObjectMasks + add hl, de + ld a, [hl] + ret +; 2712 + +MaskObject:: ; 2712 + ld a, [hMapObjectIndexBuffer] + ld e, a + ld d, $0 + ld hl, wObjectMasks + add hl, de + ld [hl], -1 ; , masked + ret +; 271e + +UnmaskObject:: ; 271e + ld a, [hMapObjectIndexBuffer] + ld e, a + ld d, $0 + ld hl, wObjectMasks + add hl, de + ld [hl], 0 ; unmasked + ret +; 272a + +ScrollMapDown:: ; 272a + hlcoord 0, 0 + ld de, BGMapBuffer + call BackupBGMapRow + ld c, 2 * SCREEN_WIDTH + call FarCallScrollBGMapPalettes + ld a, [wBGMapAnchor] + ld e, a + ld a, [wBGMapAnchor + 1] + ld d, a + call UpdateBGMapRow + ld a, $1 + ld [hBGMapUpdate], a + ret +; 2748 + +ScrollMapUp:: ; 2748 + hlcoord 0, SCREEN_HEIGHT - 2 + ld de, BGMapBuffer + call BackupBGMapRow + ld c, 2 * SCREEN_WIDTH + call FarCallScrollBGMapPalettes + ld a, [wBGMapAnchor] + ld l, a + ld a, [wBGMapAnchor + 1] + ld h, a + ld bc, $0200 + add hl, bc +; cap d at VBGMap1 / $100 + ld a, h + and %00000011 + or VBGMap0 / $100 + ld e, l + ld d, a + call UpdateBGMapRow + ld a, $1 + ld [hBGMapUpdate], a + ret +; 2771 + +ScrollMapRight:: ; 2771 + hlcoord 0, 0 + ld de, BGMapBuffer + call BackupBGMapColumn + ld c, 2 * SCREEN_HEIGHT + call FarCallScrollBGMapPalettes + ld a, [wBGMapAnchor] + ld e, a + ld a, [wBGMapAnchor + 1] + ld d, a + call UpdateBGMapColumn + ld a, $1 + ld [hBGMapUpdate], a + ret +; 278f + +ScrollMapLeft:: ; 278f + hlcoord SCREEN_WIDTH - 2, 0 + ld de, BGMapBuffer + call BackupBGMapColumn + ld c, 2 * SCREEN_HEIGHT + call FarCallScrollBGMapPalettes + ld a, [wBGMapAnchor] + ld e, a + and %11100000 + ld b, a + ld a, e + add SCREEN_HEIGHT + and %00011111 + or b + ld e, a + ld a, [wBGMapAnchor + 1] + ld d, a + call UpdateBGMapColumn + ld a, $1 + ld [hBGMapUpdate], a + ret +; 27b7 + +BackupBGMapRow:: ; 27b7 + ld c, 2 * SCREEN_WIDTH +.loop + ld a, [hli] + ld [de], a + inc de + dec c + jr nz, .loop + ret +; 27c0 + +BackupBGMapColumn:: ; 27c0 + ld c, SCREEN_HEIGHT +.loop + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + ld [de], a + inc de + ld a, SCREEN_WIDTH - 1 + add l + ld l, a + jr nc, .skip + inc h + +.skip + dec c + jr nz, .loop + ret +; 27d3 + +UpdateBGMapRow:: ; 27d3 + ld hl, BGMapBufferPtrs + push de + call .iteration + pop de + ld a, $20 + add e + ld e, a + +.iteration + ld c, 10 +.loop + ld a, e + ld [hli], a + ld a, d + ld [hli], a + ld a, e + inc a + inc a + and $1f + ld b, a + ld a, e + and $e0 + or b + ld e, a + dec c + jr nz, .loop + ld a, SCREEN_WIDTH + ld [hFFDC], a + ret +; 27f8 + +UpdateBGMapColumn:: ; 27f8 + ld hl, BGMapBufferPtrs + ld c, SCREEN_HEIGHT +.loop + ld a, e + ld [hli], a + ld a, d + ld [hli], a + ld a, $20 + add e + ld e, a + jr nc, .skip + inc d +; cap d at VBGMap1 / $100 + ld a, d + and $3 + or VBGMap0 / $100 + ld d, a + +.skip + dec c + jr nz, .loop + ld a, SCREEN_HEIGHT + ld [hFFDC], a + ret +; 2816 + +; unreferenced + ld hl, BGMapBuffer + ld bc, SGBPredef - BGMapBuffer + xor a + call ByteFill + ret +; 2821 + +LoadTileset:: ; 2821 + ld hl, TilesetAddress + ld a, [hli] + ld h, [hl] + ld l, a + ld a, [TilesetBank] + ld e, a + + ld a, [rSVBK] + push af + ld a, $6 + ld [rSVBK], a + + ld a, e + ld de, wDecompressScratch + call FarDecompress + + ld hl, wDecompressScratch + ld de, VTiles2 + ld bc, $60 tiles + call CopyBytes + + ld a, [rVBK] + push af + ld a, $1 + ld [rVBK], a + + ld hl, w6_d600 + ld de, VTiles2 + ld bc, $60 tiles + call CopyBytes + + pop af + ld [rVBK], a + + pop af + ld [rSVBK], a + + ld a, [wTileset] + cp TILESET_JOHTO_1 + jr z, .load_roof + cp TILESET_JOHTO_2 + jr z, .load_roof + cp TILESET_BATTLE_TOWER_OUTSIDE + jr z, .load_roof + jr .skip_roof + +.load_roof + callba LoadMapGroupRoof + +.skip_roof + xor a + ld [hTileAnimFrame], a + ret +; 2879 + +BufferScreen:: ; 2879 + ld hl, wOverworldMapAnchor + ld a, [hli] + ld h, [hl] + ld l, a + ld de, wScreenSave + ld c, $5 + ld b, $6 +.row + push bc + push hl +.col + ld a, [hli] + ld [de], a + inc de + dec b + jr nz, .col + pop hl + ld a, [MapWidth] + add $6 + ld c, a + ld b, $0 + add hl, bc + pop bc + dec c + jr nz, .row + ret +; 289d + +SaveScreen:: ; 289d + ld hl, wOverworldMapAnchor + ld a, [hli] + ld h, [hl] + ld l, a + ld de, wScreenSave + ld a, [MapWidth] + add 6 + ld [hMapObjectIndexBuffer], a + ld a, [wPlayerStepDirection] + and a + jr z, .down + cp UP + jr z, .up + cp LEFT + jr z, .left + cp RIGHT + jr z, .right + ret + +.up + ld de, wScreenSave + 6 + ld a, [hMapObjectIndexBuffer] + ld c, a + ld b, $0 + add hl, bc + jr .vertical + +.down + ld de, wScreenSave +.vertical + ld b, 6 + ld c, 4 + jr SaveScreen_LoadNeighbor + +.left + ld de, wScreenSave + 1 + inc hl + jr .horizontal + +.right + ld de, wScreenSave +.horizontal + ld b, 5 + ld c, 5 + jr SaveScreen_LoadNeighbor + +LoadNeighboringBlockData:: ; 28e3 + ld hl, wOverworldMapAnchor + ld a, [hli] + ld h, [hl] + ld l, a + ld a, [MapWidth] + add 6 + ld [hConnectionStripLength], a + ld de, wScreenSave + ld b, 6 + ld c, 5 + +SaveScreen_LoadNeighbor:: ; 28f7 +.row + push bc + push hl + push de +.col + ld a, [de] + inc de + ld [hli], a + dec b + jr nz, .col + pop de + ld a, e + add 6 + ld e, a + jr nc, .okay + inc d + +.okay + pop hl + ld a, [hConnectionStripLength] + ld c, a + ld b, 0 + add hl, bc + pop bc + dec c + jr nz, .row + ret +; 2914 + +GetMovementPermissions:: ; 2914 + xor a + ld [TilePermissions], a + call .LeftRight + call .UpDown +; get coords of current tile + ld a, [PlayerStandingMapX] + ld d, a + ld a, [PlayerStandingMapY] + ld e, a + call GetCoordTile + ld [PlayerStandingTile], a + call .CheckHiNybble + ret nz + + ld a, [PlayerStandingTile] + and 7 + ld hl, .MovementPermissionsData + add l + ld l, a + ld a, 0 + adc h + ld h, a + ld a, [hl] + ld hl, TilePermissions + or [hl] + ld [hl], a + ret +; 2945 + +.MovementPermissionsData ; 2945 + db 1, 2, 4, 8, 9, 10, 5, 6 +; 294d + +.UpDown + ld a, [PlayerStandingMapX] + ld d, a + ld a, [PlayerStandingMapY] + ld e, a + + push de + inc e + call GetCoordTile + ld [TileDown], a + call .Down + + pop de + dec e + call GetCoordTile + ld [TileUp], a + call .Up + ret +; 296c + +.LeftRight + ld a, [PlayerStandingMapX] + ld d, a + ld a, [PlayerStandingMapY] + ld e, a + + push de + dec d + call GetCoordTile + ld [TileLeft], a + call .Left + + pop de + inc d + call GetCoordTile + ld [TileRight], a + call .Right + ret +; 298b + +.Down + call .CheckHiNybble + ret nz + ld a, [TileDown] + and 7 + cp $2 + jr z, .ok_down + cp $6 + jr z, .ok_down + cp $7 + ret nz + +.ok_down + ld a, [TilePermissions] + or FACE_DOWN + ld [TilePermissions], a + ret +; 29a8 + +.Up + call .CheckHiNybble + ret nz + ld a, [TileUp] + and 7 + cp $3 + jr z, .ok_up + cp $4 + jr z, .ok_up + cp $5 + ret nz + +.ok_up + ld a, [TilePermissions] + or FACE_UP + ld [TilePermissions], a + ret +; 29c5 + +.Right + call .CheckHiNybble + ret nz + ld a, [TileRight] + and 7 + cp $1 + jr z, .ok_right + cp $5 + jr z, .ok_right + cp $7 + ret nz + +.ok_right + ld a, [TilePermissions] + or FACE_RIGHT + ld [TilePermissions], a + ret +; 29e2 + +.Left + call .CheckHiNybble + ret nz + ld a, [TileLeft] + and 7 + cp $0 + jr z, .ok_left + cp $4 + jr z, .ok_left + cp $6 + ret nz + +.ok_left + ld a, [TilePermissions] + or FACE_LEFT + ld [TilePermissions], a + ret +; 29ff + +.CheckHiNybble + and $f0 + cp $b0 + ret z + cp $c0 + ret +; 2a07 + +GetFacingTileCoord:: ; 2a07 +; Return map coordinates in (d, e) and tile id in a +; of the tile the player is facing. + + ld a, [PlayerDirection] + and %1100 + srl a + srl a + ld l, a + ld h, 0 + add hl, hl + add hl, hl + ld de, .Directions + add hl, de + + ld d, [hl] + inc hl + ld e, [hl] + inc hl + + ld a, [hli] + ld h, [hl] + ld l, a + + ld a, [PlayerStandingMapX] + add d + ld d, a + ld a, [PlayerStandingMapY] + add e + ld e, a + ld a, [hl] + ret + +.Directions + ; x, y + db 0, 1 + dw TileDown + db 0, -1 + dw TileUp + db -1, 0 + dw TileLeft + db 1, 0 + dw TileRight +; 2a3c + +GetCoordTile:: ; 2a3c +; Get the collision byte for tile d, e + call GetBlockLocation + ld a, [hl] + and a + jr z, .nope + ld l, a + ld h, $0 + add hl, hl + add hl, hl + ld a, [TilesetCollisionAddress] + ld c, a + ld a, [TilesetCollisionAddress + 1] + ld b, a + add hl, bc + rr d + jr nc, .nocarry + inc hl + +.nocarry + rr e + jr nc, .nocarry2 + inc hl + inc hl + +.nocarry2 + ld a, [TilesetCollisionBank] + call GetFarByte + ret + +.nope + ld a, -1 + ret +; 2a66 + +GetBlockLocation:: ; 2a66 + ld a, [MapWidth] + add 6 + ld c, a + ld b, 0 + ld hl, wc801 + add hl, bc + ld a, e + srl a + jr z, .nope + and a +.loop + srl a + jr nc, .ok + add hl, bc + +.ok + sla c + rl b + and a + jr nz, .loop + +.nope + ld c, d + srl c + ld b, 0 + add hl, bc + ret +; 2a8b + +CheckFacingSign:: ; 2a8b + call GetFacingTileCoord +; Load facing into b. + ld b, a +; Convert the coordinates at de to within-boundaries coordinates. + ld a, d + sub 4 + ld d, a + ld a, e + sub 4 + ld e, a +; If there are no signposts, we don't need to be here. + ld a, [wCurrentMapSignpostCount] + and a + ret z + + ld c, a + ld a, [hROMBank] + push af + call SwitchToMapScriptHeaderBank + call CheckIfFacingTileCoordIsSign + pop hl + ld a, h + rst Bankswitch + ret +; 2aaa + +CheckIfFacingTileCoordIsSign:: ; 2aaa +; Checks to see if you are facing a signpost. If so, copies it into EngineBuffer1 and sets carry. + ld hl, wCurrentMapSignpostHeaderPointer + ld a, [hli] + ld h, [hl] + ld l, a +.loop + push hl + ld a, [hli] + cp e + jr nz, .next + ld a, [hli] + cp d + jr nz, .next + jr .copysign + +.next + pop hl + ld a, 5 ; signpost event length + add l + ld l, a + jr nc, .nocarry + inc h + +.nocarry + dec c + jr nz, .loop + xor a + ret + +.copysign + pop hl + ld de, wCurSignpostYCoord + ld bc, 5 ; signpost event length + call CopyBytes + scf + ret +; 2ad4 + +CheckCurrentMapXYTriggers:: ; 2ad4 +; If there are no xy triggers, we don't need to be here. + ld a, [wCurrentMapXYTriggerCount] + and a + ret z +; Copy the trigger count into c. + ld c, a + ld a, [hROMBank] + push af + call SwitchToMapScriptHeaderBank + call .TriggerCheck + pop hl + ld a, h + rst Bankswitch + ret + +.TriggerCheck +; Checks to see if you are standing on an xy-trigger. If yes, copies the trigger to EngineBuffer1 and sets carry. + ld hl, wCurrentMapXYTriggerHeaderPointer + ld a, [hli] + ld h, [hl] + ld l, a +; Load the active trigger ID into b + call CheckTriggers + ld b, a +; Load your current coordinates into de. This will be used to check if your position is in the xy-trigger table for the current map. + ld a, [PlayerStandingMapX] + sub 4 + ld d, a + ld a, [PlayerStandingMapY] + sub 4 + ld e, a + +.loop + push hl + ld a, [hli] + cp b + jr z, .got_id + cp -1 + jr nz, .next + +.got_id + ld a, [hli] + cp e + jr nz, .next + ld a, [hli] + cp d + jr nz, .next + jr .copytrigger + +.next + pop hl + ld a, $8 ; xy-trigger size + add l + ld l, a + jr nc, .nocarry + inc h + +.nocarry + dec c + jr nz, .loop + xor a + ret + +.copytrigger + pop hl + ld de, wCurCoordEventTriggerID + ld bc, 8 ; xy-trigger size + call CopyBytes + scf + ret +; 2b29 + +FadeToMenu:: ; 2b29 + xor a + ld [hBGMapMode], a + call LoadStandardMenuDataHeader + callba FadeOutPalettes + call ClearSprites + call DisableSpriteUpdates + ret +; 2b3c + +CloseSubmenu:: ; 2b3c + call ClearBGPalettes + call ReloadTilesetAndPalettes + call UpdateSprites + call Call_ExitMenu + call ret_d90 + jr FinishExitMenu +; 2b4d + +ExitAllMenus:: ; 2b4d + call ClearBGPalettes + call Call_ExitMenu + call ReloadTilesetAndPalettes + call UpdateSprites + call ret_d90 +FinishExitMenu:: ; 2b5c + ld b, SCGB_MAPPALS + call GetSGBLayout + callba LoadOW_BGPal7 + call WaitBGMap2 + callba FadeInPalettes + call EnableSpriteUpdates + ret +; 2b74 + +ReturnToMapWithSpeechTextbox:: ; 0x2b74 + push af + ld a, $1 + ld [wSpriteUpdatesEnabled], a + call ClearBGPalettes + call ClearSprites + call ReloadTilesetAndPalettes + hlcoord 0, 12 + lb bc, 4, 18 + call TextBox + ld hl, VramState + set 0, [hl] + call UpdateSprites + call WaitBGMap2 + ld b, SCGB_MAPPALS + call GetSGBLayout + callba LoadOW_BGPal7 + call UpdateTimePals + call DelayFrame + ld a, $1 + ld [hMapAnims], a + pop af + ret +; 0x2bae + +ReloadTilesetAndPalettes:: ; 2bae + call DisableLCD + call ClearSprites + callba RefreshSprites + call LoadStandardFont + call LoadFontsExtra + ld a, [hROMBank] + push af + ld a, [MapGroup] + ld b, a + ld a, [MapNumber] + ld c, a + call SwitchToAnyMapBank + callba UpdateTimeOfDayPal + call OverworldTextModeSwitch + call LoadTileset + ld a, 9 + call SkipMusic + pop af + rst Bankswitch + + call EnableLCD + ret +; 2be5 + +GetMapHeaderPointer:: ; 2be5 + ld a, [MapGroup] + ld b, a + ld a, [MapNumber] + ld c, a +GetAnyMapHeaderPointer:: ; 0x2bed +; Prior to calling this function, you must have switched banks so that +; MapGroupPointers is visible. + +; inputs: +; b = map group, c = map number +; XXX de = ??? + +; outputs: +; hl points to the map header + push bc ; save map number for later + + ; get pointer to map group + dec b + ld c, b + ld b, 0 + ld hl, MapGroupPointers + add hl, bc + add hl, bc + + ld a, [hli] + ld h, [hl] + ld l, a + pop bc ; restore map number + + ; find the cth map header + dec c + ld b, 0 + ld a, 9 + call AddNTimes + ret +; 0x2c04 + +GetMapHeaderMember:: ; 0x2c04 +; Extract data from the current map's header. + +; inputs: +; de = offset of desired data within the mapheader + +; outputs: +; bc = data from the current map's header +; (e.g., de = $0003 would return a pointer to the secondary map header) + + ld a, [MapGroup] + ld b, a + ld a, [MapNumber] + ld c, a +GetAnyMapHeaderMember:: ; 0x2c0c + ; bankswitch + ld a, [hROMBank] + push af + ld a, BANK(MapGroupPointers) + rst Bankswitch + + call GetAnyMapHeaderPointer + add hl, de + ld c, [hl] + inc hl + ld b, [hl] + + ; bankswitch back + pop af + rst Bankswitch + ret +; 0x2c1c + +SwitchToMapBank:: ; 2c1c + ld a, [MapGroup] + ld b, a + ld a, [MapNumber] + ld c, a +SwitchToAnyMapBank:: ; 2c24 + call GetAnyMapBank + rst Bankswitch + ret +; 2c29 + +GetMapBank:: ; 2c29 + ld a, [MapGroup] + ld b, a + ld a, [MapNumber] + ld c, a +GetAnyMapBank:: ; 2c31 + push hl + push de + ld de, 0 + call GetAnyMapHeaderMember + ld a, c + pop de + pop hl + ret +; 2c3d + +PartiallyCopyMapHeader:: ; 2c3d +; Copy second map header bank, tileset, permission, and second map header address +; from the current map's map header. + ld a, [hROMBank] + push af + ld a, BANK(MapGroupPointers) + rst Bankswitch + + call GetMapHeaderPointer + ld de, wSecondMapHeaderBank + ld bc, MapHeader - wSecondMapHeaderBank + call CopyBytes + + pop af + rst Bankswitch + ret +; 2c52 + +SwitchToMapScriptHeaderBank:: ; 2c52 + ld a, [MapScriptHeaderBank] + rst Bankswitch + ret +; 2c57 + +GetMapScriptHeaderBank:: ; 2c57 + ld a, [MapScriptHeaderBank] + ret +; 2c5b + +GetAnyMapBlockdataBank:: ; 2c5b +; Return the blockdata bank for group b map c. + push hl + push de + push bc + + push bc + ld de, 3 ; second map header pointer + call GetAnyMapHeaderMember + ld l, c + ld h, b + pop bc + + push hl + ld de, 0 ; second map header bank + call GetAnyMapHeaderMember + pop hl + + ld de, 3 ; blockdata bank + add hl, de + ld a, c + call GetFarByte + rst Bankswitch + + pop bc + pop de + pop hl + ret +; 2c7d + +GetSecondaryMapHeaderPointer:: ; 0x2c7d +; returns the current map's secondary map header pointer in hl. + push bc + push de + ld de, 3 ; secondary map header pointer (offset within header) + call GetMapHeaderMember + ld l, c + ld h, b + pop de + pop bc + ret +; 2c8a + +GetMapPermission:: ; 2c8a + push hl + push de + push bc + ld de, 2 ; permission + call GetMapHeaderMember + ld a, c + pop bc + pop de + pop hl + ret +; 2c98 + + ret ; XXX +; 2c99 + +GetAnyMapPermission:: ; 2c99 + push hl + push de + push bc + ld de, 2 ; permission + call GetAnyMapHeaderMember + ld a, c + pop bc + pop de + pop hl + ret +; 2ca7 + +GetAnyMapTileset:: ; 2ca7 + ld de, 1 ; tileset + call GetAnyMapHeaderMember + ld a, c + ret +; 2caf + +GetWorldMapLocation:: ; 0x2caf +; given a map group/id in bc, return its location on the Pokégear map. + push hl + push de + push bc + + ld de, 5 ; landmark + call GetAnyMapHeaderMember + ld a, c + + pop bc + pop de + pop hl + ret +; 0x2cbd + +GetMapHeaderMusic:: ; 2cbd +RADIO_TOWER_MUSIC EQU 7 + + push hl + push bc + ld de, 6 ; music + call GetMapHeaderMember + ld a, c + cp MUSIC_MAHOGANY_MART + jr z, .mahoganymart + bit RADIO_TOWER_MUSIC, c + jr nz, .radiotower + callba Function8b342 + ld e, c + ld d, 0 +.done + pop bc + pop hl + ret + +.radiotower + ld a, [StatusFlags2] + bit 0, a + jr z, .clearedradiotower + ld de, MUSIC_ROCKET_OVERTURE + jr .done + +.clearedradiotower + ; the rest of the byte + ld a, c + and 1 << RADIO_TOWER_MUSIC - 1 + ld e, a + ld d, 0 + jr .done + +.mahoganymart + ld a, [StatusFlags2] + bit 7, a + jr z, .clearedmahogany + ld de, MUSIC_ROCKET_HIDEOUT + jr .done + +.clearedmahogany + ld de, MUSIC_CHERRYGROVE_CITY + jr .done +; 2cff + +GetMapHeaderTimeOfDayNybble:: ; 2cff + call GetPhoneServiceTimeOfDayByte + and $f + ret +; 2d05 + +GetMapHeaderPhoneServiceNybble:: ; 2d05 + call GetPhoneServiceTimeOfDayByte + and $f0 + swap a + ret +; 2d0d + +GetPhoneServiceTimeOfDayByte:: ; 2d0d + push hl + push bc + + ld de, 7 ; phone service and time of day + call GetMapHeaderMember + ld a, c + + pop bc + pop hl + ret +; 2d19 + +GetFishingGroup:: ; 2d19 + push de + push hl + push bc + + ld de, 8 ; fishing group + call GetMapHeaderMember + ld a, c + + pop bc + pop hl + pop de + ret +; 2d27 + +LoadTilesetHeader:: ; 2d27 + push hl + push bc + + ld hl, Tilesets + ld bc, Tileset01 - Tileset00 + ld a, [wTileset] + call AddNTimes + + ld de, TilesetBank + ld bc, Tileset01 - Tileset00 + + ld a, BANK(Tilesets) + call FarCopyBytes + + pop bc + pop hl + ret +; 2d43 diff --git a/home/map_objects.asm b/home/map_objects.asm new file mode 100644 index 00000000..f4a4d6d5 --- /dev/null +++ b/home/map_objects.asm @@ -0,0 +1,670 @@ +; Functions handling map objects. + +GetSpritePalette:: ; 17ff + push hl + push de + push bc + ld c, a + + callba _GetSpritePalette + + ld a, c + pop bc + pop de + pop hl + ret +; 180e + +GetSpriteVTile:: ; 180e + push hl + push bc + ld hl, UsedSprites + 2 + ld c, SPRITE_GFX_LIST_CAPACITY - 1 + ld b, a + ld a, [hMapObjectIndexBuffer] + cp 0 + jr z, .nope + ld a, b +.loop + cp [hl] + jr z, .found +rept 2 + inc hl +endr + dec c + jr nz, .loop + ld a, [UsedSprites + 1] + scf + jr .done + +.nope + ld a, [UsedSprites + 1] + jr .done + +.found + inc hl + xor a + ld a, [hl] + +.done + pop bc + pop hl + ret +; 1836 + +DoesSpriteHaveFacings:: ; 1836 + push de + push hl + + ld b, a + ld a, [hROMBank] + push af + ld a, BANK(_DoesSpriteHaveFacings) + rst Bankswitch + + ld a, b + call _DoesSpriteHaveFacings + ld c, a + + pop de + ld a, d + rst Bankswitch + + pop hl + pop de + ret +; 184a + +GetPlayerStandingTile:: ; 184a + ld a, [PlayerStandingTile] + call GetTileCollision + ld b, a + ret +; 1852 + +CheckOnWater:: ; 1852 + ld a, [PlayerStandingTile] + call GetTileCollision + sub 1 + ret z + and a + ret +; 185d + +GetTileCollision:: ; 185d +; Get the collision type of tile a. + + push de + push hl + + ld hl, TileCollisionTable + ld e, a + ld d, 0 + add hl, de + + ld a, [hROMBank] + push af + ld a, BANK(TileCollisionTable) + rst Bankswitch + ld e, [hl] + pop af + rst Bankswitch + + ld a, e + and $f ; lo nybble only + + pop hl + pop de + ret +; 1875 + +CheckGrassTile:: ; 1875 + ld d, a + and $f0 + cp $10 + jr z, .ok_10 + cp $20 + jr z, .ok_20 + scf + ret + +.ok_10 + ld a, d + and 7 + ret z + scf + ret +; For some reason, the above code is duplicated down here. +.ok_20 + ld a, d + and 7 + ret z + scf + ret +; 188e + +CheckSuperTallGrassTile:: ; 188e + cp $14 + ret z + cp $1c + ret +; 1894 + +CheckCutTreeTile:: ; 1894 + cp $12 + ret z + cp $1a + ret +; 189a + +CheckHeadbuttTreeTile:: ; 189a + cp $15 + ret z + cp $1d + ret +; 18a0 + +CheckCounterTile:: ; 18a0 + cp $90 + ret z + cp $98 + ret +; 18a6 + +CheckPitTile:: ; 18a6 + cp $60 + ret z + cp $68 + ret +; 18ac + +CheckIceTile:: ; 18ac + cp $23 + ret z + cp $2b + ret z + scf + ret +; 18b4 + +CheckWhirlpoolTile:: ; 18b4 + nop + cp $24 + ret z + cp $2c + ret z + scf + ret +; 18bd + +CheckWaterfallTile:: ; 18bd + cp $33 + ret z + cp $3b + ret +; 18c3 + +CheckStandingOnEntrance:: ; 18c3 + ld a, [PlayerStandingTile] + cp $71 ; door + ret z + cp $79 + ret z + cp $7a ; stairs + ret z + cp $7b ; cave + ret +; 18d2 + +GetMapObject:: ; 18d2 +; Return the location of map object a in bc. + ld hl, MapObjects + ld bc, OBJECT_LENGTH + call AddNTimes + ld b, h + ld c, l + ret +; 18de + +CheckObjectVisibility:: ; 18de +; Sets carry if the object is not visible on the screen. + ld [hMapObjectIndexBuffer], a + call GetMapObject + ld hl, MAPOBJECT_OBJECT_STRUCT_ID + add hl, bc + ld a, [hl] + cp -1 + jr z, .not_visible + ld [hObjectStructIndexBuffer], a + call GetObjectStruct + and a + ret + +.not_visible + scf + ret +; 18f5 + +CheckObjectTime:: ; 18f5 + ld hl, MAPOBJECT_HOUR + add hl, bc + ld a, [hl] + cp -1 + jr nz, .check_hour + ld hl, MAPOBJECT_TIMEOFDAY + add hl, bc + ld a, [hl] + cp -1 + jr z, .timeofday_always + ld hl, .TimeOfDayValues_191e + ld a, [TimeOfDay] + add l + ld l, a + jr nc, .ok + inc h + +.ok + ld a, [hl] + ld hl, MAPOBJECT_TIMEOFDAY + add hl, bc + and [hl] + jr nz, .timeofday_always + scf + ret + +.timeofday_always + and a + ret + +.TimeOfDayValues_191e + db 1 << MORN ; 1 + db 1 << DAY ; 2 + db 1 << NITE ; 4 + +.check_hour + ld hl, MAPOBJECT_HOUR + add hl, bc + ld d, [hl] + ld hl, MAPOBJECT_TIMEOFDAY + add hl, bc + ld e, [hl] + ld hl, hHours + ld a, d + cp e + jr z, .yes + jr c, .check_timeofday + ld a, [hl] + cp d + jr nc, .yes + cp e + jr c, .yes + jr z, .yes + jr .no + +.check_timeofday + ld a, e + cp [hl] + jr c, .no + ld a, [hl] + cp d + jr nc, .yes + jr .no + +.yes + and a + ret + +.no + scf + ret +; 194d + +; XXX + ld [hMapObjectIndexBuffer], a + call GetMapObject + call CopyObjectStruct + ret +; 1956 + +_CopyObjectStruct:: ; 1956 + ld [hMapObjectIndexBuffer], a + call UnmaskObject + ld a, [hMapObjectIndexBuffer] + call GetMapObject + callba CopyObjectStruct + ret +; 1967 + +ApplyDeletionToMapObject:: ; 1967 + ld [hMapObjectIndexBuffer], a + call GetMapObject + ld hl, MAPOBJECT_OBJECT_STRUCT_ID + add hl, bc + ld a, [hl] + cp -1 + ret z ; already hidden + ld [hl], -1 + push af + call .CheckStopFollow + pop af + call GetObjectStruct + callba DeleteMapObject + ret + +.CheckStopFollow + ld hl, wObjectFollow_Leader + cp [hl] + jr z, .ok + ld hl, wObjectFollow_Follower + cp [hl] + ret nz +.ok + callba StopFollow + ld a, -1 + ld [wObjectFollow_Leader], a + ld [wObjectFollow_Follower], a + ret +; 199f + +DeleteObjectStruct:: ; 199f + call ApplyDeletionToMapObject + call MaskObject + ret +; 19a6 + +CopyPlayerObjectTemplate:: ; 19a6 + push hl + call GetMapObject + ld d, b + ld e, c + ld a, -1 + ld [de], a + inc de + pop hl + ld bc, OBJECT_LENGTH - 1 + call CopyBytes + ret +; 19b8 + +; XXX + call GetMapObject + ld hl, MAPOBJECT_OBJECT_STRUCT_ID + add hl, bc + ld a, [hl] + push af + ld [hl], -1 + inc hl + ld bc, OBJECT_LENGTH - 1 + xor a + call ByteFill + pop af + cp -1 + ret z + cp $d + ret nc + ld b, a + ld a, [wObjectFollow_Leader] + cp b + jr nz, .ok + ld a, -1 + ld [wObjectFollow_Leader], a + +.ok + ld a, b + call GetObjectStruct + callba DeleteMapObject + ret +; 19e9 + +LoadMovementDataPointer:: ; 19e9 +; Load the movement data pointer for person a. + ld [wMovementPerson], a + ld a, [hROMBank] + ld [wMovementDataPointer], a + ld a, l + ld [wMovementDataPointer + 1], a + ld a, h + ld [wMovementDataPointer + 2], a + ld a, [wMovementPerson] + call CheckObjectVisibility + ret c + + ld hl, OBJECT_MOVEMENTTYPE + add hl, bc + ld [hl], SPRITEMOVEDATA_SCRIPTED + + ld hl, OBJECT_STEP_TYPE + add hl, bc + ld [hl], STEP_TYPE_00 + + ld hl, VramState + set 7, [hl] + and a + ret +; 1a13 + +FindFirstEmptyObjectStruct:: ; 1a13 +; Returns the index of the first empty object struct in A and its address in HL, then sets carry. +; If all object structs are occupied, A = 0 and Z is set. +; Preserves BC and DE. + push bc + push de + ld hl, ObjectStructs + ld de, OBJECT_STRUCT_LENGTH + ld c, NUM_OBJECT_STRUCTS +.loop + ld a, [hl] + and a + jr z, .break + add hl, de + dec c + jr nz, .loop + xor a + jr .done + +.break + ld a, NUM_OBJECT_STRUCTS + sub c + scf + +.done + pop de + pop bc + ret +; 1a2f + +GetSpriteMovementFunction:: ; 1a2f + ld hl, OBJECT_MOVEMENTTYPE + add hl, bc + ld a, [hl] + cp NUM_SPRITEMOVEDATA + jr c, .ok + xor a + +.ok + ld hl, SpriteMovementData + ld e, a + ld d, 0 +rept SPRITEMOVEDATA_FIELDS + add hl,de +endr + ld a, [hl] + ret +; 1a47 + +GetInitialFacing:: ; 1a47 + push bc + push de + ld e, a + ld d, 0 + ld hl, SpriteMovementData + 1 ; init facing +rept SPRITEMOVEDATA_FIELDS + add hl,de +endr + ld a, BANK(SpriteMovementData) + call GetFarByte +rept 2 + add a +endr + and $c + pop de + pop bc + ret +; 1a61 + +CopySpriteMovementData:: ; 1a61 + ld l, a + ld a, [hROMBank] + push af + ld a, BANK(SpriteMovementData) + rst Bankswitch + ld a, l + push bc + + call .CopyData + + pop bc + pop af + rst Bankswitch + + ret +; 1a71 + +.CopyData ; 1a71 + ld hl, OBJECT_MOVEMENTTYPE + add hl, de + ld [hl], a + + push de + ld e, a + ld d, 0 + ld hl, SpriteMovementData + 1 ; init facing +rept SPRITEMOVEDATA_FIELDS + add hl, de +endr + ld b, h + ld c, l + pop de + + ld a, [bc] + inc bc + rlca + rlca + and %00001100 + ld hl, OBJECT_FACING + add hl, de + ld [hl], a + + ld a, [bc] + inc bc + ld hl, OBJECT_ACTION + add hl, de + ld [hl], a + + ld a, [bc] + inc bc + ld hl, OBJECT_FLAGS1 + add hl, de + ld [hl], a + + ld a, [bc] + inc bc + ld hl, OBJECT_FLAGS2 + add hl, de + ld [hl], a + + ld a, [bc] + inc bc + ld hl, OBJECT_PALETTE + add hl, de + ld [hl], a + ret +; 1aae + +_GetMovementByte:: ; 1aae +; Switch to the movement data bank + ld a, [hROMBank] + push af + ld a, [hli] + rst Bankswitch +; Load the current script byte as given by OBJECT_MOVEMENT_BYTE_INDEX, and increment OBJECT_MOVEMENT_BYTE_INDEX + ld a, [hli] + ld d, [hl] + ld hl, OBJECT_MOVEMENT_BYTE_INDEX + add hl, bc + add [hl] + ld e, a + ld a, d + adc 0 + ld d, a + inc [hl] + ld a, [de] + ld h, a + pop af + rst Bankswitch + + ld a, h + ret +; 1ac6 + +SetVramState_Bit0:: ; 1ac6 + ld hl, VramState + set 0, [hl] + ret +; 1acc + +ResetVramState_Bit0:: ; 1acc + ld hl, VramState + res 0, [hl] + ret +; 1ad2 + +UpdateSprites:: ; 1ad2 + ld a, [VramState] + bit 0, a + ret z + + callba Function55e0 + callba _UpdateSprites + ret +; 1ae5 + +GetObjectStruct:: ; 1ae5 + ld bc, OBJECT_STRUCT_LENGTH + ld hl, ObjectStructs + call AddNTimes + ld b, h + ld c, l + ret +; 1af1 + +GetObjectSprite:: ; 1af1 + ld hl, OBJECT_SPRITE + add hl, bc + ld a, [hl] + and a + ret +; 1af8 + +SetSpriteDirection:: ; 1af8 + ; preserves other flags + push af + ld hl, OBJECT_FACING + add hl, bc + ld a, [hl] + and %11110011 + ld e, a + pop af + and %00001100 + or e + ld [hl], a + ret +; 1b07 + +GetSpriteDirection:: ; 1b07 + ld hl, OBJECT_FACING + add hl, bc + ld a, [hl] + and %00001100 + ret +; 1b0f diff --git a/home/math.asm b/home/math.asm new file mode 100644 index 00000000..c320fd15 --- /dev/null +++ b/home/math.asm @@ -0,0 +1,86 @@ +AddNTimes:: ; 0x30fe +; Add bc * a to hl. + and a + ret z +.loop + add hl, bc + dec a + jr nz, .loop + ret +; 0x3105 + +SimpleMultiply:: ; 3105 +; Return a * c. + and a + ret z + + push bc + ld b, a + xor a +.loop + add c + dec b + jr nz, .loop + pop bc + ret +; 3110 + + +SimpleDivide:: ; 3110 +; Divide a by c. Return quotient b and remainder a. + ld b, 0 +.loop + inc b + sub c + jr nc, .loop + dec b + add c + ret +; 3119 + + +Multiply:: ; 3119 +; Multiply hMultiplicand (3 bytes) by hMultiplier. Result in hProduct. +; All values are big endian. + push hl + push bc + + callab _Multiply + + pop bc + pop hl + ret +; 3124 + + +Divide:: ; 3124 +; Divide hDividend length b (max 4 bytes) by hDivisor. Result in hQuotient. +; All values are big endian. + push hl + push de + push bc + ld a, [hROMBank] + push af + ld a, BANK(_Divide) + rst Bankswitch + + call _Divide + + pop af + rst Bankswitch + pop bc + pop de + pop hl + ret +; 3136 + + +SubtractSigned:: ; 3136 +; Return a - b, sign in carry. + sub b + ret nc + cpl + add 1 + scf + ret +; 313d diff --git a/home/menu.asm b/home/menu.asm new file mode 100644 index 00000000..3e04af8c --- /dev/null +++ b/home/menu.asm @@ -0,0 +1,591 @@ +; Functions used in displaying and handling menus. + + +LoadMenuDataHeader:: + call CopyMenuDataHeader + call PushWindow + ret + +CopyMenuDataHeader:: + ld de, wMenuDataHeader + ld bc, wMenuDataHeaderEnd - wMenuDataHeader + call CopyBytes + ld a, [hROMBank] + ld [wMenuDataBank], a + ret +; 0x1d4b + +StoreTo_wMenuCursorBuffer:: ; 1d4b + ld [wMenuCursorBuffer], a + ret +; 1d4f + + +MenuTextBox:: ; 1d4f + push hl + call LoadMenuTextBox + pop hl + jp PrintText +; 1d57 + +ret_1d57:: ; 1d57 +; unreferenced + ret +; 1d58 + +LoadMenuTextBox:: ; 1d58 + ld hl, .MenuDataHeader + call LoadMenuDataHeader + ret +; 1d5f + +.MenuDataHeader ; 1d5f + db $40 ; tile backup + db 12, 0 ; start coords + db 17, 19 ; end coords + dw VTiles0 + db 0 ; default option +; 1d67 + +MenuTextBoxBackup:: ; 1d67 + call MenuTextBox + call CloseWindow + ret +; 1d6e + +LoadStandardMenuDataHeader:: ; 1d6e + ld hl, .MenuDataHeader + call LoadMenuDataHeader + ret +; 1d75 + +.MenuDataHeader ; 1d75 + db $40 ; tile backup + db 0, 0 ; start coords + db 17, 19 ; end coords + dw 0 + db 1 ; default option +; 1d7d + +Call_ExitMenu:: ; 1d7d + call ExitMenu + ret +; 1d81 + +VerticalMenu:: + xor a + ld [hBGMapMode], a + call MenuBox + call UpdateSprites + call PlaceVerticalMenuItems + call ApplyTilemap + call CopyMenuData2 + ld a, [wMenuData2Flags] + bit 7, a + jr z, .cancel + call InitVerticalMenuCursor + call StaticMenuJoypad + call MenuClickSound + bit 1, a + jr z, .okay +.cancel + scf + ret + +.okay + and a + ret +; 0x1dab + +GetMenu2:: ; 1dab + call LoadMenuDataHeader + call VerticalMenu + call CloseWindow + ld a, [wMenuCursorY] + ret +; 1db8 + +CopyNameFromMenu:: + push hl + push bc + push af + ld hl, wMenuData2Pointer + ld a, [hli] + ld h, [hl] + ld l, a + inc hl + inc hl + pop af + call GetNthString + ld d, h + ld e, l + call CopyName1 + pop bc + pop hl + ret +; 0x1dcf + + +YesNoBox:: ; 1dcf + lb bc, SCREEN_WIDTH - 6, 7 + +PlaceYesNoBox:: ; 1dd2 + jr _YesNoBox + +PlaceGenericTwoOptionBox:: ; 1dd4 + call LoadMenuDataHeader + jr InterpretTwoOptionMenu + +_YesNoBox:: ; 1dd9 +; Return nc (yes) or c (no). + push bc + ld hl, YesNoMenuDataHeader + call CopyMenuDataHeader + pop bc +; This seems to be an overflow prevention, but +; it was coded wrong. + ld a, b + cp SCREEN_WIDTH - 6 + jr nz, .okay ; should this be "jr nc"? + ld a, SCREEN_WIDTH - 6 + ld b, a + +.okay + ld a, b + ld [wMenuBorderLeftCoord], a + add 5 + ld [wMenuBorderRightCoord], a + ld a, c + ld [wMenuBorderTopCoord], a + add 4 + ld [wMenuBorderBottomCoord], a + call PushWindow + +InterpretTwoOptionMenu:: ; 1dfe + call VerticalMenu + push af + ld c, $f + call DelayFrames + call CloseWindow + pop af + jr c, .no + ld a, [wMenuCursorY] + cp 2 ; no + jr z, .no + and a + ret + +.no + ld a, 2 + ld [wMenuCursorY], a + scf + ret +; 1e1d + +YesNoMenuDataHeader:: ; 1e1d + db $40 ; tile backup + db 5, 10 ; start coords + db 9, 15 ; end coords + dw .MenuData2 + db 1 ; default option +; 1e25 + +.MenuData2 ; 1e25 + db $c0 ; flags + db 2 + db "YES@" + db "NO@" +; 1e2e + +OffsetMenuDataHeader:: ; 1e2e + call _OffsetMenuDataHeader + call PushWindow + ret +; 1e35 + +_OffsetMenuDataHeader:: ; 1e35 + push de + call CopyMenuDataHeader + pop de + ld a, [wMenuBorderLeftCoord] + ld h, a + ld a, [wMenuBorderRightCoord] + sub h + ld h, a + ld a, d + ld [wMenuBorderLeftCoord], a + add h + ld [wMenuBorderRightCoord], a + ld a, [wMenuBorderTopCoord] + ld l, a + ld a, [wMenuBorderBottomCoord] + sub l + ld l, a + ld a, e + ld [wMenuBorderTopCoord], a + add l + ld [wMenuBorderBottomCoord], a + ret +; 1e5d + +DoNthMenu:: ; 1e5d + call MenuFunc_1e7f + call MenuWriteText + call Function1eff + call Function1f23 + call GetMenuJoypad + call MenuClickSound + ret +; 1e70 + +SetUpMenu:: ; 1e70 + call MenuFunc_1e7f ; ??? + call MenuWriteText + call Function1eff ; set up selection pointer + ld hl, w2DMenuFlags1 + set 7, [hl] + ret + +MenuFunc_1e7f:: + call CopyMenuData2 + call GetMenuIndexSet + call Function1ea6 + call MenuBox + ret + +MenuWriteText:: + xor a + ld [hBGMapMode], a + call GetMenuIndexSet ; sort out the text + call Function1eda ; actually write it + call Function2e31 + ld a, [hOAMUpdate] + push af + ld a, $1 + ld [hOAMUpdate], a + call ApplyTilemap + pop af + ld [hOAMUpdate], a + ret +; 0x1ea6 + +Function1ea6:: ; 1ea6 + ld a, [wMenuBorderLeftCoord] + ld c, a + ld a, [wMenuBorderRightCoord] + sub c + ld c, a + ld a, [wMenuData2Items] + add a + inc a + ld b, a + ld a, [wMenuBorderTopCoord] + add b + ld [wMenuBorderBottomCoord], a + ret +; 1ebd + +GetMenuIndexSet:: ; 1ebd + ld hl, wMenuData2IndicesPointer + ld a, [hli] + ld h, [hl] + ld l, a + ld a, [wWhichIndexSet] + and a + jr z, .skip + ld b, a + ld c, -1 +.loop + ld a, [hli] + cp c + jr nz, .loop + dec b + jr nz, .loop + +.skip + ld d, h + ld e, l + ld a, [hl] + ld [wMenuData2Items], a + ret +; 1eda + +Function1eda:: ; 1eda + call MenuBoxCoord2Tile + ld bc, 2 * SCREEN_WIDTH + 2 + add hl, bc +.loop + inc de + ld a, [de] + cp -1 + ret z + ld [MenuSelection], a + push de + push hl + ld d, h + ld e, l + ld hl, wMenuData2DisplayFunctionPointer + call .__wMenuData2DisplayFunction__ + pop hl + ld de, 2 * SCREEN_WIDTH + add hl, de + pop de + jr .loop +; 1efb + +.__wMenuData2DisplayFunction__ ; 1efb + ld a, [hli] + ld h, [hl] + ld l, a + jp [hl] +; 1eff + +Function1eff:: ; 1eff + call InitVerticalMenuCursor + ld hl, wMenuJoypadFilter + ld a, [wMenuData2Flags] + bit 3, a + jr z, .disallow_select + set START_F, [hl] + +.disallow_select + ld a, [wMenuData2Flags] + bit 2, a + jr z, .disallow_left_right + set D_LEFT_F, [hl] + set D_RIGHT_F, [hl] + +.disallow_left_right + ret +; 1f1a + + +Function1f1a:: ; 1f1a + call ScrollingMenuJoypad + ld hl, wMenuJoypadFilter + and [hl] + jr Function1f2a +; 1f23 + +Function1f23:: ; 1f23 + xor a + ld [wMenuJoypad], a + call StaticMenuJoypad +; 1f2a + +Function1f2a:: ; 1f2a + bit A_BUTTON_F, a + jr nz, .a_button + bit B_BUTTON_F, a + jr nz, .b_start + bit START_F, a + jr nz, .b_start + bit D_RIGHT_F, a + jr nz, .d_right + bit D_LEFT_F, a + jr nz, .d_left + xor a + ld [wMenuJoypad], a + jr .done + +.d_right + ld a, D_RIGHT + ld [wMenuJoypad], a + jr .done + +.d_left + ld a, D_LEFT + ld [wMenuJoypad], a + jr .done + +.a_button + ld a, A_BUTTON + ld [wMenuJoypad], a + +.done + call GetMenuIndexSet + ld a, [wMenuCursorY] + ld l, a + ld h, $0 + add hl, de + ld a, [hl] + ld [MenuSelection], a + ld a, [wMenuCursorY] + ld [wMenuCursorBuffer], a + and a + ret + +.b_start + ld a, B_BUTTON + ld [wMenuJoypad], a + ld a, -1 + ld [MenuSelection], a + scf + ret +; 1f79 + +PlaceMenuStrings:: ; 1f79 + push de + ld hl, wMenuData2PointerTableAddr + ld a, [hli] + ld h, [hl] + ld l, a + ld a, [MenuSelection] + call GetNthString + ld d, h + ld e, l + pop hl + call PlaceString + ret +; 1f8d + +PlaceNthMenuStrings:: ; 1f8d + push de + ld a, [MenuSelection] + call GetMenuDataPointerTableEntry + inc hl + inc hl + ld a, [hli] + ld d, [hl] + ld e, a + pop hl + call PlaceString + ret +; 1f9e + +Function1f9e:: ; 1f9e +; unreferenced + call GetMenuDataPointerTableEntry + inc hl + inc hl + ld a, [hli] + ld d, [hl] + ld e, a + ret +; 1fa7 + +MenuJumptable:: ; 1fa7 + ld a, [MenuSelection] + call GetMenuDataPointerTableEntry + ld a, [hli] + ld h, [hl] + ld l, a + jp [hl] +; 1fb1 + +GetMenuDataPointerTableEntry:: ; 1fb1 + ld e, a + ld d, $0 + ld hl, wMenuData2PointerTableAddr + ld a, [hli] + ld h, [hl] + ld l, a + add hl, de + add hl, de + add hl, de + add hl, de + ret +; 1fbf + +ClearWindowData:: ; 1fbf + ld hl, wWindowStackPointer + call .bytefill + ld hl, wMenuDataHeader + call .bytefill + ld hl, wMenuData2Flags + call .bytefill + ld hl, w2DMenuCursorInitY + call .bytefill + + ld a, [rSVBK] + push af + ld a, $7 + ld [rSVBK], a + + xor a + ld hl, wWindowStackBottom + ld [hld], a + ld [hld], a + ld a, l + ld [wWindowStackPointer], a + ld a, h + ld [wWindowStackPointer + 1], a + + pop af + ld [rSVBK], a + ret +; 1ff0 + +.bytefill: ; 1ff0 + ld bc, $0010 + xor a + call ByteFill + ret +; 1ff8 + +MenuClickSound:: ; 1ff8 + push af + and A_BUTTON | B_BUTTON + jr z, .nosound + ld hl, wMenuFlags + bit 3, [hl] + jr nz, .nosound + call PlayClickSFX +.nosound + pop af + ret +; 2009 + + +PlayClickSFX:: ; 2009 + push de + ld de, SFX_READ_TEXT_2 + call PlaySFX + pop de + ret +; 0x2012 + +MenuTextBoxWaitButton:: ; 2012 + call MenuTextBox + call WaitButton + call ExitMenu + ret +; 201c + +Place2DMenuItemName:: ; 201c + ld [hBuffer], a + ld a, [hROMBank] + push af + ld a, [hBuffer] + rst Bankswitch + + call PlaceString + pop af + rst Bankswitch + + ret +; 202a + +_2DMenu:: ; 202a + ld a, [hROMBank] + ld [wMenuData2_2DMenuItemStringsBank], a + callba _2DMenu_ + ld a, [wMenuCursorBuffer] + ret +; 2039 + +InterpretBattleMenu:: ; 2039 + ld a, [hROMBank] + ld [wMenuData2_2DMenuItemStringsBank], a + callba _InterpretBattleMenu + ld a, [wMenuCursorBuffer] + ret +; 2048 + +InterpretMobileMenu:: ; 2048 + ld a, [hROMBank] + ld [wMenuData2_2DMenuItemStringsBank], a + callba _InterpretMobileMenu + ld a, [wMenuCursorBuffer] + ret +; 2057 diff --git a/home/mobile.asm b/home/mobile.asm new file mode 100644 index 00000000..32692f6a --- /dev/null +++ b/home/mobile.asm @@ -0,0 +1,315 @@ +Function3e32:: ; 3e32 +; Mobile + cp $2 + ld [$c988], a + ld a, l + ld [$c986], a + ld a, h + ld [$c987], a + jr nz, .asm_3e4f + + ld [$c982], a + ld a, l + ld [$c981], a + ld hl, $c983 + ld a, c + ld [hli], a + ld a, b + ld [hl], a + +.asm_3e4f + ld hl, $c822 + set 6, [hl] + ld a, [hROMBank] + push af + ld a, BANK(Function110030) + ld [$c981], a + rst Bankswitch + + jp Function110030 +; 3e60 + +Function3e60:: ; 3e60 + ld [$c986], a + ld a, l + ld [$c987], a + ld a, h + ld [$c988], a + + pop bc + ld a, b + ld [$c981], a + rst Bankswitch + + ld hl, $c822 + res 6, [hl] + ld hl, $c987 + ld a, [hli] + ld h, [hl] + ld l, a + ld a, [$c986] + ret +; 3e80 + +MobileReceive:: ; 3e80 + ld a, [hROMBank] + push af + ld a, BANK(_MobileReceive) + ld [$c981], a + rst Bankswitch + + call _MobileReceive + pop bc + ld a, b + ld [$c981], a + rst Bankswitch + + ret +; 3e93 + + +Timer:: ; 3e93 + push af + push bc + push de + push hl + + ld a, [hMobile] + and a + jr z, .pop_ret + + xor a + ld [rTAC], a + +; Turn off timer interrupt + ld a, [rIF] + and 1 << VBLANK | 1 << LCD_STAT | 1 << SERIAL | 1 << JOYPAD + ld [rIF], a + + ld a, [$c86a] + or a + jr z, .pop_ret + + ld a, [$c822] + bit 1, a + jr nz, .skip_Timer + + ld a, [rSC] + and 1 << rSC_ON + jr nz, .skip_Timer + + ld a, [hROMBank] + push af + ld a, BANK(_Timer) + ld [$c981], a + rst Bankswitch + + call _Timer + + pop bc + ld a, b + ld [$c981], a + rst Bankswitch + +.skip_Timer + ld a, [rTMA] + ld [rTIMA], a + + ld a, 1 << rTAC_ON | rTAC_65536_HZ + ld [rTAC], a + +.pop_ret + pop hl + pop de + pop bc + pop af + reti +; 3ed7 + +Function3ed7:: ; 3ed7 +; unreferenced + ld [$dc02], a + ld a, [hROMBank] + push af + ld a, BANK(Function114243) + rst Bankswitch + + call Function114243 + pop bc + ld a, b + rst Bankswitch + + ld a, [$dc02] + ret +; 3eea + +Function3eea:: ; 3eea + push hl + push bc + ld de, AttrMap - TileMap + add hl, de + inc b + inc b + inc c + inc c + call Function3f35 + pop bc + pop hl + call MobileHome_PlaceBox + ret +; 3efd + +Function3efd:: ; 3efd +; unreferenced + push hl + hlcoord 0, 12 + ld b, 4 + ld c, 18 + call .fill_attr + pop hl + call PrintTextBoxText + ret +; 3f0d + +.fill_attr + push hl + push bc + ld de, AttrMap - TileMap + add hl, de + inc b + inc b + inc c + inc c + call Function3f35 + pop bc + pop hl + call TextBoxBorder + ret +; 3f20 + +Function3f20:: ; 3f20 + hlcoord 0, 0, AttrMap + ld b, 6 + ld c, 20 + call Function3f35 + hlcoord 0, 0 + ld b, 4 + ld c, 18 + call MobileHome_PlaceBox + ret +; 3f35 + +Function3f35:: ; 3f35 + ld a, 6 + ld de, SCREEN_WIDTH +.row + push bc + push hl +.col + ld [hli], a + dec c + jr nz, .col + pop hl + add hl, de + pop bc + dec b + jr nz, .row + ret +; 3f47 + +MobileHome_PlaceBox: ; 3f47 + push bc + call .FillTop + pop bc +.RowLoop + push bc + call .FillMiddle + pop bc + dec b + jr nz, .RowLoop + call .FillBottom + ret +; 3f58 + +.FillTop + ld a, $63 + ld d, $62 + ld e, $64 + jr .FillRow + +.FillBottom + ld a, $68 + ld d, $67 + ld e, $69 + jr .FillRow + +.FillMiddle + ld a, $7f + ld d, $65 + ld e, $66 + +.FillRow + push hl + ld [hl], d + inc hl +.FillLoop + ld [hli], a + dec c + jr nz, .FillLoop + ld [hl], e + pop hl + ld de, SCREEN_WIDTH + add hl, de + ret +; 3f7c + +Function3f7c:: ; 3f7c + call MenuBoxCoord2Tile + call GetMenuBoxDims + dec b + dec c + call Function3eea + ret +; 3f88 + +Function3f88:: ; 3f88 + ld hl, wDecompressScratch + ld b, 0 +.row + push bc + ld c, 1 tiles / 2 +.col + ld a, [de] + inc de + cpl + ld [hl], 0 + inc hl + ld [hli], a + dec c + jr nz, .col + pop bc + dec c + jr nz, .row + ret +; 3f9f + +Function3f9f:: ; 3f9f + ld hl, wDecompressScratch +.row + push bc + ld c, 1 tiles / 2 +.col + ld a, [de] + inc de + inc de + cpl + ld [hl], $0 + inc hl + ld [hli], a + dec c + jr nz, .col + pop bc + dec c + jr nz, .row + ret +; 3fb5 diff --git a/home/movement.asm b/home/movement.asm new file mode 100644 index 00000000..f962c831 --- /dev/null +++ b/home/movement.asm @@ -0,0 +1,208 @@ +InitMovementBuffer:: ; 1b1e + ld [wMovementBufferPerson], a + xor a + ld [wMovementBufferCount], a + ld a, $0 ; useless + ld [wd004], a + ld a, $7 + ld [wd005], a + ld a, $d0 + ld [wd006], a + ret +; 1b35 + +DecrementMovementBufferCount:: ; 1b35 + ld a, [wMovementBufferCount] + and a + ret z + dec a + ld [wMovementBufferCount], a + ret +; 1b3f + +AppendToMovementBuffer:: ; 1b3f + push hl + push de + ld hl, wMovementBufferCount + ld e, [hl] + inc [hl] + ld d, 0 + ld hl, MovementBuffer + add hl, de + ld [hl], a + pop de + pop hl + ret +; 1b50 + +AppendToMovementBufferNTimes:: ; 1b50 + push af + ld a, c + and a + jr nz, .okay + pop af + ret + +.okay + pop af +.loop + call AppendToMovementBuffer + dec c + jr nz, .loop + ret +; 1b5f + +ComputePathToWalkToPlayer:: ; 1b5f + push af +; compare x coords, load left/right into h, and x distance into d + ld a, b + sub d + ld h, LEFT + jr nc, .got_x_distance + dec a + cpl + ld h, RIGHT + +.got_x_distance + ld d, a +; compare y coords, load up/down into l, and y distance into e + ld a, c + sub e + ld l, UP + jr nc, .got_y_distance + dec a + cpl + ld l, DOWN + +.got_y_distance + ld e, a +; if the x distance is less than the y distance, swap h and l, and swap d and e + cp d + jr nc, .done + ld a, h + ld h, l + ld l, a + ld a, d + ld d, e + ld e, a + +.done + pop af + ld b, a +; Add movement in the longer direction first... + ld a, h + call .GetMovementData + ld c, d + call AppendToMovementBufferNTimes +; ... then add the shorter direction. + ld a, l + call .GetMovementData + ld c, e + call AppendToMovementBufferNTimes + ret +; 1b92 + +.GetMovementData: ; 1b92 + push de + push hl + ld l, b + ld h, 0 +rept 2 + add hl, hl +endr + ld e, a + ld d, 0 + add hl, de + ld de, .MovementData + add hl, de + ld a, [hl] + pop hl + pop de + ret +; 1ba5 + +.MovementData + slow_step_down + slow_step_up + slow_step_left + slow_step_right + step_down + step_up + step_left + step_right + big_step_down + big_step_up + big_step_left + big_step_right +; 1bb1 + +SetMenuAttributes:: ; 1bb1 + push hl + push bc + ld hl, w2DMenuCursorInitY + ld b, $8 +.loop + ld a, [de] + inc de + ld [hli], a + dec b + jr nz, .loop + ld a, $1 +rept 2 + ld [hli], a +endr + xor a +rept 3 + ld [hli], a +endr + pop bc + pop hl + ret +; 1bc9 + +StaticMenuJoypad:: ; 1bc9 + callab _StaticMenuJoypad + call GetMenuJoypad + ret +; 1bd3 + +ScrollingMenuJoypad:: ; 1bd3 + callab _ScrollingMenuJoypad + call GetMenuJoypad + ret +; 1bdd + +GetMenuJoypad:: ; 1bdd + push bc + push af + ld a, [hJoyLast] + and D_PAD + ld b, a + ld a, [hJoyPressed] + and BUTTONS + or b + ld b, a + pop af + ld a, b + pop bc + ret +; 1bee + +PlaceHollowCursor:: ; 1bee + ld hl, wCursorCurrentTile + ld a, [hli] + ld h, [hl] + ld l, a + ld [hl], "▷" + ret +; 1bf7 + +HideCursor:: ; 1bf7 + ld hl, wCursorCurrentTile + ld a, [hli] + ld h, [hl] + ld l, a + ld [hl], " " + ret +; 1c00 + diff --git a/home/palettes.asm b/home/palettes.asm new file mode 100644 index 00000000..2f179209 --- /dev/null +++ b/home/palettes.asm @@ -0,0 +1,365 @@ +; Functions dealing with palettes. + + +UpdatePalsIfCGB:: ; c2f +; update bgp data from BGPals +; update obp data from OBPals +; return carry if successful + +; check cgb + ld a, [hCGB] + and a + ret z + + +UpdateCGBPals:: ; c33 +; return carry if successful +; any pals to update? + ld a, [hCGBPalUpdate] + and a + ret z + + +ForceUpdateCGBPals:: ; c37 + + ld a, [rSVBK] + push af + ld a, 5 ; BANK(BGPals) + ld [rSVBK], a + + ld hl, BGPals ; 5:d080 + +; copy 8 pals to bgpd + ld a, %10000000 ; auto increment, index 0 + ld [rBGPI], a + ld c, rBGPD % $100 + ld b, 4 ; NUM_PALS / 2 +.bgp +rept 2 palettes + ld a, [hli] + ld [$ff00+c], a +endr + + dec b + jr nz, .bgp + +; hl is now 5:d0c0 OBPals + +; copy 8 pals to obpd + ld a, %10000000 ; auto increment, index 0 + ld [rOBPI], a + ld c, rOBPD % $100 + ld b, 4 ; NUM_PALS / 2 +.obp +rept 2 palettes + ld a, [hli] + ld [$ff00+c], a +endr + + dec b + jr nz, .obp + + pop af + ld [rSVBK], a + +; clear pal update queue + xor a + ld [hCGBPalUpdate], a + + scf + ret +; c9f + + +DmgToCgbBGPals:: ; c9f +; exists to forego reinserting cgb-converted image data + +; input: a -> bgp + + ld [rBGP], a + push af + +; Don't need to be here if DMG + ld a, [hCGB] + and a + jr z, .end + + push hl + push de + push bc + ld a, [rSVBK] + push af + + ld a, 5 ; gfx + ld [rSVBK], a + +; copy & reorder bg pal buffer + ld hl, BGPals ; to + ld de, UnknBGPals ; from +; order + ld a, [rBGP] + ld b, a +; all pals + ld c, 8 + call CopyPals +; request pal update + ld a, 1 + ld [hCGBPalUpdate], a + + pop af + ld [rSVBK], a + pop bc + pop de + pop hl +.end + pop af + ret +; ccb + + +DmgToCgbObjPals:: ; ccb +; exists to forego reinserting cgb-converted image data + +; input: d -> obp1 +; e -> obp2 + + ld a, e + ld [rOBP0], a + ld a, d + ld [rOBP1], a + + ld a, [hCGB] + and a + ret z + + push hl + push de + push bc + ld a, [rSVBK] + push af + + ld a, 5 + ld [rSVBK], a + +; copy & reorder obj pal buffer + ld hl, OBPals ; to + ld de, UnknOBPals ; from +; order + ld a, [rOBP0] + ld b, a +; all pals + ld c, 8 + call CopyPals +; request pal update + ld a, 1 + ld [hCGBPalUpdate], a + + pop af + ld [rSVBK], a + pop bc + pop de + pop hl + ret +; cf8 + + +DmgToCgbObjPal0:: ; cf8 + ld [rOBP0], a + push af + +; Don't need to be here if not CGB + ld a, [hCGB] + and a + jr z, .dmg + + push hl + push de + push bc + + ld a, [rSVBK] + push af + ld a, 5 ; gfx + ld [rSVBK], a + + ld hl, OBPals + ld de, UnknOBPals + ld a, [rOBP0] + ld b, a + ld c, 1 + call CopyPals + ld a, 1 + ld [hCGBPalUpdate], a + + pop af + ld [rSVBK], a + + pop bc + pop de + pop hl + +.dmg + pop af + ret +; d24 + +DmgToCgbObjPal1:: ; d24 + ld [rOBP1], a + push af + + ld a, [hCGB] + and a + jr z, .dmg + + push hl + push de + push bc + + ld a, [rSVBK] + push af + ld a, 5 ; gfx + ld [rSVBK], a + + ld hl, OBPals + 1 palettes + ld de, UnknOBPals + 1 palettes + ld a, [rOBP1] + ld b, a + ld c, 1 + call CopyPals + ld a, 1 + ld [hCGBPalUpdate], a + + pop af + ld [rSVBK], a + + pop bc + pop de + pop hl + +.dmg + pop af + ret +; d50 + + + +CopyPals:: ; d50 +; copy c palettes in order b from de to hl + + push bc + ld c, 4 ; NUM_PAL_COLORS +.loop + push de + push hl + +; get pal color + ld a, b + and %11 ; color +; 2 bytes per color + add a + ld l, a + ld h, 0 + add hl, de + ld e, [hl] + inc hl + ld d, [hl] + +; dest + pop hl +; write color + ld [hl], e + inc hl + ld [hl], d + inc hl +; next pal color + srl b + srl b +; source + pop de +; done pal? + dec c + jr nz, .loop + +; de += 8 (next pal) + ld a, 1 palettes ; NUM_PAL_COLORS * 2 ; bytes per pal + add e + jr nc, .ok + inc d +.ok + ld e, a + +; how many more pals? + pop bc + dec c + jr nz, CopyPals + ret +; d79 + + +ClearVBank1:: ; d79 + ld a, [hCGB] + and a + ret z + + ld a, 1 + ld [rVBK], a + + ld hl, VTiles0 + ld bc, VRAM_End - VTiles0 + xor a + call ByteFill + + ld a, 0 + ld [rVBK], a + ret +; d90 + + +ret_d90:: ; d90 + ret +; d91 + + +Special_ReloadSpritesNoPalettes:: ; d91 + ld a, [hCGB] + and a + ret z + ld a, [rSVBK] + push af + ld a, 5 ; BANK(BGPals) + ld [rSVBK], a + ld hl, BGPals + ld bc, $40 + $10 + xor a + call ByteFill + pop af + ld [rSVBK], a + ld a, 1 + ld [hCGBPalUpdate], a + call DelayFrame + ret +; db1 + + +FarCallSwapTextboxPalettes:: ; db1 + ld a, [hROMBank] + push af + ld a, BANK(SwapTextboxPalettes) + rst Bankswitch + call SwapTextboxPalettes + pop af + rst Bankswitch + ret +; dbd + +FarCallScrollBGMapPalettes:: ; dbd + ld a, [hROMBank] + push af + ld a, BANK(ScrollBGMapPalettes) + rst Bankswitch + + call ScrollBGMapPalettes + + pop af + rst Bankswitch + ret +; dc9 diff --git a/home/pokedex_flags.asm b/home/pokedex_flags.asm new file mode 100644 index 00000000..7aacd498 --- /dev/null +++ b/home/pokedex_flags.asm @@ -0,0 +1,38 @@ +SetSeenAndCaughtMon:: ; 3380 + push af + ld c, a + ld hl, PokedexCaught + ld b, SET_FLAG + call PokedexFlagAction + pop af + ; fallthrough +; 338b + +SetSeenMon:: ; 338b + ld c, a + ld hl, PokedexSeen + ld b, SET_FLAG + jr PokedexFlagAction +; 3393 + +CheckCaughtMon:: ; 3393 + ld c, a + ld hl, PokedexCaught + ld b, CHECK_FLAG + jr PokedexFlagAction +; 339b + +CheckSeenMon:: ; 339b + ld c, a + ld hl, PokedexSeen + ld b, CHECK_FLAG + ; fallthrough +; 33a1 + +PokedexFlagAction:: ; 33a1 + ld d, 0 + predef FlagPredef + ld a, c + and a + ret +; 33ab diff --git a/home/predef.asm b/home/predef.asm new file mode 100644 index 00000000..03f74146 --- /dev/null +++ b/home/predef.asm @@ -0,0 +1,53 @@ +Predef:: ; 2d83 +; Call predefined function a. +; Preserves bc, de, hl and f. + + ld [PredefID], a + ld a, [hROMBank] + push af + + ld a, BANK(GetPredefPointer) + rst Bankswitch + call GetPredefPointer ; stores hl in PredefTemp + +; Switch to the new function's bank + rst Bankswitch + +; Instead of directly calling stuff, +; push it to the stack in reverse. + + ld hl, .Return + push hl + +; Call the Predef function + ld a, [PredefAddress] + ld h, a + ld a, [PredefAddress + 1] + ld l, a + push hl + +; Get hl back + ld a, [PredefTemp] + ld h, a + ld a, [PredefTemp + 1] + ld l, a + ret + +.Return +; Clean up after the Predef call + + ld a, h + ld [PredefTemp], a + ld a, l + ld [PredefTemp+1], a + + pop hl + ld a, h + rst Bankswitch + + ld a, [PredefTemp] + ld h, a + ld a, [PredefTemp + 1] + ld l, a + ret +; 2dba diff --git a/home/random.asm b/home/random.asm new file mode 100644 index 00000000..ae39f439 --- /dev/null +++ b/home/random.asm @@ -0,0 +1,84 @@ +Random:: ; 2f8c +; A simple hardware-based random number generator (RNG). + +; Two random numbers are generated by adding and subtracting +; the divider to the respective values every time it's called. + +; The divider is a register that increments at a rate of 16384Hz. +; For comparison, the Game Boy operates at a clock speed of 4.2MHz. + +; Additionally, an equivalent function is executed in VBlank. + +; This leaves a with the value in hRandomSub. + + push bc + + ld a, [rDIV] + ld b, a + ld a, [hRandomAdd] + adc b + ld [hRandomAdd], a + + ld a, [rDIV] + ld b, a + ld a, [hRandomSub] + sbc b + ld [hRandomSub], a + + pop bc + ret +; 2f9f + +BattleRandom:: ; 2f9f +; _BattleRandom lives in another bank. + +; It handles all RNG calls in the battle engine, allowing +; link battles to remain in sync using a shared PRNG. + + ld a, [hROMBank] + push af + ld a, BANK(_BattleRandom) + rst Bankswitch + + call _BattleRandom + + ld [PredefTemp + 1], a + pop af + rst Bankswitch + ld a, [PredefTemp + 1] + ret +; 2fb1 + + +RandomRange:: ; 2fb1 +; Return a random number between 0 and a (non-inclusive). + + push bc + ld c, a + + ; b = $100 % c + xor a + sub c +.mod + sub c + jr nc, .mod + add c + ld b, a + + ; Get a random number + ; from 0 to $ff - b. + push bc +.loop + call Random + ld a, [hRandomAdd] + ld c, a + add b + jr c, .loop + ld a, c + pop bc + + call SimpleDivide + + pop bc + ret +; 2fcb diff --git a/home/rtc.asm b/home/rtc.asm new file mode 100644 index 00000000..9fb71c0b --- /dev/null +++ b/home/rtc.asm @@ -0,0 +1,24 @@ +RTC:: ; 46f +; update time and time-sensitive palettes + +; rtc enabled? + ld a, [wSpriteUpdatesEnabled] + cp 0 + ret z + + call UpdateTime + +; obj update on? + ld a, [VramState] + bit 0, a ; obj update + ret z + +TimeOfDayPals:: ; 47e + callab _TimeOfDayPals + ret +; 485 + +UpdateTimePals:: ; 485 + callab _UpdateTimePals + ret +; 48c diff --git a/home/serial.asm b/home/serial.asm new file mode 100644 index 00000000..ad7d9610 --- /dev/null +++ b/home/serial.asm @@ -0,0 +1,410 @@ +Serial:: ; 6ef +; The serial interrupt. + + push af + push bc + push de + push hl + + ld a, [hMobileReceive] + and a + jr nz, .mobile + + ld a, [wc2d4] + bit 0, a + jr nz, .printer + + ld a, [hLinkPlayerNumber] + inc a ; is it equal to -1? + jr z, .init_player_number + + ld a, [rSB] + ld [hSerialReceive], a + + ld a, [hSerialSend] + ld [rSB], a + + ld a, [hLinkPlayerNumber] + cp $2 + jr z, .player2 + + ld a, 0 << rSC_ON + ld [rSC], a + ld a, 1 << rSC_ON + ld [rSC], a + jr .player2 + +.mobile + call MobileReceive + jr .end + +.printer + call PrinterReceive + jr .end + +.init_player_number + ld a, [rSB] + cp $1 + jr z, .player1 + cp $2 + jr nz, .player2 + +.player1 + ld [hSerialReceive], a + ld [hLinkPlayerNumber], a + cp $2 + jr z, ._player2 + + xor a + ld [rSB], a + ld a, $3 + ld [rDIV], a + +.wait_bit_7 + ld a, [rDIV] + bit 7, a + jr nz, .wait_bit_7 + + ld a, 0 << rSC_ON + ld [rSC], a + ld a, 1 << rSC_ON + ld [rSC], a + jr .player2 + +._player2 + xor a + ld [rSB], a + +.player2 + ld a, $1 + ld [hFFCA], a + ld a, -2 + ld [hSerialSend], a + +.end + pop hl + pop de + pop bc + pop af + reti +; 75f + +Function75f:: ; 75f + ld a, $1 + ld [hFFCC], a +.loop + ld a, [hl] + ld [hSerialSend], a + call Function78a + push bc + ld b, a + inc hl + ld a, $30 +.wait + dec a + jr nz, .wait + ld a, [hFFCC] + and a + ld a, b + pop bc + jr z, .load + dec hl + cp $fd + jr nz, .loop + xor a + ld [hFFCC], a + jr .loop + +.load + ld [de], a + inc de + dec bc + ld a, b + or c + jr nz, .loop + ret +; 78a + +Function78a:: ; 78a + xor a + ld [hFFCA], a + ld a, [hLinkPlayerNumber] + cp $2 + jr nz, .asm_79b + ld a, $1 + ld [rSC], a + ld a, $81 + ld [rSC], a + +.asm_79b + ld a, [hFFCA] + and a + jr nz, .asm_7e5 + ld a, [hLinkPlayerNumber] + cp $1 + jr nz, .asm_7c0 + call Function82b + jr z, .asm_7c0 + call .asm_825 + push hl + ld hl, wcf5c + inc [hl] + jr nz, .asm_7b7 + dec hl + inc [hl] + +.asm_7b7 + pop hl + call Function82b + jr nz, .asm_79b + jp Function833 + +.asm_7c0 + ld a, [rIE] + and $f + cp $8 + jr nz, .asm_79b + ld a, [wcf5d] + dec a + ld [wcf5d], a + jr nz, .asm_79b + ld a, [wcf5d + 1] + dec a + ld [wcf5d + 1], a + jr nz, .asm_79b + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .asm_7e5 + ld a, $ff +.asm_7e2 + dec a + jr nz, .asm_7e2 + +.asm_7e5 + xor a + ld [hFFCA], a + ld a, [rIE] + and $f + sub $8 + jr nz, .asm_7f8 + ld [wcf5d], a + ld a, $50 + ld [wcf5d + 1], a + +.asm_7f8 + ld a, [hSerialReceive] + cp $fe + ret nz + call Function82b + jr z, .asm_813 + push hl + ld hl, wcf5c + ld a, [hl] + dec a + ld [hld], a + inc a + jr nz, .asm_80d + dec [hl] + +.asm_80d + pop hl + call Function82b + jr z, Function833 + +.asm_813 + ld a, [rIE] + and $f + cp $8 + ld a, $fe + ret z + ld a, [hl] + ld [hSerialSend], a + call DelayFrame + jp Function78a + +.asm_825 + ld a, $f +.asm_827 + dec a + jr nz, .asm_827 + ret +; 82b + +Function82b:: ; 82b + push hl + ld hl, wcf5b + ld a, [hli] + or [hl] + pop hl + ret +; 833 + +Function833:: ; 833 + dec a + ld [wcf5b], a + ld [wcf5c], a + ret +; 83b + +Function83b:: ; 83b + ld hl, wPlayerLinkAction + ld de, wOtherPlayerLinkMode + ld c, $2 + ld a, $1 + ld [hFFCC], a +.asm_847 + call DelayFrame + ld a, [hl] + ld [hSerialSend], a + call Function78a + ld b, a + inc hl + ld a, [hFFCC] + and a + ld a, $0 + ld [hFFCC], a + jr nz, .asm_847 + ld a, b + ld [de], a + inc de + dec c + jr nz, .asm_847 + ret +; 862 + +Function862:: ; 862 + call LoadTileMapToTempTileMap + callab PlaceWaitingText + call Function87d + jp Call_LoadTempTileMapToTileMap +; 871 + + +Function871:: ; 871 + call LoadTileMapToTempTileMap + callab PlaceWaitingText + jp Function87d +; 87d + +; One "giant" leap for machinekind + +Function87d:: ; 87d + ld a, $ff + ld [wOtherPlayerLinkAction], a +.loop + call LinkTransfer + call DelayFrame + call Function82b + jr z, .check + push hl + ld hl, wcf5c + dec [hl] + jr nz, .skip + dec hl + dec [hl] + jr nz, .skip + pop hl + xor a + jp Function833 + +.skip + pop hl + +.check + ld a, [wOtherPlayerLinkAction] + inc a + jr z, .loop + + ld b, 10 +.receive + call DelayFrame + call LinkTransfer + dec b + jr nz, .receive + + ld b, 10 +.acknowledge + call DelayFrame + call LinkDataReceived + dec b + jr nz, .acknowledge + + ld a, [wOtherPlayerLinkAction] + ld [wOtherPlayerLinkMode], a + ret +; 8c1 + +LinkTransfer:: ; 8c1 + push bc + ld b, SERIAL_TIMECAPSULE + ld a, [wLinkMode] + cp LINK_TIMECAPSULE + jr z, .got_high_nybble + ld b, SERIAL_TIMECAPSULE + jr c, .got_high_nybble + cp LINK_TRADECENTER + ld b, SERIAL_TRADECENTER + jr z, .got_high_nybble + ld b, SERIAL_BATTLE + +.got_high_nybble + call .Receive + ld a, [wPlayerLinkAction] + add b + ld [hSerialSend], a + ld a, [hLinkPlayerNumber] + cp $2 + jr nz, .player_1 + ld a, $1 + ld [rSC], a + ld a, $81 + ld [rSC], a + +.player_1 + call .Receive + pop bc + ret +; 8f3 + +.Receive ; 8f3 + ld a, [hSerialReceive] + ld [wOtherPlayerLinkMode], a + and $f0 + cp b + ret nz + xor a + ld [hSerialReceive], a + ld a, [wOtherPlayerLinkMode] + and $f + ld [wOtherPlayerLinkAction], a + ret +; 908 + +LinkDataReceived:: ; 908 +; Let the other system know that the data has been received. + xor a + ld [hSerialSend], a + ld a, [hLinkPlayerNumber] + cp $2 + ret nz + ld a, $1 + ld [rSC], a + ld a, $81 + ld [rSC], a + ret +; 919 + +Function919:: ; 919 + ld a, [wLinkMode] + and a + ret nz + ld a, $2 + ld [rSB], a + xor a + ld [hSerialReceive], a + ld a, $0 + ld [rSC], a + ld a, $80 + ld [rSC], a + ret +; 92e diff --git a/home/sine.asm b/home/sine.asm new file mode 100644 index 00000000..e1552db2 --- /dev/null +++ b/home/sine.asm @@ -0,0 +1,21 @@ +Cosine:: ; 1b0f +; Return d * cos(a) in hl + add $10 ; 90 degrees + +Sine:: ; 1b11 +; Return d * sin(a) in hl +; a is a signed 6-bit value. + + ld e, a + + ld a, [hROMBank] + push af + ld a, BANK(_Sine) + rst Bankswitch + + call _Sine + + pop af + rst Bankswitch + ret +; 1b1e diff --git a/home/sram.asm b/home/sram.asm new file mode 100644 index 00000000..05d4fdb6 --- /dev/null +++ b/home/sram.asm @@ -0,0 +1,20 @@ + +OpenSRAM:: + push af ; 30e1 + ld a, $1 ; 30e2 + ld [MBC3LatchClock], a ; 30e4 + ld a, $a ; 30e7 + ld [MBC3SRamEnable], a ; 30e9 + pop af ; 30ec + ld [MBC3SRamBank], a ; 30ed + ret ; 30f0 +; 30f1 + +CloseSRAM:: + push af ; 30f1 + ld a, $0 ; 30f2 + ld [MBC3LatchClock], a ; 30f4 + ld [MBC3SRamEnable], a ; 30f7 + pop af ; 30fa + ret ; 30fb +; 30fc diff --git a/home/string.asm b/home/string.asm new file mode 100644 index 00000000..70a0f2dd --- /dev/null +++ b/home/string.asm @@ -0,0 +1,38 @@ +InitString:: ; 2ef6 +; Init a string of length c. + push hl + jr _InitString +; 2ef9 + +InitName:: ; 2ef9 +; Intended for names, so this function is limited to ten characters. + push hl + ld c, 10 +; 2efc + +_InitString:: ; 2efc +; if the string pointed to by hl is empty (defined as "zero or more spaces +; followed by a null"), then initialize it to the string pointed to by de. + push bc +.loop + ld a, [hli] + cp "@" + jr z, .blank + cp " " + jr nz, .notblank + dec c + jr nz, .loop +.blank + pop bc + ld l, e + ld h, d + pop de + ld b, 0 + inc c + call CopyBytes + ret +.notblank + pop bc + pop hl + ret +; 2f17 diff --git a/home/text.asm b/home/text.asm new file mode 100644 index 00000000..e3dacb47 --- /dev/null +++ b/home/text.asm @@ -0,0 +1,1183 @@ +BORDER_WIDTH EQU 2 +TEXTBOX_WIDTH EQU SCREEN_WIDTH +TEXTBOX_INNERW EQU TEXTBOX_WIDTH - BORDER_WIDTH +TEXTBOX_HEIGHT EQU 6 +TEXTBOX_INNERH EQU TEXTBOX_HEIGHT - BORDER_WIDTH +TEXTBOX_X EQU 0 +TEXTBOX_INNERX EQU TEXTBOX_X + 1 +TEXTBOX_Y EQU SCREEN_HEIGHT - TEXTBOX_HEIGHT +TEXTBOX_INNERY EQU TEXTBOX_Y + 2 + +TEXTBOX_PAL EQU 7 + + +ClearBox:: ; fb6 +; Fill a c*b box at hl with blank tiles. + + ld a, " " + +FillBoxWithByte:: +.row + push bc + push hl +.col + ld [hli], a + dec c + jr nz, .col + pop hl + ld bc, SCREEN_WIDTH + add hl, bc + pop bc + dec b + jr nz, .row + ret +; fc8 + + +ClearTileMap:: ; fc8 +; Fill TileMap with blank tiles. + + hlcoord 0, 0 + ld a, " " + ld bc, TileMapEnd - TileMap + call ByteFill + + ; Update the BG Map. + ld a, [rLCDC] + bit 7, a + ret z + jp WaitBGMap +; fdb + + +ClearScreen:: ; fdb + ld a, TEXTBOX_PAL + hlcoord 0, 0, AttrMap + ld bc, SCREEN_WIDTH * SCREEN_HEIGHT + call ByteFill + jr ClearTileMap +; fe8 + + + +TextBox:: ; fe8 +; Draw a text box at hl with room for +; b lines of c characters each. +; Places a border around the textbox, +; then switches the palette to the +; text black-and-white scheme. + push bc + push hl + call TextBoxBorder + pop hl + pop bc + jr TextBoxPalette +; ff1 + + +TextBoxBorder:: ; ff1 + + ; Top + push hl + ld a, "┌" + ld [hli], a + inc a ; "─" + call .PlaceChars + inc a ; "┐" + ld [hl], a + pop hl + + ; Middle + ld de, SCREEN_WIDTH + add hl, de +.row + push hl + ld a, "│" + ld [hli], a + ld a, " " + call .PlaceChars + ld [hl], "│" + pop hl + + ld de, SCREEN_WIDTH + add hl, de + dec b + jr nz, .row + + ; Bottom + ld a, "└" + ld [hli], a + ld a, "─" + call .PlaceChars + ld [hl], "┘" + + ret +; 101e + +.PlaceChars: ; 101e +; Place char a c times. + ld d, c +.loop + ld [hli], a + dec d + jr nz, .loop + ret +; 1024 + + +TextBoxPalette:: ; 1024 +; Fill text box width c height b at hl with pal 7 + ld de, AttrMap - TileMap + add hl, de +rept 2 + inc b +endr +rept 2 + inc c +endr + ld a, TEXTBOX_PAL +.col + push bc + push hl +.row + ld [hli], a + dec c + jr nz, .row + pop hl + ld de, SCREEN_WIDTH + add hl, de + pop bc + dec b + jr nz, .col + ret +; 103e + + +SpeechTextBox:: ; 103e +; Standard textbox. + hlcoord TEXTBOX_X, TEXTBOX_Y + ld b, TEXTBOX_INNERH + ld c, TEXTBOX_INNERW + jp TextBox +; 1048 + +TestText:: ; 1048 + text "ゲームフりーク!" + done +; 1052 + +RadioTerminator:: ; 1052 + ld hl, .stop + ret +.stop db "@" +; 1057 + + +PrintText:: ; 1057 + call SetUpTextBox +BuenaPrintText:: ; 105a + push hl + hlcoord TEXTBOX_INNERX, TEXTBOX_INNERY + lb bc, TEXTBOX_INNERH - 1, TEXTBOX_INNERW + call ClearBox + pop hl + +PrintTextBoxText:: ; 1065 + bccoord TEXTBOX_INNERX, TEXTBOX_INNERY + call PlaceWholeStringInBoxAtOnce + ret +; 106c + +SetUpTextBox:: ; 106c + push hl + call SpeechTextBox + call UpdateSprites + call ApplyTilemap + pop hl + ret +; 1078 + + +PlaceString:: ; 1078 + push hl + +PlaceNextChar:: ; 1079 + ld a, [de] + cp "@" + jr nz, CheckDict + ld b, h + ld c, l + pop hl + ret + pop de + +NextChar:: ; 1083 + inc de + jp PlaceNextChar + +CheckDict:: ; 1087 +dict: macro +if \1 == 0 + and a +else + cp \1 +endc + jp z, \2 +endm + +dict2: macro +if \1 == 0 + and a +else + cp \1 +endc + jr nz, \@ + ld a, \2 +\@: +endm + +dict3: macro +if \1 == 0 + and a +else + cp \1 +endc + jr z, \2 +endm + + dict "<DAY>", Char15 + dict "<LINE>", LineChar + dict "<NEXT>", NextLineChar + dict TX_FAR, TextFar + dict $00, NullChar + dict $4c, Char4C + dict $4b, Char4B + dict "<PARA>", Paragraph + dict "<MOM>", PrintMomsName + dict "<PLAYER>", PrintPlayerName + dict "<RIVAL>", PrintRivalName + dict $35, Char35 + dict $36, Char36 + dict $37, Char37 + dict "<RED>", PrintRedsName + dict "<GREEN>", PrintGreensName + dict "#", PlacePOKe + dict "<PC>", PCChar + dict "<ROCKET>", RocketChar + dict "<TM>", TMChar + dict "<TRNER>", TrainerChar + dict $23, PlaceKougeki + dict "<LNBRK>", Char22 + dict "<CONT>", ContText + dict "<......>", SixDotsChar + dict "<DONE>", DoneText + dict "<PROMPT>", PromptText + dict "<PKMN>", PlacePKMN + dict "<POKE>", PlacePOKE + dict $25, NextChar + dict2 $1f, " " + dict "<DEXEND>", PlaceDexEnd + dict "<TARGET>", PlaceMoveTargetsName + dict "<USER>", PlaceMoveUsersName + dict "<ENEMY>", PlaceEnemysName + dict "<PLAY_G>", PlaceGenderedPlayerName + dict3 $e4, .place + dict3 $e5, .place + + jr .nope + ld b, a + call Diacritic + jp NextChar +.nope + + cp $60 + jr nc, .place + + cp $40 + jr nc, .handakuten + +.dakuten + + cp $20 + jr nc, .daku1 + add $80 + jr .daku2 +.daku1 + add $90 +.daku2 + ld b, $e5 ; dakuten + call Diacritic + jr .place + +.handakuten + cp "ぱ" + jr nc, .han1 + add "ハ" - "パ" + jr .han2 +.han1 + add "は" - "ぱ" +.han2 + ld b, $e4 ; handakuten + call Diacritic + +.place + ld [hli], a + call PrintLetterDelay + jp NextChar +; 0x117b + + +Char15:: ; 117b + ld c, l + ld b, h + callba Function17f036 + jp PlaceNextChar +; 1186 + + +print_name: macro + push de + ld de, \1 + jp PlaceCommandCharacter +endm + +PrintMomsName: print_name MomsName ; 1186 +PrintPlayerName: print_name PlayerName ; 118d +PrintRivalName: print_name RivalName ; 1194 +PrintRedsName: print_name RedsName ; 119b +PrintGreensName: print_name GreensName ; 11a2 + +TrainerChar: print_name TrainerCharText ; 11a9 +TMChar: print_name TMCharText ; 11b0 +PCChar: print_name PCCharText ; 11b7 +RocketChar: print_name RocketCharText ; 11be +PlacePOKe: print_name PlacePOKeText ; 11c5 +PlaceKougeki: print_name KougekiText ; 11cc +SixDotsChar: print_name SixDotsCharText ; 11d3 +PlacePKMN: print_name PlacePKMNText ; 11da +PlacePOKE: print_name PlacePOKEText ; 11e1 +Char35: print_name Char35Text ; 11e8 +Char36: print_name Char36Text ; 11ef +Char37: print_name Char37Text ; 11f6 + + +PlaceMoveTargetsName:: ; 11fd + ld a, [hBattleTurn] + xor 1 + jr PlaceMoveTargetsName_5A + +PlaceMoveUsersName:: ; 1203 + ld a, [hBattleTurn] + +PlaceMoveTargetsName_5A: ; 1205 + push de + and a + jr nz, .enemy + + ld de, BattleMonNick + jr PlaceCommandCharacter + +.enemy + ld de, EnemyText ; Enemy + call PlaceString + ld h, b + ld l, c + ld de, EnemyMonNick + jr PlaceCommandCharacter + + +PlaceEnemysName:: ; 121b + push de + + ld a, [wLinkMode] + and a + jr nz, .linkbattle + + ld a, [TrainerClass] + cp RIVAL1 + jr z, .rival + cp RIVAL2 + jr z, .rival + + ld de, OTClassName + call PlaceString + ld h, b + ld l, c + ld de, String12a2 + call PlaceString + push bc + callab Battle_GetTrainerName + pop hl + ld de, StringBuffer1 + jr PlaceCommandCharacter + +.rival + ld de, RivalName + jr PlaceCommandCharacter + +.linkbattle + ld de, OTClassName + jr PlaceCommandCharacter + + +PlaceGenderedPlayerName:: ; 1252 + push de + ld de, PlayerName + call PlaceString + ld h, b + ld l, c + ld a, [PlayerGender] + bit 0, a + ld de, String_kun + jr z, PlaceCommandCharacter + ld de, String_chan + jr PlaceCommandCharacter + + +PlaceCommandCharacter:: ; 126a + call PlaceString + ld h, b + ld l, c + pop de + jp NextChar +; 0x1273 + +TMCharText:: db "TM@" ; 1273 +TrainerCharText:: db "TRAINER@" ; 1276 +PCCharText:: db "PC@" ; 127e +RocketCharText:: db "ROCKET@" ; 1281 +PlacePOKeText:: db "POKé@" ; 1288 +KougekiText:: db "こうげき@" ; 128d +SixDotsCharText:: db "……@" ; 1292 +EnemyText:: db "Enemy @" ; 1295 +PlacePKMNText:: db "<PK><MN>@" ; PK MN ; 129c +PlacePOKEText:: db "<PO><KE>@" ; PO KE ; 129f +String12a2:: db " @" ; 12a2 +Char35Text:: +Char36Text:: +Char37Text:: db "@" ; 12a4 +String_kun:: db "@" ; 12a5 +String_chan:: db "@" ; 12a6 +; 12a7 + +NextLineChar:: ; 12a7 + pop hl + ld bc, SCREEN_WIDTH * 2 + add hl, bc + push hl + jp NextChar +; 12b0 + +Char22:: ; 12b0 + pop hl + ld bc, SCREEN_WIDTH + add hl, bc + push hl + jp NextChar +; 12b9 + +TextFar:: ; 12b9 + pop hl + push de + ld bc, -TileMap + $10000 + add hl, bc + ld de, -SCREEN_WIDTH + ld c, 1 +.loop + ld a, h + and a + jr nz, .next + ld a, l + cp SCREEN_WIDTH + jr c, .done + +.next + add hl, de + inc c + jr .loop + +.done + hlcoord 0, 0 + ld de, SCREEN_WIDTH + ld a, c +.loop2 + and a + jr z, .done2 + add hl, de + dec a + jr .loop2 + +.done2 + pop de + inc de + ld a, [de] + ld c, a + ld b, 0 + add hl, bc + push hl + jp NextChar +; 12ea + + +LineChar:: ; 12ea + pop hl + hlcoord TEXTBOX_INNERX, TEXTBOX_INNERY + 2 + push hl + jp NextChar +; 0x12f2 + +Paragraph:: ; 12f2 + push de + + ld a, [wLinkMode] + cp LINK_COLOSSEUM + jr z, .linkbattle + cp LINK_MOBILE + jr z, .linkbattle + call LoadBlinkingCursor + +.linkbattle + call Function13b6 + call ButtonSound + hlcoord TEXTBOX_INNERX, TEXTBOX_INNERY + lb bc, TEXTBOX_INNERH - 1, TEXTBOX_INNERW + call ClearBox + call UnloadBlinkingCursor + ld c, 20 + call DelayFrames + hlcoord TEXTBOX_INNERX, TEXTBOX_INNERY + pop de + jp NextChar +; 131f + + +Char4B:: ; 131f + ld a, [wLinkMode] + or a + jr nz, .communication + call LoadBlinkingCursor + +.communication + call Function13b6 + + push de + call ButtonSound + pop de + + ld a, [wLinkMode] + or a + call z, UnloadBlinkingCursor + +Char4C:: ; 1337 + push de + call TextScroll + call TextScroll + hlcoord TEXTBOX_INNERX, TEXTBOX_INNERY + 2 + pop de + jp NextChar +; 1345 + + +ContText:: ; 1345 + push de + ld de, .cont + ld b, h + ld c, l + call PlaceString + ld h, b + ld l, c + pop de + jp NextChar + +.cont db $4b, "@" +; 1356 + + +PlaceDexEnd:: ; 1356 +; Legacy: ends a Pokédex entry (Red). +; Dex entries are now regular strings. + ld [hl], "." + pop hl + ret +; 135a + +PromptText:: ; 135a + ld a, [wLinkMode] + cp LINK_COLOSSEUM + jr z, .ok + cp LINK_MOBILE + jr z, .ok + call LoadBlinkingCursor + +.ok + call Function13b6 + call ButtonSound + ld a, [wLinkMode] + cp LINK_COLOSSEUM + jr z, DoneText + cp LINK_MOBILE + jr z, DoneText + call UnloadBlinkingCursor + +DoneText:: ; 137c + pop hl + ld de, .stop + dec de + ret +.stop db "@" +; 1383 + +NullChar:: ; 1383 + ld a, "?" + ld [hli], a + call PrintLetterDelay + jp NextChar +; 138c + +TextScroll:: ; 138c + hlcoord TEXTBOX_INNERX, TEXTBOX_INNERY + decoord TEXTBOX_INNERX, TEXTBOX_INNERY - 1 + ld a, TEXTBOX_INNERH - 1 + +.col + push af + ld c, TEXTBOX_INNERW + +.row + ld a, [hli] + ld [de], a + inc de + dec c + jr nz, .row + +rept 2 + inc de +endr +rept 2 + inc hl +endr + pop af + dec a + jr nz, .col + + hlcoord TEXTBOX_INNERX, TEXTBOX_INNERY + 2 + ld a, " " + ld bc, TEXTBOX_INNERW + call ByteFill + ld c, 5 + call DelayFrames + ret +; 13b6 + +Function13b6:: ; 13b6 + push bc + ld a, [hOAMUpdate] + push af + ld a, 1 + ld [hOAMUpdate], a + + call WaitBGMap + + pop af + ld [hOAMUpdate], a + pop bc + ret +; 13c6 + +Diacritic:: ; 13c6 + ret +; 13c7 + +LoadBlinkingCursor:: ; 13c7 + ld a, "▼" + ldcoord_a 18, 17 + ret +; 13cd + +UnloadBlinkingCursor:: ; 13cd + lda_coord 17, 17 + ldcoord_a 18, 17 + ret +; 13d4 + +FarString:: ; 13d4 + ld b, a + ld a, [hROMBank] + push af + + ld a, b + rst Bankswitch + call PlaceString + + pop af + rst Bankswitch + ret +; 13e0 + +PokeFluteTerminatorCharacter:: ; 13e0 + ld hl, .stop + ret + +.stop db "@" +; 13e5 + + +PlaceWholeStringInBoxAtOnce:: ; 13e5 + ld a, [TextBoxFlags] + push af + set 1, a + ld [TextBoxFlags], a + + call DoTextUntilTerminator + + pop af + ld [TextBoxFlags], a + ret +; 13f6 + +DoTextUntilTerminator:: ; 13f6 + ld a, [hli] + cp "@" + ret z + call .TextCommand + jr DoTextUntilTerminator + +.TextCommand: + push hl + push bc + ld c, a + ld b, 0 + ld hl, TextCommands +rept 2 + add hl, bc +endr + ld e, [hl] + inc hl + ld d, [hl] + pop bc + pop hl + + ; jp de + push de + ret +; 1410 + +TextCommands:: ; 1410 + dw Text_TX + dw Text_TX_RAM + dw Text_TX_BCD + dw Text_TX_MOVE + dw Text_TX_BOX + dw Text_TX_LOW + dw Text_WAIT_BUTTON + dw Text_TX_SCROLL + dw Text_START_ASM + dw Text_TX_NUM + dw Text_TX_EXIT + dw Text_PlaySound ; $0b + dw Text_TX_DOTS + dw Text_0D + dw Text_PlaySound ; $0e + dw Text_PlaySound ; $0f + dw Text_PlaySound ; $10 + dw Text_PlaySound ; $11 + dw Text_PlaySound ; $12 + dw Text_PlaySound ; $13 + dw Text_TX_STRINGBUFFER + dw Text_TX_DAY + dw Text_TX_FAR +; 143e + +Text_TX:: ; 143e +; TX +; write text until "@" +; [$00]["...@"] + + ld d, h + ld e, l + ld h, b + ld l, c + call PlaceString + ld h, d + ld l, e + inc hl + ret +; 1449 + +Text_TX_RAM:: ; 1449 +; text_from_ram +; write text from a ram address +; little endian +; [$01][addr] + + ld a, [hli] + ld e, a + ld a, [hli] + ld d, a + push hl + ld h, b + ld l, c + call PlaceString + pop hl + ret +; 1455 + +Text_TX_FAR:: ; 1455 +; text_jump +; write text from a different bank +; little endian +; [$16][addr][bank] + + ld a, [hROMBank] + push af + + ld a, [hli] + ld e, a + ld a, [hli] + ld d, a + ld a, [hli] + + ld [hROMBank], a + ld [MBC3RomBank], a + + push hl + ld h, d + ld l, e + call DoTextUntilTerminator + pop hl + + pop af + ld [hROMBank], a + ld [MBC3RomBank], a + ret +; 1470 + +Text_TX_BCD:: ; 1470 +; TX_BCD +; write bcd from address, typically ram +; [$02][addr][flags] +; flags: see PrintBCDNumber + + ld a, [hli] + ld e, a + ld a, [hli] + ld d, a + ld a, [hli] + push hl + ld h, b + ld l, c + ld c, a + call PrintBCDNumber + ld b, h + ld c, l + pop hl + ret +; 1480 + +Text_TX_MOVE:: ; 1480 +; TX_MOVE +; move to a new tile +; [$03][addr] + + ld a, [hli] + ld [wMenuScrollPosition + 2], a + ld c, a + ld a, [hli] + ld [wMenuScrollPosition + 2 + 1], a + ld b, a + ret +; 148b + +Text_TX_BOX:: ; 148b +; TX_BOX +; draw a box +; little endian +; [$04][addr][height][width] + + ld a, [hli] + ld e, a + ld a, [hli] + ld d, a + ld a, [hli] + ld b, a + ld a, [hli] + ld c, a + push hl + ld h, d + ld l, e + call TextBox + pop hl + ret +; 149b + +Text_TX_LOW:: ; 149b +; TX_LOW +; write text at (1,16) +; [$05] + + bccoord TEXTBOX_INNERX, TEXTBOX_INNERY + 2 + ret +; 149f + +Text_WAIT_BUTTON:: ; 149f +; TX_WAITBUTTON +; wait for button press +; show arrow +; [06] + + ld a, [wLinkMode] + cp LINK_COLOSSEUM + jp z, Text_0D + cp LINK_MOBILE + jp z, Text_0D + + push hl + call LoadBlinkingCursor + push bc + call ButtonSound + pop bc + call UnloadBlinkingCursor + pop hl + ret +; 14ba + +Text_TX_SCROLL:: ; 14ba +; pushes text up two lines and sets the BC cursor to the border tile +; below the first character column of the text box. + push hl + call UnloadBlinkingCursor + call TextScroll + call TextScroll + pop hl + bccoord TEXTBOX_INNERX, TEXTBOX_INNERY + 2 + ret +; 14c9 + +Text_START_ASM:: ; 14c9 +; TX_ASM + + bit 7, h + jr nz, .not_rom + jp [hl] + +.not_rom + ld a, "@" + ld [hl], a + ret +; 14d2 + +Text_TX_NUM:: ; 14d2 +; TX_NUM +; [$09][addr][hi:bytes lo:digits] + ld a, [hli] + ld e, a + ld a, [hli] + ld d, a + ld a, [hli] + push hl + ld h, b + ld l, c + ld b, a + and $f + ld c, a + ld a, b + and $f0 + swap a + set PRINTNUM_RIGHTALIGN_F, a + ld b, a + call PrintNum + ld b, h + ld c, l + pop hl + ret +; 14ed + +Text_TX_EXIT:: ; 14ed + push hl + push bc + call GetJoypad + ld a, [hJoyDown] + and A_BUTTON | B_BUTTON + jr nz, .done + ld c, 30 + call DelayFrames +.done + pop bc + pop hl + ret +; 1500 + +Text_PlaySound:: ; 1500 +; chars: +; $0b, $0e, $0f, $10, $11, $12, $13 +; see TextSFX + + push bc + dec hl + ld a, [hli] + ld b, a + push hl + ld hl, TextSFX +.loop + ld a, [hli] + cp -1 + jr z, .done + cp b + jr z, .play +rept 2 + inc hl +endr + jr .loop + +.play + push de + ld e, [hl] + inc hl + ld d, [hl] + call PlaySFX + call WaitSFX + pop de + +.done + pop hl + pop bc + ret +; 1522 + +Function1522:: ; 1522 + push de + ld e, [hl] + inc hl + ld d, [hl] + call PlayCry + pop de + pop hl + pop bc + ret +; 152d + +TextSFX:: ; 152d + dbw TX_SOUND_0B, SFX_DEX_FANFARE_50_79 + dbw TX_SOUND_12, SFX_FANFARE + dbw TX_SOUND_0E, SFX_DEX_FANFARE_20_49 + dbw TX_SOUND_0F, SFX_ITEM + dbw TX_SOUND_10, SFX_CAUGHT_MON + dbw TX_SOUND_11, SFX_DEX_FANFARE_80_109 + dbw TX_SOUND_13, SFX_SLOT_MACHINE_START + db -1 +; 1543 + +Text_TX_DOTS:: ; 1543 +; [$0C][num] + ld a, [hli] + ld d, a + push hl + ld h, b + ld l, c + +.loop + push de + ld a, "…" + ld [hli], a + call GetJoypad + ld a, [hJoyDown] + and A_BUTTON | B_BUTTON + jr nz, .next + ld c, 10 + call DelayFrames +.next + pop de + dec d + jr nz, .loop + + ld b, h + ld c, l + pop hl + ret +; 1562 + +Text_0D:: ; 1562 +; wait for key down +; display arrow + push hl + push bc + call ButtonSound + pop bc + pop hl + ret +; 156a + +Text_TX_STRINGBUFFER:: ; 156a +; Print a string from one of the following: +; 0: StringBuffer3 +; 1: StringBuffer4 +; 2: StringBuffer5 +; 3: StringBuffer2 +; 4: StringBuffer1 +; 5: EnemyMonNick +; 6: BattleMonNick +; [$14][id] + + ld a, [hli] + push hl + ld e, a + ld d, 0 + ld hl, StringBufferPointers +rept 2 + add hl, de +endr + ld a, BANK(StringBufferPointers) + call GetFarHalfword + ld d, h + ld e, l + ld h, b + ld l, c + call PlaceString + pop hl + ret +; 1582 + +Text_TX_DAY:: ; 1582 +; TX_DAY + + call GetWeekday + push hl + push bc + ld c, a + ld b, 0 + ld hl, .Days +rept 2 + add hl, bc +endr + ld a, [hli] + ld h, [hl] + ld l, a + ld d, h + ld e, l + pop hl + call PlaceString + ld h, b + ld l, c + ld de, .Day + call PlaceString + pop hl + ret + +.Days ; 15a2 + dw .Sun + dw .Mon + dw .Tues + dw .Wednes + dw .Thurs + dw .Fri + dw .Satur + +.Sun db "SUN@" +.Mon db "MON@" +.Tues db "TUES@" +.Wednes db "WEDNES@" +.Thurs db "THURS@" +.Fri db "FRI@" +.Satur db "SATUR@" +.Day db "DAY@" +; 15d8 diff --git a/home/tilemap.asm b/home/tilemap.asm new file mode 100644 index 00000000..152f7568 --- /dev/null +++ b/home/tilemap.asm @@ -0,0 +1,257 @@ +PushWindow:: ; 1c00 + callab _PushWindow + ret +; 1c07 + +ExitMenu:: ; 0x1c07 + push af + callab _ExitMenu + pop af + ret + +InitVerticalMenuCursor:: ; 0x1c10 + callab _InitVerticalMenuCursor + ret + +CloseWindow:: ; 0x1c17 + push af + call ExitMenu + call ApplyTilemap + call UpdateSprites + pop af + ret + +RestoreTileBackup:: ; 0x1c23 + call MenuBoxCoord2Tile + call .copy + call MenuBoxCoord2Attr + call .copy + ret +; 0x1c30 + +.copy: ; 0x1c30 + call GetMenuBoxDims + inc b + inc c + +.row + push bc + push hl + +.col + ld a, [de] + ld [hli], a + dec de + dec c + jr nz, .col ; 0x1c3b $fa + + pop hl + ld bc, SCREEN_WIDTH + add hl, bc + pop bc + dec b + jr nz, .row ; 0x1c44 $ef + + ret + +PopWindow:: ; 0x1c47 + ld b, $10 + ld de, wMenuFlags +.loop + ld a, [hld] + ld [de], a + inc de + dec b + jr nz, .loop ; 0x1c50 $fa + ret + +GetMenuBoxDims:: ; 0x1c53 + ld a, [wMenuBorderTopCoord] ; top + ld b, a + ld a, [wMenuBorderBottomCoord] ; bottom + sub b + ld b, a + ld a, [wMenuBorderLeftCoord] ; left + ld c, a + ld a, [wMenuBorderRightCoord] ; right + sub c + ld c, a + ret +; 0x1c66 + +CopyMenuData2:: ; 1c66 + push hl + push de + push bc + push af + ld hl, wMenuData2Pointer + ld a, [hli] + ld h, [hl] + ld l, a + ld de, wMenuData2Flags + ld bc, wMenuData2End - wMenuData2Flags + call CopyBytes + pop af + pop bc + pop de + pop hl + ret +; 1c7e + +GetWindowStackTop:: ; 1c7e + ld hl, wWindowStackPointer + ld a, [hli] + ld h, [hl] + ld l, a + inc hl + ld a, [hli] + ld h, [hl] + ld l, a + ret +; 1c89 + +PlaceVerticalMenuItems:: ; 1c89 + call CopyMenuData2 + ld hl, wMenuData2Pointer + ld e, [hl] + inc hl + ld d, [hl] + call GetMenuTextStartCoord + call Coord2Tile ; hl now contains the TileMap address where we will start printing text. + inc de + ld a, [de] ; Number of items + inc de + ld b, a +.loop + push bc + call PlaceString + inc de + ld bc, 2 * SCREEN_WIDTH + add hl, bc + pop bc + dec b + jr nz, .loop + + ld a, [wMenuData2Flags] + bit 4, a + ret z + + call MenuBoxCoord2Tile + ld a, [de] + ld c, a + inc de + ld b, $0 + add hl, bc + jp PlaceString +; 1cbb + +MenuBox:: ; 1cbb + call MenuBoxCoord2Tile + call GetMenuBoxDims + dec b + dec c + jp TextBox +; 1cc6 + +GetMenuTextStartCoord:: ; 1cc6 + ld a, [wMenuBorderTopCoord] + ld b, a + inc b + ld a, [wMenuBorderLeftCoord] + ld c, a + inc c +; bit 6: if not set, leave extra room on top + ld a, [wMenuData2Flags] + bit 6, a + jr nz, .bit_6_set + inc b + +.bit_6_set +; bit 7: if set, leave extra room on the left + ld a, [wMenuData2Flags] + bit 7, a + jr z, .bit_7_clear + inc c + +.bit_7_clear + ret +; 1ce1 + +ClearMenuBoxInterior:: ; 1ce1 + call MenuBoxCoord2Tile + ld bc, SCREEN_WIDTH + 1 + add hl, bc + call GetMenuBoxDims + dec b + dec c + call ClearBox + ret +; 1cf1 + +ClearWholeMenuBox:: ; 1cf1 + call MenuBoxCoord2Tile + call GetMenuBoxDims + inc c + inc b + call ClearBox + ret +; 1cfd + + +MenuBoxCoord2Tile:: ; 1cfd + ld a, [wMenuBorderLeftCoord] + ld c, a + ld a, [wMenuBorderTopCoord] + ld b, a +; 1d05 + + +Coord2Tile:: ; 1d05 +; Return the address of TileMap(c, b) in hl. + xor a + ld h, a + ld l, b + ld a, c + ld b, h + ld c, l + add hl, hl + add hl, hl + add hl, bc + add hl, hl + add hl, hl + ld c, a + xor a + ld b, a + add hl, bc + bccoord 0, 0 + add hl, bc + ret +; 1d19 + +MenuBoxCoord2Attr:: ; 1d19 + ld a, [wMenuBorderLeftCoord] + ld c, a + ld a, [wMenuBorderTopCoord] + ld b, a + +Coord2Attr:: ; 1d21 +; Return the address of AttrMap(c, b) in hl. + xor a + ld h, a + ld l, b + ld a, c + ld b, h + ld c, l + add hl, hl + add hl, hl + add hl, bc + add hl, hl + add hl, hl + ld c, a + xor a + ld b, a + add hl, bc + bccoord 0, 0, AttrMap + add hl, bc + ret +; 1d35 diff --git a/home/time.asm b/home/time.asm new file mode 100644 index 00000000..2d432be3 --- /dev/null +++ b/home/time.asm @@ -0,0 +1,312 @@ +; Functions relating to the timer interrupt and the real-time-clock. + + +AskTimer:: ; 591 + push af + ld a, [hMobile] + and a + jr z, .not_mobile + call Timer + +.not_mobile + pop af + reti +; 59c + + +LatchClock:: ; 59c +; latch clock counter data + ld a, 0 + ld [MBC3LatchClock], a + ld a, 1 + ld [MBC3LatchClock], a + ret +; 5a7 + + +UpdateTime:: ; 5a7 + call GetClock + call FixDays + call FixTime + callba GetTimeOfDay + ret +; 5b7 + + +GetClock:: ; 5b7 +; store clock data in hRTCDayHi-hRTCSeconds + +; enable clock r/w + ld a, SRAM_ENABLE + ld [MBC3SRamEnable], a + +; clock data is 'backwards' in hram + + call LatchClock + ld hl, MBC3SRamBank + ld de, MBC3RTC + + ld [hl], RTC_S + ld a, [de] + and $3f + ld [hRTCSeconds], a + + ld [hl], RTC_M + ld a, [de] + and $3f + ld [hRTCMinutes], a + + ld [hl], RTC_H + ld a, [de] + and $1f + ld [hRTCHours], a + + ld [hl], RTC_DL + ld a, [de] + ld [hRTCDayLo], a + + ld [hl], RTC_DH + ld a, [de] + ld [hRTCDayHi], a + +; unlatch clock / disable clock r/w + call CloseSRAM + ret +; 5e8 + + +FixDays:: ; 5e8 +; fix day count +; mod by 140 + +; check if day count > 255 (bit 8 set) + ld a, [hRTCDayHi] ; DH + bit 0, a + jr z, .daylo +; reset dh (bit 8) + res 0, a + ld [hRTCDayHi], a ; DH + +; mod 140 +; mod twice since bit 8 (DH) was set + ld a, [hRTCDayLo] ; DL +.modh + sub 140 + jr nc, .modh +.modl + sub 140 + jr nc, .modl + add 140 + +; update dl + ld [hRTCDayLo], a ; DL + +; flag for sRTCStatusFlags + ld a, %01000000 + jr .set + +.daylo +; quit if fewer than 140 days have passed + ld a, [hRTCDayLo] ; DL + cp 140 + jr c, .quit + +; mod 140 +.mod + sub 140 + jr nc, .mod + add 140 + +; update dl + ld [hRTCDayLo], a ; DL + +; flag for sRTCStatusFlags + ld a, %00100000 + +.set +; update clock with modded day value + push af + call SetClock + pop af + scf + ret + +.quit + xor a + ret +; 61d + + +FixTime:: ; 61d +; add ingame time (set at newgame) to current time +; day hr min sec +; store time in CurDay, hHours, hMinutes, hSeconds + +; second + ld a, [hRTCSeconds] ; S + ld c, a + ld a, [StartSecond] + add c + sub 60 + jr nc, .updatesec + add 60 +.updatesec + ld [hSeconds], a + +; minute + ccf ; carry is set, so turn it off + ld a, [hRTCMinutes] ; M + ld c, a + ld a, [StartMinute] + adc c + sub 60 + jr nc, .updatemin + add 60 +.updatemin + ld [hMinutes], a + +; hour + ccf ; carry is set, so turn it off + ld a, [hRTCHours] ; H + ld c, a + ld a, [StartHour] + adc c + sub 24 + jr nc, .updatehr + add 24 +.updatehr + ld [hHours], a + +; day + ccf ; carry is set, so turn it off + ld a, [hRTCDayLo] ; DL + ld c, a + ld a, [StartDay] + adc c + ld [CurDay], a + ret +; 658 + +SetTimeOfDay:: ; 658 + xor a + ld [StringBuffer2], a + ld a, $0 ; useless + ld [StringBuffer2 + 3], a + jr InitTime + +SetDayOfWeek:: ; 663 + call UpdateTime + ld a, [hHours] + ld [StringBuffer2 + 1], a + ld a, [hMinutes] + ld [StringBuffer2 + 2], a + ld a, [hSeconds] + ld [StringBuffer2 + 3], a + jr InitTime ; useless + +InitTime:: ; 677 + callba _InitTime + ret +; 67e + + + +PanicResetClock:: ; 67e + call .ClearhRTC + call SetClock + ret +; 685 + +.ClearhRTC ; 685 + xor a + ld [hRTCSeconds], a + ld [hRTCMinutes], a + ld [hRTCHours], a + ld [hRTCDayLo], a + ld [hRTCDayHi], a + ret +; 691 + + +SetClock:: ; 691 +; set clock data from hram + +; enable clock r/w + ld a, SRAM_ENABLE + ld [MBC3SRamEnable], a + +; set clock data +; stored 'backwards' in hram + + call LatchClock + ld hl, MBC3SRamBank + ld de, MBC3RTC + +; seems to be a halt check that got partially commented out +; this block is totally pointless + ld [hl], RTC_DH + ld a, [de] + bit 6, a ; halt + ld [de], a + +; seconds + ld [hl], RTC_S + ld a, [hRTCSeconds] + ld [de], a +; minutes + ld [hl], RTC_M + ld a, [hRTCMinutes] + ld [de], a +; hours + ld [hl], RTC_H + ld a, [hRTCHours] + ld [de], a +; day lo + ld [hl], RTC_DL + ld a, [hRTCDayLo] + ld [de], a +; day hi + ld [hl], RTC_DH + ld a, [hRTCDayHi] + res 6, a ; make sure timer is active + ld [de], a + +; cleanup + call CloseSRAM ; unlatch clock, disable clock r/w + ret +; 6c4 + + +ClearRTCStatus:: ; 6c4 +; clear sRTCStatusFlags + xor a + push af + ld a, BANK(sRTCStatusFlags) + call GetSRAMBank + pop af + ld [sRTCStatusFlags], a + call CloseSRAM + ret +; 6d3 + +RecordRTCStatus:: ; 6d3 +; append flags to sRTCStatusFlags + ld hl, sRTCStatusFlags + push af + ld a, BANK(sRTCStatusFlags) + call GetSRAMBank + pop af + or [hl] + ld [hl], a + call CloseSRAM + ret +; 6e3 + +CheckRTCStatus:: ; 6e3 +; check sRTCStatusFlags + ld a, BANK(sRTCStatusFlags) + call GetSRAMBank + ld a, [sRTCStatusFlags] + call CloseSRAM + ret +; 6ef diff --git a/home/vblank.asm b/home/vblank.asm new file mode 100644 index 00000000..1c0824c5 --- /dev/null +++ b/home/vblank.asm @@ -0,0 +1,442 @@ +; VBlank is the interrupt responsible for updating VRAM. + +; In Pokemon Crystal, VBlank has been hijacked to act as the +; main loop. After time-sensitive graphics operations have been +; performed, joypad input and sound functions are executed. + +; This prevents the display and audio output from lagging. + + +VBlank:: ; 283 + push af + push bc + push de + push hl + + ld a, [hVBlank] + and 7 + + ld e, a + ld d, 0 + ld hl, .VBlanks +rept 2 + add hl, de +endr + ld a, [hli] + ld h, [hl] + ld l, a + + call _hl_ + + call GameTimer + + pop hl + pop de + pop bc + pop af + reti +; 2a1 + +.VBlanks ; 2a1 + dw VBlank0 + dw VBlank1 + dw VBlank2 + dw VBlank3 + dw VBlank4 + dw VBlank5 + dw VBlank6 + dw VBlank0 ; just in case +; 2b1 + + +VBlank0:: ; 2b1 +; normal operation + +; rng +; scx, scy, wy, wx +; bg map buffer +; palettes +; dma transfer +; bg map +; tiles +; oam +; joypad +; sound + + ; inc frame counter + ld hl, hVBlankCounter + inc [hl] + + ; advance random variables + ld a, [rDIV] + ld b, a + ld a, [hRandomAdd] + adc b + ld [hRandomAdd], a + + ld a, [rDIV] + ld b, a + ld a, [hRandomSub] + sbc b + ld [hRandomSub], a + + ld a, [hROMBank] + ld [hROMBankBackup], a + + ld a, [hSCX] + ld [rSCX], a + ld a, [hSCY] + ld [rSCY], a + ld a, [hWY] + ld [rWY], a + ld a, [hWX] + ld [rWX], a + + ; There's only time to call one of these in one vblank. + ; Calls are in order of priority. + + call UpdateBGMapBuffer + jr c, .done + call UpdatePalsIfCGB + jr c, .done + call DMATransfer + jr c, .done + call UpdateBGMap + + ; These have their own timing checks. + + call Serve2bppRequest + call Serve1bppRequest + call AnimateTileset + +.done + + ld a, [hOAMUpdate] + and a + jr nz, .done_oam + call hPushOAM +.done_oam + + + ; vblank-sensitive operations are done + + xor a + ld [VBlankOccurred], a + + ld a, [OverworldDelay] + and a + jr z, .ok + dec a + ld [OverworldDelay], a +.ok + + ld a, [TextDelayFrames] + and a + jr z, .ok2 + dec a + ld [TextDelayFrames], a +.ok2 + + call Joypad + + ld a, BANK(_UpdateSound) + rst Bankswitch + call _UpdateSound + ld a, [hROMBankBackup] + rst Bankswitch + + ld a, [hSeconds] + ld [hSecondsBackup], a + + ret +; 325 + + +VBlank2:: ; 325 +; sound only + + ld a, [hROMBank] + ld [hROMBankBackup], a + + ld a, BANK(_UpdateSound) + rst Bankswitch + call _UpdateSound + + ld a, [hROMBankBackup] + rst Bankswitch + + xor a + ld [VBlankOccurred], a + ret +; 337 + + +VBlank1:: ; 337 +; scx, scy +; palettes +; bg map +; tiles +; oam +; sound / lcd stat + + ld a, [hROMBank] + ld [hROMBankBackup], a + + ld a, [hSCX] + ld [rSCX], a + ld a, [hSCY] + ld [rSCY], a + + call UpdatePals + jr c, .done + + call UpdateBGMap + call Serve2bppRequest@VBlank + + call hPushOAM +.done + + xor a + ld [VBlankOccurred], a + + ; get requested ints + ld a, [rIF] + ld b, a + ; discard requested ints + xor a + ld [rIF], a + ; enable lcd stat + ld a, %10 ; lcd stat + ld [rIE], a + ; rerequest serial int if applicable (still disabled) + ; request lcd stat + ld a, b + and %1000 ; serial + or %10 ; lcd stat + ld [rIF], a + + ei + ld a, BANK(_UpdateSound) + rst Bankswitch + call _UpdateSound + ld a, [hROMBankBackup] + rst Bankswitch + di + + ; get requested ints + ld a, [rIF] + ld b, a + ; discard requested ints + xor a + ld [rIF], a + ; enable ints besides joypad + ld a, %1111 ; serial timer lcdstat vblank + ld [rIE], a + ; rerequest ints + ld a, b + ld [rIF], a + ret +; 37f + + +UpdatePals:: ; 37f +; update pals for either dmg or cgb + + ld a, [hCGB] + and a + jp nz, UpdateCGBPals + + ; update gb pals + ld a, [wBGP] + ld [rBGP], a + ld a, [wOBP0] + ld [rOBP0], a + ld a, [wOBP1] + ld [rOBP1], a + + and a + ret +; 396 + + +VBlank3:: ; 396 +; scx, scy +; palettes +; bg map +; tiles +; oam +; sound / lcd stat + + ld a, [hROMBank] + ld [hROMBankBackup], a + + ld a, [hSCX] + ld [rSCX], a + ld a, [hSCY] + ld [rSCY], a + + ld a, [hCGBPalUpdate] + and a + call nz, ForceUpdateCGBPals + jr c, .done + + call UpdateBGMap + call Serve2bppRequest@VBlank + + call hPushOAM +.done + + xor a + ld [VBlankOccurred], a + + ld a, [rIF] + push af + xor a + ld [rIF], a + ld a, %10 ; lcd stat + ld [rIE], a + ld [rIF], a + + ei + ld a, BANK(_UpdateSound) + rst Bankswitch + call _UpdateSound + ld a, [hROMBankBackup] + rst Bankswitch + di + + ; request lcdstat + ld a, [rIF] + ld b, a + ; and any other ints + pop af + or b + ld b, a + ; reset ints + xor a + ld [rIF], a + ; enable ints besides joypad + ld a, %1111 ; serial timer lcdstat vblank + ld [rIE], a + ; request ints + ld a, b + ld [rIF], a + ret +; 3df + + +VBlank4:: ; 3df +; bg map +; tiles +; oam +; joypad +; serial +; sound + + ld a, [hROMBank] + ld [hROMBankBackup], a + + call UpdateBGMap + call Serve2bppRequest + + call hPushOAM + + call Joypad + + xor a + ld [VBlankOccurred], a + + call AskSerial + + ld a, BANK(_UpdateSound) + rst Bankswitch + call _UpdateSound + + ld a, [hROMBankBackup] + rst Bankswitch + ret +; 400 + + +VBlank5:: ; 400 +; scx +; palettes +; bg map +; tiles +; joypad +; + + ld a, [hROMBank] + ld [hROMBankBackup], a + + ld a, [hSCX] + ld [rSCX], a + + call UpdatePalsIfCGB + jr c, .done + + call UpdateBGMap + call Serve2bppRequest +.done + + xor a + ld [VBlankOccurred], a + + call Joypad + + xor a + ld [rIF], a + ld a, %10 ; lcd stat + ld [rIE], a + ; request lcd stat + ld [rIF], a + + ei + ld a, BANK(_UpdateSound) + rst Bankswitch + call _UpdateSound + ld a, [hROMBankBackup] + rst Bankswitch + di + + xor a + ld [rIF], a + ; enable ints besides joypad + ld a, %1111 ; serial timer lcdstat vblank + ld [rIE], a + ret +; 436 + + +VBlank6:: ; 436 +; palettes +; tiles +; dma transfer +; sound + + ld a, [hROMBank] + ld [hROMBankBackup], a + + ; inc frame counter + ld hl, hVBlankCounter + inc [hl] + + call UpdateCGBPals + jr c, .done + + call Serve2bppRequest + call Serve1bppRequest + call DMATransfer +.done + + xor a + ld [VBlankOccurred], a + + ld a, BANK(_UpdateSound) + rst Bankswitch + call _UpdateSound + + ld a, [hROMBankBackup] + rst Bankswitch + ret +; 45a diff --git a/home/video.asm b/home/video.asm new file mode 100644 index 00000000..c88e0e55 --- /dev/null +++ b/home/video.asm @@ -0,0 +1,486 @@ +; Functions dealing with VRAM. + +DMATransfer:: ; 15d8 +; Return carry if the transfer is completed. + + ld a, [hDMATransfer] + and a + ret z + +; Start transfer + ld [rHDMA5], a + +; Execution is halted until the transfer is complete. + + xor a + ld [hDMATransfer], a + scf + ret +; 15e3 + + +UpdateBGMapBuffer:: ; 15e3 +; Copy [hFFDC] 16x8 tiles from BGMapBuffer +; to bg map addresses in BGMapBufferPtrs. + +; [hFFDC] must be even since this is done in pairs. + +; Return carry on success. + + ld a, [hBGMapUpdate] + and a + ret z + + ld a, [rVBK] + push af + ld [hSPBuffer], sp + + ld hl, BGMapBufferPtrs + ld sp, hl + +; We can now pop the addresses of affected spots on the BG Map + + ld hl, BGMapPalBuffer + ld de, BGMapBuffer + + +.next +; Copy a pair of 16x8 blocks (one 16x16 block) + +rept 2 +; Get our BG Map address + pop bc + +; Palettes + ld a, 1 + ld [rVBK], a + + ld a, [hli] + ld [bc], a + inc c + ld a, [hli] + ld [bc], a + dec c + +; Tiles + ld a, 0 + ld [rVBK], a + + ld a, [de] + inc de + ld [bc], a + inc c + ld a, [de] + inc de + ld [bc], a +endr + +; We've done 2 16x8 blocks + ld a, [hFFDC] + dec a + dec a + ld [hFFDC], a + + jr nz, .next + + + ld a, [hSPBuffer] + ld l, a + ld a, [hSPBuffer + 1] + ld h, a + ld sp, hl + + pop af + ld [rVBK], a + + xor a + ld [hBGMapUpdate], a + scf + ret +; 163a + + +WaitTop:: ; 163a +; Wait until the top third of the BG Map is being updated. + + ld a, [hBGMapMode] + and a + ret z + + ld a, [hBGMapThird] + and a + jr z, .done + + call DelayFrame + jr WaitTop + +.done + xor a + ld [hBGMapMode], a + ret +; 164c + + +UpdateBGMap:: ; 164c +; Update the BG Map, in thirds, from TileMap and AttrMap. + + ld a, [hBGMapMode] + and a + ret z + +; BG Map 0 + dec a ; 1 + jr z, .Tiles + dec a ; 2 + jr z, .Attr + +; BG Map 1 + dec a + + ld a, [hBGMapAddress] + ld l, a + ld a, [hBGMapAddress + 1] + ld h, a + push hl + + xor a + ld [hBGMapAddress], a + ld a, VBGMap1 >> 8 + ld [hBGMapAddress + 1], a + + ld a, [hBGMapMode] + push af + cp 3 + call z, .Tiles + pop af + cp 4 + call z, .Attr + + pop hl + ld a, l + ld [hBGMapAddress], a + ld a, h + ld [hBGMapAddress + 1], a + ret + + +.Attr + ld a, 1 + ld [rVBK], a + + hlcoord 0, 0, AttrMap + call .update + + ld a, 0 + ld [rVBK], a + ret + + +.Tiles + hlcoord 0, 0 + + +.update + ld [hSPBuffer], sp + +; Which third? + ld a, [hBGMapThird] + and a ; 0 + jr z, .top + dec a ; 1 + jr z, .middle + ; 2 + + +THIRD_HEIGHT EQU SCREEN_HEIGHT / 3 + + +.bottom + ld de, 2 * THIRD_HEIGHT * SCREEN_WIDTH + add hl, de + ld sp, hl + + ld a, [hBGMapAddress + 1] + ld h, a + ld a, [hBGMapAddress] + ld l, a + + ld de, 2 * THIRD_HEIGHT * BG_MAP_WIDTH + add hl, de + +; Next time: top third + xor a + jr .start + + +.middle + ld de, THIRD_HEIGHT * SCREEN_WIDTH + add hl, de + ld sp, hl + + ld a, [hBGMapAddress + 1] + ld h, a + ld a, [hBGMapAddress] + ld l, a + + ld de, THIRD_HEIGHT * BG_MAP_WIDTH + add hl, de + +; Next time: bottom third + ld a, 2 + jr .start + + +.top + ld sp, hl + + ld a, [hBGMapAddress + 1] + ld h, a + ld a, [hBGMapAddress] + ld l, a + +; Next time: middle third + ld a, 1 + + +.start +; Which third to update next time + ld [hBGMapThird], a + +; Rows of tiles in a third + ld a, SCREEN_HEIGHT / 3 + +; Discrepancy between TileMap and BGMap + ld bc, BG_MAP_WIDTH - (SCREEN_WIDTH - 1) + + +.row +; Copy a row of 20 tiles +rept SCREEN_WIDTH / 2 - 1 + pop de + ld [hl], e + inc l + ld [hl], d + inc l +endr + pop de + ld [hl], e + inc l + ld [hl], d + + add hl, bc + dec a + jr nz, .row + + + ld a, [hSPBuffer] + ld l, a + ld a, [hSPBuffer + 1] + ld h, a + ld sp, hl + ret +; 170a + + +Serve1bppRequest:: ; 170a +; Only call during the first fifth of VBlank + + ld a, [Requested1bpp] + and a + ret z + +; Back out if we're too far into VBlank + ld a, [rLY] + cp 144 + ret c + cp 146 + ret nc + +; Copy [Requested1bpp] 1bpp tiles from [Requested1bppSource] to [Requested1bppDest] + + ld [hSPBuffer], sp + +; Source + ld hl, Requested1bppSource + ld a, [hli] + ld h, [hl] + ld l, a + ld sp, hl + +; Destination + ld hl, Requested1bppDest + ld a, [hli] + ld h, [hl] + ld l, a + +; # tiles to copy + ld a, [Requested1bpp] + ld b, a + + xor a + ld [Requested1bpp], a + +.next + +rept 3 + pop de + ld [hl], e + inc l + ld [hl], e + inc l + ld [hl], d + inc l + ld [hl], d + inc l +endr + pop de + ld [hl], e + inc l + ld [hl], e + inc l + ld [hl], d + inc l + ld [hl], d + + inc hl + dec b + jr nz, .next + + + ld a, l + ld [Requested1bppDest], a + ld a, h + ld [Requested1bppDest + 1], a + + ld [Requested1bppSource], sp + + ld a, [hSPBuffer] + ld l, a + ld a, [hSPBuffer + 1] + ld h, a + ld sp, hl + ret +; 1769 + + +Serve2bppRequest:: ; 1769 +; Only call during the first fifth of VBlank + + ld a, [Requested2bpp] + and a + ret z + +; Back out if we're too far into VBlank + ld a, [rLY] + cp 144 + ret c + cp 146 + ret nc + jr _Serve2bppRequest + + +Serve2bppRequest@VBlank:: ; 1778 + + ld a, [Requested2bpp] + and a + ret z + +_Serve2bppRequest:: ; 177d +; Copy [Requested2bpp] 2bpp tiles from [Requested2bppSource] to [Requested2bppDest] + + ld [hSPBuffer], sp + +; Source + ld hl, Requested2bppSource + ld a, [hli] + ld h, [hl] + ld l, a + ld sp, hl + +; Destination + ld hl, Requested2bppDest + ld a, [hli] + ld h, [hl] + ld l, a + +; # tiles to copy + ld a, [Requested2bpp] + ld b, a + + xor a + ld [Requested2bpp], a + +.next + +rept 7 + pop de + ld [hl], e + inc l + ld [hl], d + inc l +endr + pop de + ld [hl], e + inc l + ld [hl], d + + inc hl + dec b + jr nz, .next + + + ld a, l + ld [Requested2bppDest], a + ld a, h + ld [Requested2bppDest + 1], a + + ld [Requested2bppSource], sp + + ld a, [hSPBuffer] + ld l, a + ld a, [hSPBuffer + 1] + ld h, a + ld sp, hl + ret +; 17d3 + + +AnimateTileset:: ; 17d3 +; Only call during the first fifth of VBlank + + ld a, [hMapAnims] + and a + ret z + +; Back out if we're too far into VBlank + ld a, [rLY] + cp 144 + ret c + cp 151 + ret nc + + ld a, [hROMBank] + push af + ld a, BANK(_AnimateTileset) + rst Bankswitch + + ld a, [rSVBK] + push af + ld a, 1 + ld [rSVBK], a + + ld a, [rVBK] + push af + ld a, 0 + ld [rVBK], a + + call _AnimateTileset + + pop af + ld [rVBK], a + pop af + ld [rSVBK], a + pop af + rst Bankswitch + ret +; 17ff diff --git a/home/window.asm b/home/window.asm new file mode 100644 index 00000000..32494ee3 --- /dev/null +++ b/home/window.asm @@ -0,0 +1,99 @@ +RefreshScreen:: ; 2dba + + call ClearWindowData + ld a, [hROMBank] + push af + ld a, BANK(Function6454) ; and BANK(Function64bf) + rst Bankswitch + + call Function6454 + call Function2e20 + call Function64bf + + pop af + rst Bankswitch + ret +; 2dcf + + +CloseText:: ; 2dcf + ld a, [hOAMUpdate] + push af + ld a, $1 + ld [hOAMUpdate], a + + call .CloseText + + pop af + ld [hOAMUpdate], a + ld hl, VramState + res 6, [hl] + ret +; 2de2 + +.CloseText ; 2de2 + call ClearWindowData + xor a + ld [hBGMapMode], a + call OverworldTextModeSwitch + call Function2e20 + xor a + ld [hBGMapMode], a + call Function2e31 + ld a, $90 + ld [hWY], a + call ReplaceKrisSprite + callba ReturnFromMapSetupScript + callba LoadOverworldFont + ret +; 2e08 + +OpenText:: ; 2e08 + call ClearWindowData + ld a, [hROMBank] + push af + ld a, BANK(Function6454) ; and BANK(Function64bf) + rst Bankswitch + + call Function6454 ; clear bgmap + call SpeechTextBox + call Function2e20 ; anchor bgmap + call Function64bf ; load font + pop af + rst Bankswitch + + ret +; 2e20 + +Function2e20:: ; 2e20 + ld a, [hOAMUpdate] + push af + ld a, $1 + ld [hOAMUpdate], a + + callba Function104110 + + pop af + ld [hOAMUpdate], a + ret +; 2e31 + +Function2e31:: ; 2e31 + ld a, [hOAMUpdate] + push af + ld a, [hBGMapMode] + push af + xor a + ld [hBGMapMode], a + ld a, $1 + ld [hOAMUpdate], a + call UpdateSprites + xor a + ld [hOAMUpdate], a + call DelayFrame + pop af + ld [hBGMapMode], a + pop af + ld [hOAMUpdate], a + ret +; 2e4e |