This commit is contained in:
dannye 2021-03-23 00:53:43 -05:00
commit e8dd755e18
3702 changed files with 163333 additions and 159040 deletions

21
home/array.asm Normal file
View file

@ -0,0 +1,21 @@
; skips a text entries, each of size NAME_LENGTH (like trainer name, OT name, rival name, ...)
; hl: base pointer, will be incremented by NAME_LENGTH * a
SkipFixedLengthTextEntries::
and a
ret z
ld bc, NAME_LENGTH
.skipLoop
add hl, bc
dec a
jr nz, .skipLoop
ret
AddNTimes::
; add bc to hl a times
and a
ret z
.loop
add hl, bc
dec a
jr nz, .loop
ret

47
home/array2.asm Normal file
View file

@ -0,0 +1,47 @@
CallFunctionInTable::
; Call function a in jumptable hl.
; de is not preserved.
push hl
push de
push bc
add a
ld d, 0
ld e, a
add hl, de
ld a, [hli]
ld h, [hl]
ld l, a
ld de, .returnAddress
push de
jp hl
.returnAddress
pop bc
pop de
pop hl
ret
IsInArray::
; Search an array at hl for the value in a.
; Entry size is de bytes.
; Return count b and carry if found.
ld b, 0
IsInRestOfArray::
ld c, a
.loop
ld a, [hl]
cp -1
jr z, .notfound
cp c
jr z, .found
inc b
add hl, de
jr .loop
.notfound
and a
ret
.found
scf
ret

View file

@ -108,16 +108,16 @@ OpenSRAMForSound::
;
; call OpenSRAMForSound
;
; ldh a, [hROMBank]
; ldh a, [hLoadedROMBank]
; push af
; ld a, BANK(_MapSetup_Sound_Off)
; ldh [hROMBank], a
; ldh [hLoadedROMBank], a
; ld [MBC1RomBank], a
;
; call _MapSetup_Sound_Off
;
; pop af
; ldh [hROMBank], a
; ldh [hLoadedROMBank], a
; ld [MBC1RomBank], a
;
; pop af
@ -136,16 +136,16 @@ UpdateSound::
and a
ret nz
ldh a, [hROMBank]
ldh a, [hLoadedROMBank]
push af
ld a, BANK(_UpdateSound)
ldh [hROMBank], a
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
call _UpdateSound
pop af
ldh [hROMBank], a
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
; pop af
@ -156,14 +156,14 @@ UpdateSound::
_LoadMusicByte::
; wCurMusicByte = [a:de]
ldh [hROMBank], a
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
ld a, [de]
ld [wCurMusicByte], a
ld a, BANK(LoadMusicByte)
ldh [hROMBank], a
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
ret
@ -178,10 +178,10 @@ PlayMusic::
push bc
push af
ldh a, [hROMBank]
ldh a, [hLoadedROMBank]
push af
ld a, BANK(_PlayMusic) ; aka BANK(_MapSetup_Sound_Off)
ldh [hROMBank], a
ld a, BANK(_PlayMusic) ; aka BANK(_InitSound)
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
ld a, e
@ -192,11 +192,11 @@ PlayMusic::
jr .end
.nomusic
call _MapSetup_Sound_Off
call _InitSound
.end
pop af
ldh [hROMBank], a
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
pop af
pop bc
@ -215,10 +215,10 @@ PlayMusic::
; push bc
; push af
;
; ldh a, [hROMBank]
; ldh a, [hLoadedROMBank]
; push af
; ld a, BANK(_PlayMusic)
; ldh [hROMBank], a
; ldh [hLoadedROMBank], a
; ld [MBC1RomBank], a
;
; push de
@ -229,7 +229,7 @@ PlayMusic::
; call _PlayMusic
;
; pop af
; ldh [hROMBank], a
; ldh [hLoadedROMBank], a
; ld [MBC1RomBank], a
;
; pop af
@ -253,12 +253,12 @@ PlayCry::
ld e, a
ld d, 0
ldh a, [hROMBank]
ldh a, [hLoadedROMBank]
push af
; Cries are stuck in one bank.
ld a, BANK(PokemonCries)
ldh [hROMBank], a
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
ld hl, PokemonCries
@ -281,13 +281,13 @@ endr
ld [wCryLength + 1], a
ld a, BANK(_PlayCry)
ldh [hROMBank], a
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
call _PlayCry
pop af
ldh [hROMBank], a
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
call WaitForSoundToFinish
@ -317,10 +317,10 @@ PlaySFX::
; jr c, .done
.play
ldh a, [hROMBank]
ldh a, [hLoadedROMBank]
push af
ld a, BANK(_PlaySFX)
ldh [hROMBank], a
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
ld a, e
@ -328,7 +328,7 @@ PlaySFX::
call _PlaySFX
pop af
ldh [hROMBank], a
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
.done

35
home/bankswitch.asm Normal file
View file

@ -0,0 +1,35 @@
BankswitchHome::
; switches to bank # in a
; Only use this when in the home bank!
ld [wBankswitchHomeTemp], a
ldh a, [hLoadedROMBank]
ld [wBankswitchHomeSavedROMBank], a
ld a, [wBankswitchHomeTemp]
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
ret
BankswitchBack::
; returns from BankswitchHome
ld a, [wBankswitchHomeSavedROMBank]
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
ret
Bankswitch::
; self-contained bankswitch, use this when not in the home bank
; switches to the bank in b
ldh a, [hLoadedROMBank]
push af
ld a, b
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
ld bc, .Return
push bc
jp hl
.Return
pop bc
ld a, b
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
ret

21
home/clear_sprites.asm Normal file
View file

@ -0,0 +1,21 @@
ClearSprites::
xor a
ld hl, wOAMBuffer
ld b, wOAMBufferEnd - wOAMBuffer
.loop
ld [hli], a
dec b
jr nz, .loop
ret
HideSprites::
ld a, 160
ld hl, wOAMBuffer
ld de, 4
ld b, 40
.loop
ld [hl], a
add hl, de
dec b
jr nz, .loop
ret

11
home/compare.asm Normal file
View file

@ -0,0 +1,11 @@
; Compare strings, c bytes in length, at de and hl.
; Often used to compare big endian numbers in battle calculations.
StringCmp::
ld a, [de]
cp [hl]
ret nz
inc de
inc hl
dec c
jr nz, StringCmp
ret

View file

@ -1,14 +1,14 @@
FarCopyData::
; Copy bc bytes from a:hl to de.
ld [wBuffer], a
ld a, [H_LOADEDROMBANK]
ldh a, [hLoadedROMBank]
push af
ld a, [wBuffer]
ld [H_LOADEDROMBANK], a
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
call CopyData
pop af
ld [H_LOADEDROMBANK], a
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
ret

View file

@ -1,25 +1,25 @@
FarCopyData2::
; Identical to FarCopyData, but uses hROMBankTemp
; as temp space instead of wBuffer.
ld [hROMBankTemp], a
ld a, [H_LOADEDROMBANK]
ldh [hROMBankTemp], a
ldh a, [hLoadedROMBank]
push af
ld a, [hROMBankTemp]
ld [H_LOADEDROMBANK], a
ldh a, [hROMBankTemp]
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
call CopyData
pop af
ld [H_LOADEDROMBANK], a
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
ret
FarCopyData3::
; Copy bc bytes from a:de to hl.
ld [hROMBankTemp], a
ld a, [H_LOADEDROMBANK]
ldh [hROMBankTemp], a
ldh a, [hLoadedROMBank]
push af
ld a, [hROMBankTemp]
ld [H_LOADEDROMBANK], a
ldh a, [hROMBankTemp]
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
push hl
push de
@ -31,18 +31,18 @@ FarCopyData3::
pop de
pop hl
pop af
ld [H_LOADEDROMBANK], a
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
ret
FarCopyDataDouble::
; Expand bc bytes of 1bpp image data
; from a:hl to 2bpp data at de.
ld [hROMBankTemp], a
ld a, [H_LOADEDROMBANK]
ldh [hROMBankTemp], a
ldh a, [hLoadedROMBank]
push af
ld a, [hROMBankTemp]
ld [H_LOADEDROMBANK], a
ldh a, [hROMBankTemp]
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
.loop
ld a, [hli]
@ -55,7 +55,7 @@ FarCopyDataDouble::
or b
jr nz, .loop
pop af
ld [H_LOADEDROMBANK], a
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
ret
@ -64,27 +64,27 @@ CopyVideoData::
; tiles from b:de to hl, 8 tiles at a time.
; This takes c/8 frames.
ld a, [H_AUTOBGTRANSFERENABLED]
ldh a, [hAutoBGTransferEnabled]
push af
xor a ; disable auto-transfer while copying
ld [H_AUTOBGTRANSFERENABLED], a
ldh [hAutoBGTransferEnabled], a
ld a, [H_LOADEDROMBANK]
ld [hROMBankTemp], a
ldh a, [hLoadedROMBank]
ldh [hROMBankTemp], a
ld a, b
ld [H_LOADEDROMBANK], a
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
ld a, e
ld [H_VBCOPYSRC], a
ldh [hVBlankCopySource], a
ld a, d
ld [H_VBCOPYSRC + 1], a
ldh [hVBlankCopySource + 1], a
ld a, l
ld [H_VBCOPYDEST], a
ldh [hVBlankCopyDest], a
ld a, h
ld [H_VBCOPYDEST + 1], a
ldh [hVBlankCopyDest + 1], a
.loop
ld a, c
@ -92,18 +92,18 @@ CopyVideoData::
jr nc, .keepgoing
.done
ld [H_VBCOPYSIZE], a
ldh [hVBlankCopySize], a
call DelayFrame
ld a, [hROMBankTemp]
ld [H_LOADEDROMBANK], a
ldh a, [hROMBankTemp]
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
pop af
ld [H_AUTOBGTRANSFERENABLED], a
ldh [hAutoBGTransferEnabled], a
ret
.keepgoing
ld a, 8
ld [H_VBCOPYSIZE], a
ldh [hVBlankCopySize], a
call DelayFrame
ld a, c
sub 8
@ -114,26 +114,26 @@ CopyVideoDataDouble::
; Wait for the next VBlank, then copy c 1bpp
; tiles from b:de to hl, 8 tiles at a time.
; This takes c/8 frames.
ld a, [H_AUTOBGTRANSFERENABLED]
ldh a, [hAutoBGTransferEnabled]
push af
xor a ; disable auto-transfer while copying
ld [H_AUTOBGTRANSFERENABLED], a
ld a, [H_LOADEDROMBANK]
ld [hROMBankTemp], a
ldh [hAutoBGTransferEnabled], a
ldh a, [hLoadedROMBank]
ldh [hROMBankTemp], a
ld a, b
ld [H_LOADEDROMBANK], a
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
ld a, e
ld [H_VBCOPYDOUBLESRC], a
ldh [hVBlankCopyDoubleSource], a
ld a, d
ld [H_VBCOPYDOUBLESRC + 1], a
ldh [hVBlankCopyDoubleSource + 1], a
ld a, l
ld [H_VBCOPYDOUBLEDEST], a
ldh [hVBlankCopyDoubleDest], a
ld a, h
ld [H_VBCOPYDOUBLEDEST + 1], a
ldh [hVBlankCopyDoubleDest + 1], a
.loop
ld a, c
@ -141,18 +141,18 @@ CopyVideoDataDouble::
jr nc, .keepgoing
.done
ld [H_VBCOPYDOUBLESIZE], a
ldh [hVBlankCopyDoubleSize], a
call DelayFrame
ld a, [hROMBankTemp]
ld [H_LOADEDROMBANK], a
ldh a, [hROMBankTemp]
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
pop af
ld [H_AUTOBGTRANSFERENABLED], a
ldh [hAutoBGTransferEnabled], a
ret
.keepgoing
ld a, 8
ld [H_VBCOPYDOUBLESIZE], a
ldh [hVBlankCopyDoubleSize], a
call DelayFrame
ld a, c
sub 8
@ -184,32 +184,32 @@ CopyScreenTileBufferToVRAM::
ld c, 6
ld hl, $600 * 0
coord de, 0, 6 * 0
decoord 0, 6 * 0
call .setup
call DelayFrame
ld hl, $600 * 1
coord de, 0, 6 * 1
decoord 0, 6 * 1
call .setup
call DelayFrame
ld hl, $600 * 2
coord de, 0, 6 * 2
decoord 0, 6 * 2
call .setup
jp DelayFrame
.setup
ld a, d
ld [H_VBCOPYBGSRC+1], a
ldh [hVBlankCopyBGSource+1], a
call GetRowColAddressBgMap
ld a, l
ld [H_VBCOPYBGDEST], a
ldh [hVBlankCopyBGDest], a
ld a, h
ld [H_VBCOPYBGDEST+1], a
ldh [hVBlankCopyBGDest+1], a
ld a, c
ld [H_VBCOPYBGNUMROWS], a
ldh [hVBlankCopyBGNumRows], a
ld a, e
ld [H_VBCOPYBGSRC], a
ldh [hVBlankCopyBGSource], a
ret
ClearScreen::
@ -217,7 +217,7 @@ ClearScreen::
; for the bg map to update.
ld bc, 20 * 18
inc b
coord hl, 0, 0
hlcoord 0, 0
ld a, " "
.loop
ld [hli], a

13
home/copy_string.asm Normal file
View file

@ -0,0 +1,13 @@
; copies a string from [de] to [wcf4b]
CopyStringToCF4B::
ld hl, wcf4b
; fall through
; copies a string from [de] to [hl]
CopyString::
ld a, [de]
inc de
ld [hli], a
cp "@"
jr nz, CopyString
ret

24
home/count_set_bits.asm Normal file
View file

@ -0,0 +1,24 @@
; function to count how many bits are set in a string of bytes
; INPUT:
; hl = address of string of bytes
; b = length of string of bytes
; OUTPUT:
; [wNumSetBits] = number of set bits
CountSetBits::
ld c, 0
.loop
ld a, [hli]
ld e, a
ld d, 8
.innerLoop ; count how many bits are set in the current byte
srl e
ld a, 0
adc c
ld c, a
dec d
jr nz, .innerLoop
dec b
jr nz, .loop
ld a, c
ld [wNumSetBits], a
ret

6
home/delay.asm Normal file
View file

@ -0,0 +1,6 @@
DelayFrames::
; wait c frames
call DelayFrame
dec c
jr nz, DelayFrames
ret

View file

@ -1,7 +1,7 @@
; These routines manage gradual fading
; (e.g., entering a doorway)
LoadGBPal::
ld a, [wMapPalOffset] ;tells if wCurMap is dark (requires HM5_FLASH?)
ld a, [wMapPalOffset] ; tells if wCurMap is dark (requires HM5_FLASH?)
ld b, a
ld hl, FadePal4
ld a, l
@ -11,11 +11,11 @@ LoadGBPal::
dec h
.ok
ld a, [hli]
ld [rBGP], a
ldh [rBGP], a
ld a, [hli]
ld [rOBP0], a
ldh [rOBP0], a
ld a, [hli]
ld [rOBP1], a
ldh [rOBP1], a
ret
GBFadeInFromBlack::
@ -29,11 +29,11 @@ GBFadeOutToWhite::
GBFadeIncCommon:
ld a, [hli]
ld [rBGP], a
ldh [rBGP], a
ld a, [hli]
ld [rOBP0], a
ldh [rOBP0], a
ld a, [hli]
ld [rOBP1], a
ldh [rOBP1], a
ld c, 8
call DelayFrames
dec b
@ -51,11 +51,11 @@ GBFadeInFromWhite::
GBFadeDecCommon:
ld a, [hld]
ld [rOBP1], a
ldh [rOBP1], a
ld a, [hld]
ld [rOBP0], a
ldh [rOBP0], a
ld a, [hld]
ld [rBGP], a
ldh [rBGP], a
ld c, 8
call DelayFrames
dec b

48
home/fade_audio.asm Normal file
View file

@ -0,0 +1,48 @@
FadeOutAudio::
ld a, [wAudioFadeOutControl]
and a ; currently fading out audio?
jr nz, .fadingOut
ld a, [wd72c]
bit 1, a
ret nz
ld a, $77
ldh [rNR50], a
ret
.fadingOut
ld a, [wAudioFadeOutCounter]
and a
jr z, .counterReachedZero
dec a
ld [wAudioFadeOutCounter], a
ret
.counterReachedZero
ld a, [wAudioFadeOutCounterReloadValue]
ld [wAudioFadeOutCounter], a
ldh a, [rNR50]
and a ; has the volume reached 0?
jr z, .fadeOutComplete
ld b, a
and $f
dec a
ld c, a
ld a, b
and $f0
swap a
dec a
swap a
or c
ldh [rNR50], a
ret
.fadeOutComplete
ld a, [wAudioFadeOutControl]
ld b, a
xor a
ld [wAudioFadeOutControl], a
ld a, SFX_STOP_ALL_MUSIC
ld [wNewSoundID], a
call PlaySound
ld a, [wAudioSavedROMBank]
ld [wAudioROMBank], a
ld a, b
ld [wNewSoundID], a
jp PlaySound

26
home/give.asm Normal file
View file

@ -0,0 +1,26 @@
GiveItem::
; Give player quantity c of item b,
; and copy the item's name to wcf4b.
; Return carry on success.
ld a, b
ld [wd11e], a
ld [wcf91], a
ld a, c
ld [wItemQuantity], a
ld hl, wNumBagItems
call AddItemToInventory
ret nc
call GetItemName
call CopyStringToCF4B
scf
ret
GivePokemon::
; Give the player monster b at level c.
ld a, b
ld [wcf91], a
ld a, c
ld [wCurEnemyLVL], a
xor a ; PLAYER_PARTY_DATA
ld [wMonDataLocation], a
farjp _GivePokemon

81
home/header.asm Normal file
View file

@ -0,0 +1,81 @@
; rst vectors (unused)
SECTION "rst0", ROM0[$0000]
rst $38
ds $08 - @, 0 ; unused
SECTION "rst8", ROM0[$0008]
rst $38
ds $10 - @, 0 ; unused
SECTION "rst10", ROM0[$0010]
rst $38
ds $18 - @, 0 ; unused
SECTION "rst18", ROM0[$0018]
rst $38
ds $20 - @, 0 ; unused
SECTION "rst20", ROM0[$0020]
rst $38
ds $28 - @, 0 ; unused
SECTION "rst28", ROM0[$0028]
rst $38
ds $30 - @, 0 ; unused
SECTION "rst30", ROM0[$0030]
rst $38
ds $38 - @, 0 ; unused
SECTION "rst38", ROM0[$0038]
rst $38
ds $40 - @, 0 ; unused
; Game Boy hardware interrupts
SECTION "vblank", ROM0[$0040]
jp VBlank
ds $48 - @, 0 ; unused
SECTION "lcd", ROM0[$0048]
rst $38
ds $50 - @, 0 ; unused
SECTION "timer", ROM0[$0050]
jp Timer
ds $58 - @, 0 ; unused
SECTION "serial", ROM0[$0058]
jp Serial
ds $60 - @, 0 ; unused
SECTION "joypad", ROM0[$0060]
reti
SECTION "Header", ROM0[$0100]
Start::
; Nintendo requires all Game Boy ROMs to begin with a nop ($00) and a jp ($C3)
; to the starting address.
nop
jp _Start
; The Game Boy cartridge header data is patched over by rgbfix.
; This makes sure it doesn't get used for anything else.
ds $0150 - @

39
home/hidden_objects.asm Normal file
View file

@ -0,0 +1,39 @@
UpdateCinnabarGymGateTileBlocks::
farjp UpdateCinnabarGymGateTileBlocks_
CheckForHiddenObjectOrBookshelfOrCardKeyDoor::
ldh a, [hLoadedROMBank]
push af
ldh a, [hJoyHeld]
bit 0, a ; A button
jr z, .nothingFound
; A button is pressed
ld a, BANK(CheckForHiddenObject)
ld [MBC1RomBank], a
ldh [hLoadedROMBank], a
call CheckForHiddenObject
ldh a, [hDidntFindAnyHiddenObject]
and a
jr nz, .hiddenObjectNotFound
ld a, [wHiddenObjectFunctionRomBank]
ld [MBC1RomBank], a
ldh [hLoadedROMBank], a
ld de, .returnAddress
push de
jp hl
.returnAddress
xor a
jr .done
.hiddenObjectNotFound
farcall PrintBookshelfText
ldh a, [hFFDB]
and a
jr z, .done
.nothingFound
ld a, $ff
.done
ldh [hItemAlreadyFound], a
pop af
ld [MBC1RomBank], a
ldh [hLoadedROMBank], a
ret

View file

@ -21,28 +21,28 @@ rLCDC_DEFAULT EQU %11100011
di
xor a
ld [rIF], a
ld [rIE], a
ld [rSCX], a
ld [rSCY], a
ld [rSB], a
ld [rSC], a
ld [rWX], a
ld [rWY], a
ld [rTMA], a
ld [rTAC], a
ld [rBGP], a
ld [rOBP0], a
ld [rOBP1], a
ldh [rIF], a
ldh [rIE], a
ldh [rSCX], a
ldh [rSCY], a
ldh [rSB], a
ldh [rSC], a
ldh [rWX], a
ldh [rWY], a
ldh [rTMA], a
ldh [rTAC], a
ldh [rBGP], a
ldh [rOBP0], a
ldh [rOBP1], a
ld a, rLCDC_ENABLE_MASK
ld [rLCDC], a
ldh [rLCDC], a
call DisableLCD
ld sp, wStack
ld hl, $c000 ; start of WRAM
ld bc, $2000 ; size of WRAM
ld hl, WRAM0_Begin
ld bc, WRAM1_End - WRAM0_Begin
.loop
ld [hl], 0
inc hl
@ -53,44 +53,44 @@ rLCDC_DEFAULT EQU %11100011
call ClearVram
ld hl, $ff80
ld bc, $ffff - $ff80
ld hl, HRAM_Begin
ld bc, HRAM_End - HRAM_Begin
call FillMemory
call ClearSprites
ld a, Bank(WriteDMACodeToHRAM)
ld [H_LOADEDROMBANK], a
ld a, BANK(WriteDMACodeToHRAM)
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
call WriteDMACodeToHRAM
xor a
ld [hTilesetType], a
ld [rSTAT], a
ld [hSCX], a
ld [hSCY], a
ld [rIF], a
ldh [hTileAnimations], a
ldh [rSTAT], a
ldh [hSCX], a
ldh [hSCY], a
ldh [rIF], a
ld a, 1 << VBLANK + 1 << TIMER + 1 << SERIAL
ld [rIE], a
ldh [rIE], a
ld a, 144 ; move the window off-screen
ld [hWY], a
ld [rWY], a
ldh [hWY], a
ldh [rWY], a
ld a, 7
ld [rWX], a
ldh [rWX], a
ld a, CONNECTION_NOT_ESTABLISHED
ld [hSerialConnectionStatus], a
ldh [hSerialConnectionStatus], a
ld h, vBGMap0 / $100
ld h, HIGH(vBGMap0)
call ClearBgMap
ld h, vBGMap1 / $100
ld h, HIGH(vBGMap1)
call ClearBgMap
ld a, rLCDC_DEFAULT
ld [rLCDC], a
ldh [rLCDC], a
ld a, 16
ld [hSoftReset], a
ldh [hSoftReset], a
call StopAllSounds
ei
@ -101,9 +101,9 @@ rLCDC_DEFAULT EQU %11100011
ld [wAudioROMBank], a
ld [wAudioSavedROMBank], a
ld a, $9c
ld [H_AUTOBGTRANSFERDEST + 1], a
ldh [hAutoBGTransferDest + 1], a
xor a
ld [H_AUTOBGTRANSFERDEST], a
ldh [hAutoBGTransferDest], a
dec a
ld [wUpdateSpritesEnabled], a
@ -114,13 +114,13 @@ rLCDC_DEFAULT EQU %11100011
call GBPalNormal
call ClearSprites
ld a, rLCDC_DEFAULT
ld [rLCDC], a
ldh [rLCDC], a
jp SetDefaultNamesBeforeTitlescreen
ClearVram:
ld hl, $8000
ld bc, $2000
ClearVram::
ld hl, VRAM_Begin
ld bc, VRAM_End - VRAM_Begin
xor a
jp FillMemory
@ -128,7 +128,7 @@ ClearVram:
StopAllSounds::
call OpenSRAMForSound
ld a, 0 ; BANK(Audio1_UpdateMusic)
ld a, 0 ; BANK("Audio Engine 1")
ld [wAudioROMBank], a
ld [wAudioSavedROMBank], a
xor a

38
home/inventory.asm Normal file
View file

@ -0,0 +1,38 @@
; subtracts the amount the player paid from their money
; OUTPUT: carry = 0(success) or 1(fail because there is not enough money)
SubtractAmountPaidFromMoney::
farjp SubtractAmountPaidFromMoney_
; adds the amount the player sold to their money
AddAmountSoldToMoney::
ld de, wPlayerMoney + 2
ld hl, hMoney + 2 ; total price of items
ld c, 3 ; length of money in bytes
predef AddBCDPredef ; add total price to money
ld a, MONEY_BOX
ld [wTextBoxID], a
call DisplayTextBoxID ; redraw money text box
ld a, SFX_PURCHASE
call PlaySoundWaitForCurrent
jp WaitForSoundToFinish
; function to remove an item (in varying quantities) from the player's bag or PC box
; INPUT:
; HL = address of inventory (either wNumBagItems or wNumBoxItems)
; [wWhichPokemon] = index (within the inventory) of the item to remove
; [wItemQuantity] = quantity to remove
RemoveItemFromInventory::
homecall RemoveItemFromInventory_
ret
; function to add an item (in varying quantities) to the player's bag or PC box
; INPUT:
; HL = address of inventory (either wNumBagItems or wNumBoxItems)
; [wcf91] = item ID
; [wItemQuantity] = item quantity
; sets carry flag if successful, unsets carry flag if unsuccessful
AddItemToInventory::
push bc
homecall_sf AddItemToInventory_
pop bc
ret

49
home/item.asm Normal file
View file

@ -0,0 +1,49 @@
; uses an item
; UseItem is used with dummy items to perform certain other functions as well
; INPUT:
; [wcf91] = item ID
; OUTPUT:
; [wActionResultOrTookBattleTurn] = success
; 00: unsuccessful
; 01: successful
; 02: not able to be used right now, no extra menu displayed (only certain items use this)
UseItem::
farjp UseItem_
; confirms the item toss and then tosses the item
; INPUT:
; hl = address of inventory (either wNumBagItems or wNumBoxItems)
; [wcf91] = item ID
; [wWhichPokemon] = index of item within inventory
; [wItemQuantity] = quantity to toss
; OUTPUT:
; clears carry flag if the item is tossed, sets carry flag if not
TossItem::
ldh a, [hLoadedROMBank]
push af
ld a, BANK(TossItem_)
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
call TossItem_
pop de
ld a, d
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
ret
; checks if an item is a key item
; INPUT:
; [wcf91] = item ID
; OUTPUT:
; [wIsKeyItem] = result
; 00: item is not key item
; 01: item is key item
IsKeyItem::
push hl
push de
push bc
farcall IsKeyItem_
pop bc
pop de
pop hl
ret

44
home/item_price.asm Normal file
View file

@ -0,0 +1,44 @@
GetItemPrice::
; Stores item's price as BCD at hItemPrice (3 bytes)
; Input: [wcf91] = item id
ldh a, [hLoadedROMBank]
push af
ld a, [wListMenuID]
cp MOVESLISTMENU
ld a, BANK(ItemPrices)
jr nz, .ok
ld a, $f ; hardcoded Bank
.ok
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
ld hl, wItemPrices
ld a, [hli]
ld h, [hl]
ld l, a
ld a, [wcf91] ; a contains item id
cp HM01
jr nc, .getTMPrice
ld bc, $3
.loop
add hl, bc
dec a
jr nz, .loop
dec hl
ld a, [hld]
ldh [hItemPrice + 2], a
ld a, [hld]
ldh [hItemPrice + 1], a
ld a, [hl]
ldh [hItemPrice], a
jr .done
.getTMPrice
ld a, BANK(GetMachinePrice)
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
call GetMachinePrice
.done
ld de, hItemPrice
pop af
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
ret

View file

@ -6,28 +6,28 @@ ReadJoypad::
ld a, 1 << 5 ; select direction keys
ld c, 0
ld [rJOYP], a
rept 6
ld a, [rJOYP]
endr
ldh [rJOYP], a
REPT 6
ldh a, [rJOYP]
ENDR
cpl
and %1111
swap a
ld b, a
ld a, 1 << 4 ; select button keys
ld [rJOYP], a
rept 10
ld a, [rJOYP]
endr
ldh [rJOYP], a
REPT 10
ldh a, [rJOYP]
ENDR
cpl
and %1111
or b
ld [hJoyInput], a
ldh [hJoyInput], a
ld a, 1 << 4 + 1 << 5 ; deselect keys
ld [rJOYP], a
ldh [rJOYP], a
ret
Joypad::

95
home/joypad2.asm Normal file
View file

@ -0,0 +1,95 @@
; this function is used when lower button sensitivity is wanted (e.g. menus)
; OUTPUT: [hJoy5] = pressed buttons in usual format
; there are two flags that control its functionality, [hJoy6] and [hJoy7]
; there are essentially three modes of operation
; 1. Get newly pressed buttons only
; ([hJoy7] == 0, [hJoy6] == any)
; Just copies [hJoyPressed] to [hJoy5].
; 2. Get currently pressed buttons at low sample rate with delay
; ([hJoy7] == 1, [hJoy6] != 0)
; If the user holds down buttons for more than half a second,
; report buttons as being pressed up to 12 times per second thereafter.
; If the user holds down buttons for less than half a second,
; report only one button press.
; 3. Same as 2, but report no buttons as pressed if A or B is held down.
; ([hJoy7] == 1, [hJoy6] == 0)
JoypadLowSensitivity::
call Joypad
ldh a, [hJoy7] ; flag
and a ; get all currently pressed buttons or only newly pressed buttons?
ldh a, [hJoyPressed] ; newly pressed buttons
jr z, .storeButtonState
ldh a, [hJoyHeld] ; all currently pressed buttons
.storeButtonState
ldh [hJoy5], a
ldh a, [hJoyPressed] ; newly pressed buttons
and a ; have any buttons been newly pressed since last check?
jr z, .noNewlyPressedButtons
.newlyPressedButtons
ld a, 30 ; half a second delay
ldh [hFrameCounter], a
ret
.noNewlyPressedButtons
ldh a, [hFrameCounter]
and a ; is the delay over?
jr z, .delayOver
.delayNotOver
xor a
ldh [hJoy5], a ; report no buttons as pressed
ret
.delayOver
; if [hJoy6] = 0 and A or B is pressed, report no buttons as pressed
ldh a, [hJoyHeld]
and A_BUTTON | B_BUTTON
jr z, .setShortDelay
ldh a, [hJoy6] ; flag
and a
jr nz, .setShortDelay
xor a
ldh [hJoy5], a
.setShortDelay
ld a, 5 ; 1/12 of a second delay
ldh [hFrameCounter], a
ret
WaitForTextScrollButtonPress::
ldh a, [hDownArrowBlinkCount1]
push af
ldh a, [hDownArrowBlinkCount2]
push af
xor a
ldh [hDownArrowBlinkCount1], a
ld a, $6
ldh [hDownArrowBlinkCount2], a
.loop
push hl
ld a, [wTownMapSpriteBlinkingEnabled]
and a
jr z, .skipAnimation
call TownMapSpriteBlinkingAnimation
.skipAnimation
hlcoord 18, 16
call HandleDownArrowBlinkTiming
pop hl
call JoypadLowSensitivity
predef CableClub_Run
ldh a, [hJoy5]
and A_BUTTON | B_BUTTON
jr z, .loop
pop af
ldh [hDownArrowBlinkCount2], a
pop af
ldh [hDownArrowBlinkCount1], a
ret
; (unless in link battle) waits for A or B being pressed and outputs the scrolling sound effect
ManualTextScroll::
ld a, [wLinkState]
cp LINK_STATE_BATTLING
jr z, .inLinkBattle
call WaitForTextScrollButtonPress
ld a, SFX_PRESS_AB
jp PlaySound
.inLinkBattle
ld c, 65
jp DelayFrames

25
home/lcd.asm Normal file
View file

@ -0,0 +1,25 @@
DisableLCD::
xor a
ldh [rIF], a
ldh a, [rIE]
ld b, a
res 0, a
ldh [rIE], a
.wait
ldh a, [rLY]
cp LY_VBLANK
jr nz, .wait
ldh a, [rLCDC]
and $ff ^ rLCDC_ENABLE_MASK
ldh [rLCDC], a
ld a, b
ldh [rIE], a
ret
EnableLCD::
ldh a, [rLCDC]
set rLCDC_ENABLE, a
ldh [rLCDC], a
ret

526
home/list_menu.asm Normal file
View file

@ -0,0 +1,526 @@
; INPUT:
; [wListMenuID] = list menu ID
; [wListPointer] = address of the list (2 bytes)
DisplayListMenuID::
xor a
ldh [hAutoBGTransferEnabled], a ; disable auto-transfer
ld a, 1
ldh [hJoy7], a ; joypad state update flag
ld a, [wBattleType]
and a ; is it the Old Man battle?
jr nz, .specialBattleType
ld a, $01 ; hardcoded bank
jr .bankswitch
.specialBattleType ; Old Man battle
ld a, BANK(DisplayBattleMenu)
.bankswitch
call BankswitchHome
ld hl, wd730
set 6, [hl] ; turn off letter printing delay
xor a
ld [wMenuItemToSwap], a ; 0 means no item is currently being swapped
ld [wListCount], a
ld a, [wListPointer]
ld l, a
ld a, [wListPointer + 1]
ld h, a ; hl = address of the list
ld a, [hl] ; the first byte is the number of entries in the list
ld [wListCount], a
ld a, LIST_MENU_BOX
ld [wTextBoxID], a
call DisplayTextBoxID ; draw the menu text box
call UpdateSprites ; disable sprites behind the text box
; the code up to .skipMovingSprites appears to be useless
hlcoord 4, 2 ; coordinates of upper left corner of menu text box
lb de, 9, 14 ; height and width of menu text box
ld a, [wListMenuID]
and a ; PCPOKEMONLISTMENU?
jr nz, .skipMovingSprites
call UpdateSprites
.skipMovingSprites
ld a, 1 ; max menu item ID is 1 if the list has less than 2 entries
ld [wMenuWatchMovingOutOfBounds], a
ld a, [wListCount]
cp 2 ; does the list have less than 2 entries?
jr c, .setMenuVariables
ld a, 2 ; max menu item ID is 2 if the list has at least 2 entries
.setMenuVariables
ld [wMaxMenuItem], a
ld a, 4
ld [wTopMenuItemY], a
ld a, 5
ld [wTopMenuItemX], a
ld a, A_BUTTON | B_BUTTON | SELECT
ld [wMenuWatchedKeys], a
ld c, 10
call DelayFrames
DisplayListMenuIDLoop::
xor a
ldh [hAutoBGTransferEnabled], a ; disable transfer
call PrintListMenuEntries
ld a, 1
ldh [hAutoBGTransferEnabled], a ; enable transfer
call Delay3
ld a, [wBattleType]
and a ; is it the Old Man battle?
jr z, .notOldManBattle
.oldManBattle
ld a, "▶"
ldcoord_a 5, 4 ; place menu cursor in front of first menu entry
ld c, 80
call DelayFrames
xor a
ld [wCurrentMenuItem], a
hlcoord 5, 4
ld a, l
ld [wMenuCursorLocation], a
ld a, h
ld [wMenuCursorLocation + 1], a
jr .buttonAPressed
.notOldManBattle
call LoadGBPal
call HandleMenuInput
push af
call PlaceMenuCursor
pop af
bit 0, a ; was the A button pressed?
jp z, .checkOtherKeys
.buttonAPressed
ld a, [wCurrentMenuItem]
call PlaceUnfilledArrowMenuCursor
; pointless because both values are overwritten before they are read
ld a, $01
ld [wMenuExitMethod], a
ld [wChosenMenuItem], a
xor a
ld [wMenuWatchMovingOutOfBounds], a
ld a, [wCurrentMenuItem]
ld c, a
ld a, [wListScrollOffset]
add c
ld c, a
ld a, [wListCount]
and a ; is the list empty?
jp z, ExitListMenu ; if so, exit the menu
dec a
cp c ; did the player select Cancel?
jp c, ExitListMenu ; if so, exit the menu
ld a, c
ld [wWhichPokemon], a
ld a, [wListMenuID]
cp ITEMLISTMENU
jr nz, .skipMultiplying
; if it's an item menu
sla c ; item entries are 2 bytes long, so multiply by 2
.skipMultiplying
ld a, [wListPointer]
ld l, a
ld a, [wListPointer + 1]
ld h, a
inc hl ; hl = beginning of list entries
ld b, 0
add hl, bc
ld a, [hl]
ld [wcf91], a
ld a, [wListMenuID]
and a ; PCPOKEMONLISTMENU?
jr z, .pokemonList
push hl
call GetItemPrice
pop hl
ld a, [wListMenuID]
cp ITEMLISTMENU
jr nz, .skipGettingQuantity
; if it's an item menu
inc hl
ld a, [hl] ; a = item quantity
ld [wMaxItemQuantity], a
.skipGettingQuantity
ld a, [wcf91]
ld [wd0b5], a
ld a, BANK(ItemNames)
ld [wPredefBank], a
call GetName
jr .storeChosenEntry
.pokemonList
ld hl, wPartyCount
ld a, [wListPointer]
cp l ; is it a list of party pokemon or box pokemon?
ld hl, wPartyMonNicks
jr z, .getPokemonName
ld hl, wBoxMonNicks ; box pokemon names
.getPokemonName
ld a, [wWhichPokemon]
call GetPartyMonName
.storeChosenEntry ; store the menu entry that the player chose and return
ld de, wcd6d
call CopyStringToCF4B ; copy name to wcf4b
ld a, CHOSE_MENU_ITEM
ld [wMenuExitMethod], a
ld a, [wCurrentMenuItem]
ld [wChosenMenuItem], a
xor a
ldh [hJoy7], a ; joypad state update flag
ld hl, wd730
res 6, [hl] ; turn on letter printing delay
jp BankswitchBack
.checkOtherKeys ; check B, SELECT, Up, and Down keys
bit 1, a ; was the B button pressed?
jp nz, ExitListMenu ; if so, exit the menu
bit 2, a ; was the select button pressed?
jp nz, HandleItemListSwapping ; if so, allow the player to swap menu entries
ld b, a
bit 7, b ; was Down pressed?
ld hl, wListScrollOffset
jr z, .upPressed
.downPressed
ld a, [hl]
add 3
ld b, a
ld a, [wListCount]
cp b ; will going down scroll past the Cancel button?
jp c, DisplayListMenuIDLoop
inc [hl] ; if not, go down
jp DisplayListMenuIDLoop
.upPressed
ld a, [hl]
and a
jp z, DisplayListMenuIDLoop
dec [hl]
jp DisplayListMenuIDLoop
DisplayChooseQuantityMenu::
; text box dimensions/coordinates for just quantity
hlcoord 15, 9
ld b, 1 ; height
ld c, 3 ; width
ld a, [wListMenuID]
cp PRICEDITEMLISTMENU
jr nz, .drawTextBox
; text box dimensions/coordinates for quantity and price
hlcoord 7, 9
ld b, 1 ; height
ld c, 11 ; width
.drawTextBox
call TextBoxBorder
hlcoord 16, 10
ld a, [wListMenuID]
cp PRICEDITEMLISTMENU
jr nz, .printInitialQuantity
hlcoord 8, 10
.printInitialQuantity
ld de, InitialQuantityText
call PlaceString
xor a
ld [wItemQuantity], a ; initialize current quantity to 0
jp .incrementQuantity
.waitForKeyPressLoop
call JoypadLowSensitivity
ldh a, [hJoyPressed] ; newly pressed buttons
bit 0, a ; was the A button pressed?
jp nz, .buttonAPressed
bit 1, a ; was the B button pressed?
jp nz, .buttonBPressed
bit 6, a ; was Up pressed?
jr nz, .incrementQuantity
bit 7, a ; was Down pressed?
jr nz, .decrementQuantity
jr .waitForKeyPressLoop
.incrementQuantity
ld a, [wMaxItemQuantity]
inc a
ld b, a
ld hl, wItemQuantity ; current quantity
inc [hl]
ld a, [hl]
cp b
jr nz, .handleNewQuantity
; wrap to 1 if the player goes above the max quantity
ld a, 1
ld [hl], a
jr .handleNewQuantity
.decrementQuantity
ld hl, wItemQuantity ; current quantity
dec [hl]
jr nz, .handleNewQuantity
; wrap to the max quantity if the player goes below 1
ld a, [wMaxItemQuantity]
ld [hl], a
.handleNewQuantity
hlcoord 17, 10
ld a, [wListMenuID]
cp PRICEDITEMLISTMENU
jr nz, .printQuantity
.printPrice
ld c, $03
ld a, [wItemQuantity]
ld b, a
ld hl, hMoney ; total price
; initialize total price to 0
xor a
ld [hli], a
ld [hli], a
ld [hl], a
.addLoop ; loop to multiply the individual price by the quantity to get the total price
ld de, hMoney + 2
ld hl, hItemPrice + 2
push bc
predef AddBCDPredef ; add the individual price to the current sum
pop bc
dec b
jr nz, .addLoop
ldh a, [hHalveItemPrices]
and a ; should the price be halved (for selling items)?
jr z, .skipHalvingPrice
xor a
ldh [hDivideBCDDivisor], a
ldh [hDivideBCDDivisor + 1], a
ld a, $02
ldh [hDivideBCDDivisor + 2], a
predef DivideBCDPredef3 ; halves the price
; store the halved price
ldh a, [hDivideBCDQuotient]
ldh [hMoney], a
ldh a, [hDivideBCDQuotient + 1]
ldh [hMoney + 1], a
ldh a, [hDivideBCDQuotient + 2]
ldh [hMoney + 2], a
.skipHalvingPrice
hlcoord 12, 10
ld de, SpacesBetweenQuantityAndPriceText
call PlaceString
ld de, hMoney ; total price
ld c, $a3
call PrintBCDNumber
hlcoord 9, 10
.printQuantity
ld de, wItemQuantity ; current quantity
lb bc, LEADING_ZEROES | 1, 2 ; 1 byte, 2 digits
call PrintNumber
jp .waitForKeyPressLoop
.buttonAPressed ; the player chose to make the transaction
xor a
ld [wMenuItemToSwap], a ; 0 means no item is currently being swapped
ret
.buttonBPressed ; the player chose to cancel the transaction
xor a
ld [wMenuItemToSwap], a ; 0 means no item is currently being swapped
ld a, $ff
ret
InitialQuantityText::
db "×01@"
SpacesBetweenQuantityAndPriceText::
db " @"
ExitListMenu::
ld a, [wCurrentMenuItem]
ld [wChosenMenuItem], a
ld a, CANCELLED_MENU
ld [wMenuExitMethod], a
ld [wMenuWatchMovingOutOfBounds], a
xor a
ldh [hJoy7], a
ld hl, wd730
res 6, [hl]
call BankswitchBack
xor a
ld [wMenuItemToSwap], a ; 0 means no item is currently being swapped
scf
ret
PrintListMenuEntries::
hlcoord 5, 3
ld b, 9
ld c, 14
call ClearScreenArea
ld a, [wListPointer]
ld e, a
ld a, [wListPointer + 1]
ld d, a
inc de ; de = beginning of list entries
ld a, [wListScrollOffset]
ld c, a
ld a, [wListMenuID]
cp ITEMLISTMENU
ld a, c
jr nz, .skipMultiplying
; if it's an item menu
; item entries are 2 bytes long, so multiply by 2
sla a
sla c
.skipMultiplying
add e
ld e, a
jr nc, .noCarry
inc d
.noCarry
hlcoord 6, 4 ; coordinates of first list entry name
ld b, 4 ; print 4 names
.loop
ld a, b
ld [wWhichPokemon], a
ld a, [de]
ld [wd11e], a
cp $ff
jp z, .printCancelMenuItem
push bc
push de
push hl
push hl
push de
ld a, [wListMenuID]
and a ; PCPOKEMONLISTMENU?
jr z, .pokemonPCMenu
cp MOVESLISTMENU
jr z, .movesMenu
.itemMenu
call GetItemName
jr .placeNameString
.pokemonPCMenu
push hl
ld hl, wPartyCount
ld a, [wListPointer]
cp l ; is it a list of party pokemon or box pokemon?
ld hl, wPartyMonNicks
jr z, .getPokemonName
ld hl, wBoxMonNicks ; box pokemon names
.getPokemonName
ld a, [wWhichPokemon]
ld b, a
ld a, 4
sub b
ld b, a
ld a, [wListScrollOffset]
add b
call GetPartyMonName
pop hl
jr .placeNameString
.movesMenu
call GetMoveName
.placeNameString
call PlaceString
pop de
pop hl
ld a, [wPrintItemPrices]
and a ; should prices be printed?
jr z, .skipPrintingItemPrice
.printItemPrice
push hl
ld a, [de]
ld de, ItemPrices
ld [wcf91], a
call GetItemPrice ; get price
pop hl
ld bc, SCREEN_WIDTH + 5 ; 1 row down and 5 columns right
add hl, bc
ld c, $a3 ; no leading zeroes, right-aligned, print currency symbol, 3 bytes
call PrintBCDNumber
.skipPrintingItemPrice
ld a, [wListMenuID]
and a ; PCPOKEMONLISTMENU?
jr nz, .skipPrintingPokemonLevel
.printPokemonLevel
ld a, [wd11e]
push af
push hl
ld hl, wPartyCount
ld a, [wListPointer]
cp l ; is it a list of party pokemon or box pokemon?
ld a, PLAYER_PARTY_DATA
jr z, .next
ld a, BOX_DATA
.next
ld [wMonDataLocation], a
ld hl, wWhichPokemon
ld a, [hl]
ld b, a
ld a, $04
sub b
ld b, a
ld a, [wListScrollOffset]
add b
ld [hl], a
call LoadMonData
ld a, [wMonDataLocation]
and a ; is it a list of party pokemon or box pokemon?
jr z, .skipCopyingLevel
.copyLevel
ld a, [wLoadedMonBoxLevel]
ld [wLoadedMonLevel], a
.skipCopyingLevel
pop hl
ld bc, $1c
add hl, bc
call PrintLevel
pop af
ld [wd11e], a
.skipPrintingPokemonLevel
pop hl
pop de
inc de
ld a, [wListMenuID]
cp ITEMLISTMENU
jr nz, .nextListEntry
.printItemQuantity
ld a, [wd11e]
ld [wcf91], a
call IsKeyItem ; check if item is unsellable
ld a, [wIsKeyItem]
and a ; is the item unsellable?
jr nz, .skipPrintingItemQuantity ; if so, don't print the quantity
push hl
ld bc, SCREEN_WIDTH + 8 ; 1 row down and 8 columns right
add hl, bc
ld a, "×"
ld [hli], a
ld a, [wd11e]
push af
ld a, [de]
ld [wMaxItemQuantity], a
push de
ld de, wd11e
ld [de], a
lb bc, 1, 2
call PrintNumber
pop de
pop af
ld [wd11e], a
pop hl
.skipPrintingItemQuantity
inc de
pop bc
inc c
push bc
inc c
ld a, [wMenuItemToSwap] ; ID of item chosen for swapping (counts from 1)
and a ; is an item being swapped?
jr z, .nextListEntry
sla a
cp c ; is it this item?
jr nz, .nextListEntry
dec hl
ld a, "▷"
ld [hli], a
.nextListEntry
ld bc, 2 * SCREEN_WIDTH ; 2 rows
add hl, bc
pop bc
inc c
dec b
jp nz, .loop
ld bc, -8
add hl, bc
ld a, "▼"
ld [hl], a
ret
.printCancelMenuItem
ld de, ListMenuCancelText
jp PlaceString
ListMenuCancelText::
db "CANCEL@"

47
home/load_font.asm Normal file
View file

@ -0,0 +1,47 @@
LoadFontTilePatterns::
ldh a, [rLCDC]
bit 7, a ; is the LCD enabled?
jr nz, .on
.off
ld hl, FontGraphics
ld de, vFont
ld bc, FontGraphicsEnd - FontGraphics
ld a, BANK(FontGraphics)
jp FarCopyDataDouble ; if LCD is off, transfer all at once
.on
ld de, FontGraphics
ld hl, vFont
lb bc, BANK(FontGraphics), (FontGraphicsEnd - FontGraphics) / $8
jp CopyVideoDataDouble ; if LCD is on, transfer during V-blank
LoadTextBoxTilePatterns::
ldh a, [rLCDC]
bit 7, a ; is the LCD enabled?
jr nz, .on
.off
ld hl, TextBoxGraphics
ld de, vChars2 tile $60
ld bc, TextBoxGraphicsEnd - TextBoxGraphics
ld a, BANK(TextBoxGraphics)
jp FarCopyData2 ; if LCD is off, transfer all at once
.on
ld de, TextBoxGraphics
ld hl, vChars2 tile $60
lb bc, BANK(TextBoxGraphics), (TextBoxGraphicsEnd - TextBoxGraphics) / $10
jp CopyVideoData ; if LCD is on, transfer during V-blank
LoadHpBarAndStatusTilePatterns::
ldh a, [rLCDC]
bit 7, a ; is the LCD enabled?
jr nz, .on
.off
ld hl, HpBarAndStatusGraphics
ld de, vChars2 tile $62
ld bc, HpBarAndStatusGraphicsEnd - HpBarAndStatusGraphics
ld a, BANK(HpBarAndStatusGraphics)
jp FarCopyData2 ; if LCD is off, transfer all at once
.on
ld de, HpBarAndStatusGraphics
ld hl, vChars2 tile $62
lb bc, BANK(HpBarAndStatusGraphics), (HpBarAndStatusGraphicsEnd - HpBarAndStatusGraphics) / $10
jp CopyVideoData ; if LCD is on, transfer during V-blank

248
home/map_objects.asm Normal file
View file

@ -0,0 +1,248 @@
; checks if the player's coordinates match an arrow movement tile's coordinates
; and if so, decodes the RLE movement data
; b = player Y
; c = player X
DecodeArrowMovementRLE::
ld a, [hli]
cp $ff
ret z ; no match in the list
cp b
jr nz, .nextArrowMovementTileEntry1
ld a, [hli]
cp c
jr nz, .nextArrowMovementTileEntry2
ld a, [hli]
ld d, [hl]
ld e, a
ld hl, wSimulatedJoypadStatesEnd
call DecodeRLEList
dec a
ld [wSimulatedJoypadStatesIndex], a
ret
.nextArrowMovementTileEntry1
inc hl
.nextArrowMovementTileEntry2
inc hl
inc hl
jr DecodeArrowMovementRLE
TextScript_ItemStoragePC::
call SaveScreenTilesToBuffer2
ld b, BANK(PlayerPC)
ld hl, PlayerPC
jr bankswitchAndContinue
TextScript_BillsPC::
call SaveScreenTilesToBuffer2
ld b, BANK(BillsPC_)
ld hl, BillsPC_
jr bankswitchAndContinue
TextScript_GameCornerPrizeMenu::
; XXX find a better name for this function
; special_F7
ld b, BANK(CeladonPrizeMenu)
ld hl, CeladonPrizeMenu
bankswitchAndContinue::
call Bankswitch
jp HoldTextDisplayOpen ; continue to main text-engine function
TextScript_PokemonCenterPC::
ld b, BANK(ActivatePC)
ld hl, ActivatePC
jr bankswitchAndContinue
StartSimulatingJoypadStates::
xor a
ld [wOverrideSimulatedJoypadStatesMask], a
ld [wSpritePlayerStateData2MovementByte1], a
ld hl, wd730
set 7, [hl]
ret
IsItemInBag::
; given an item_id in b
; set zero flag if item isn't in player's bag
; else reset zero flag
; related to Pokémon Tower and ghosts
predef GetQuantityOfItemInBag
ld a, b
and a
ret
DisplayPokedex::
ld [wd11e], a
farjp _DisplayPokedex
SetSpriteFacingDirectionAndDelay::
call SetSpriteFacingDirection
ld c, 6
jp DelayFrames
SetSpriteFacingDirection::
ld a, SPRITESTATEDATA1_FACINGDIRECTION
ldh [hSpriteDataOffset], a
call GetPointerWithinSpriteStateData1
ldh a, [hSpriteFacingDirection]
ld [hl], a
ret
SetSpriteImageIndexAfterSettingFacingDirection::
ld de, SPRITESTATEDATA1_IMAGEINDEX - SPRITESTATEDATA1_FACINGDIRECTION
add hl, de
ld [hl], a
ret
; tests if the player's coordinates are in a specified array
; INPUT:
; hl = address of array
; OUTPUT:
; [wCoordIndex] = if there is match, the matching array index
; sets carry if the coordinates are in the array, clears carry if not
ArePlayerCoordsInArray::
ld a, [wYCoord]
ld b, a
ld a, [wXCoord]
ld c, a
; fallthrough
CheckCoords::
xor a
ld [wCoordIndex], a
.loop
ld a, [hli]
cp $ff ; reached terminator?
jr z, .notInArray
push hl
ld hl, wCoordIndex
inc [hl]
pop hl
.compareYCoord
cp b
jr z, .compareXCoord
inc hl
jr .loop
.compareXCoord
ld a, [hli]
cp c
jr nz, .loop
.inArray
scf
ret
.notInArray
and a
ret
; tests if a boulder's coordinates are in a specified array
; INPUT:
; hl = address of array
; [hSpriteIndex] = index of boulder sprite
; OUTPUT:
; [wCoordIndex] = if there is match, the matching array index
; sets carry if the coordinates are in the array, clears carry if not
CheckBoulderCoords::
push hl
ld hl, wSpritePlayerStateData2MapY
ldh a, [hSpriteIndex]
swap a
ld d, $0
ld e, a
add hl, de
ld a, [hli]
sub $4 ; because sprite coordinates are offset by 4
ld b, a
ld a, [hl]
sub $4 ; because sprite coordinates are offset by 4
ld c, a
pop hl
jp CheckCoords
GetPointerWithinSpriteStateData1::
ld h, HIGH(wSpriteStateData1)
jr _GetPointerWithinSpriteStateData
GetPointerWithinSpriteStateData2::
ld h, HIGH(wSpriteStateData2)
_GetPointerWithinSpriteStateData:
ldh a, [hSpriteDataOffset]
ld b, a
ldh a, [hSpriteIndex]
swap a
add b
ld l, a
ret
; decodes a $ff-terminated RLEncoded list
; each entry is a pair of bytes <byte value> <repetitions>
; the final $ff will be replicated in the output list and a contains the number of bytes written
; de: input list
; hl: output list
DecodeRLEList::
xor a
ld [wRLEByteCount], a ; count written bytes here
.listLoop
ld a, [de]
cp $ff
jr z, .endOfList
ldh [hRLEByteValue], a ; store byte value to be written
inc de
ld a, [de]
ld b, $0
ld c, a ; number of bytes to be written
ld a, [wRLEByteCount]
add c
ld [wRLEByteCount], a ; update total number of written bytes
ldh a, [hRLEByteValue]
call FillMemory ; write a c-times to output
inc de
jr .listLoop
.endOfList
ld a, $ff
ld [hl], a ; write final $ff
ld a, [wRLEByteCount]
inc a ; include sentinel in counting
ret
; sets movement byte 1 for sprite [hSpriteIndex] to $FE and byte 2 to [hSpriteMovementByte2]
SetSpriteMovementBytesToFE::
push hl
call GetSpriteMovementByte1Pointer
ld [hl], $fe
call GetSpriteMovementByte2Pointer
ldh a, [hSpriteMovementByte2]
ld [hl], a
pop hl
ret
; sets both movement bytes for sprite [hSpriteIndex] to $FF
SetSpriteMovementBytesToFF::
push hl
call GetSpriteMovementByte1Pointer
ld [hl], $FF
call GetSpriteMovementByte2Pointer
ld [hl], $FF ; prevent person from walking?
pop hl
ret
; returns the sprite movement byte 1 pointer for sprite [hSpriteIndex] in hl
GetSpriteMovementByte1Pointer::
ld h, $C2
ldh a, [hSpriteIndex]
swap a
add 6
ld l, a
ret
; returns the sprite movement byte 2 pointer for sprite [hSpriteIndex] in hl
GetSpriteMovementByte2Pointer::
push de
ld hl, wMapSpriteData
ldh a, [hSpriteIndex]
dec a
add a
ld d, 0
ld e, a
add hl, de
pop de
ret

33
home/math.asm Normal file
View file

@ -0,0 +1,33 @@
; function to do multiplication
; all values are big endian
; INPUT
; FF96-FF98 = multiplicand
; FF99 = multiplier
; OUTPUT
; FF95-FF98 = product
Multiply::
push hl
push bc
callfar _Multiply
pop bc
pop hl
ret
; function to do division
; all values are big endian
; INPUT
; FF95-FF98 = dividend
; FF99 = divisor
; b = number of bytes in the dividend (starting from FF95)
; OUTPUT
; FF95-FF98 = quotient
; FF99 = remainder
Divide::
push hl
push de
push bc
homecall _Divide
pop bc
pop de
pop hl
ret

15
home/money.asm Normal file
View file

@ -0,0 +1,15 @@
HasEnoughMoney::
; Check if the player has at least as much
; money as the 3-byte BCD value at hMoney.
ld de, wPlayerMoney
ld hl, hMoney
ld c, 3
jp StringCmp
HasEnoughCoins::
; Check if the player has at least as many
; coins as the 2-byte BCD value at hCoins.
ld de, wPlayerCoins
ld hl, hCoins
ld c, 2
jp StringCmp

239
home/move_mon.asm Normal file
View file

@ -0,0 +1,239 @@
; Copies [hl, bc) to [de, de + bc - hl).
; In other words, the source data is from hl up to but not including bc,
; and the destination is de.
CopyDataUntil::
ld a, [hli]
ld [de], a
inc de
ld a, h
cp b
jr nz, CopyDataUntil
ld a, l
cp c
jr nz, CopyDataUntil
ret
; Function to remove a pokemon from the party or the current box.
; wWhichPokemon determines the pokemon.
; [wRemoveMonFromBox] == 0 specifies the party.
; [wRemoveMonFromBox] != 0 specifies the current box.
RemovePokemon::
jpfar _RemovePokemon
AddPartyMon::
push hl
push de
push bc
farcall _AddPartyMon
pop bc
pop de
pop hl
ret
; calculates all 5 stats of current mon and writes them to [de]
CalcStats::
ld c, $0
.statsLoop
inc c
call CalcStat
ldh a, [hMultiplicand+1]
ld [de], a
inc de
ldh a, [hMultiplicand+2]
ld [de], a
inc de
ld a, c
cp NUM_STATS
jr nz, .statsLoop
ret
; calculates stat c of current mon
; c: stat to calc (HP=1,Atk=2,Def=3,Spd=4,Spc=5)
; b: consider stat exp?
; hl: base ptr to stat exp values ([hl + 2*c - 1] and [hl + 2*c])
CalcStat::
push hl
push de
push bc
ld a, b
ld d, a
push hl
ld hl, wMonHeader
ld b, $0
add hl, bc
ld a, [hl] ; read base value of stat
ld e, a
pop hl
push hl
sla c
ld a, d
and a
jr z, .statExpDone ; consider stat exp?
add hl, bc ; skip to corresponding stat exp value
.statExpLoop ; calculates ceil(Sqrt(stat exp)) in b
xor a
ldh [hMultiplicand], a
ldh [hMultiplicand+1], a
inc b ; increment current stat exp bonus
ld a, b
cp $ff
jr z, .statExpDone
ldh [hMultiplicand+2], a
ldh [hMultiplier], a
call Multiply
ld a, [hld]
ld d, a
ldh a, [hProduct + 3]
sub d
ld a, [hli]
ld d, a
ldh a, [hProduct + 2]
sbc d ; test if (current stat exp bonus)^2 < stat exp
jr c, .statExpLoop
.statExpDone
srl c
pop hl
push bc
ld bc, wPartyMon1DVs - (wPartyMon1HPExp - 1) ; also wEnemyMonDVs - wEnemyMonHP
add hl, bc
pop bc
ld a, c
cp $2
jr z, .getAttackIV
cp $3
jr z, .getDefenseIV
cp $4
jr z, .getSpeedIV
cp $5
jr z, .getSpecialIV
.getHpIV
push bc
ld a, [hl] ; Atk IV
swap a
and $1
sla a
sla a
sla a
ld b, a
ld a, [hli] ; Def IV
and $1
sla a
sla a
add b
ld b, a
ld a, [hl] ; Spd IV
swap a
and $1
sla a
add b
ld b, a
ld a, [hl] ; Spc IV
and $1
add b ; HP IV: LSB of the other 4 IVs
pop bc
jr .calcStatFromIV
.getAttackIV
ld a, [hl]
swap a
and $f
jr .calcStatFromIV
.getDefenseIV
ld a, [hl]
and $f
jr .calcStatFromIV
.getSpeedIV
inc hl
ld a, [hl]
swap a
and $f
jr .calcStatFromIV
.getSpecialIV
inc hl
ld a, [hl]
and $f
.calcStatFromIV
ld d, $0
add e
ld e, a
jr nc, .noCarry
inc d ; de = Base + IV
.noCarry
sla e
rl d ; de = (Base + IV) * 2
srl b
srl b ; b = ceil(Sqrt(stat exp)) / 4
ld a, b
add e
jr nc, .noCarry2
inc d ; de = (Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4
.noCarry2
ldh [hMultiplicand+2], a
ld a, d
ldh [hMultiplicand+1], a
xor a
ldh [hMultiplicand], a
ld a, [wCurEnemyLVL]
ldh [hMultiplier], a
call Multiply ; ((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level
ldh a, [hMultiplicand]
ldh [hDividend], a
ldh a, [hMultiplicand+1]
ldh [hDividend+1], a
ldh a, [hMultiplicand+2]
ldh [hDividend+2], a
ld a, $64
ldh [hDivisor], a
ld a, $3
ld b, a
call Divide ; (((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level) / 100
ld a, c
cp $1
ld a, 5 ; + 5 for non-HP stat
jr nz, .notHPStat
ld a, [wCurEnemyLVL]
ld b, a
ldh a, [hMultiplicand+2]
add b
ldh [hMultiplicand+2], a
jr nc, .noCarry3
ldh a, [hMultiplicand+1]
inc a
ldh [hMultiplicand+1], a ; HP: (((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level) / 100 + Level
.noCarry3
ld a, 10 ; +10 for HP stat
.notHPStat
ld b, a
ldh a, [hMultiplicand+2]
add b
ldh [hMultiplicand+2], a
jr nc, .noCarry4
ldh a, [hMultiplicand+1]
inc a ; non-HP: (((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level) / 100 + 5
ldh [hMultiplicand+1], a ; HP: (((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level) / 100 + Level + 10
.noCarry4
ldh a, [hMultiplicand+1] ; check for overflow (>999)
cp HIGH(MAX_STAT_VALUE) + 1
jr nc, .overflow
cp HIGH(MAX_STAT_VALUE)
jr c, .noOverflow
ldh a, [hMultiplicand+2]
cp LOW(MAX_STAT_VALUE) + 1
jr c, .noOverflow
.overflow
ld a, HIGH(MAX_STAT_VALUE) ; overflow: cap at 999
ldh [hMultiplicand+1], a
ld a, LOW(MAX_STAT_VALUE)
ldh [hMultiplicand+2], a
.noOverflow
pop bc
pop de
pop hl
ret
AddEnemyMonToPlayerParty::
homecall_sf _AddEnemyMonToPlayerParty
ret
MoveMon::
homecall_sf _MoveMon
ret

141
home/names.asm Normal file
View file

@ -0,0 +1,141 @@
GetMonName::
push hl
ldh a, [hLoadedROMBank]
push af
ld a, BANK(MonsterNames)
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
ld a, [wd11e]
dec a
ld hl, MonsterNames
ld c, 10
ld b, 0
call AddNTimes
ld de, wcd6d
push de
ld bc, 10
call CopyData
ld hl, wcd6d + 10
ld [hl], "@"
pop de
pop af
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
pop hl
ret
GetItemName::
; given an item ID at [wd11e], store the name of the item into a string
; starting at wcd6d
push hl
push bc
ld a, [wd11e]
cp HM01 ; is this a TM/HM?
jr nc, .Machine
ld [wd0b5], a
ld a, ITEM_NAME
ld [wNameListType], a
ld a, BANK(ItemNames)
ld [wPredefBank], a
call GetName
jr .Finish
.Machine
call GetMachineName
.Finish
ld de, wcd6d ; pointer to where item name is stored in RAM
pop bc
pop hl
ret
GetMachineName::
; copies the name of the TM/HM in [wd11e] to wcd6d
push hl
push de
push bc
ld a, [wd11e]
push af
cp TM01 ; is this a TM? [not HM]
jr nc, .WriteTM
; if HM, then write "HM" and add NUM_HMS to the item ID, so we can reuse the
; TM printing code
add NUM_HMS
ld [wd11e], a
ld hl, HiddenPrefix ; points to "HM"
ld bc, 2
jr .WriteMachinePrefix
.WriteTM
ld hl, TechnicalPrefix ; points to "TM"
ld bc, 2
.WriteMachinePrefix
ld de, wcd6d
call CopyData
; now get the machine number and convert it to text
ld a, [wd11e]
sub TM01 - 1
ld b, "0"
.FirstDigit
sub 10
jr c, .SecondDigit
inc b
jr .FirstDigit
.SecondDigit
add 10
push af
ld a, b
ld [de], a
inc de
pop af
ld b, "0"
add b
ld [de], a
inc de
ld a, "@"
ld [de], a
pop af
ld [wd11e], a
pop bc
pop de
pop hl
ret
TechnicalPrefix::
db "TM"
HiddenPrefix::
db "HM"
; sets carry if item is HM, clears carry if item is not HM
; Input: a = item ID
IsItemHM::
cp HM01
jr c, .notHM
cp TM01
ret
.notHM
and a
ret
; sets carry if move is an HM, clears carry if move is not an HM
; Input: a = move ID
IsMoveHM::
ld hl, HMMoves
ld de, 1
jp IsInArray
HMMoves::
INCLUDE "data/moves/hm_moves.asm"
GetMoveName::
push hl
ld a, MOVE_NAME
ld [wNameListType], a
ld a, [wd11e]
ld [wd0b5], a
ld a, BANK(MoveNames)
ld [wPredefBank], a
call GetName
ld de, wcd6d ; pointer to where move name is stored in RAM
pop hl
ret

94
home/names2.asm Normal file
View file

@ -0,0 +1,94 @@
NamePointers::
; entries correspond to *_NAME constants
dw MonsterNames
dw MoveNames
dw UnusedBadgeNames
dw ItemNames
dw wPartyMonOT ; player's OT names list
dw wEnemyMonOT ; enemy's OT names list
dw TrainerNames
GetName::
; arguments:
; [wd0b5] = which name
; [wNameListType] = which list
; [wPredefBank] = bank of list
;
; returns pointer to name in de
ld a, [wd0b5]
ld [wd11e], a
; TM names are separate from item names.
; BUG: This applies to all names instead of just items.
cp HM01
jp nc, GetMachineName
ldh a, [hLoadedROMBank]
push af
push hl
push bc
push de
ld a, [wNameListType] ;List3759_entrySelector
dec a
jr nz, .otherEntries
;1 = MON_NAMES
call GetMonName
ld hl, NAME_LENGTH
add hl, de
ld e, l
ld d, h
jr .gotPtr
.otherEntries
;2-7 = OTHER ENTRIES
ld a, [wPredefBank]
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
ld a, [wNameListType] ;VariousNames' entryID
dec a
add a
ld d, 0
ld e, a
jr nc, .skip
inc d
.skip
ld hl, NamePointers
add hl, de
ld a, [hli]
ldh [hSwapTemp + 1], a
ld a, [hl]
ldh [hSwapTemp], a
ldh a, [hSwapTemp]
ld h, a
ldh a, [hSwapTemp + 1]
ld l, a
ld a, [wd0b5]
ld b, a
ld c, 0
.nextName
ld d, h
ld e, l
.nextChar
ld a, [hli]
cp "@"
jr nz, .nextChar
inc c ;entry counter
ld a, b ;wanted entry
cp c
jr nz, .nextName
ld h, d
ld l, e
ld de, wcd6d
ld bc, $14
call CopyData
.gotPtr
ld a, e
ld [wUnusedCF8D], a
ld a, d
ld [wUnusedCF8D + 1], a
pop de
pop bc
pop hl
pop af
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
ret

64
home/npc_movement.asm Normal file
View file

@ -0,0 +1,64 @@
; not zero if an NPC movement script is running, the player character is
; automatically stepping down from a door, or joypad states are being simulated
IsPlayerCharacterBeingControlledByGame::
ld a, [wNPCMovementScriptPointerTableNum]
and a
ret nz
ld a, [wd736]
bit 1, a ; currently stepping down from door bit
ret nz
ld a, [wd730]
and $80
ret
RunNPCMovementScript::
ld hl, wd736
bit 0, [hl]
res 0, [hl]
jr nz, .playerStepOutFromDoor
ld a, [wNPCMovementScriptPointerTableNum]
and a
ret z
dec a
add a
ld d, 0
ld e, a
ld hl, .NPCMovementScriptPointerTables
add hl, de
ld a, [hli]
ld h, [hl]
ld l, a
ldh a, [hLoadedROMBank]
push af
ld a, [wNPCMovementScriptBank]
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
ld a, [wNPCMovementScriptFunctionNum]
call CallFunctionInTable
pop af
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
ret
.NPCMovementScriptPointerTables
dw PalletMovementScriptPointerTable
dw PewterMuseumGuyMovementScriptPointerTable
dw PewterGymGuyMovementScriptPointerTable
.playerStepOutFromDoor
farjp PlayerStepOutFromDoor
EndNPCMovementScript::
farjp _EndNPCMovementScript
DebugPressedOrHeldB::
IF DEF(_DEBUG)
ld a, [wd732]
bit 1, a
ret z
ldh a, [hJoyHeld]
bit BIT_B_BUTTON, a
ret nz
ldh a, [hJoyPressed]
bit BIT_B_BUTTON, a
ENDC
ret

36
home/oam.asm Normal file
View file

@ -0,0 +1,36 @@
; INPUT:
; a = oam block index (each block is 4 oam entries)
; b = Y coordinate of upper left corner of sprite
; c = X coordinate of upper left corner of sprite
; de = base address of 4 tile number and attribute pairs
WriteOAMBlock::
ld h, HIGH(wOAMBuffer)
swap a ; multiply by 16
ld l, a
call .writeOneEntry ; upper left
push bc
ld a, 8
add c
ld c, a
call .writeOneEntry ; upper right
pop bc
ld a, 8
add b
ld b, a
call .writeOneEntry ; lower left
ld a, 8
add c
ld c, a
; lower right
.writeOneEntry
ld [hl], b ; Y coordinate
inc hl
ld [hl], c ; X coordinate
inc hl
ld a, [de] ; tile number
inc de
ld [hli], a
ld a, [de] ; attribute
inc de
ld [hli], a
ret

File diff suppressed because it is too large Load diff

31
home/overworld_text.asm Normal file
View file

@ -0,0 +1,31 @@
TextScriptEndingText::
text_end
TextScriptEnd::
ld hl, TextScriptEndingText
ret
ExclamationText::
text_far _ExclamationText
text_end
GroundRoseText::
text_far _GroundRoseText
text_end
BoulderText::
text_far _BoulderText
text_end
MartSignText::
text_far _MartSignText
text_end
PokeCenterSignText::
text_far _PokeCenterSignText
text_end
PickUpItemText::
text_asm
predef PickUpItem
jp TextScriptEnd

57
home/palettes.asm Normal file
View file

@ -0,0 +1,57 @@
RestoreScreenTilesAndReloadTilePatterns::
call ClearSprites
ld a, $1
ld [wUpdateSpritesEnabled], a
call ReloadMapSpriteTilePatterns
call LoadScreenTilesFromBuffer2
call LoadTextBoxTilePatterns
call RunDefaultPaletteCommand
jr Delay3
GBPalWhiteOutWithDelay3::
call GBPalWhiteOut
Delay3::
; The bg map is updated each frame in thirds.
; Wait three frames to let the bg map fully update.
ld c, 3
jp DelayFrames
GBPalNormal::
; Reset BGP and OBP0.
ld a, %11100100 ; 3210
ldh [rBGP], a
ld a, %11010000 ; 3100
ldh [rOBP0], a
ret
GBPalWhiteOut::
; White out all palettes.
xor a
ldh [rBGP], a
ldh [rOBP0], a
ldh [rOBP1], a
ret
RunDefaultPaletteCommand::
ld b, SET_PAL_DEFAULT
RunPaletteCommand::
ld a, [wOnSGB]
and a
ret z
predef_jump _RunPaletteCommand
GetHealthBarColor::
; Return at hl the palette of
; an HP bar e pixels long.
ld a, e
cp 27
ld d, 0 ; green
jr nc, .gotColor
cp 10
inc d ; yellow
jr nc, .gotColor
inc d ; red
.gotColor
ld [hl], d
ret

65
home/pathfinding.asm Normal file
View file

@ -0,0 +1,65 @@
; calculates the difference |a-b|, setting carry flag if a<b
CalcDifference::
sub b
ret nc
cpl
add $1
scf
ret
MoveSprite::
; move the sprite [hSpriteIndex] with the movement pointed to by de
; actually only copies the movement data to wNPCMovementDirections for later
call SetSpriteMovementBytesToFF
MoveSprite_::
push hl
push bc
call GetSpriteMovementByte1Pointer
xor a
ld [hl], a
ld hl, wNPCMovementDirections
ld c, 0
.loop
ld a, [de]
ld [hli], a
inc de
inc c
cp -1 ; have we reached the end of the movement data?
jr nz, .loop
ld a, c
ld [wNPCNumScriptedSteps], a ; number of steps taken
pop bc
ld hl, wd730
set 0, [hl]
pop hl
xor a
ld [wOverrideSimulatedJoypadStatesMask], a
ld [wSimulatedJoypadStatesEnd], a
dec a
ld [wJoyIgnore], a
ld [wWastedByteCD3A], a
ret
; divides [hDividend2] by [hDivisor2] and stores the quotient in [hQuotient2]
DivideBytes::
push hl
ld hl, hQuotient2
xor a
ld [hld], a
ld a, [hld]
and a
jr z, .done
ld a, [hli]
.loop
sub [hl]
jr c, .done
inc hl
inc [hl]
dec hl
jr .loop
.done
pop hl
ret

196
home/pics.asm Normal file
View file

@ -0,0 +1,196 @@
; uncompresses the front or back sprite of the specified mon
; assumes the corresponding mon header is already loaded
; hl contains offset to sprite pointer ($b for front or $d for back)
UncompressMonSprite::
ld bc, wMonHeader
add hl, bc
ld a, [hli]
ld [wSpriteInputPtr], a ; fetch sprite input pointer
ld a, [hl]
ld [wSpriteInputPtr+1], a
; define (by index number) the bank that a pokemon's image is in
; index = Mew, bank 1
; index = Kabutops fossil, bank $B
; index < $1F, bank 9
; $1F ≤ index < $4A, bank $A
; $4A ≤ index < $74, bank $B
; $74 ≤ index < $99, bank $C
; $99 ≤ index, bank $D
ld a, [wcf91] ; XXX name for this ram location
ld b, a
cp MEW
ld a, BANK(MewPicFront)
jr z, .GotBank
ld a, b
cp FOSSIL_KABUTOPS
ld a, BANK(FossilKabutopsPic)
jr z, .GotBank
ld a, b
cp TANGELA + 1
ld a, BANK(TangelaPicFront)
jr c, .GotBank
ld a, b
cp MOLTRES + 1
ld a, BANK(MoltresPicFront)
jr c, .GotBank
ld a, b
cp BEEDRILL + 2
ld a, BANK(BeedrillPicFront)
jr c, .GotBank
ld a, b
cp STARMIE + 1
ld a, BANK(StarmiePicFront)
jr c, .GotBank
ld a, BANK(VictreebelPicFront)
.GotBank
jp UncompressSpriteData
; de: destination location
LoadMonFrontSprite::
push de
ld hl, wMonHFrontSprite - wMonHeader
call UncompressMonSprite
ld hl, wMonHSpriteDim
ld a, [hli]
ld c, a
pop de
; fall through
; postprocesses uncompressed sprite chunks to a 2bpp sprite and loads it into video ram
; calculates alignment parameters to place both sprite chunks in the center of the 7*7 tile sprite buffers
; de: destination location
; a,c: sprite dimensions (in tiles of 8x8 each)
LoadUncompressedSpriteData::
push de
and $f
ldh [hSpriteWidth], a ; each byte contains 8 pixels (in 1bpp), so tiles=bytes for width
ld b, a
ld a, $7
sub b ; 7-w
inc a ; 8-w
srl a ; (8-w)/2 ; horizontal center (in tiles, rounded up)
ld b, a
add a
add a
add a
sub b ; 7*((8-w)/2) ; skip for horizontal center (in tiles)
ldh [hSpriteOffset], a
ld a, c
swap a
and $f
ld b, a
add a
add a
add a ; 8*tiles is height in bytes
ldh [hSpriteHeight], a
ld a, $7
sub b ; 7-h ; skip for vertical center (in tiles, relative to current column)
ld b, a
ldh a, [hSpriteOffset]
add b ; 7*((8-w)/2) + 7-h ; combined overall offset (in tiles)
add a
add a
add a ; 8*(7*((8-w)/2) + 7-h) ; combined overall offset (in bytes)
ldh [hSpriteOffset], a
xor a
ld [MBC1SRamBank], a
ld hl, sSpriteBuffer0
call ZeroSpriteBuffer ; zero buffer 0
ld de, sSpriteBuffer1
ld hl, sSpriteBuffer0
call AlignSpriteDataCentered ; copy and align buffer 1 to 0 (containing the MSB of the 2bpp sprite)
ld hl, sSpriteBuffer1
call ZeroSpriteBuffer ; zero buffer 1
ld de, sSpriteBuffer2
ld hl, sSpriteBuffer1
call AlignSpriteDataCentered ; copy and align buffer 2 to 1 (containing the LSB of the 2bpp sprite)
pop de
jp InterlaceMergeSpriteBuffers
; copies and aligns the sprite data properly inside the sprite buffer
; sprite buffers are 7*7 tiles in size, the loaded sprite is centered within this area
AlignSpriteDataCentered::
ldh a, [hSpriteOffset]
ld b, $0
ld c, a
add hl, bc
ldh a, [hSpriteWidth]
.columnLoop
push af
push hl
ldh a, [hSpriteHeight]
ld c, a
.columnInnerLoop
ld a, [de]
inc de
ld [hli], a
dec c
jr nz, .columnInnerLoop
pop hl
ld bc, 7*8 ; 7 tiles
add hl, bc ; advance one full column
pop af
dec a
jr nz, .columnLoop
ret
; fills the sprite buffer (pointed to in hl) with zeros
ZeroSpriteBuffer::
ld bc, SPRITEBUFFERSIZE
.nextByteLoop
xor a
ld [hli], a
dec bc
ld a, b
or c
jr nz, .nextByteLoop
ret
; combines the (7*7 tiles, 1bpp) sprite chunks in buffer 0 and 1 into a 2bpp sprite located in buffer 1 through 2
; in the resulting sprite, the rows of the two source sprites are interlaced
; de: output address
InterlaceMergeSpriteBuffers::
xor a
ld [MBC1SRamBank], a
push de
ld hl, sSpriteBuffer2 + (SPRITEBUFFERSIZE - 1) ; destination: end of buffer 2
ld de, sSpriteBuffer1 + (SPRITEBUFFERSIZE - 1) ; source 2: end of buffer 1
ld bc, sSpriteBuffer0 + (SPRITEBUFFERSIZE - 1) ; source 1: end of buffer 0
ld a, SPRITEBUFFERSIZE/2 ; $c4
ldh [hSpriteInterlaceCounter], a
.interlaceLoop
ld a, [de]
dec de
ld [hld], a ; write byte of source 2
ld a, [bc]
dec bc
ld [hld], a ; write byte of source 1
ld a, [de]
dec de
ld [hld], a ; write byte of source 2
ld a, [bc]
dec bc
ld [hld], a ; write byte of source 1
ldh a, [hSpriteInterlaceCounter]
dec a
ldh [hSpriteInterlaceCounter], a
jr nz, .interlaceLoop
ld a, [wSpriteFlipped]
and a
jr z, .notFlipped
ld bc, 2*SPRITEBUFFERSIZE
ld hl, sSpriteBuffer1
.swapLoop
swap [hl] ; if flipped swap nybbles in all bytes
inc hl
dec bc
ld a, b
or c
jr nz, .swapLoop
.notFlipped
pop hl
ld de, sSpriteBuffer1
ld c, (2*SPRITEBUFFERSIZE)/16 ; $31, number of 16 byte chunks to be copied
ldh a, [hLoadedROMBank]
ld b, a
jp CopyVideoData

451
home/pokemon.asm Normal file
View file

@ -0,0 +1,451 @@
DrawHPBar::
; Draw an HP bar d tiles long, and fill it to e pixels.
; If c is nonzero, show at least a sliver regardless.
; The right end of the bar changes with [wHPBarType].
push hl
push de
push bc
; Left
ld a, $71 ; "HP:"
ld [hli], a
ld a, $62
ld [hli], a
push hl
; Middle
ld a, $63 ; empty
.draw
ld [hli], a
dec d
jr nz, .draw
; Right
ld a, [wHPBarType]
dec a
ld a, $6d ; status screen and battle
jr z, .ok
dec a ; pokemon menu
.ok
ld [hl], a
pop hl
ld a, e
and a
jr nz, .fill
; If c is nonzero, draw a pixel anyway.
ld a, c
and a
jr z, .done
ld e, 1
.fill
ld a, e
sub 8
jr c, .partial
ld e, a
ld a, $6b ; full
ld [hli], a
ld a, e
and a
jr z, .done
jr .fill
.partial
; Fill remaining pixels at the end if necessary.
ld a, $63 ; empty
add e
ld [hl], a
.done
pop bc
pop de
pop hl
ret
; loads pokemon data from one of multiple sources to wLoadedMon
; loads base stats to wMonHeader
; INPUT:
; [wWhichPokemon] = index of pokemon within party/box
; [wMonDataLocation] = source
; 00: player's party
; 01: enemy's party
; 02: current box
; 03: daycare
; OUTPUT:
; [wcf91] = pokemon ID
; wLoadedMon = base address of pokemon data
; wMonHeader = base address of base stats
LoadMonData::
jpfar LoadMonData_
OverwritewMoves::
; Write c to [wMoves + b]. Unused.
ld hl, wMoves
ld e, b
ld d, 0
add hl, de
ld a, c
ld [hl], a
ret
LoadFlippedFrontSpriteByMonIndex::
ld a, 1
ld [wSpriteFlipped], a
LoadFrontSpriteByMonIndex::
push hl
ld a, [wd11e]
push af
ld a, [wcf91]
ld [wd11e], a
predef IndexToPokedex
ld hl, wd11e
ld a, [hl]
pop bc
ld [hl], b
and a
pop hl
jr z, .invalidDexNumber ; dex #0 invalid
cp NUM_POKEMON + 1
jr c, .validDexNumber ; dex >#151 invalid
.invalidDexNumber
ld a, RHYDON ; $1
ld [wcf91], a
ret
.validDexNumber
push hl
ld de, vFrontPic
call LoadMonFrontSprite
pop hl
ldh a, [hLoadedROMBank]
push af
ld a, BANK(CopyUncompressedPicToHL)
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
xor a
ldh [hStartTileID], a
call CopyUncompressedPicToHL
xor a
ld [wSpriteFlipped], a
pop af
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
ret
; PlayCry
GetCryData::
; Load cry data for monster a.
dec a
ld c, a
ld b, 0
ld hl, CryData
add hl, bc
add hl, bc
add hl, bc
ld a, BANK(CryData)
call BankswitchHome
ld a, [hli]
ld b, a ; cry id
ld a, [hli]
ld [wFrequencyModifier], a
ld a, [hl]
ld [wTempoModifier], a
call BankswitchBack
; Cry headers have 3 channels,
; and start from index CRY_SFX_START,
; so add 3 times the cry id.
ld a, b
ld c, $14 ; CRY_SFX_START
rlca ; * 2
add b
add c
ret
DisplayPartyMenu::
ldh a, [hTileAnimations]
push af
xor a
ldh [hTileAnimations], a
call GBPalWhiteOutWithDelay3
call ClearSprites
call PartyMenuInit
call DrawPartyMenu
jp HandlePartyMenuInput
GoBackToPartyMenu::
ldh a, [hTileAnimations]
push af
xor a
ldh [hTileAnimations], a
call PartyMenuInit
call RedrawPartyMenu
jp HandlePartyMenuInput
PartyMenuInit::
ld a, 1 ; hardcoded bank
call BankswitchHome
call LoadHpBarAndStatusTilePatterns
ld hl, wd730
set 6, [hl] ; turn off letter printing delay
xor a ; PLAYER_PARTY_DATA
ld [wMonDataLocation], a
ld [wMenuWatchMovingOutOfBounds], a
ld hl, wTopMenuItemY
inc a
ld [hli], a ; top menu item Y
xor a
ld [hli], a ; top menu item X
ld a, [wPartyAndBillsPCSavedMenuItem]
push af
ld [hli], a ; current menu item ID
inc hl
ld a, [wPartyCount]
and a ; are there more than 0 pokemon in the party?
jr z, .storeMaxMenuItemID
dec a
; if party is not empty, the max menu item ID is ([wPartyCount] - 1)
; otherwise, it is 0
.storeMaxMenuItemID
ld [hli], a ; max menu item ID
ld a, [wForcePlayerToChooseMon]
and a
ld a, A_BUTTON | B_BUTTON
jr z, .next
xor a
ld [wForcePlayerToChooseMon], a
inc a ; a = A_BUTTON
.next
ld [hli], a ; menu watched keys
pop af
ld [hl], a ; old menu item ID
ret
HandlePartyMenuInput::
ld a, 1
ld [wMenuWrappingEnabled], a
ld a, $40
ld [wPartyMenuAnimMonEnabled], a
call HandleMenuInput_
call PlaceUnfilledArrowMenuCursor
ld b, a
xor a
ld [wPartyMenuAnimMonEnabled], a
ld a, [wCurrentMenuItem]
ld [wPartyAndBillsPCSavedMenuItem], a
ld hl, wd730
res 6, [hl] ; turn on letter printing delay
ld a, [wMenuItemToSwap]
and a
jp nz, .swappingPokemon
pop af
ldh [hTileAnimations], a
bit 1, b
jr nz, .noPokemonChosen
ld a, [wPartyCount]
and a
jr z, .noPokemonChosen
ld a, [wCurrentMenuItem]
ld [wWhichPokemon], a
ld hl, wPartySpecies
ld b, 0
ld c, a
add hl, bc
ld a, [hl]
ld [wcf91], a
ld [wBattleMonSpecies2], a
call BankswitchBack
and a
ret
.noPokemonChosen
call BankswitchBack
scf
ret
.swappingPokemon
bit 1, b ; was the B button pressed?
jr z, .handleSwap ; if not, handle swapping the pokemon
.cancelSwap ; if the B button was pressed
farcall ErasePartyMenuCursors
xor a
ld [wMenuItemToSwap], a
ld [wPartyMenuTypeOrMessageID], a
call RedrawPartyMenu
jr HandlePartyMenuInput
.handleSwap
ld a, [wCurrentMenuItem]
ld [wWhichPokemon], a
farcall SwitchPartyMon
jr HandlePartyMenuInput
DrawPartyMenu::
ld hl, DrawPartyMenu_
jr DrawPartyMenuCommon
RedrawPartyMenu::
ld hl, RedrawPartyMenu_
DrawPartyMenuCommon::
ld b, BANK(RedrawPartyMenu_)
jp Bankswitch
; prints a pokemon's status condition
; INPUT:
; de = address of status condition
; hl = destination address
PrintStatusCondition::
push de
dec de
dec de ; de = address of current HP
ld a, [de]
ld b, a
dec de
ld a, [de]
or b ; is the pokemon's HP zero?
pop de
jr nz, PrintStatusConditionNotFainted
; if the pokemon's HP is 0, print "FNT"
ld a, "F"
ld [hli], a
ld a, "N"
ld [hli], a
ld [hl], "T"
and a
ret
PrintStatusConditionNotFainted::
homecall_sf PrintStatusAilment
ret
; function to print pokemon level, leaving off the ":L" if the level is at least 100
; INPUT:
; hl = destination address
; [wLoadedMonLevel] = level
PrintLevel::
ld a, "<LV>" ; ":L" tile ID
ld [hli], a
ld c, 2 ; number of digits
ld a, [wLoadedMonLevel] ; level
cp 100
jr c, PrintLevelCommon
; if level at least 100, write over the ":L" tile
dec hl
inc c ; increment number of digits to 3
jr PrintLevelCommon
; prints the level without leaving off ":L" regardless of level
; INPUT:
; hl = destination address
; [wLoadedMonLevel] = level
PrintLevelFull::
ld a, "<LV>" ; ":L" tile ID
ld [hli], a
ld c, 3 ; number of digits
ld a, [wLoadedMonLevel] ; level
PrintLevelCommon::
ld [wd11e], a
ld de, wd11e
ld b, LEFT_ALIGN | 1 ; 1 byte
jp PrintNumber
GetwMoves::
; Unused. Returns the move at index a from wMoves in a
ld hl, wMoves
ld c, a
ld b, 0
add hl, bc
ld a, [hl]
ret
; copies the base stat data of a pokemon to wMonHeader
; INPUT:
; [wd0b5] = pokemon ID
GetMonHeader::
ldh a, [hLoadedROMBank]
push af
ld a, BANK(BaseStats)
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
push bc
push de
push hl
ld a, [wd11e]
push af
ld a, [wd0b5]
ld [wd11e], a
ld de, FossilKabutopsPic
ld b, $66 ; size of Kabutops fossil and Ghost sprites
cp FOSSIL_KABUTOPS ; Kabutops fossil
jr z, .specialID
ld de, GhostPic
cp MON_GHOST ; Ghost
jr z, .specialID
ld de, FossilAerodactylPic
ld b, $77 ; size of Aerodactyl fossil sprite
cp FOSSIL_AERODACTYL ; Aerodactyl fossil
jr z, .specialID
cp MEW
jr z, .mew
predef IndexToPokedex ; convert pokemon ID in [wd11e] to pokedex number
ld a, [wd11e]
dec a
ld bc, MonBaseStatsEnd - MonBaseStats
ld hl, BaseStats
call AddNTimes
ld de, wMonHeader
ld bc, MonBaseStatsEnd - MonBaseStats
call CopyData
jr .done
.specialID
ld hl, wMonHSpriteDim
ld [hl], b ; write sprite dimensions
inc hl
ld [hl], e ; write front sprite pointer
inc hl
ld [hl], d
jr .done
.mew
ld hl, MewBaseStats
ld de, wMonHeader
ld bc, MonBaseStatsEnd - MonBaseStats
ld a, BANK(MewBaseStats)
call FarCopyData
.done
ld a, [wd0b5]
ld [wMonHIndex], a
pop af
ld [wd11e], a
pop hl
pop de
pop bc
pop af
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
ret
; copy party pokemon's name to wcd6d
GetPartyMonName2::
ld a, [wWhichPokemon] ; index within party
ld hl, wPartyMonNicks
; this is called more often
GetPartyMonName::
push hl
push bc
call SkipFixedLengthTextEntries ; add NAME_LENGTH to hl, a times
ld de, wcd6d
push de
ld bc, NAME_LENGTH
call CopyData
pop de
pop bc
pop hl
ret

View file

@ -8,18 +8,18 @@ Predef::
; A hack for LoadDestinationWarpPosition.
; See LoadTilesetHeader (predef $19).
ld a, [H_LOADEDROMBANK]
ldh a, [hLoadedROMBank]
ld [wPredefParentBank], a
push af
ld a, BANK(GetPredefPointer)
ld [H_LOADEDROMBANK], a
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
call GetPredefPointer
ld a, [wPredefBank]
ld [H_LOADEDROMBANK], a
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
ld de, .done
@ -28,7 +28,7 @@ Predef::
.done
pop af
ld [H_LOADEDROMBANK], a
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
ret

28
home/predef_text.asm Normal file
View file

@ -0,0 +1,28 @@
PrintPredefTextID::
ldh [hSpriteIndexOrTextID], a
ld hl, TextPredefs
call SetMapTextPointer
ld hl, wTextPredefFlag
set 0, [hl]
call DisplayTextID
RestoreMapTextPointer::
ld hl, wMapTextPtr
ldh a, [hSavedMapTextPtr]
ld [hli], a
ldh a, [hSavedMapTextPtr + 1]
ld [hl], a
ret
SetMapTextPointer::
ld a, [wMapTextPtr]
ldh [hSavedMapTextPtr], a
ld a, [wMapTextPtr + 1]
ldh [hSavedMapTextPtr + 1], a
ld a, l
ld [wMapTextPtr], a
ld a, h
ld [wMapTextPtr + 1], a
ret
INCLUDE "data/text_predef_pointers.asm"

77
home/print_bcd.asm Normal file
View file

@ -0,0 +1,77 @@
; function to print a BCD (Binary-coded decimal) number
; de = address of BCD number
; hl = destination address
; c = flags and length
; bit 7: if set, do not print leading zeroes
; if unset, print leading zeroes
; bit 6: if set, left-align the string (do not pad empty digits with spaces)
; if unset, right-align the string
; bit 5: if set, print currency symbol at the beginning of the string
; if unset, do not print the currency symbol
; bits 0-4: length of BCD number in bytes
; Note that bits 5 and 7 are modified during execution. The above reflects
; their meaning at the beginning of the functions's execution.
PrintBCDNumber::
ld b, c ; save flags in b
res 7, c
res 6, c
res 5, c ; c now holds the length
bit 5, b
jr z, .loop
bit 7, b
jr nz, .loop
ld [hl], "¥"
inc hl
.loop
ld a, [de]
swap a
call PrintBCDDigit ; print upper digit
ld a, [de]
call PrintBCDDigit ; print lower digit
inc de
dec c
jr nz, .loop
bit 7, b ; were any non-zero digits printed?
jr z, .done ; if so, we are done
.numberEqualsZero ; if every digit of the BCD number is zero
bit 6, b ; left or right alignment?
jr nz, .skipRightAlignmentAdjustment
dec hl ; if the string is right-aligned, it needs to be moved back one space
.skipRightAlignmentAdjustment
bit 5, b
jr z, .skipCurrencySymbol
ld [hl], "¥"
inc hl
.skipCurrencySymbol
ld [hl], "0"
call PrintLetterDelay
inc hl
.done
ret
PrintBCDDigit::
and $f
and a
jr z, .zeroDigit
.nonzeroDigit
bit 7, b ; have any non-space characters been printed?
jr z, .outputDigit
; if bit 7 is set, then no numbers have been printed yet
bit 5, b ; print the currency symbol?
jr z, .skipCurrencySymbol
ld [hl], "¥"
inc hl
res 5, b
.skipCurrencySymbol
res 7, b ; unset 7 to indicate that a nonzero digit has been reached
.outputDigit
add "0"
ld [hli], a
jp PrintLetterDelay
.zeroDigit
bit 7, b ; either printing leading zeroes or already reached a nonzero digit?
jr z, .outputDigit ; if so, print a zero digit
bit 6, b ; left or right alignment?
ret nz
inc hl ; if right-aligned, "print" a space by advancing the pointer
ret

219
home/print_num.asm Normal file
View file

@ -0,0 +1,219 @@
PrintNumber::
; Print the c-digit, b-byte value at de.
; Allows 2 to 7 digits. For 1-digit numbers, add
; the value to char "0" instead of calling PrintNumber.
; Flags LEADING_ZEROES and LEFT_ALIGN can be given
; in bits 7 and 6 of b respectively.
push bc
xor a
ldh [hPastLeadingZeros], a
ldh [hNumToPrint], a
ldh [hNumToPrint + 1], a
ld a, b
and $f
cp 1
jr z, .byte
cp 2
jr z, .word
.long
ld a, [de]
ldh [hNumToPrint], a
inc de
ld a, [de]
ldh [hNumToPrint + 1], a
inc de
ld a, [de]
ldh [hNumToPrint + 2], a
jr .start
.word
ld a, [de]
ldh [hNumToPrint + 1], a
inc de
ld a, [de]
ldh [hNumToPrint + 2], a
jr .start
.byte
ld a, [de]
ldh [hNumToPrint + 2], a
.start
push de
ld d, b
ld a, c
ld b, a
xor a
ld c, a
ld a, b
cp 2
jr z, .tens
cp 3
jr z, .hundreds
cp 4
jr z, .thousands
cp 5
jr z, .ten_thousands
cp 6
jr z, .hundred_thousands
print_digit: MACRO
IF (\1) / $10000
ld a, \1 / $10000 % $100
ELSE
xor a
ENDC
ldh [hPowerOf10 + 0], a
IF (\1) / $100
ld a, \1 / $100 % $100
ELSE
xor a
ENDC
ldh [hPowerOf10 + 1], a
ld a, \1 / $1 % $100
ldh [hPowerOf10 + 2], a
call .PrintDigit
call .NextDigit
ENDM
.millions print_digit 1000000
.hundred_thousands print_digit 100000
.ten_thousands print_digit 10000
.thousands print_digit 1000
.hundreds print_digit 100
.tens
ld c, 0
ldh a, [hNumToPrint + 2]
.mod
cp 10
jr c, .ok
sub 10
inc c
jr .mod
.ok
ld b, a
ldh a, [hPastLeadingZeros]
or c
ldh [hPastLeadingZeros], a
jr nz, .past
call .PrintLeadingZero
jr .next
.past
ld a, "0"
add c
ld [hl], a
.next
call .NextDigit
.ones
ld a, "0"
add b
ld [hli], a
pop de
dec de
pop bc
ret
.PrintDigit:
; Divide by the current decimal place.
; Print the quotient, and keep the modulus.
ld c, 0
.loop
ldh a, [hPowerOf10]
ld b, a
ldh a, [hNumToPrint]
ldh [hSavedNumToPrint], a
cp b
jr c, .underflow0
sub b
ldh [hNumToPrint], a
ldh a, [hPowerOf10 + 1]
ld b, a
ldh a, [hNumToPrint + 1]
ldh [hSavedNumToPrint + 1], a
cp b
jr nc, .noborrow1
ldh a, [hNumToPrint]
or 0
jr z, .underflow1
dec a
ldh [hNumToPrint], a
ldh a, [hNumToPrint + 1]
.noborrow1
sub b
ldh [hNumToPrint + 1], a
ldh a, [hPowerOf10 + 2]
ld b, a
ldh a, [hNumToPrint + 2]
ldh [hSavedNumToPrint + 2], a
cp b
jr nc, .noborrow2
ldh a, [hNumToPrint + 1]
and a
jr nz, .borrowed
ldh a, [hNumToPrint]
and a
jr z, .underflow2
dec a
ldh [hNumToPrint], a
xor a
.borrowed
dec a
ldh [hNumToPrint + 1], a
ldh a, [hNumToPrint + 2]
.noborrow2
sub b
ldh [hNumToPrint + 2], a
inc c
jr .loop
.underflow2
ldh a, [hSavedNumToPrint + 1]
ldh [hNumToPrint + 1], a
.underflow1
ldh a, [hSavedNumToPrint]
ldh [hNumToPrint], a
.underflow0
ldh a, [hPastLeadingZeros]
or c
jr z, .PrintLeadingZero
ld a, "0"
add c
ld [hl], a
ldh [hPastLeadingZeros], a
ret
.PrintLeadingZero:
bit BIT_LEADING_ZEROES, d
ret z
ld [hl], "0"
ret
.NextDigit:
; Increment unless the number is left-aligned,
; leading zeroes are not printed, and no digits
; have been printed yet.
bit BIT_LEADING_ZEROES, d
jr nz, .inc
bit BIT_LEFT_ALIGN, d
jr z, .inc
ldh a, [hPastLeadingZeros]
and a
ret z
.inc
inc hl
ret

45
home/print_text.asm Normal file
View file

@ -0,0 +1,45 @@
; This function is used to wait a short period after printing a letter to the
; screen unless the player presses the A/B button or the delay is turned off
; through the [wd730] or [wLetterPrintingDelayFlags] flags.
PrintLetterDelay::
ld a, [wd730]
bit 6, a
ret nz
ld a, [wLetterPrintingDelayFlags]
bit 1, a
ret z
push hl
push de
push bc
ld a, [wLetterPrintingDelayFlags]
bit 0, a
jr z, .waitOneFrame
ld a, [wOptions]
and $f
ldh [hFrameCounter], a
jr .checkButtons
.waitOneFrame
ld a, 1
ldh [hFrameCounter], a
.checkButtons
call Joypad
ldh a, [hJoyHeld]
.checkAButton
bit 0, a ; is the A button pressed?
jr z, .checkBButton
jr .endWait
.checkBButton
bit 1, a ; is the B button pressed?
jr z, .buttonsNotPressed
.endWait
call DelayFrame
jr .done
.buttonsNotPressed ; if neither A nor B is pressed
ldh a, [hFrameCounter]
and a
jr nz, .checkButtons
.done
pop bc
pop de
pop hl
ret

12
home/random.asm Normal file
View file

@ -0,0 +1,12 @@
Random::
; Return a random number in a.
; For battles, use BattleRandom.
push hl
push de
push bc
farcall Random_
ldh a, [hRandomAdd]
pop bc
pop de
pop hl
ret

19
home/reload_sprites.asm Normal file
View file

@ -0,0 +1,19 @@
; Copy the current map's sprites' tile patterns to VRAM again after they have
; been overwritten by other tile patterns.
ReloadMapSpriteTilePatterns::
ld hl, wFontLoaded
ld a, [hl]
push af
res 0, [hl]
push hl
xor a
ld [wSpriteSetID], a
call DisableLCD
farcall InitMapSprites
call EnableLCD
pop hl
pop af
ld [hl], a
call LoadPlayerSpriteGraphics
call LoadFontTilePatterns
jp UpdateSprites

41
home/reload_tiles.asm Normal file
View file

@ -0,0 +1,41 @@
; reloads text box tile patterns, current map view, and tileset tile patterns
ReloadMapData::
ldh a, [hLoadedROMBank]
push af
ld a, [wCurMap]
call SwitchToMapRomBank
call DisableLCD
call LoadTextBoxTilePatterns
call LoadCurrentMapView
call LoadTilesetTilePatternData
call EnableLCD
pop af
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
ret
; reloads tileset tile patterns
ReloadTilesetTilePatterns::
ldh a, [hLoadedROMBank]
push af
ld a, [wCurMap]
call SwitchToMapRomBank
call DisableLCD
call LoadTilesetTilePatternData
call EnableLCD
pop af
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
ret
; shows the town map and lets the player choose a destination to fly to
ChooseFlyDestination::
ld hl, wd72e
res 4, [hl]
farjp LoadTownMap_Fly
; causes the text box to close without waiting for a button press after displaying text
DisableWaitingAfterTextDisplay::
ld a, $01
ld [wDoNotWaitForButtonPressAfterDisplayingText], a
ret

View file

@ -0,0 +1,20 @@
ResetPlayerSpriteData::
ld hl, wSpriteStateData1
call ResetPlayerSpriteData_ClearSpriteData
ld hl, wSpriteStateData2
call ResetPlayerSpriteData_ClearSpriteData
ld a, $1
ld [wSpritePlayerStateData1PictureID], a
ld [wSpritePlayerStateData2ImageBaseOffset], a
ld hl, wSpritePlayerStateData1YPixels
ld [hl], $3c ; set Y screen pos
inc hl
inc hl
ld [hl], $40 ; set X screen pos
ret
; overwrites sprite data with zeroes
ResetPlayerSpriteData_ClearSpriteData::
ld bc, $10
xor a
jp FillMemory

View file

@ -3,46 +3,46 @@ Serial::
push bc
push de
push hl
ld a, [hSerialConnectionStatus]
ldh a, [hSerialConnectionStatus]
inc a
jr z, .connectionNotYetEstablished
ld a, [rSB]
ld [hSerialReceiveData], a
ld a, [hSerialSendData]
ld [rSB], a
ld a, [hSerialConnectionStatus]
ldh a, [rSB]
ldh [hSerialReceiveData], a
ldh a, [hSerialSendData]
ldh [rSB], a
ldh a, [hSerialConnectionStatus]
cp USING_INTERNAL_CLOCK
jr z, .done
; using external clock
ld a, START_TRANSFER_EXTERNAL_CLOCK
ld [rSC], a
ldh [rSC], a
jr .done
.connectionNotYetEstablished
ld a, [rSB]
ld [hSerialReceiveData], a
ld [hSerialConnectionStatus], a
ldh a, [rSB]
ldh [hSerialReceiveData], a
ldh [hSerialConnectionStatus], a
cp USING_INTERNAL_CLOCK
jr z, .usingInternalClock
; using external clock
xor a
ld [rSB], a
ldh [rSB], a
ld a, $3
ld [rDIV], a
ldh [rDIV], a
.waitLoop
ld a, [rDIV]
ldh a, [rDIV]
bit 7, a
jr nz, .waitLoop
ld a, START_TRANSFER_EXTERNAL_CLOCK
ld [rSC], a
ldh [rSC], a
jr .done
.usingInternalClock
xor a
ld [rSB], a
ldh [rSB], a
.done
ld a, $1
ld [hSerialReceivedNewData], a
ldh [hSerialReceivedNewData], a
ld a, SERIAL_NO_DATA_BYTE
ld [hSerialSendData], a
ldh [hSerialSendData], a
pop hl
pop de
pop bc
@ -54,10 +54,10 @@ Serial::
; bc = length of data
Serial_ExchangeBytes::
ld a, 1
ld [hSerialIgnoringInitialData], a
ldh [hSerialIgnoringInitialData], a
.loop
ld a, [hl]
ld [hSerialSendData], a
ldh [hSerialSendData], a
call Serial_ExchangeByte
push bc
ld b, a
@ -66,7 +66,7 @@ Serial_ExchangeBytes::
.waitLoop
dec a
jr nz, .waitLoop
ld a, [hSerialIgnoringInitialData]
ldh a, [hSerialIgnoringInitialData]
and a
ld a, b
pop bc
@ -75,7 +75,7 @@ Serial_ExchangeBytes::
cp SERIAL_PREAMBLE_BYTE
jr nz, .loop
xor a
ld [hSerialIgnoringInitialData], a
ldh [hSerialIgnoringInitialData], a
jr .loop
.storeReceivedByte
ld [de], a
@ -88,17 +88,17 @@ Serial_ExchangeBytes::
Serial_ExchangeByte::
xor a
ld [hSerialReceivedNewData], a
ld a, [hSerialConnectionStatus]
ldh [hSerialReceivedNewData], a
ldh a, [hSerialConnectionStatus]
cp USING_INTERNAL_CLOCK
jr nz, .loop
ld a, START_TRANSFER_INTERNAL_CLOCK
ld [rSC], a
ldh [rSC], a
.loop
ld a, [hSerialReceivedNewData]
ldh a, [hSerialReceivedNewData]
and a
jr nz, .ok
ld a, [hSerialConnectionStatus]
ldh a, [hSerialConnectionStatus]
cp USING_EXTERNAL_CLOCK
jr nz, .doNotIncrementUnknownCounter
call IsUnknownCounterZero
@ -116,7 +116,7 @@ Serial_ExchangeByte::
jr nz, .loop
jp SetUnknownCounterToFFFF
.doNotIncrementUnknownCounter
ld a, [rIE]
ldh a, [rIE]
and (1 << SERIAL) | (1 << TIMER) | (1 << LCD_STAT) | (1 << VBLANK)
cp (1 << SERIAL)
jr nz, .loop
@ -128,7 +128,7 @@ Serial_ExchangeByte::
dec a
ld [wUnknownSerialCounter2 + 1], a
jr nz, .loop
ld a, [hSerialConnectionStatus]
ldh a, [hSerialConnectionStatus]
cp USING_EXTERNAL_CLOCK
jr z, .ok
ld a, 255
@ -137,8 +137,8 @@ Serial_ExchangeByte::
jr nz, .waitLoop
.ok
xor a
ld [hSerialReceivedNewData], a
ld a, [rIE]
ldh [hSerialReceivedNewData], a
ldh a, [rIE]
and (1 << SERIAL) | (1 << TIMER) | (1 << LCD_STAT) | (1 << VBLANK)
sub (1 << SERIAL)
jr nz, .skipReloadingUnknownCounter2
@ -146,7 +146,7 @@ Serial_ExchangeByte::
ld a, $50
ld [wUnknownSerialCounter2 + 1], a
.skipReloadingUnknownCounter2
ld a, [hSerialReceiveData]
ldh a, [hSerialReceiveData]
cp SERIAL_NO_DATA_BYTE
ret nz
call IsUnknownCounterZero
@ -164,13 +164,13 @@ Serial_ExchangeByte::
call IsUnknownCounterZero
jr z, SetUnknownCounterToFFFF
.done
ld a, [rIE]
ldh a, [rIE]
and (1 << SERIAL) | (1 << TIMER) | (1 << LCD_STAT) | (1 << VBLANK)
cp (1 << SERIAL)
ld a, SERIAL_NO_DATA_BYTE
ret z
ld a, [hl]
ld [hSerialSendData], a
ldh [hSerialSendData], a
call DelayFrame
jp Serial_ExchangeByte
@ -203,18 +203,18 @@ Serial_ExchangeLinkMenuSelection::
ld de, wLinkMenuSelectionReceiveBuffer
ld c, 2 ; number of bytes to save
ld a, 1
ld [hSerialIgnoringInitialData], a
ldh [hSerialIgnoringInitialData], a
.loop
call DelayFrame
ld a, [hl]
ld [hSerialSendData], a
ldh [hSerialSendData], a
call Serial_ExchangeByte
ld b, a
inc hl
ld a, [hSerialIgnoringInitialData]
ldh a, [hSerialIgnoringInitialData]
and a
ld a, 0
ld [hSerialIgnoringInitialData], a
ldh [hSerialIgnoringInitialData], a
jr nz, .loop
ld a, b
ld [de], a
@ -225,7 +225,7 @@ Serial_ExchangeLinkMenuSelection::
Serial_PrintWaitingTextAndSyncAndExchangeNybble::
call SaveScreenTilesToBuffer1
callab PrintWaitingText
callfar PrintWaitingText
call Serial_SyncAndExchangeNybble
jp LoadScreenTilesFromBuffer1
@ -273,20 +273,20 @@ Serial_ExchangeNybble::
call .doExchange
ld a, [wSerialExchangeNybbleSendData]
add $60
ld [hSerialSendData], a
ld a, [hSerialConnectionStatus]
ldh [hSerialSendData], a
ldh a, [hSerialConnectionStatus]
cp USING_INTERNAL_CLOCK
jr nz, .doExchange
ld a, START_TRANSFER_INTERNAL_CLOCK
ld [rSC], a
ldh [rSC], a
.doExchange
ld a, [hSerialReceiveData]
ldh a, [hSerialReceiveData]
ld [wSerialExchangeNybbleTempReceiveData], a
and $f0
cp $60
ret nz
xor a
ld [hSerialReceiveData], a
ldh [hSerialReceiveData], a
ld a, [wSerialExchangeNybbleTempReceiveData]
and $f
ld [wSerialExchangeNybbleReceiveData], a
@ -294,19 +294,19 @@ Serial_ExchangeNybble::
Serial_SendZeroByte::
xor a
ld [hSerialSendData], a
ld a, [hSerialConnectionStatus]
ldh [hSerialSendData], a
ldh a, [hSerialConnectionStatus]
cp USING_INTERNAL_CLOCK
ret nz
ld a, START_TRANSFER_INTERNAL_CLOCK
ld [rSC], a
ldh [rSC], a
ret
Serial_TryEstablishingExternallyClockedConnection::
ld a, ESTABLISH_CONNECTION_WITH_EXTERNAL_CLOCK
ld [rSB], a
ldh [rSB], a
xor a
ld [hSerialReceiveData], a
ldh [hSerialReceiveData], a
ld a, START_TRANSFER_EXTERNAL_CLOCK
ld [rSC], a
ldh [rSC], a
ret

10
home/start.asm Normal file
View file

@ -0,0 +1,10 @@
_Start::
cp GBC
jr z, .gbc
xor a
jr .ok
.gbc
ld a, FALSE
.ok
ld [wGBC], a
jp Init

85
home/start_menu.asm Normal file
View file

@ -0,0 +1,85 @@
DisplayStartMenu::
ld a, BANK(StartMenu_Pokedex)
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
ld a, [wWalkBikeSurfState] ; walking/biking/surfing
ld [wWalkBikeSurfStateCopy], a
ld a, SFX_START_MENU
call PlaySound
RedisplayStartMenu::
farcall DrawStartMenu
farcall PrintSafariZoneSteps ; print Safari Zone info, if in Safari Zone
call UpdateSprites
.loop
call HandleMenuInput
ld b, a
.checkIfUpPressed
bit 6, a ; was Up pressed?
jr z, .checkIfDownPressed
ld a, [wCurrentMenuItem] ; menu selection
and a
jr nz, .loop
ld a, [wLastMenuItem]
and a
jr nz, .loop
; if the player pressed tried to go past the top item, wrap around to the bottom
CheckEvent EVENT_GOT_POKEDEX
ld a, 6 ; there are 7 menu items with the pokedex, so the max index is 6
jr nz, .wrapMenuItemId
dec a ; there are only 6 menu items without the pokedex
.wrapMenuItemId
ld [wCurrentMenuItem], a
call EraseMenuCursor
jr .loop
.checkIfDownPressed
bit 7, a
jr z, .buttonPressed
; if the player pressed tried to go past the bottom item, wrap around to the top
CheckEvent EVENT_GOT_POKEDEX
ld a, [wCurrentMenuItem]
ld c, 7 ; there are 7 menu items with the pokedex
jr nz, .checkIfPastBottom
dec c ; there are only 6 menu items without the pokedex
.checkIfPastBottom
cp c
jr nz, .loop
; the player went past the bottom, so wrap to the top
xor a
ld [wCurrentMenuItem], a
call EraseMenuCursor
jr .loop
.buttonPressed ; A, B, or Start button pressed
call PlaceUnfilledArrowMenuCursor
ld a, [wCurrentMenuItem]
ld [wBattleAndStartSavedMenuItem], a ; save current menu selection
ld a, b
and %00001010 ; was the Start button or B button pressed?
jp nz, CloseStartMenu
call SaveScreenTilesToBuffer2 ; copy background from wTileMap to wTileMapBackup2
CheckEvent EVENT_GOT_POKEDEX
ld a, [wCurrentMenuItem]
jr nz, .displayMenuItem
inc a ; adjust position to account for missing pokedex menu item
.displayMenuItem
cp 0
jp z, StartMenu_Pokedex
cp 1
jp z, StartMenu_Pokemon
cp 2
jp z, StartMenu_Item
cp 3
jp z, StartMenu_TrainerInfo
cp 4
jp z, StartMenu_SaveReset
cp 5
jp z, StartMenu_Option
; EXIT falls through to here
CloseStartMenu::
call Joypad
ldh a, [hJoyPressed]
bit 0, a ; was A button newly pressed?
jr nz, CloseStartMenu
call LoadTextBoxTilePatterns
jp CloseTextDisplay

View file

@ -5,9 +5,9 @@ TextBoxBorder::
push hl
ld a, "┌"
ld [hli], a
inc a ;
call NPlaceChar
inc a ;
inc a ; "─"
call .PlaceChars
inc a ; "┐"
ld [hl], a
pop hl
@ -20,7 +20,7 @@ TextBoxBorder::
ld a, "│"
ld [hli], a
ld a, " "
call NPlaceChar
call .PlaceChars
ld [hl], "│"
pop hl
@ -33,11 +33,11 @@ TextBoxBorder::
ld a, "└"
ld [hli], a
ld a, "─"
call NPlaceChar
call .PlaceChars
ld [hl], "┘"
ret
NPlaceChar::
.PlaceChars::
; Place char a c times.
ld d, c
.loop
@ -48,21 +48,21 @@ NPlaceChar::
PlaceString::
push hl
PlaceNextChar::
ld a, [de]
cp "@"
jr nz, Char4ETest
jr nz, .NotTerminator
ld b, h
ld c, l
pop hl
ret
Char4ETest::
cp $4E ; next
jr nz, .char4FTest
.NotTerminator
cp "<NEXT>"
jr nz, .NotNext
ld bc, 2 * SCREEN_WIDTH
ld a, [hFlags_0xFFF6]
ldh a, [hUILayoutFlags]
bit 2, a
jr z, .ok
ld bc, SCREEN_WIDTH
@ -70,142 +70,101 @@ Char4ETest::
pop hl
add hl, bc
push hl
jp PlaceNextChar_inc
jp NextChar
.char4FTest
cp $4F ; line
jr nz, .next3
.NotNext
cp "<LINE>"
jr nz, .NotLine
pop hl
coord hl, 1, 16
hlcoord 1, 16
push hl
jp PlaceNextChar_inc
jp NextChar
.next3 ; Check against a dictionary
dict: macro
if \1 == 0
and a
else
cp \1
endc
jp z, \2
endm
.NotLine
dict $00, Char00 ; error
dict $4C, Char4C ; autocont
dict $4B, Char4B ; cont_
dict $51, Char51 ; para
dict $49, Char49 ; page
dict $52, Char52 ; player
dict $53, Char53 ; rival
dict $54, Char54 ; POKé
dict $5B, Char5B ; PC
dict $5E, Char5E ; ROCKET
dict $5C, Char5C ; TM
dict $5D, Char5D ; TRAINER
dict $55, Char55 ; cont
dict $56, Char56 ; 6 dots
dict $57, Char57 ; done
dict $58, Char58 ; prompt
dict $4A, Char4A ; PKMN
dict $5F, Char5F ; dex
dict $59, Char59 ; TARGET
dict $5A, Char5A ; USER
; Check against a dictionary
dict "<NULL>", NullChar
dict "<SCROLL>", _ContTextNoPause
dict "<_CONT>", _ContText
dict "<PARA>", Paragraph
dict "<PAGE>", PageChar
dict "<PLAYER>", PrintPlayerName
dict "<RIVAL>", PrintRivalName
dict "#", PlacePOKe
dict "<PC>", PCChar
dict "<ROCKET>", RocketChar
dict "<TM>", TMChar
dict "<TRAINER>", TrainerChar
dict "<CONT>", ContText
dict "<……>", SixDotsChar
dict "<DONE>", DoneText
dict "<PROMPT>", PromptText
dict "<PKMN>", PlacePKMN
dict "<DEXEND>", PlaceDexEnd
dict "<TARGET>", PlaceMoveTargetsName
dict "<USER>", PlaceMoveUsersName
ld [hli], a
call PrintLetterDelay
PlaceNextChar_inc::
NextChar::
inc de
jp PlaceNextChar
Char00::
NullChar::
ld b, h
ld c, l
pop hl
ld de, Char00Text
ld de, TextIDErrorText
dec de
ret
Char00Text:: ; “%d ERROR.”
TX_FAR _Char00Text
db "@"
TextIDErrorText:: ; "[hSpriteIndexOrTextID] ERROR."
text_far _TextIDErrorText
text_end
Char52:: ; players name
print_name: MACRO
push de
ld de, wPlayerName
jr FinishDTE
ld de, \1
jr PlaceCommandCharacter
ENDM
Char53:: ; rivals name
push de
ld de, wRivalName
jr FinishDTE
PrintPlayerName:: print_name wPlayerName
PrintRivalName:: print_name wRivalName
Char5D:: ; TRAINER
push de
ld de, Char5DText
jr FinishDTE
TrainerChar:: print_name TrainerCharText
TMChar:: print_name TMCharText
PCChar:: print_name PCCharText
RocketChar:: print_name RocketCharText
PlacePOKe:: print_name PlacePOKeText
SixDotsChar:: print_name SixDotsCharText
PlacePKMN:: print_name PlacePKMNText
Char5C:: ; TM
push de
ld de, Char5CText
jr FinishDTE
Char5B:: ; PC
push de
ld de, Char5BText
jr FinishDTE
Char5E:: ; ROCKET
push de
ld de, Char5EText
jr FinishDTE
Char54:: ; POKé
push de
ld de, Char54Text
jr FinishDTE
Char56:: ; ……
push de
ld de, Char56Text
jr FinishDTE
Char4A:: ; PKMN
push de
ld de, Char4AText
jr FinishDTE
Char59::
; depending on whose turn it is, print
; enemy active monsters name, prefixed with “Enemy ”
; or
; player active monsters name
; (like Char5A but flipped)
ld a, [H_WHOSETURN]
PlaceMoveTargetsName::
ldh a, [hWhoseTurn]
xor 1
jr MonsterNameCharsCommon
jr PlaceMoveUsersName.place
Char5A::
; depending on whose turn it is, print
; player active monsters name
; or
; enemy active monsters name, prefixed with “Enemy ”
ld a, [H_WHOSETURN]
MonsterNameCharsCommon::
PlaceMoveUsersName::
ldh a, [hWhoseTurn]
.place:
push de
and a
jr nz, .Enemy
ld de, wBattleMonNick ; player active monster name
jr FinishDTE
jr nz, .enemy
.Enemy
; print “Enemy ”
ld de, Char5AText
ld de, wBattleMonNick
jr PlaceCommandCharacter
.enemy
ld de, EnemyText
call PlaceString
ld h, b
ld l, c
ld de, wEnemyMonNick ; enemy active monster name
ld de, wEnemyMonNick
; fallthrough
FinishDTE::
PlaceCommandCharacter::
call PlaceString
ld h, b
ld l, c
@ -213,28 +172,20 @@ FinishDTE::
inc de
jp PlaceNextChar
Char5CText::
db "TM@"
Char5DText::
db "TRAINER@"
Char5BText::
db "PC@"
Char5EText::
db "ROCKET@"
Char54Text::
db "POKé@"
Char56Text::
db "……@"
Char5AText::
db "Enemy @"
Char4AText::
db $E1,$E2,"@" ; PKMN
TMCharText:: db "TM@"
TrainerCharText:: db "TRAINER@"
PCCharText:: db "PC@"
RocketCharText:: db "ROCKET@"
PlacePOKeText:: db "POKé@"
SixDotsCharText:: db "……@"
EnemyText:: db "Enemy @"
PlacePKMNText:: db "<PK><MN>@"
Char55::
ContText::
push de
ld b, h
ld c, l
ld hl, Char55Text
ld hl, ContCharText
call TextCommandProcessor
ld h, b
ld l, c
@ -242,94 +193,92 @@ Char55::
inc de
jp PlaceNextChar
Char55Text::
; equivalent to Char4B
TX_FAR _Char55Text
db "@"
ContCharText::
text_far _ContCharText
text_end
Char5F::
; ends a Pokédex entry
PlaceDexEnd::
ld [hl], "."
pop hl
ret
Char58:: ; prompt
PromptText::
ld a, [wLinkState]
cp LINK_STATE_BATTLING
jp z, .ok
ld a, "▼"
Coorda 18, 16
ldcoord_a 18, 16
.ok
call ProtectedDelay3
call ManualTextScroll
ld a, " "
Coorda 18, 16
Char57:: ; done
ldcoord_a 18, 16
DoneText::
pop hl
ld de, Char58Text
ld de, .stop
dec de
ret
Char58Text::
db "@"
.stop:
text_end
Char51:: ; para
Paragraph::
push de
ld a, "▼"
Coorda 18, 16
ldcoord_a 18, 16
call ProtectedDelay3
call ManualTextScroll
coord hl, 1, 13
hlcoord 1, 13
lb bc, 4, 18
call ClearScreenArea
ld c, 20
call DelayFrames
pop de
coord hl, 1, 14
jp PlaceNextChar_inc
hlcoord 1, 14
jp NextChar
Char49::
PageChar::
push de
ld a, "▼"
Coorda 18, 16
ldcoord_a 18, 16
call ProtectedDelay3
call ManualTextScroll
coord hl, 1, 10
hlcoord 1, 10
lb bc, 7, 18
call ClearScreenArea
ld c, 20
call DelayFrames
pop de
pop hl
coord hl, 1, 11
hlcoord 1, 11
push hl
jp PlaceNextChar_inc
jp NextChar
Char4B::
_ContText::
ld a, "▼"
Coorda 18, 16
ldcoord_a 18, 16
call ProtectedDelay3
push de
call ManualTextScroll
pop de
ld a, " "
Coorda 18, 16
;fall through
Char4C::
ldcoord_a 18, 16
_ContTextNoPause::
push de
call ScrollTextUpOneLine
call ScrollTextUpOneLine
coord hl, 1, 16
hlcoord 1, 16
pop de
jp PlaceNextChar_inc
jp NextChar
; move both rows of text in the normal text box up one row
; always called twice in a row
; first time, copy the two rows of text to the "in between" rows that are usually emtpy
; second time, copy the bottom row of text into the top row of text
ScrollTextUpOneLine::
coord hl, 0, 14 ; top row of text
coord de, 0, 13 ; empty line above text
hlcoord 0, 14 ; top row of text
decoord 0, 13 ; empty line above text
ld b, SCREEN_WIDTH * 3
.copyText
ld a, [hli]
@ -337,7 +286,7 @@ ScrollTextUpOneLine::
inc de
dec b
jr nz, .copyText
coord hl, 1, 16
hlcoord 1, 16
ld a, " "
ld b, SCREEN_WIDTH - 2
.clearText
@ -345,7 +294,6 @@ ScrollTextUpOneLine::
dec b
jr nz, .clearText
; wait five frames
ld b, 5
.WaitFrame
call DelayFrame
@ -365,7 +313,7 @@ TextCommandProcessor::
push af
set 1, a
ld e, a
ld a, [$fff4]
ldh a, [hClearLetterPrintingDelayFlags]
xor e
ld [wLetterPrintingDelayFlags], a
ld a, c
@ -375,18 +323,18 @@ TextCommandProcessor::
NextTextCommand::
ld a, [hli]
cp "@" ; terminator
jr nz, .doTextCommand
cp TX_END
jr nz, .TextCommand
pop af
ld [wLetterPrintingDelayFlags], a
ret
.doTextCommand
.TextCommand:
push hl
cp $17
jp z, TextCommand17
cp $0e
jp nc, TextCommand0B ; if a != 0x17 and a >= 0xE, go to command 0xB
; if a < 0xE, use a jump table
cp TX_FAR
jp z, TextCommand_FAR
cp TX_SOUND_POKEDEX_RATING
jp nc, TextCommand_SOUND
ld hl, TextCommandJumpTable
push bc
add a
@ -399,12 +347,8 @@ NextTextCommand::
ld l, a
jp hl
; draw box
; 04AAAABBCC
; AAAA = address of upper left corner
; BB = height
; CC = width
TextCommand04::
TextCommand_BOX::
; draw a box (height, width)
pop hl
ld a, [hli]
ld e, a
@ -421,9 +365,8 @@ TextCommand04::
pop hl
jr NextTextCommand
; place string inline
; 00{string}
TextCommand00::
TextCommand_START::
; write text until "@"
pop hl
ld d, h
ld e, l
@ -435,10 +378,8 @@ TextCommand00::
inc hl
jr NextTextCommand
; place string from RAM
; 01AAAA
; AAAA = address of string
TextCommand01::
TextCommand_RAM::
; write text from a ram address (little endian)
pop hl
ld a, [hli]
ld e, a
@ -451,13 +392,8 @@ TextCommand01::
pop hl
jr NextTextCommand
; print BCD number
; 02AAAABB
; AAAA = address of BCD number
; BB
; bits 0-4 = length in bytes
; bits 5-7 = unknown flags
TextCommand02::
TextCommand_BCD::
; write bcd from address, typically ram
pop hl
ld a, [hli]
ld e, a
@ -474,10 +410,8 @@ TextCommand02::
pop hl
jr NextTextCommand
; repoint destination address
; 03AAAA
; AAAA = new destination address
TextCommand03::
TextCommand_MOVE::
; move to a new tile
pop hl
ld a, [hli]
ld [wTextDest], a
@ -487,58 +421,47 @@ TextCommand03::
ld b, a
jp NextTextCommand
; repoint destination to second line of dialogue text box
; 05
; (no arguments)
TextCommand05::
TextCommand_LOW::
; write text at (1,16)
pop hl
coord bc, 1, 16 ; address of second line of dialogue text box
bccoord 1, 16 ; second line of dialogue text box
jp NextTextCommand
; blink arrow and wait for A or B to be pressed
; 06
; (no arguments)
TextCommand06::
TextCommand_PROMPT_BUTTON::
; wait for button press; show arrow
ld a, [wLinkState]
cp LINK_STATE_BATTLING
jp z, TextCommand0D
jp z, TextCommand_WAIT_BUTTON
ld a, "▼"
Coorda 18, 16 ; place down arrow in lower right corner of dialogue text box
ldcoord_a 18, 16 ; place down arrow in lower right corner of dialogue text box
push bc
call ManualTextScroll ; blink arrow and wait for A or B to be pressed
pop bc
ld a, " "
Coorda 18, 16 ; overwrite down arrow with blank space
ldcoord_a 18, 16 ; overwrite down arrow with blank space
pop hl
jp NextTextCommand
; scroll text up one line
; 07
; (no arguments)
TextCommand07::
TextCommand_SCROLL::
; pushes text up two lines and sets the BC cursor to the border tile
; below the first character column of the text box.
ld a, " "
Coorda 18, 16 ; place blank space in lower right corner of dialogue text box
ldcoord_a 18, 16 ; place blank space in lower right corner of dialogue text box
call ScrollTextUpOneLine
call ScrollTextUpOneLine
pop hl
coord bc, 1, 16 ; address of second line of dialogue text box
bccoord 1, 16 ; second line of dialogue text box
jp NextTextCommand
; execute asm inline
; 08{code}
TextCommand08::
TextCommand_START_ASM::
; run assembly code
pop hl
ld de, NextTextCommand
push de ; return address
push de
jp hl
; print decimal number (converted from binary number)
; 09AAAABB
; AAAA = address of number
; BB
; bits 0-3 = how many digits to display
; bits 4-7 = how long the number is in bytes
TextCommand09::
TextCommand_NUM::
; print a number
pop hl
ld a, [hli]
ld e, a
@ -554,7 +477,7 @@ TextCommand09::
ld a, b
and $f0
swap a
set BIT_LEFT_ALIGN,a
set BIT_LEFT_ALIGN, a
ld b, a
call PrintNumber
ld b, h
@ -562,45 +485,42 @@ TextCommand09::
pop hl
jp NextTextCommand
; wait half a second if the user doesn't hold A or B
; 0A
; (no arguments)
TextCommand0A::
TextCommand_PAUSE::
; wait for button press or 30 frames
push bc
call Joypad
ld a, [hJoyHeld]
ldh a, [hJoyHeld]
and A_BUTTON | B_BUTTON
jr nz, .skipDelay
ld c, 30
jr nz, .done
ld c, 30 ; half a second
call DelayFrames
.skipDelay
.done
pop bc
pop hl
jp NextTextCommand
; plays sounds
; this actually handles various command ID's, not just 0B
; (no arguments)
TextCommand0B::
TextCommand_SOUND::
; play a sound effect from TextCommandSounds
pop hl
push bc
dec hl
ld a, [hli]
ld b, a ; b = command number that got us here
ld b, a ; b = text command number that got us here
push hl
ld hl, TextCommandSounds
.loop
ld a, [hli]
cp b
jr z, .matchFound
jr z, .play
inc hl
jr .loop
.matchFound
cp $14
.play
cp TX_SOUND_CRY_NIDORINA
jr z, .pokemonCry
cp $15
cp TX_SOUND_CRY_PIDGEOT
jr z, .pokemonCry
cp $16
cp TX_SOUND_CRY_DEWGONG
jr z, .pokemonCry
ld a, [hl]
call PlaySound
@ -608,6 +528,7 @@ TextCommand0B::
pop hl
pop bc
jp NextTextCommand
.pokemonCry
push de
ld a, [hl]
@ -617,95 +538,99 @@ TextCommand0B::
pop bc
jp NextTextCommand
; format: text command ID, sound ID or cry ID
TextCommandSounds::
db $0B, SFX_GET_ITEM_1 ; actually plays SFX_LEVEL_UP when the battle music engine is loaded
db $12, SFX_CAUGHT_MON
db $0E, SFX_POKEDEX_RATING ; unused?
db $0F, SFX_GET_ITEM_1 ; unused?
db $10, SFX_GET_ITEM_2
db $11, SFX_GET_KEY_ITEM
db $13, SFX_DEX_PAGE_ADDED
db $14, NIDORINA ; used in OakSpeech
db $15, PIDGEOT ; used in SaffronCityText12
db $16, DEWGONG ; unused?
db TX_SOUND_GET_ITEM_1, SFX_GET_ITEM_1 ; actually plays SFX_LEVEL_UP when the battle music engine is loaded
db TX_SOUND_CAUGHT_MON, SFX_CAUGHT_MON
db TX_SOUND_POKEDEX_RATING, SFX_POKEDEX_RATING ; unused
db TX_SOUND_GET_ITEM_1_DUPLICATE, SFX_GET_ITEM_1 ; unused
db TX_SOUND_GET_ITEM_2, SFX_GET_ITEM_2
db TX_SOUND_GET_KEY_ITEM, SFX_GET_KEY_ITEM
db TX_SOUND_DEX_PAGE_ADDED, SFX_DEX_PAGE_ADDED
db TX_SOUND_CRY_NIDORINA, NIDORINA ; used in OakSpeech
db TX_SOUND_CRY_PIDGEOT, PIDGEOT ; used in SaffronCityText12
db TX_SOUND_CRY_DEWGONG, DEWGONG ; unused
; draw ellipses
; 0CAA
; AA = number of ellipses to draw
TextCommand0C::
TextCommand_DOTS::
; wait for button press or 30 frames while printing "…"s
pop hl
ld a, [hli]
ld d, a
push hl
ld h, b
ld l, c
.loop
ld a, "…"
ld [hli], a
push de
call Joypad
pop de
ld a, [hJoyHeld] ; joypad state
ldh a, [hJoyHeld] ; joypad state
and A_BUTTON | B_BUTTON
jr nz, .skipDelay ; if so, skip the delay
jr nz, .next ; if so, skip the delay
ld c, 10
call DelayFrames
.skipDelay
.next
dec d
jr nz, .loop
ld b, h
ld c, l
pop hl
jp NextTextCommand
; wait for A or B to be pressed
; 0D
; (no arguments)
TextCommand0D::
TextCommand_WAIT_BUTTON::
; wait for button press; don't show arrow
push bc
call ManualTextScroll ; wait for A or B to be pressed
call ManualTextScroll
pop bc
pop hl
jp NextTextCommand
; process text commands in another ROM bank
; 17AAAABB
; AAAA = address of text commands
; BB = bank
TextCommand17::
TextCommand_FAR::
; write text from a different bank (little endian)
pop hl
ld a, [H_LOADEDROMBANK]
ldh a, [hLoadedROMBank]
push af
ld a, [hli]
ld e, a
ld a, [hli]
ld d, a
ld a, [hli]
ld [H_LOADEDROMBANK], a
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
push hl
ld l, e
ld h, d
call TextCommandProcessor
pop hl
pop af
ld [H_LOADEDROMBANK], a
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
jp NextTextCommand
TextCommandJumpTable::
dw TextCommand00
dw TextCommand01
dw TextCommand02
dw TextCommand03
dw TextCommand04
dw TextCommand05
dw TextCommand06
dw TextCommand07
dw TextCommand08
dw TextCommand09
dw TextCommand0A
dw TextCommand0B
dw TextCommand0C
dw TextCommand0D
; entries correspond to TX_* constants (see macros/scripts/text.asm)
dw TextCommand_START ; TX_START
dw TextCommand_RAM ; TX_RAM
dw TextCommand_BCD ; TX_BCD
dw TextCommand_MOVE ; TX_MOVE
dw TextCommand_BOX ; TX_BOX
dw TextCommand_LOW ; TX_LOW
dw TextCommand_PROMPT_BUTTON ; TX_PROMPT_BUTTON
IF DEF(_DEBUG)
dw _ContTextNoPause ; TX_SCROLL
ELSE
dw TextCommand_SCROLL ; TX_SCROLL
ENDC
dw TextCommand_START_ASM ; TX_START_ASM
dw TextCommand_NUM ; TX_NUM
dw TextCommand_PAUSE ; TX_PAUSE
dw TextCommand_SOUND ; TX_SOUND_GET_ITEM_1 (also handles other TX_SOUND_* commands)
dw TextCommand_DOTS ; TX_DOTS
dw TextCommand_WAIT_BUTTON ; TX_WAIT_BUTTON
; greater TX_* constants are handled directly by NextTextCommand

215
home/text_script.asm Normal file
View file

@ -0,0 +1,215 @@
; this function is used to display sign messages, sprite dialog, etc.
; INPUT: [hSpriteIndexOrTextID] = sprite ID or text ID
DisplayTextID::
ldh a, [hLoadedROMBank]
push af
farcall DisplayTextIDInit ; initialization
ld hl, wTextPredefFlag
bit 0, [hl]
res 0, [hl]
jr nz, .skipSwitchToMapBank
ld a, [wCurMap]
call SwitchToMapRomBank
.skipSwitchToMapBank
ld a, 30 ; half a second
ldh [hFrameCounter], a ; used as joypad poll timer
ld hl, wMapTextPtr
ld a, [hli]
ld h, [hl]
ld l, a ; hl = map text pointer
ld d, $00
ldh a, [hSpriteIndexOrTextID] ; text ID
ld [wSpriteIndex], a
dict TEXT_START_MENU, DisplayStartMenu
dict TEXT_SAFARI_GAME_OVER, DisplaySafariGameOverText
dict TEXT_MON_FAINTED, DisplayPokemonFaintedText
dict TEXT_BLACKED_OUT, DisplayPlayerBlackedOutText
dict TEXT_REPEL_WORE_OFF, DisplayRepelWoreOffText
ld a, [wNumSprites]
ld e, a
ldh a, [hSpriteIndexOrTextID] ; sprite ID
cp e
jr z, .spriteHandling
jr nc, .skipSpriteHandling
.spriteHandling
; get the text ID of the sprite
push hl
push de
push bc
farcall UpdateSpriteFacingOffsetAndDelayMovement ; update the graphics of the sprite the player is talking to (to face the right direction)
pop bc
pop de
ld hl, wMapSpriteData ; NPC text entries
ldh a, [hSpriteIndexOrTextID]
dec a
add a
add l
ld l, a
jr nc, .noCarry
inc h
.noCarry
inc hl
ld a, [hl] ; a = text ID of the sprite
pop hl
.skipSpriteHandling
; look up the address of the text in the map's text entries
dec a
ld e, a
sla e
add hl, de
ld a, [hli]
ld h, [hl]
ld l, a ; hl = address of the text
ld a, [hl] ; a = first byte of text
; check first byte of text for special cases
dict2: MACRO
cp \1
jr nz, .not\@
\2
jr AfterDisplayingTextID
.not\@
ENDM
dict TX_SCRIPT_MART, DisplayPokemartDialogue
dict TX_SCRIPT_POKECENTER_NURSE, DisplayPokemonCenterDialogue
dict TX_SCRIPT_PLAYERS_PC, TextScript_ItemStoragePC
dict TX_SCRIPT_BILLS_PC, TextScript_BillsPC
dict TX_SCRIPT_POKECENTER_PC, TextScript_PokemonCenterPC
dict2 TX_SCRIPT_VENDING_MACHINE, farcall VendingMachineMenu
dict TX_SCRIPT_PRIZE_VENDOR, TextScript_GameCornerPrizeMenu
dict2 TX_SCRIPT_CABLE_CLUB_RECEPTIONIST, callfar CableClubNPC
call PrintText_NoCreatingTextBox ; display the text
ld a, [wDoNotWaitForButtonPressAfterDisplayingText]
and a
jr nz, HoldTextDisplayOpen
AfterDisplayingTextID::
ld a, [wEnteringCableClub]
and a
jr nz, HoldTextDisplayOpen
call WaitForTextScrollButtonPress ; wait for a button press after displaying all the text
; loop to hold the dialogue box open as long as the player keeps holding down the A button
HoldTextDisplayOpen::
call Joypad
ldh a, [hJoyHeld]
bit 0, a ; is the A button being pressed?
jr nz, HoldTextDisplayOpen
CloseTextDisplay::
ld a, [wCurMap]
call SwitchToMapRomBank
ld a, $90
ldh [hWY], a ; move the window off the screen
call DelayFrame
call LoadGBPal
xor a
ldh [hAutoBGTransferEnabled], a ; disable continuous WRAM to VRAM transfer each V-blank
; loop to make sprites face the directions they originally faced before the dialogue
ld hl, wSprite01StateData2OrigFacingDirection
ld c, $0f
ld de, $10
.restoreSpriteFacingDirectionLoop
ld a, [hl] ; x#SPRITESTATEDATA2_ORIGFACINGDIRECTION
dec h
ld [hl], a ; [x#SPRITESTATEDATA1_FACINGDIRECTION]
inc h
add hl, de
dec c
jr nz, .restoreSpriteFacingDirectionLoop
ld a, BANK(InitMapSprites)
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
call InitMapSprites ; reload sprite tile pattern data (since it was partially overwritten by text tile patterns)
ld hl, wFontLoaded
res 0, [hl]
ld a, [wd732]
bit 3, a ; used fly warp
call z, LoadPlayerSpriteGraphics
call LoadCurrentMapView
pop af
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
jp UpdateSprites
DisplayPokemartDialogue::
push hl
ld hl, PokemartGreetingText
call PrintText
pop hl
inc hl
call LoadItemList
ld a, PRICEDITEMLISTMENU
ld [wListMenuID], a
homecall DisplayPokemartDialogue_
jp AfterDisplayingTextID
PokemartGreetingText::
text_far _PokemartGreetingText
text_end
LoadItemList::
ld a, 1
ld [wUpdateSpritesEnabled], a
ld a, h
ld [wItemListPointer], a
ld a, l
ld [wItemListPointer + 1], a
ld de, wItemList
.loop
ld a, [hli]
ld [de], a
inc de
cp $ff
jr nz, .loop
ret
DisplayPokemonCenterDialogue::
; zeroing these doesn't appear to serve any purpose
xor a
ldh [hItemPrice], a
ldh [hItemPrice + 1], a
ldh [hItemPrice + 2], a
inc hl
homecall DisplayPokemonCenterDialogue_
jp AfterDisplayingTextID
DisplaySafariGameOverText::
callfar PrintSafariGameOverText
jp AfterDisplayingTextID
DisplayPokemonFaintedText::
ld hl, PokemonFaintedText
call PrintText
jp AfterDisplayingTextID
PokemonFaintedText::
text_far _PokemonFaintedText
text_end
DisplayPlayerBlackedOutText::
ld hl, PlayerBlackedOutText
call PrintText
ld a, [wd732]
res 5, a ; reset forced to use bike bit
ld [wd732], a
jp HoldTextDisplayOpen
PlayerBlackedOutText::
text_far _PlayerBlackedOutText
text_end
DisplayRepelWoreOffText::
ld hl, RepelWoreOffText
call PrintText
jp AfterDisplayingTextID
RepelWoreOffText::
text_far _RepelWoreOffText
text_end

7
home/textbox.asm Normal file
View file

@ -0,0 +1,7 @@
; function to draw various text boxes
; INPUT:
; [wTextBoxID] = text box ID
; b, c = y, x cursor position (TWO_OPTION_MENU only)
DisplayTextBoxID::
homecall_sf DisplayTextBoxID_
ret

61
home/tilemap.asm Normal file
View file

@ -0,0 +1,61 @@
FillMemory::
; Fill bc bytes at hl with a.
push de
ld d, a
.loop
ld a, d
ld [hli], a
dec bc
ld a, b
or c
jr nz, .loop
pop de
ret
UncompressSpriteFromDE::
; Decompress pic at a:de.
ld hl, wSpriteInputPtr
ld [hl], e
inc hl
ld [hl], d
jp UncompressSpriteData
SaveScreenTilesToBuffer2::
hlcoord 0, 0
ld de, wTileMapBackup2
ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
call CopyData
ret
LoadScreenTilesFromBuffer2::
call LoadScreenTilesFromBuffer2DisableBGTransfer
ld a, 1
ldh [hAutoBGTransferEnabled], a
ret
; loads screen tiles stored in wTileMapBackup2 but leaves hAutoBGTransferEnabled disabled
LoadScreenTilesFromBuffer2DisableBGTransfer::
xor a
ldh [hAutoBGTransferEnabled], a
ld hl, wTileMapBackup2
decoord 0, 0
ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
call CopyData
ret
SaveScreenTilesToBuffer1::
hlcoord 0, 0
ld de, wTileMapBackup
ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
jp CopyData
LoadScreenTilesFromBuffer1::
xor a
ldh [hAutoBGTransferEnabled], a
ld hl, wTileMapBackup
decoord 0, 0
ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
call CopyData
ld a, 1
ldh [hAutoBGTransferEnabled], a
ret

442
home/trainers.asm Normal file
View file

@ -0,0 +1,442 @@
; stores hl in [wTrainerHeaderPtr]
StoreTrainerHeaderPointer::
ld a, h
ld [wTrainerHeaderPtr], a
ld a, l
ld [wTrainerHeaderPtr+1], a
ret
; executes the current map script from the function pointer array provided in de.
; a: map script index to execute (unless overridden by [wd733] bit 4)
; hl: trainer header pointer
ExecuteCurMapScriptInTable::
push af
push de
call StoreTrainerHeaderPointer
pop hl
pop af
push hl
ld hl, wFlags_D733
bit 4, [hl]
res 4, [hl]
jr z, .useProvidedIndex ; test if map script index was overridden manually
ld a, [wCurMapScript]
.useProvidedIndex
pop hl
ld [wCurMapScript], a
call CallFunctionInTable
ld a, [wCurMapScript]
ret
LoadGymLeaderAndCityName::
push de
ld de, wGymCityName
ld bc, $11
call CopyData ; load city name
pop hl
ld de, wGymLeaderName
ld bc, NAME_LENGTH
jp CopyData ; load gym leader name
; reads specific information from trainer header (pointed to at wTrainerHeaderPtr)
; a: offset in header data
; 0 -> flag's bit (into wTrainerHeaderFlagBit)
; 2 -> flag's byte ptr (into hl)
; 4 -> before battle text (into hl)
; 6 -> after battle text (into hl)
; 8 -> end battle text (into hl)
ReadTrainerHeaderInfo::
push de
push af
ld d, $0
ld e, a
ld hl, wTrainerHeaderPtr
ld a, [hli]
ld l, [hl]
ld h, a
add hl, de
pop af
and a
jr nz, .nonZeroOffset
ld a, [hl]
ld [wTrainerHeaderFlagBit], a ; store flag's bit
jr .done
.nonZeroOffset
cp $2
jr z, .readPointer ; read flag's byte ptr
cp $4
jr z, .readPointer ; read before battle text
cp $6
jr z, .readPointer ; read after battle text
cp $8
jr z, .readPointer ; read end battle text
cp $a
jr nz, .done
ld a, [hli] ; read end battle text (2) but override the result afterwards (XXX why, bug?)
ld d, [hl]
ld e, a
jr .done
.readPointer
ld a, [hli]
ld h, [hl]
ld l, a
.done
pop de
ret
TrainerFlagAction::
predef_jump FlagActionPredef
TalkToTrainer::
call StoreTrainerHeaderPointer
xor a
call ReadTrainerHeaderInfo ; read flag's bit
ld a, $2
call ReadTrainerHeaderInfo ; read flag's byte ptr
ld a, [wTrainerHeaderFlagBit]
ld c, a
ld b, FLAG_TEST
call TrainerFlagAction ; read trainer's flag
ld a, c
and a
jr z, .trainerNotYetFought ; test trainer's flag
ld a, $6
call ReadTrainerHeaderInfo ; print after battle text
jp PrintText
.trainerNotYetFought
ld a, $4
call ReadTrainerHeaderInfo ; print before battle text
call PrintText
ld a, $a
call ReadTrainerHeaderInfo ; (?) does nothing apparently (maybe bug in ReadTrainerHeaderInfo)
push de
ld a, $8
call ReadTrainerHeaderInfo ; read end battle text
pop de
call SaveEndBattleTextPointers
ld hl, wFlags_D733
set 4, [hl] ; activate map script index override (index is set below)
ld hl, wFlags_0xcd60
bit 0, [hl] ; test if player is already engaging the trainer (because the trainer saw the player)
ret nz
; if the player talked to the trainer of his own volition
call EngageMapTrainer
ld hl, wCurMapScript
inc [hl] ; increment map script index before StartTrainerBattle increments it again (next script function is usually EndTrainerBattle)
jp StartTrainerBattle
; checks if any trainers are seeing the player and wanting to fight
CheckFightingMapTrainers::
IF DEF(_DEBUG)
call DebugPressedOrHeldB
jr nz, .trainerNotEngaging
ENDC
call CheckForEngagingTrainers
ld a, [wSpriteIndex]
cp $ff
jr nz, .trainerEngaging
.trainerNotEngaging
xor a
ld [wSpriteIndex], a
ld [wTrainerHeaderFlagBit], a
ret
.trainerEngaging
ld hl, wFlags_D733
set 3, [hl]
ld [wEmotionBubbleSpriteIndex], a
xor a ; EXCLAMATION_BUBBLE
ld [wWhichEmotionBubble], a
predef EmotionBubble
ld a, D_RIGHT | D_LEFT | D_UP | D_DOWN
ld [wJoyIgnore], a
xor a
ldh [hJoyHeld], a
call TrainerWalkUpToPlayer_Bank0
ld hl, wCurMapScript
inc [hl] ; increment map script index (next script function is usually DisplayEnemyTrainerTextAndStartBattle)
ret
; display the before battle text after the enemy trainer has walked up to the player's sprite
DisplayEnemyTrainerTextAndStartBattle::
ld a, [wd730]
and $1
ret nz ; return if the enemy trainer hasn't finished walking to the player's sprite
ld [wJoyIgnore], a
ld a, [wSpriteIndex]
ldh [hSpriteIndexOrTextID], a
call DisplayTextID
; fall through
StartTrainerBattle::
xor a
ld [wJoyIgnore], a
call InitBattleEnemyParameters
ld hl, wd72d
set 6, [hl]
set 7, [hl]
ld hl, wd72e
set 1, [hl]
ld hl, wCurMapScript
inc [hl] ; increment map script index (next script function is usually EndTrainerBattle)
ret
EndTrainerBattle::
ld hl, wCurrentMapScriptFlags
set 5, [hl]
set 6, [hl]
ld hl, wd72d
res 7, [hl]
ld hl, wFlags_0xcd60
res 0, [hl] ; player is no longer engaged by any trainer
ld a, [wIsInBattle]
cp $ff
jp z, ResetButtonPressedAndMapScript
ld a, $2
call ReadTrainerHeaderInfo
ld a, [wTrainerHeaderFlagBit]
ld c, a
ld b, FLAG_SET
call TrainerFlagAction ; flag trainer as fought
ld a, [wEnemyMonOrTrainerClass]
cp OPP_ID_OFFSET
jr nc, .skipRemoveSprite ; test if trainer was fought (in that case skip removing the corresponding sprite)
ld hl, wMissableObjectList
ld de, $2
ld a, [wSpriteIndex]
call IsInArray ; search for sprite ID
inc hl
ld a, [hl]
ld [wMissableObjectIndex], a ; load corresponding missable object index and remove it
predef HideObject
.skipRemoveSprite
ld hl, wd730
bit 4, [hl]
res 4, [hl]
ret nz
ResetButtonPressedAndMapScript::
xor a
ld [wJoyIgnore], a
ldh [hJoyHeld], a
ldh [hJoyPressed], a
ldh [hJoyReleased], a
ld [wCurMapScript], a ; reset battle status
ret
; calls TrainerWalkUpToPlayer
TrainerWalkUpToPlayer_Bank0::
farjp TrainerWalkUpToPlayer
; sets opponent type and mon set/lvl based on the engaging trainer data
InitBattleEnemyParameters::
ld a, [wEngagedTrainerClass]
ld [wCurOpponent], a
ld [wEnemyMonOrTrainerClass], a
cp OPP_ID_OFFSET
ld a, [wEngagedTrainerSet]
jr c, .noTrainer
ld [wTrainerNo], a
ret
.noTrainer
ld [wCurEnemyLVL], a
ret
GetSpritePosition1::
ld hl, _GetSpritePosition1
jr SpritePositionBankswitch
GetSpritePosition2::
ld hl, _GetSpritePosition2
jr SpritePositionBankswitch
SetSpritePosition1::
ld hl, _SetSpritePosition1
jr SpritePositionBankswitch
SetSpritePosition2::
ld hl, _SetSpritePosition2
SpritePositionBankswitch::
ld b, BANK(_GetSpritePosition1) ; BANK(_GetSpritePosition2), BANK(_SetSpritePosition1), BANK(_SetSpritePosition2)
jp Bankswitch ; indirect jump to one of the four functions
CheckForEngagingTrainers::
xor a
call ReadTrainerHeaderInfo ; read trainer flag's bit (unused)
ld d, h ; store trainer header address in de
ld e, l
.trainerLoop
call StoreTrainerHeaderPointer ; set trainer header pointer to current trainer
ld a, [de]
ld [wSpriteIndex], a ; store trainer flag's bit
ld [wTrainerHeaderFlagBit], a
cp -1
ret z
ld a, $2
call ReadTrainerHeaderInfo ; read trainer flag's byte ptr
ld b, FLAG_TEST
ld a, [wTrainerHeaderFlagBit]
ld c, a
call TrainerFlagAction ; read trainer flag
ld a, c
and a ; has the trainer already been defeated?
jr nz, .continue
push hl
push de
push hl
xor a
call ReadTrainerHeaderInfo ; get trainer header pointer
inc hl
ld a, [hl] ; read trainer engage distance
pop hl
ld [wTrainerEngageDistance], a
ld a, [wSpriteIndex]
swap a
ld [wTrainerSpriteOffset], a
predef TrainerEngage
pop de
pop hl
ld a, [wTrainerSpriteOffset]
and a
ret nz ; break if the trainer is engaging
.continue
ld hl, $c
add hl, de
ld d, h
ld e, l
jr .trainerLoop
; hl = text if the player wins
; de = text if the player loses
SaveEndBattleTextPointers::
ldh a, [hLoadedROMBank]
ld [wEndBattleTextRomBank], a
ld a, h
ld [wEndBattleWinTextPointer], a
ld a, l
ld [wEndBattleWinTextPointer + 1], a
ld a, d
ld [wEndBattleLoseTextPointer], a
ld a, e
ld [wEndBattleLoseTextPointer + 1], a
ret
; loads data of some trainer on the current map and plays pre-battle music
; [wSpriteIndex]: sprite ID of trainer who is engaged
EngageMapTrainer::
ld hl, wMapSpriteExtraData
ld d, $0
ld a, [wSpriteIndex]
dec a
add a
ld e, a
add hl, de ; seek to engaged trainer data
ld a, [hli] ; load trainer class
ld [wEngagedTrainerClass], a
ld a, [hl] ; load trainer mon set
ld [wEngagedTrainerSet], a
jp PlayTrainerMusic
PrintEndBattleText::
push hl
ld hl, wd72d
bit 7, [hl]
res 7, [hl]
pop hl
ret z
ldh a, [hLoadedROMBank]
push af
ld a, [wEndBattleTextRomBank]
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
push hl
farcall SaveTrainerName
ld hl, TrainerEndBattleText
call PrintText
pop hl
pop af
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
farcall FreezeEnemyTrainerSprite
jp WaitForSoundToFinish
GetSavedEndBattleTextPointer::
ld a, [wBattleResult]
and a
; won battle
jr nz, .lostBattle
ld a, [wEndBattleWinTextPointer]
ld h, a
ld a, [wEndBattleWinTextPointer + 1]
ld l, a
ret
.lostBattle
ld a, [wEndBattleLoseTextPointer]
ld h, a
ld a, [wEndBattleLoseTextPointer + 1]
ld l, a
ret
TrainerEndBattleText::
text_far _TrainerNameText
text_asm
call GetSavedEndBattleTextPointer
call TextCommandProcessor
jp TextScriptEnd
; only engage with the trainer if the player is not already
; engaged with another trainer
; XXX unused?
CheckIfAlreadyEngaged::
ld a, [wFlags_0xcd60]
bit 0, a
ret nz
call EngageMapTrainer
xor a
ret
PlayTrainerMusic::
ld a, [wEngagedTrainerClass]
cp OPP_RIVAL1
ret z
cp OPP_RIVAL2
ret z
cp OPP_RIVAL3
ret z
ld a, [wGymLeaderNo]
and a
ret nz
xor a
ld [wAudioFadeOutControl], a
ld a, SFX_STOP_ALL_MUSIC
call PlaySound
ld a, 0 ; BANK(Music_MeetEvilTrainer)
ld [wAudioROMBank], a
ld [wAudioSavedROMBank], a
ld a, [wEngagedTrainerClass]
ld b, a
ld hl, EvilTrainerList
.evilTrainerListLoop
ld a, [hli]
cp $ff
jr z, .noEvilTrainer
cp b
jr nz, .evilTrainerListLoop
ld a, MUSIC_MEET_EVIL_TRAINER
jr .PlaySound
.noEvilTrainer
ld hl, FemaleTrainerList
.femaleTrainerListLoop
ld a, [hli]
cp $ff
jr z, .maleTrainer
cp b
jr nz, .femaleTrainerListLoop
ld a, MUSIC_MEET_FEMALE_TRAINER
jr .PlaySound
.maleTrainer
ld a, MUSIC_MEET_MALE_TRAINER
.PlaySound
ld [wNewSoundID], a
jp PlayMusic
INCLUDE "data/trainers/encounter_types.asm"

35
home/trainers2.asm Normal file
View file

@ -0,0 +1,35 @@
GetTrainerInformation::
call GetTrainerName
ld a, [wLinkState]
and a
jr nz, .linkBattle
ld a, BANK(TrainerPicAndMoneyPointers)
call BankswitchHome
ld a, [wTrainerClass]
dec a
ld hl, TrainerPicAndMoneyPointers
ld bc, $5
call AddNTimes
ld de, wTrainerPicPointer
ld a, [hli]
ld [de], a
inc de
ld a, [hli]
ld [de], a
ld de, wTrainerBaseMoney
ld a, [hli]
ld [de], a
inc de
ld a, [hli]
ld [de], a
jp BankswitchBack
.linkBattle
ld hl, wTrainerPicPointer
ld de, RedPicFront
ld [hl], e
inc hl
ld [hl], d
ret
GetTrainerName::
farjp GetTrainerName_

View file

@ -2,10 +2,10 @@
; bank is given in a, sprite input stream is pointed to in wSpriteInputPtr
UncompressSpriteData::
ld b, a
ld a, [H_LOADEDROMBANK]
ldh a, [hLoadedROMBank]
push af
ld a, b
ld [H_LOADEDROMBANK], a
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
ld a, SRAM_ENABLE
ld [MBC1SRamEnable], a
@ -13,15 +13,15 @@ UncompressSpriteData::
ld [MBC1SRamBank], a
call _UncompressSpriteData
pop af
ld [H_LOADEDROMBANK], a
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
ret
; initializes necessary data to load a sprite and runs UncompressSpriteDataLoop
_UncompressSpriteData::
ld hl, sSpriteBuffer1
ld c, (2*SPRITEBUFFERSIZE) % $100
ld b, (2*SPRITEBUFFERSIZE) / $100
ld c, LOW(2 * SPRITEBUFFERSIZE)
ld b, HIGH(2 * SPRITEBUFFERSIZE)
xor a
call FillMemory ; clear sprite buffer 1 and 2
ld a, $1
@ -561,7 +561,7 @@ ResetSpriteBufferPointers::
; maps each nybble to its reverse
NybbleReverseTable::
db $0, $8, $4, $c, $2, $a, $6 ,$e, $1, $9, $5, $d, $3, $b, $7 ,$f
db $0, $8, $4, $c, $2, $a, $6, $e, $1, $9, $5, $d, $3, $b, $7, $f
; combines the two loaded chunks with xor (the chunk loaded second is the destination). Both chunks are differeintial decoded beforehand.
UnpackSpriteMode2::

6
home/update_sprites.asm Normal file
View file

@ -0,0 +1,6 @@
UpdateSprites::
ld a, [wUpdateSpritesEnabled]
dec a
ret nz
homecall _UpdateSprites
ret

View file

@ -5,19 +5,19 @@ VBlank::
push de
push hl
ld a, [H_LOADEDROMBANK]
ldh a, [hLoadedROMBank]
ld [wVBlankSavedROMBank], a
ld a, [hSCX]
ld [rSCX], a
ld a, [hSCY]
ld [rSCY], a
ldh a, [hSCX]
ldh [rSCX], a
ldh a, [hSCY]
ldh [rSCY], a
ld a, [wDisableVBlankWYUpdate]
and a
jr nz, .ok
ld a, [hWY]
ld [rWY], a
ldh a, [hWY]
ldh [rWY], a
.ok
call AutoBgMapTransfer
@ -26,9 +26,9 @@ VBlank::
call VBlankCopy
call VBlankCopyDouble
call UpdateMovingBgTiles
call $ff80 ; hOAMDMA
call hDMARoutine
ld a, BANK(PrepareOAMData)
ld [H_LOADEDROMBANK], a
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
call PrepareOAMData
@ -36,25 +36,25 @@ VBlank::
call Random
ld a, [H_VBLANKOCCURRED]
ldh a, [hVBlankOccurred]
and a
jr z, .skipZeroing
xor a
ld [H_VBLANKOCCURRED], a
ldh [hVBlankOccurred], a
.skipZeroing
ld a, [H_FRAMECOUNTER]
ldh a, [hFrameCounter]
and a
jr z, .skipDec
dec a
ld [H_FRAMECOUNTER], a
ldh [hFrameCounter], a
.skipDec
; call FadeOutAudio
call UpdateSound
; ld a, [wAudioROMBank] ; music ROM bank
; ld [H_LOADEDROMBANK], a
; ldh [hLoadedROMBank], a
; ld [MBC1RomBank], a
; cp BANK(Audio1_UpdateMusic)
@ -73,14 +73,14 @@ VBlank::
; call Audio3_UpdateMusic
;.afterMusic
callba TrackPlayTime ; keep track of time played
farcall TrackPlayTime ; keep track of time played
ld a, [hDisableJoypadPolling]
ldh a, [hDisableJoypadPolling]
and a
call z, ReadJoypad
ld a, [wVBlankSavedROMBank]
ld [H_LOADEDROMBANK], a
ldh [hLoadedROMBank], a
ld [MBC1RomBank], a
pop hl
@ -97,10 +97,10 @@ DelayFrame::
NOT_VBLANKED EQU 1
ld a, NOT_VBLANKED
ld [H_VBLANKOCCURRED], a
ldh [hVBlankOccurred], a
.halt
halt
ld a, [H_VBLANKOCCURRED]
ldh a, [hVBlankOccurred]
and a
jr nz, .halt
ret

View file

@ -40,19 +40,19 @@ ClearBgMap::
; However, this function is also called repeatedly to redraw the whole screen
; when necessary. It is also used in trade animation and elevator code.
RedrawRowOrColumn::
ld a, [hRedrawRowOrColumnMode]
ldh a, [hRedrawRowOrColumnMode]
and a
ret z
ld b, a
xor a
ld [hRedrawRowOrColumnMode], a
ldh [hRedrawRowOrColumnMode], a
dec b
jr nz, .redrawRow
.redrawColumn
ld hl, wRedrawRowOrColumnSrcTiles
ld a, [hRedrawRowOrColumnDest]
ldh a, [hRedrawRowOrColumnDest]
ld e, a
ld a, [hRedrawRowOrColumnDest + 1]
ldh a, [hRedrawRowOrColumnDest + 1]
ld d, a
ld c, SCREEN_HEIGHT
.loop1
@ -75,13 +75,13 @@ RedrawRowOrColumn::
dec c
jr nz, .loop1
xor a
ld [hRedrawRowOrColumnMode], a
ldh [hRedrawRowOrColumnMode], a
ret
.redrawRow
ld hl, wRedrawRowOrColumnSrcTiles
ld a, [hRedrawRowOrColumnDest]
ldh a, [hRedrawRowOrColumnDest]
ld e, a
ld a, [hRedrawRowOrColumnDest + 1]
ldh a, [hRedrawRowOrColumnDest + 1]
ld d, a
push de
call .DrawHalf ; draw upper half
@ -120,63 +120,63 @@ RedrawRowOrColumn::
; the above function, RedrawRowOrColumn, is used when walking to
; improve efficiency.
AutoBgMapTransfer::
ld a, [H_AUTOBGTRANSFERENABLED]
ldh a, [hAutoBGTransferEnabled]
and a
ret z
ld hl, sp + 0
ld a, h
ld [H_SPTEMP], a
ldh [hSPTemp], a
ld a, l
ld [H_SPTEMP + 1], a ; save stack pinter
ld a, [H_AUTOBGTRANSFERPORTION]
ldh [hSPTemp + 1], a ; save stack pinter
ldh a, [hAutoBGTransferPortion]
and a
jr z, .transferTopThird
dec a
jr z, .transferMiddleThird
.transferBottomThird
coord hl, 0, 12
hlcoord 0, 12
ld sp, hl
ld a, [H_AUTOBGTRANSFERDEST + 1]
ldh a, [hAutoBGTransferDest + 1]
ld h, a
ld a, [H_AUTOBGTRANSFERDEST]
ldh a, [hAutoBGTransferDest]
ld l, a
ld de, (12 * 32)
add hl, de
xor a ; TRANSFERTOP
jr .doTransfer
.transferTopThird
coord hl, 0, 0
hlcoord 0, 0
ld sp, hl
ld a, [H_AUTOBGTRANSFERDEST + 1]
ldh a, [hAutoBGTransferDest + 1]
ld h, a
ld a, [H_AUTOBGTRANSFERDEST]
ldh a, [hAutoBGTransferDest]
ld l, a
ld a, TRANSFERMIDDLE
jr .doTransfer
.transferMiddleThird
coord hl, 0, 6
hlcoord 0, 6
ld sp, hl
ld a, [H_AUTOBGTRANSFERDEST + 1]
ldh a, [hAutoBGTransferDest + 1]
ld h, a
ld a, [H_AUTOBGTRANSFERDEST]
ldh a, [hAutoBGTransferDest]
ld l, a
ld de, (6 * 32)
add hl, de
ld a, TRANSFERBOTTOM
.doTransfer
ld [H_AUTOBGTRANSFERPORTION], a ; store next portion
ldh [hAutoBGTransferPortion], a ; store next portion
ld b, 6
TransferBgRows::
; unrolled loop and using pop for speed
rept 20 / 2 - 1
REPT 20 / 2 - 1
pop de
ld [hl], e
inc l
ld [hl], d
inc l
endr
ENDR
pop de
ld [hl], e
@ -192,76 +192,76 @@ TransferBgRows::
dec b
jr nz, TransferBgRows
ld a, [H_SPTEMP]
ldh a, [hSPTemp]
ld h, a
ld a, [H_SPTEMP + 1]
ldh a, [hSPTemp + 1]
ld l, a
ld sp, hl
ret
; Copies [H_VBCOPYBGNUMROWS] rows from H_VBCOPYBGSRC to H_VBCOPYBGDEST.
; If H_VBCOPYBGSRC is XX00, the transfer is disabled.
; Copies [hVBlankCopyBGNumRows] rows from hVBlankCopyBGSource to hVBlankCopyBGDest.
; If hVBlankCopyBGSource is XX00, the transfer is disabled.
VBlankCopyBgMap::
ld a, [H_VBCOPYBGSRC] ; doubles as enabling byte
ldh a, [hVBlankCopyBGSource] ; doubles as enabling byte
and a
ret z
ld hl, sp + 0
ld a, h
ld [H_SPTEMP], a
ldh [hSPTemp], a
ld a, l
ld [H_SPTEMP + 1], a ; save stack pointer
ld a, [H_VBCOPYBGSRC]
ldh [hSPTemp + 1], a ; save stack pointer
ldh a, [hVBlankCopyBGSource]
ld l, a
ld a, [H_VBCOPYBGSRC + 1]
ldh a, [hVBlankCopyBGSource + 1]
ld h, a
ld sp, hl
ld a, [H_VBCOPYBGDEST]
ldh a, [hVBlankCopyBGDest]
ld l, a
ld a, [H_VBCOPYBGDEST + 1]
ldh a, [hVBlankCopyBGDest + 1]
ld h, a
ld a, [H_VBCOPYBGNUMROWS]
ldh a, [hVBlankCopyBGNumRows]
ld b, a
xor a
ld [H_VBCOPYBGSRC], a ; disable transfer so it doesn't continue next V-blank
ldh [hVBlankCopyBGSource], a ; disable transfer so it doesn't continue next V-blank
jr TransferBgRows
VBlankCopyDouble::
; Copy [H_VBCOPYDOUBLESIZE] 1bpp tiles
; from H_VBCOPYDOUBLESRC to H_VBCOPYDOUBLEDEST.
; Copy [hVBlankCopyDoubleSize] 1bpp tiles
; from hVBlankCopyDoubleSource to hVBlankCopyDoubleDest.
; While we're here, convert to 2bpp.
; The process is straightforward:
; copy each byte twice.
ld a, [H_VBCOPYDOUBLESIZE]
ldh a, [hVBlankCopyDoubleSize]
and a
ret z
ld hl, sp + 0
ld a, h
ld [H_SPTEMP], a
ldh [hSPTemp], a
ld a, l
ld [H_SPTEMP + 1], a
ldh [hSPTemp + 1], a
ld a, [H_VBCOPYDOUBLESRC]
ldh a, [hVBlankCopyDoubleSource]
ld l, a
ld a, [H_VBCOPYDOUBLESRC + 1]
ldh a, [hVBlankCopyDoubleSource + 1]
ld h, a
ld sp, hl
ld a, [H_VBCOPYDOUBLEDEST]
ldh a, [hVBlankCopyDoubleDest]
ld l, a
ld a, [H_VBCOPYDOUBLEDEST + 1]
ldh a, [hVBlankCopyDoubleDest + 1]
ld h, a
ld a, [H_VBCOPYDOUBLESIZE]
ldh a, [hVBlankCopyDoubleSize]
ld b, a
xor a ; transferred
ld [H_VBCOPYDOUBLESIZE], a
ldh [hVBlankCopyDoubleSize], a
.loop
rept 3
REPT 3
pop de
ld [hl], e
inc l
@ -271,7 +271,7 @@ VBlankCopyDouble::
inc l
ld [hl], d
inc l
endr
ENDR
pop de
ld [hl], e
@ -286,19 +286,19 @@ VBlankCopyDouble::
jr nz, .loop
ld a, l
ld [H_VBCOPYDOUBLEDEST], a
ldh [hVBlankCopyDoubleDest], a
ld a, h
ld [H_VBCOPYDOUBLEDEST + 1], a
ldh [hVBlankCopyDoubleDest + 1], a
ld hl, sp + 0
ld a, l
ld [H_VBCOPYDOUBLESRC], a
ldh [hVBlankCopyDoubleSource], a
ld a, h
ld [H_VBCOPYDOUBLESRC + 1], a
ldh [hVBlankCopyDoubleSource + 1], a
ld a, [H_SPTEMP]
ldh a, [hSPTemp]
ld h, a
ld a, [H_SPTEMP + 1]
ldh a, [hSPTemp + 1]
ld l, a
ld sp, hl
@ -306,46 +306,46 @@ VBlankCopyDouble::
VBlankCopy::
; Copy [H_VBCOPYSIZE] 2bpp tiles (or 16 * [H_VBCOPYSIZE] tile map entries)
; from H_VBCOPYSRC to H_VBCOPYDEST.
; Copy [hVBlankCopySize] 2bpp tiles (or 16 * [hVBlankCopySize] tile map entries)
; from hVBlankCopySource to hVBlankCopyDest.
; Source and destination addresses are updated,
; so transfer can continue in subsequent calls.
ld a, [H_VBCOPYSIZE]
ldh a, [hVBlankCopySize]
and a
ret z
ld hl, sp + 0
ld a, h
ld [H_SPTEMP], a
ldh [hSPTemp], a
ld a, l
ld [H_SPTEMP + 1], a
ldh [hSPTemp + 1], a
ld a, [H_VBCOPYSRC]
ldh a, [hVBlankCopySource]
ld l, a
ld a, [H_VBCOPYSRC + 1]
ldh a, [hVBlankCopySource + 1]
ld h, a
ld sp, hl
ld a, [H_VBCOPYDEST]
ldh a, [hVBlankCopyDest]
ld l, a
ld a, [H_VBCOPYDEST + 1]
ldh a, [hVBlankCopyDest + 1]
ld h, a
ld a, [H_VBCOPYSIZE]
ldh a, [hVBlankCopySize]
ld b, a
xor a ; transferred
ld [H_VBCOPYSIZE], a
ldh [hVBlankCopySize], a
.loop
rept 7
REPT 7
pop de
ld [hl], e
inc l
ld [hl], d
inc l
endr
ENDR
pop de
ld [hl], e
@ -356,19 +356,19 @@ VBlankCopy::
jr nz, .loop
ld a, l
ld [H_VBCOPYDEST], a
ldh [hVBlankCopyDest], a
ld a, h
ld [H_VBCOPYDEST + 1], a
ldh [hVBlankCopyDest + 1], a
ld hl, sp + 0
ld a, l
ld [H_VBCOPYSRC], a
ldh [hVBlankCopySource], a
ld a, h
ld [H_VBCOPYSRC + 1], a
ldh [hVBlankCopySource + 1], a
ld a, [H_SPTEMP]
ldh a, [hSPTemp]
ld h, a
ld a, [H_SPTEMP + 1]
ldh a, [hSPTemp + 1]
ld l, a
ld sp, hl
@ -379,13 +379,13 @@ UpdateMovingBgTiles::
; Animate water and flower
; tiles in the overworld.
ld a, [hTilesetType]
ldh a, [hTileAnimations]
and a
ret z ; no animations if indoors (or if a menu set this to 0)
ld a, [hMovingBGTilesCounter1]
ldh a, [hMovingBGTilesCounter1]
inc a
ld [hMovingBGTilesCounter1], a
ldh [hMovingBGTilesCounter1], a
cp 20
ret c
cp 21
@ -393,7 +393,7 @@ UpdateMovingBgTiles::
; water
ld hl, vTileset + $14 * $10
ld hl, vTileset tile $14
ld c, $10
ld a, [wMovingBGTilesCounter2]
@ -417,17 +417,17 @@ UpdateMovingBgTiles::
dec c
jr nz, .left
.done
ld a, [hTilesetType]
ldh a, [hTileAnimations]
rrca
ret nc
; if in a cave, no flower animations
xor a
ld [hMovingBGTilesCounter1], a
ldh [hMovingBGTilesCounter1], a
ret
.flower
xor a
ld [hMovingBGTilesCounter1], a
ldh [hMovingBGTilesCounter1], a
ld a, [wMovingBGTilesCounter2]
and 3
@ -438,7 +438,7 @@ UpdateMovingBgTiles::
jr z, .copy
ld hl, FlowerTile3
.copy
ld de, vTileset + $3 * $10
ld de, vTileset tile $03
ld c, $10
.loop
ld a, [hli]

294
home/window.asm Normal file
View file

@ -0,0 +1,294 @@
HandleMenuInput::
xor a
ld [wPartyMenuAnimMonEnabled], a
HandleMenuInput_::
ldh a, [hDownArrowBlinkCount1]
push af
ldh a, [hDownArrowBlinkCount2]
push af ; save existing values on stack
xor a
ldh [hDownArrowBlinkCount1], a ; blinking down arrow timing value 1
ld a, 6
ldh [hDownArrowBlinkCount2], a ; blinking down arrow timing value 2
.loop1
xor a
ld [wAnimCounter], a ; counter for pokemon shaking animation
call PlaceMenuCursor
call Delay3
.loop2
push hl
ld a, [wPartyMenuAnimMonEnabled]
and a ; is it a pokemon selection menu?
jr z, .getJoypadState
farcall AnimatePartyMon ; shake mini sprite of selected pokemon
.getJoypadState
pop hl
call JoypadLowSensitivity
ldh a, [hJoy5]
and a ; was a key pressed?
jr nz, .keyPressed
push hl
hlcoord 18, 11 ; coordinates of blinking down arrow in some menus
call HandleDownArrowBlinkTiming ; blink down arrow (if any)
pop hl
ld a, [wMenuJoypadPollCount]
dec a
jr z, .giveUpWaiting
jr .loop2
.giveUpWaiting
; if a key wasn't pressed within the specified number of checks
pop af
ldh [hDownArrowBlinkCount2], a
pop af
ldh [hDownArrowBlinkCount1], a ; restore previous values
xor a
ld [wMenuWrappingEnabled], a ; disable menu wrapping
ret
.keyPressed
xor a
ld [wCheckFor180DegreeTurn], a
ldh a, [hJoy5]
ld b, a
bit 6, a ; pressed Up key?
jr z, .checkIfDownPressed
.upPressed
ld a, [wCurrentMenuItem] ; selected menu item
and a ; already at the top of the menu?
jr z, .alreadyAtTop
.notAtTop
dec a
ld [wCurrentMenuItem], a ; move selected menu item up one space
jr .checkOtherKeys
.alreadyAtTop
ld a, [wMenuWrappingEnabled]
and a ; is wrapping around enabled?
jr z, .noWrappingAround
ld a, [wMaxMenuItem]
ld [wCurrentMenuItem], a ; wrap to the bottom of the menu
jr .checkOtherKeys
.checkIfDownPressed
bit 7, a
jr z, .checkOtherKeys
.downPressed
ld a, [wCurrentMenuItem]
inc a
ld c, a
ld a, [wMaxMenuItem]
cp c
jr nc, .notAtBottom
.alreadyAtBottom
ld a, [wMenuWrappingEnabled]
and a ; is wrapping around enabled?
jr z, .noWrappingAround
ld c, $00 ; wrap from bottom to top
.notAtBottom
ld a, c
ld [wCurrentMenuItem], a
.checkOtherKeys
ld a, [wMenuWatchedKeys]
and b ; does the menu care about any of the pressed keys?
jp z, .loop1
.checkIfAButtonOrBButtonPressed
ldh a, [hJoy5]
and A_BUTTON | B_BUTTON
jr z, .skipPlayingSound
.AButtonOrBButtonPressed
push hl
ld hl, wFlags_0xcd60
bit 5, [hl]
pop hl
jr nz, .skipPlayingSound
ld a, SFX_PRESS_AB
call PlaySound
.skipPlayingSound
pop af
ldh [hDownArrowBlinkCount2], a
pop af
ldh [hDownArrowBlinkCount1], a ; restore previous values
xor a
ld [wMenuWrappingEnabled], a ; disable menu wrapping
ldh a, [hJoy5]
ret
.noWrappingAround
ld a, [wMenuWatchMovingOutOfBounds]
and a ; should we return if the user tried to go past the top or bottom?
jr z, .checkOtherKeys
jr .checkIfAButtonOrBButtonPressed
PlaceMenuCursor::
ld a, [wTopMenuItemY]
and a ; is the y coordinate 0?
jr z, .adjustForXCoord
hlcoord 0, 0
ld bc, SCREEN_WIDTH
.topMenuItemLoop
add hl, bc
dec a
jr nz, .topMenuItemLoop
.adjustForXCoord
ld a, [wTopMenuItemX]
ld b, 0
ld c, a
add hl, bc
push hl
ld a, [wLastMenuItem]
and a ; was the previous menu id 0?
jr z, .checkForArrow1
push af
ldh a, [hUILayoutFlags]
bit 1, a ; is the menu double spaced?
jr z, .doubleSpaced1
ld bc, 20
jr .getOldMenuItemScreenPosition
.doubleSpaced1
ld bc, 40
.getOldMenuItemScreenPosition
pop af
.oldMenuItemLoop
add hl, bc
dec a
jr nz, .oldMenuItemLoop
.checkForArrow1
ld a, [hl]
cp "▶" ; was an arrow next to the previously selected menu item?
jr nz, .skipClearingArrow
.clearArrow
ld a, [wTileBehindCursor]
ld [hl], a
.skipClearingArrow
pop hl
ld a, [wCurrentMenuItem]
and a
jr z, .checkForArrow2
push af
ldh a, [hUILayoutFlags]
bit 1, a ; is the menu double spaced?
jr z, .doubleSpaced2
ld bc, 20
jr .getCurrentMenuItemScreenPosition
.doubleSpaced2
ld bc, 40
.getCurrentMenuItemScreenPosition
pop af
.currentMenuItemLoop
add hl, bc
dec a
jr nz, .currentMenuItemLoop
.checkForArrow2
ld a, [hl]
cp "▶" ; has the right arrow already been placed?
jr z, .skipSavingTile ; if so, don't lose the saved tile
ld [wTileBehindCursor], a ; save tile before overwriting with right arrow
.skipSavingTile
ld a, "▶" ; place right arrow
ld [hl], a
ld a, l
ld [wMenuCursorLocation], a
ld a, h
ld [wMenuCursorLocation + 1], a
ld a, [wCurrentMenuItem]
ld [wLastMenuItem], a
ret
; This is used to mark a menu cursor other than the one currently being
; manipulated. In the case of submenus, this is used to show the location of
; the menu cursor in the parent menu. In the case of swapping items in list,
; this is used to mark the item that was first chosen to be swapped.
PlaceUnfilledArrowMenuCursor::
ld b, a
ld a, [wMenuCursorLocation]
ld l, a
ld a, [wMenuCursorLocation + 1]
ld h, a
ld [hl], "▷"
ld a, b
ret
; Replaces the menu cursor with a blank space.
EraseMenuCursor::
ld a, [wMenuCursorLocation]
ld l, a
ld a, [wMenuCursorLocation + 1]
ld h, a
ld [hl], " "
ret
; This toggles a blinking down arrow at hl on and off after a delay has passed.
; This is often called even when no blinking is occurring.
; The reason is that most functions that call this initialize hDownArrowBlinkCount1 to 0.
; The effect is that if the tile at hl is initialized with a down arrow,
; this function will toggle that down arrow on and off, but if the tile isn't
; initialized with a down arrow, this function does nothing.
; That allows this to be called without worrying about if a down arrow should
; be blinking.
HandleDownArrowBlinkTiming::
ld a, [hl]
ld b, a
ld a, "▼"
cp b
jr nz, .downArrowOff
.downArrowOn
ldh a, [hDownArrowBlinkCount1]
dec a
ldh [hDownArrowBlinkCount1], a
ret nz
ldh a, [hDownArrowBlinkCount2]
dec a
ldh [hDownArrowBlinkCount2], a
ret nz
ld a, " "
ld [hl], a
ld a, $ff
ldh [hDownArrowBlinkCount1], a
ld a, $06
ldh [hDownArrowBlinkCount2], a
ret
.downArrowOff
ldh a, [hDownArrowBlinkCount1]
and a
ret z
dec a
ldh [hDownArrowBlinkCount1], a
ret nz
dec a
ldh [hDownArrowBlinkCount1], a
ldh a, [hDownArrowBlinkCount2]
dec a
ldh [hDownArrowBlinkCount2], a
ret nz
ld a, $06
ldh [hDownArrowBlinkCount2], a
ld a, "▼"
ld [hl], a
ret
; The following code either enables or disables the automatic drawing of
; text boxes by DisplayTextID. Both functions cause DisplayTextID to wait
; for a button press after displaying text (unless [wEnteringCableClub] is set).
EnableAutoTextBoxDrawing::
xor a
jr AutoTextBoxDrawingCommon
DisableAutoTextBoxDrawing::
ld a, TRUE
AutoTextBoxDrawingCommon::
ld [wAutoTextBoxDrawingControl], a
xor a
ld [wDoNotWaitForButtonPressAfterDisplayingText], a ; make DisplayTextID wait for button press
ret
PrintText::
; Print text hl at (1, 14).
push hl
ld a, MESSAGE_BOX
ld [wTextBoxID], a
call DisplayTextBoxID
call UpdateSprites
call Delay3
pop hl
PrintText_NoCreatingTextBox::
bccoord 1, 14
jp TextCommandProcessor

40
home/yes_no.asm Normal file
View file

@ -0,0 +1,40 @@
; displays yes/no choice
; yes -> set carry
YesNoChoice::
call SaveScreenTilesToBuffer1
call InitYesNoTextBoxParameters
jr DisplayYesNoChoice
Func_35f4::
ld a, TWO_OPTION_MENU
ld [wTextBoxID], a
call InitYesNoTextBoxParameters
jp DisplayTextBoxID
InitYesNoTextBoxParameters::
xor a ; YES_NO_MENU
ld [wTwoOptionMenuID], a
hlcoord 14, 7
lb bc, 8, 15
ret
YesNoChoicePokeCenter::
call SaveScreenTilesToBuffer1
ld a, HEAL_CANCEL_MENU
ld [wTwoOptionMenuID], a
hlcoord 11, 6
lb bc, 8, 12
jr DisplayYesNoChoice
WideYesNoChoice:: ; unused
call SaveScreenTilesToBuffer1
ld a, WIDE_YES_NO_MENU
ld [wTwoOptionMenuID], a
hlcoord 12, 7
lb bc, 8, 13
DisplayYesNoChoice::
ld a, TWO_OPTION_MENU
ld [wTextBoxID], a
call DisplayTextBoxID
jp LoadScreenTilesFromBuffer1