pokered/home.asm

6911 lines
133 KiB
NASM
Raw Normal View History

2014-05-25 17:26:42 +00:00
; The rst vectors are unused.
SECTION "rst00", ROM0[$00]
rst $38
SECTION "rst08", ROM0[$08]
rst $38
SECTION "rst10", ROM0[$10]
rst $38
SECTION "rst18", ROM0[$18]
rst $38
SECTION "rst20", ROM0[$20]
rst $38
SECTION "rst28", ROM0[$28]
rst $38
SECTION "rst30", ROM0[$30]
rst $38
SECTION "rst38", ROM0[$38]
rst $38
; interrupts
SECTION "vblank", ROM0[$40]
jp VBlank
SECTION "lcdc", ROM0[$48]
rst $38
SECTION "timer", ROM0[$50]
jp Timer
SECTION "serial", ROM0[$58]
jp Serial
SECTION "joypad", ROM0[$60]
reti
SECTION "bank0",ROM0[$61]
DisableLCD::
xor a
ld [rIF], a
ld a, [rIE]
ld b, a
res 0, a
ld [rIE], a
.wait
ld a, [rLY]
cp LY_VBLANK
jr nz, .wait
ld a, [rLCDC]
and $ff ^ rLCDC_ENABLE_MASK
ld [rLCDC], a
ld a, b
ld [rIE], a
ret
EnableLCD::
ld a, [rLCDC]
set rLCDC_ENABLE, a
ld [rLCDC], a
ret
ClearSprites::
xor a
ld hl, wOAMBuffer
ld b, 40 * 4
.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
FarCopyData::
; Copy bc bytes from a:hl to de.
ld [wBuffer], a
ld a, [H_LOADEDROMBANK]
push af
ld a, [wBuffer]
ld [H_LOADEDROMBANK], a
ld [MBC3RomBank], a
call CopyData
pop af
ld [H_LOADEDROMBANK], a
ld [MBC3RomBank], a
ret
CopyData::
; Copy bc bytes from hl to de.
ld a, [hli]
ld [de], a
inc de
dec bc
ld a, c
or b
jr nz, CopyData
ret
SECTION "Entry", ROM0[$100]
nop
jp Start
SECTION "Start", ROM0[$150]
Start::
cp GBC
jr z, .gbc
xor a
jr .ok
.gbc
ld a, 0
.ok
ld [wGBC], a
jp Init
INCLUDE "home/joypad.asm"
2014-05-25 17:26:42 +00:00
INCLUDE "data/map_header_pointers.asm"
INCLUDE "home/overworld.asm"
2014-05-25 17:26:42 +00:00
; this is used to check if the player wants to interrupt the opening sequence at several points
; XXX is this used anywhere else?
; INPUT:
; c = number of frames to wait
; sets carry if Up+Select+B, Start, or A is pressed within c frames
; unsets carry otherwise
CheckForUserInterruption:: ; 12f8 (0:12f8)
call DelayFrame
push bc
2014-05-25 18:21:48 +00:00
call JoypadLowSensitivity
2014-05-25 17:26:42 +00:00
pop bc
2014-05-25 17:51:53 +00:00
ld a,[hJoyHeld] ; currently pressed buttons
2014-05-25 17:26:42 +00:00
cp a,%01000110 ; Up, Select button, B button
jr z,.setCarry ; if all three keys are pressed
ld a,[$ffb5] ; either newly pressed buttons or currently pressed buttons at low sampling rate
and a,%00001001 ; Start button, A button
jr nz,.setCarry ; if either key is pressed
dec c
jr nz,CheckForUserInterruption
.unsetCarry
and a
ret
.setCarry
scf
ret
; function to load position data for destination warp when switching maps
; INPUT:
; a = ID of destination warp within destination map
LoadDestinationWarpPosition:: ; 1313 (0:1313)
ld b,a
ld a,[H_LOADEDROMBANK]
push af
ld a,[wPredefParentBank]
ld [H_LOADEDROMBANK],a
ld [$2000],a
ld a,b
add a
add a
ld c,a
ld b,0
add hl,bc
ld bc,4
ld de,wd35f
2014-05-25 17:26:42 +00:00
call CopyData
pop af
ld [H_LOADEDROMBANK],a
ld [$2000],a
ret
; INPUT:
; c: if nonzero, show at least a sliver of health
; d = number of HP bar sections (normally 6)
; e = health (in eighths of bar sections) (normally out of 48)
DrawHPBar:: ; 1336 (0:1336)
push hl
push de
push bc
ld a,$71 ; left of HP bar tile 1
ld [hli],a
ld a,$62 ; left of HP bar tile 2
ld [hli],a
push hl
ld a,$63 ; empty bar section tile
.drawEmptyBarLoop
ld [hli],a
dec d
jr nz,.drawEmptyBarLoop
ld a,[wListMenuID]
2014-05-25 17:26:42 +00:00
dec a ; what should the right of HP bar tile be?
ld a,$6d ; right of HP bar tile, in status screen and battles
jr z,.writeTile
dec a ; right of HP bar tile, in pokemon menu
.writeTile
ld [hl],a
pop hl
ld a,e
and a ; is there enough health to show up on the HP bar?
jr nz,.loop ; if so, draw the HP bar
ld a,c
and a ; should a sliver of health be shown no matter what?
jr z,.done
ld e,1 ; if so, fill one eighth of a bar section
; loop to draw every full bar section
.loop
ld a,e
sub a,8
jr c,.drawPartialBarSection
ld e,a
ld a,$6b ; filled bar section tile
ld [hli],a
ld a,e
and a
jr z,.done
jr .loop
; draws a partial bar section at the end (if necessary)
; there are 7 possible partial bar sections from 1/8 to 7/8 full
.drawPartialBarSection
ld a,$63 ; empty bar section tile
add e ; add e to get the appropriate partial bar section tile
ld [hl],a ; write the tile
.done
pop bc
pop de
pop hl
ret
; loads pokemon data from one of multiple sources to wcf98
; loads base stats to W_MONHDEXNUM
2014-05-25 17:26:42 +00:00
; INPUT:
; [wWhichPokemon] = index of pokemon within party/box
; [wcc49] = source
2014-05-25 17:26:42 +00:00
; 00: player's party
; 01: enemy's party
; 02: current box
; 03: daycare
; OUTPUT:
; [wcf91] = pokemon ID
; wcf98 = base address of pokemon data
; W_MONHDEXNUM = base address of base stats
2014-05-25 17:26:42 +00:00
LoadMonData:: ; 1372 (0:1372)
ld hl,LoadMonData_
ld b,BANK(LoadMonData_)
jp Bankswitch
; writes c to wd0dc+b
2014-05-25 17:26:42 +00:00
Func_137a:: ; 137a (0:137a)
ld hl, wd0dc
2014-05-25 17:26:42 +00:00
ld e, b
ld d, $0
add hl, de
ld a, c
ld [hl], a
ret
LoadFlippedFrontSpriteByMonIndex:: ; 1384 (0:1384)
ld a, $1
ld [W_SPRITEFLIPPED], a
LoadFrontSpriteByMonIndex:: ; 1389 (0:1389)
push hl
ld a, [wd11e]
2014-05-25 17:26:42 +00:00
push af
ld a, [wcf91]
ld [wd11e], a
2014-05-25 17:26:42 +00:00
ld a, $3a
call Predef ; indirect jump to IndexToPokedex (41010 (10:5010))
ld hl, wd11e
2014-05-25 17:26:42 +00:00
ld a, [hl]
pop bc
ld [hl], b
and a
pop hl
jr z, .invalidDexNumber ; dex #0 invalid
cp 151 + 1
jr c, .validDexNumber ; dex >#151 invalid
.invalidDexNumber
ld a, RHYDON ; $1
ld [wcf91], a
2014-05-25 17:26:42 +00:00
ret
.validDexNumber
push hl
2014-05-29 08:31:46 +00:00
ld de, vFrontPic
2014-05-25 17:26:42 +00:00
call LoadMonFrontSprite
pop hl
ld a, [H_LOADEDROMBANK]
push af
ld a, Bank(asm_3f0d0)
ld [H_LOADEDROMBANK], a
ld [$2000], a
xor a
ld [$ffe1], a
call asm_3f0d0
xor a
ld [W_SPRITEFLIPPED], a
pop af
ld [H_LOADEDROMBANK], a
ld [$2000], a
ret
; plays the cry of a pokemon
; INPUT:
; a = pokemon ID
PlayCry:: ; 13d0 (0:13d0)
call GetCryData
call PlaySound ; play cry
jp WaitForSoundToFinish ; wait for sound to be done playing
; gets a pokemon's cry data
; INPUT:
; a = pokemon ID
GetCryData:: ; 13d9 (0:13d9)
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
ld a,[hli]
ld [wc0f1],a
2014-05-25 17:26:42 +00:00
ld a,[hl]
ld [wc0f2],a
2014-05-25 17:26:42 +00:00
call BankswitchBack
ld a,b ; a = cryID
ld c,$14 ; base sound ID for pokemon cries
rlca
add b ; a = cryID * 3
add c ; a = $14 + cryID * 3
ret
DisplayPartyMenu:: ; 13fc (0:13fc)
ld a,[$ffd7]
push af
xor a
ld [$ffd7],a
call GBPalWhiteOutWithDelay3
call ClearSprites
call PartyMenuInit
call DrawPartyMenu
jp HandlePartyMenuInput
GoBackToPartyMenu:: ; 1411 (0:1411)
ld a,[$ffd7]
push af
xor a
ld [$ffd7],a
call PartyMenuInit
call RedrawPartyMenu
jp HandlePartyMenuInput
PartyMenuInit:: ; 1420 (0:1420)
ld a,$01
call BankswitchHome
call LoadHpBarAndStatusTilePatterns
ld hl,wd730
2014-05-25 17:26:42 +00:00
set 6,[hl] ; turn off letter printing delay
xor a
ld [wcc49],a
ld [wcc37],a
2014-05-25 17:26:42 +00:00
ld hl,wTopMenuItemY
inc a
ld [hli],a ; top menu item Y
xor a
ld [hli],a ; top menu item X
ld a,[wcc2b]
2014-05-25 17:26:42 +00:00
push af
ld [hli],a ; current menu item ID
inc hl
ld a,[W_NUMINPARTY]
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 ([W_NUMINPARTY] - 1)
; otherwise, it is 0
.storeMaxMenuItemID
ld [hli],a ; max menu item ID
ld a,[wd11f]
2014-05-25 17:26:42 +00:00
and a
ld a,%00000011 ; A button and B button
jr z,.next
xor a
ld [wd11f],a
2014-05-25 17:26:42 +00:00
inc a
.next
ld [hli],a ; menu watched keys
pop af
ld [hl],a ; old menu item ID
ret
HandlePartyMenuInput:: ; 145a (0:145a)
ld a,1
ld [wMenuWrappingEnabled],a
2014-05-25 17:26:42 +00:00
ld a,$40
ld [wd09b],a
2014-05-25 17:26:42 +00:00
call HandleMenuInputPokemonSelection
call PlaceUnfilledArrowMenuCursor
ld b,a
xor a
ld [wd09b],a
2014-05-25 17:26:42 +00:00
ld a,[wCurrentMenuItem]
ld [wcc2b],a
ld hl,wd730
2014-05-25 17:26:42 +00:00
res 6,[hl] ; turn on letter printing delay
ld a,[wcc35]
2014-05-25 17:26:42 +00:00
and a
jp nz,.swappingPokemon
pop af
ld [$ffd7],a
bit 1,b
jr nz,.noPokemonChosen
ld a,[W_NUMINPARTY]
and a
jr z,.noPokemonChosen
ld a,[wCurrentMenuItem]
ld [wWhichPokemon],a
ld hl,W_PARTYMON1
ld b,0
ld c,a
add hl,bc
ld a,[hl]
ld [wcf91],a
ld [wcfd9],a
2014-05-25 17:26:42 +00:00
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
callba ErasePartyMenuCursors
xor a
ld [wcc35],a
ld [wd07d],a
2014-05-25 17:26:42 +00:00
call RedrawPartyMenu
jr HandlePartyMenuInput
.handleSwap
ld a,[wCurrentMenuItem]
ld [wWhichPokemon],a
callba SwitchPartyMon
jr HandlePartyMenuInput
DrawPartyMenu:: ; 14d4 (0:14d4)
ld hl, DrawPartyMenu_
jr DrawPartyMenuCommon
RedrawPartyMenu:: ; 14d9 (0:14d9)
ld hl, RedrawPartyMenu_
DrawPartyMenuCommon:: ; 14dc (0:14dc)
ld b, BANK(RedrawPartyMenu_)
jp Bankswitch
; prints a pokemon's status condition
; INPUT:
; de = address of status condition
; hl = destination address
PrintStatusCondition:: ; 14e1 (0:14e1)
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 ; 14f6
ld a,[H_LOADEDROMBANK]
push af
ld a,BANK(PrintStatusAilment)
ld [H_LOADEDROMBANK],a
ld [$2000],a
call PrintStatusAilment ; print status condition
pop bc
ld a,b
ld [H_LOADEDROMBANK],a
ld [$2000],a
ret
; function to print pokemon level, leaving off the ":L" if the level is at least 100
; INPUT:
; hl = destination address
; [wcfb9] = level
2014-05-25 17:26:42 +00:00
PrintLevel:: ; 150b (0:150b)
ld a,$6e ; ":L" tile ID
ld [hli],a
ld c,2 ; number of digits
ld a,[wcfb9] ; level
2014-05-25 17:26:42 +00:00
cp a,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
; [wcfb9] = level
2014-05-25 17:26:42 +00:00
PrintLevelFull:: ; 151b (0:151b)
ld a,$6e ; ":L" tile ID
ld [hli],a
ld c,3 ; number of digits
ld a,[wcfb9] ; level
2014-05-25 17:26:42 +00:00
PrintLevelCommon:: ; 1523 (0:1523)
ld [wd11e],a
ld de,wd11e
2014-05-25 17:26:42 +00:00
ld b,$41 ; no leading zeroes, left-aligned, one byte
jp PrintNumber
Func_152e:: ; 152e (0:152e)
ld hl,wd0dc
2014-05-25 17:26:42 +00:00
ld c,a
ld b,0
add hl,bc
ld a,[hl]
ret
; copies the base stat data of a pokemon to W_MONHDEXNUM (W_MONHEADER)
2014-05-25 17:26:42 +00:00
; INPUT:
; [wd0b5] = pokemon ID
2014-05-25 17:26:42 +00:00
GetMonHeader:: ; 1537 (0:1537)
ld a,[H_LOADEDROMBANK]
push af
ld a,BANK(BaseStats)
ld [H_LOADEDROMBANK],a
ld [$2000],a
push bc
push de
push hl
ld a,[wd11e]
2014-05-25 17:26:42 +00:00
push af
ld a,[wd0b5]
ld [wd11e],a
2014-05-25 17:26:42 +00:00
ld de,FossilKabutopsPic
ld b,$66 ; size of Kabutops fossil and Ghost sprites
cp a,FOSSIL_KABUTOPS ; Kabutops fossil
jr z,.specialID
ld de,GhostPic
cp a,MON_GHOST ; Ghost
jr z,.specialID
ld de,FossilAerodactylPic
ld b,$77 ; size of Aerodactyl fossil sprite
cp a,FOSSIL_AERODACTYL ; Aerodactyl fossil
jr z,.specialID
cp a,MEW
jr z,.mew
ld a,$3a
call Predef ; convert pokemon ID in [wd11e] to pokedex number
ld a,[wd11e]
2014-05-25 17:26:42 +00:00
dec a
ld bc,28
ld hl,BaseStats
call AddNTimes
ld de,W_MONHEADER
ld bc,28
call CopyData
jr .done
.specialID
ld hl,W_MONHSPRITEDIM
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,W_MONHEADER
ld bc,28
ld a,BANK(MewBaseStats)
call FarCopyData
.done
ld a,[wd0b5]
ld [W_MONHDEXNUM],a
2014-05-25 17:26:42 +00:00
pop af
ld [wd11e],a
2014-05-25 17:26:42 +00:00
pop hl
pop de
pop bc
pop af
ld [H_LOADEDROMBANK],a
ld [$2000],a
ret
; copy party pokemon's name to wcd6d
2014-05-25 17:26:42 +00:00
GetPartyMonName2:: ; 15b4 (0:15b4)
ld a,[wWhichPokemon] ; index within party
ld hl,W_PARTYMON1NAME
; this is called more often
GetPartyMonName:: ; 15ba (0:15ba)
push hl
push bc
call SkipFixedLengthTextEntries ; add 11 to hl, a times
ld de,wcd6d
2014-05-25 17:26:42 +00:00
push de
ld bc,11
call CopyData
pop de
pop bc
pop hl
ret
; 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:: ; 15cd (0:15cd)
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:: ; 1604 (0:1604)
and a,%00001111
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 a,"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
; 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:: ; 1627 (0:1627)
ld bc,W_MONHEADER
add hl,bc
ld a,[hli]
ld [W_SPRITEINPUTPTR],a ; fetch sprite input pointer
ld a,[hl]
ld [W_SPRITEINPUTPTR+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
2014-05-25 17:26:42 +00:00
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:: ; 1665 (0:1665)
push de
ld hl, W_MONHFRONTSPRITE - W_MONHEADER
call UncompressMonSprite
ld hl, W_MONHSPRITEDIM
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:: ; 1672 (0:1672)
push de
and $f
ld [H_SPRITEWIDTH], 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)
ld [H_SPRITEOFFSET], a
ld a, c
swap a
and $f
ld b, a
add a
add a
add a ; 8*tiles is height in bytes
ld [H_SPRITEHEIGHT], a ; $ff8c
ld a, $7
sub b ; 7-h ; skip for vertical center (in tiles, relative to current column)
ld b, a
ld a, [H_SPRITEOFFSET]
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)
ld [H_SPRITEOFFSET], a
xor a
ld [$4000], a
ld hl, S_SPRITEBUFFER0
call ZeroSpriteBuffer ; zero buffer 0
ld de, S_SPRITEBUFFER1
ld hl, S_SPRITEBUFFER0
call AlignSpriteDataCentered ; copy and align buffer 1 to 0 (containing the MSB of the 2bpp sprite)
ld hl, S_SPRITEBUFFER1
call ZeroSpriteBuffer ; zero buffer 1
ld de, S_SPRITEBUFFER2
ld hl, S_SPRITEBUFFER1
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:: ; 16c2 (0:16c2)
ld a, [H_SPRITEOFFSET]
ld b, $0
ld c, a
add hl, bc
ld a, [H_SPRITEWIDTH] ; $ff8b
.columnLoop
push af
push hl
ld a, [H_SPRITEHEIGHT] ; $ff8c
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:: ; 16df (0:16df)
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:: ; 16ea (0:16ea)
xor a
ld [$4000], a
push de
ld hl, S_SPRITEBUFFER2 + (SPRITEBUFFERSIZE - 1) ; destination: end of buffer 2
ld de, S_SPRITEBUFFER1 + (SPRITEBUFFERSIZE - 1) ; source 2: end of buffer 1
ld bc, S_SPRITEBUFFER0 + (SPRITEBUFFERSIZE - 1) ; source 1: end of buffer 0
ld a, SPRITEBUFFERSIZE/2 ; $c4
ld [H_SPRITEINTERLACECOUNTER], a ; $ff8b
.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
ld a, [H_SPRITEINTERLACECOUNTER] ; $ff8b
dec a
ld [H_SPRITEINTERLACECOUNTER], a ; $ff8b
jr nz, .interlaceLoop
ld a, [W_SPRITEFLIPPED]
and a
jr z, .notFlipped
ld bc, 2*SPRITEBUFFERSIZE
ld hl, S_SPRITEBUFFER1
.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, S_SPRITEBUFFER1
ld c, (2*SPRITEBUFFERSIZE)/16 ; $31, number of 16 byte chunks to be copied
ld a, [H_LOADEDROMBANK]
ld b, a
jp CopyVideoData
Underground_Coll:: INCBIN "gfx/tilesets/underground.tilecoll"
Overworld_Coll:: INCBIN "gfx/tilesets/overworld.tilecoll"
2014-05-25 17:26:42 +00:00
RedsHouse1_Coll::
RedsHouse2_Coll:: INCBIN "gfx/tilesets/reds_house.tilecoll"
Mart_Coll::
Pokecenter_Coll:: INCBIN "gfx/tilesets/pokecenter.tilecoll"
2014-05-25 17:26:42 +00:00
Dojo_Coll::
Gym_Coll:: INCBIN "gfx/tilesets/gym.tilecoll"
Forest_Coll:: INCBIN "gfx/tilesets/forest.tilecoll"
House_Coll:: INCBIN "gfx/tilesets/house.tilecoll"
2014-05-25 17:26:42 +00:00
ForestGate_Coll::
Museum_Coll::
Gate_Coll:: INCBIN "gfx/tilesets/gate.tilecoll"
Ship_Coll:: INCBIN "gfx/tilesets/ship.tilecoll"
ShipPort_Coll:: INCBIN "gfx/tilesets/ship_port.tilecoll"
Cemetery_Coll:: INCBIN "gfx/tilesets/cemetery.tilecoll"
Interior_Coll:: INCBIN "gfx/tilesets/interior.tilecoll"
Cavern_Coll:: INCBIN "gfx/tilesets/cavern.tilecoll"
Lobby_Coll:: INCBIN "gfx/tilesets/lobby.tilecoll"
Mansion_Coll:: INCBIN "gfx/tilesets/mansion.tilecoll"
Lab_Coll:: INCBIN "gfx/tilesets/lab.tilecoll"
Club_Coll:: INCBIN "gfx/tilesets/club.tilecoll"
Facility_Coll:: INCBIN "gfx/tilesets/facility.tilecoll"
Plateau_Coll:: INCBIN "gfx/tilesets/plateau.tilecoll"
FarCopyData2::
; Identical to FarCopyData, but uses $ff8b
; as temp space instead of wBuffer.
2014-05-25 17:26:42 +00:00
ld [$ff8b],a
ld a,[H_LOADEDROMBANK]
push af
ld a,[$ff8b]
ld [H_LOADEDROMBANK],a
ld [MBC3RomBank],a
2014-05-25 17:26:42 +00:00
call CopyData
pop af
ld [H_LOADEDROMBANK],a
ld [MBC3RomBank],a
2014-05-25 17:26:42 +00:00
ret
FarCopyData3::
; Copy bc bytes from a:de to hl.
2014-05-25 17:26:42 +00:00
ld [$ff8b],a
ld a,[H_LOADEDROMBANK]
push af
ld a,[$ff8b]
ld [H_LOADEDROMBANK],a
ld [MBC3RomBank],a
2014-05-25 17:26:42 +00:00
push hl
push de
push de
ld d,h
ld e,l
pop hl
call CopyData
pop de
pop hl
pop af
ld [H_LOADEDROMBANK],a
ld [MBC3RomBank],a
2014-05-25 17:26:42 +00:00
ret
FarCopyDataDouble::
; Expand bc bytes of 1bpp image data
; from a:hl to 2bpp data at de.
2014-05-25 17:26:42 +00:00
ld [$ff8b],a
ld a,[H_LOADEDROMBANK]
push af
ld a,[$ff8b]
ld [H_LOADEDROMBANK],a
ld [MBC3RomBank],a
2014-05-25 17:26:42 +00:00
.loop
ld a,[hli]
ld [de],a
inc de
ld [de],a
inc de
dec bc
ld a,c
or b
jr nz,.loop
pop af
ld [H_LOADEDROMBANK],a
ld [MBC3RomBank],a
2014-05-25 17:26:42 +00:00
ret
CopyVideoData::
; Wait for the next VBlank, then copy c 2bpp
; tiles from b:de to hl, 8 tiles at a time.
; This takes c/8 frames.
ld a, [H_AUTOBGTRANSFERENABLED]
2014-05-25 17:26:42 +00:00
push af
xor a ; disable auto-transfer while copying
ld [H_AUTOBGTRANSFERENABLED], a
ld a, [H_LOADEDROMBANK]
ld [$ff8b], a
ld a, b
ld [H_LOADEDROMBANK], a
ld [MBC3RomBank], a
ld a, e
ld [H_VBCOPYSRC], a
ld a, d
ld [H_VBCOPYSRC + 1], a
ld a, l
ld [H_VBCOPYDEST], a
ld a, h
ld [H_VBCOPYDEST + 1], a
2014-05-25 17:26:42 +00:00
.loop
ld a, c
cp 8
jr nc, .keepgoing
.done
ld [H_VBCOPYSIZE], a
call DelayFrame
ld a, [$ff8b]
ld [H_LOADEDROMBANK], a
ld [MBC3RomBank], a
2014-05-25 17:26:42 +00:00
pop af
ld [H_AUTOBGTRANSFERENABLED], a
2014-05-25 17:26:42 +00:00
ret
.keepgoing
ld a, 8
ld [H_VBCOPYSIZE], a
call DelayFrame
ld a, c
sub 8
ld c, a
2014-05-25 17:26:42 +00:00
jr .loop
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]
2014-05-25 17:26:42 +00:00
push af
xor a ; disable auto-transfer while copying
ld [H_AUTOBGTRANSFERENABLED], a
ld a, [H_LOADEDROMBANK]
ld [$ff8b], a
ld a, b
ld [H_LOADEDROMBANK], a
ld [MBC3RomBank], a
ld a, e
ld [H_VBCOPYDOUBLESRC], a
ld a, d
ld [H_VBCOPYDOUBLESRC + 1], a
ld a, l
ld [H_VBCOPYDOUBLEDEST], a
ld a, h
ld [H_VBCOPYDOUBLEDEST + 1], a
2014-05-25 17:26:42 +00:00
.loop
ld a, c
cp 8
jr nc, .keepgoing
.done
ld [H_VBCOPYDOUBLESIZE], a
call DelayFrame
ld a, [$ff8b]
ld [H_LOADEDROMBANK], a
ld [MBC3RomBank], a
2014-05-25 17:26:42 +00:00
pop af
ld [H_AUTOBGTRANSFERENABLED], a
2014-05-25 17:26:42 +00:00
ret
.keepgoing
ld a, 8
ld [H_VBCOPYDOUBLESIZE], a
call DelayFrame
ld a, c
sub 8
ld c, a
2014-05-25 17:26:42 +00:00
jr .loop
ClearScreenArea::
; Clear tilemap area cxb at hl.
ld a, $7f ; blank tile
ld de, 20 ; screen width
.y
2014-05-25 17:26:42 +00:00
push hl
push bc
.x
ld [hli], a
2014-05-25 17:26:42 +00:00
dec c
jr nz, .x
2014-05-25 17:26:42 +00:00
pop bc
pop hl
add hl, de
2014-05-25 17:26:42 +00:00
dec b
jr nz, .y
2014-05-25 17:26:42 +00:00
ret
CopyScreenTileBufferToVRAM::
; Copy wTileMap to the BG Map starting at b * $100.
; This is done in thirds of 6 rows, so it takes 3 frames.
ld c, 6
ld hl, $600 * 0
ld de, wTileMap + 20 * 6 * 0
call .setup
2014-05-25 17:26:42 +00:00
call DelayFrame
ld hl, $600 * 1
ld de, wTileMap + 20 * 6 * 1
call .setup
2014-05-25 17:26:42 +00:00
call DelayFrame
ld hl, $600 * 2
ld de, wTileMap + 20 * 6 * 2
call .setup
2014-05-25 17:26:42 +00:00
jp DelayFrame
.setup
2014-05-25 17:26:42 +00:00
ld a, d
ld [H_VBCOPYBGSRC+1], a
call GetRowColAddressBgMap
ld a, l
ld [H_VBCOPYBGDEST], a
2014-05-25 17:26:42 +00:00
ld a, h
ld [H_VBCOPYBGDEST+1], a
ld a, c
ld [H_VBCOPYBGNUMROWS], a
2014-05-25 17:26:42 +00:00
ld a, e
ld [H_VBCOPYBGSRC], a
2014-05-25 17:26:42 +00:00
ret
ClearScreen::
; Clear wTileMap, then wait
; for the bg map to update.
ld bc, 20 * 18
2014-05-25 17:26:42 +00:00
inc b
ld hl, wTileMap
ld a, $7f
2014-05-25 17:26:42 +00:00
.loop
ld [hli], a
2014-05-25 17:26:42 +00:00
dec c
jr nz, .loop
2014-05-25 17:26:42 +00:00
dec b
jr nz, .loop
2014-05-25 17:26:42 +00:00
jp Delay3
2014-05-31 02:52:24 +00:00
INCLUDE "home/text.asm"
2014-05-25 17:26:42 +00:00
; this function seems to be used only once
; it store the address of a row and column of the VRAM background map in hl
; INPUT: h - row, l - column, b - high byte of background tile map address in VRAM
GetRowColAddressBgMap:: ; 1cdd (0:1cdd)
xor a
srl h
rr a
srl h
rr a
srl h
rr a
or l
ld l,a
ld a,b
or h
ld h,a
ret
; clears a VRAM background map with blank space tiles
; INPUT: h - high byte of background tile map address in VRAM
ClearBgMap:: ; 1cf0 (0:1cf0)
ld a," "
jr .next
ld a,l
.next
ld de,$400 ; size of VRAM background map
ld l,e
.loop
ld [hli],a
dec e
jr nz,.loop
dec d
jr nz,.loop
ret
; When the player takes a step, a row or column of 2x2 tile blocks at the edge
; of the screen toward which they moved is exposed and has to be redrawn.
; This function does the redrawing.
RedrawExposedScreenEdge:: ; 1d01 (0:1d01)
ld a,[H_SCREENEDGEREDRAW]
and a
ret z
ld b,a
xor a
ld [H_SCREENEDGEREDRAW],a
dec b
jr nz,.redrawRow
.redrawColumn
ld hl,wScreenEdgeTiles
ld a,[H_SCREENEDGEREDRAWADDR]
ld e,a
ld a,[H_SCREENEDGEREDRAWADDR + 1]
ld d,a
ld c,18 ; screen height
.loop1
ld a,[hli]
ld [de],a
inc de
ld a,[hli]
ld [de],a
ld a,31
add e
ld e,a
jr nc,.noCarry
inc d
.noCarry
; the following 4 lines wrap us from bottom to top if necessary
ld a,d
and a,$03
or a,$98
ld d,a
dec c
jr nz,.loop1
xor a
ld [H_SCREENEDGEREDRAW],a
ret
.redrawRow
ld hl,wScreenEdgeTiles
ld a,[H_SCREENEDGEREDRAWADDR]
ld e,a
ld a,[H_SCREENEDGEREDRAWADDR + 1]
ld d,a
push de
call .drawHalf ; draw upper half
pop de
ld a,32 ; width of VRAM background map
add e
ld e,a
; draw lower half
.drawHalf
ld c,10
.loop2
ld a,[hli]
ld [de],a
inc de
ld a,[hli]
ld [de],a
ld a,e
inc a
; the following 6 lines wrap us from the right edge to the left edge if necessary
and a,$1f
ld b,a
ld a,e
and a,$e0
or b
ld e,a
dec c
jr nz,.loop2
ret
; This function automatically transfers tile number data from the tile map at
; wTileMap to VRAM during V-blank. Note that it only transfers one third of the
; background per V-blank. It cycles through which third it draws.
; This transfer is turned off when walking around the map, but is turned
; on when talking to sprites, battling, using menus, etc. This is because
; the above function, RedrawExposedScreenEdge, is used when walking to
; improve efficiency.
AutoBgMapTransfer:: ; 1d57 (0:1d57)
ld a,[H_AUTOBGTRANSFERENABLED]
and a
ret z
ld hl,[sp + 0]
ld a,h
ld [H_SPTEMP],a
ld a,l
ld [H_SPTEMP + 1],a ; save stack pinter
ld a,[H_AUTOBGTRANSFERPORTION]
and a
jr z,.transferTopThird
dec a
jr z,.transferMiddleThird
.transferBottomThird
FuncCoord 0,12
ld hl,Coord
ld sp,hl
ld a,[H_AUTOBGTRANSFERDEST + 1]
ld h,a
ld a,[H_AUTOBGTRANSFERDEST]
ld l,a
ld de,(12 * 32)
add hl,de
xor a ; TRANSFERTOP
jr .doTransfer
.transferTopThird
FuncCoord 0,0
ld hl,Coord
ld sp,hl
ld a,[H_AUTOBGTRANSFERDEST + 1]
ld h,a
ld a,[H_AUTOBGTRANSFERDEST]
ld l,a
ld a,TRANSFERMIDDLE
jr .doTransfer
.transferMiddleThird
FuncCoord 0,6
ld hl,Coord
ld sp,hl
ld a,[H_AUTOBGTRANSFERDEST + 1]
ld h,a
ld a,[H_AUTOBGTRANSFERDEST]
ld l,a
ld de,(6 * 32)
add hl,de
ld a,TRANSFERBOTTOM
.doTransfer
ld [H_AUTOBGTRANSFERPORTION],a ; store next portion
ld b,6
TransferBgRows:: ; 1d9e (0:1d9e)
; unrolled loop and using pop for speed
rept 20 / 2 - 1
2014-05-25 17:26:42 +00:00
pop de
ld [hl], e
2014-05-25 17:26:42 +00:00
inc l
ld [hl], d
2014-05-25 17:26:42 +00:00
inc l
endr
2014-05-25 17:26:42 +00:00
pop de
ld [hl], e
2014-05-25 17:26:42 +00:00
inc l
ld [hl], d
i ld a, 32 - (20 - 1)
2014-05-25 17:26:42 +00:00
add l
ld l, a
jr nc, .ok
2014-05-25 17:26:42 +00:00
inc h
.ok
2014-05-25 17:26:42 +00:00
dec b
jr nz, TransferBgRows
ld a, [H_SPTEMP]
ld h, a
ld a, [H_SPTEMP + 1]
ld l, a
ld sp, hl
2014-05-25 17:26:42 +00:00
ret
; Copies [H_VBCOPYBGNUMROWS] rows from H_VBCOPYBGSRC to H_VBCOPYBGDEST.
; If H_VBCOPYBGSRC is XX00, the transfer is disabled.
VBlankCopyBgMap:: ; 1de1 (0:1de1)
ld a,[H_VBCOPYBGSRC] ; doubles as enabling byte
and a
ret z
ld hl,[sp + 0]
ld a,h
ld [H_SPTEMP],a
ld a,l
ld [H_SPTEMP + 1],a ; save stack pointer
ld a,[H_VBCOPYBGSRC]
ld l,a
ld a,[H_VBCOPYBGSRC + 1]
ld h,a
ld sp,hl
ld a,[H_VBCOPYBGDEST]
ld l,a
ld a,[H_VBCOPYBGDEST + 1]
ld h,a
ld a,[H_VBCOPYBGNUMROWS]
ld b,a
xor a
ld [H_VBCOPYBGSRC],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.
; While we're here, convert to 2bpp.
; The process is straightforward:
; copy each byte twice.
ld a, [H_VBCOPYDOUBLESIZE]
and a
ret z
ld hl, [sp + 0]
ld a, h
ld [H_SPTEMP], a
ld a, l
ld [H_SPTEMP + 1], a
ld a, [H_VBCOPYDOUBLESRC]
ld l, a
ld a, [H_VBCOPYDOUBLESRC + 1]
ld h, a
ld sp, hl
ld a, [H_VBCOPYDOUBLEDEST]
ld l, a
ld a, [H_VBCOPYDOUBLEDEST + 1]
ld h, a
ld a, [H_VBCOPYDOUBLESIZE]
ld b, a
xor a ; transferred
ld [H_VBCOPYDOUBLESIZE], a
.loop
rept 3
pop de
ld [hl], e
inc l
ld [hl], e
inc l
ld [hl], d
inc l
ld [hl], d
inc l
endr
pop de
ld [hl], e
inc l
ld [hl], e
inc l
ld [hl], d
inc l
ld [hl], d
inc hl
dec b
jr nz, .loop
ld a, l
ld [H_VBCOPYDOUBLEDEST], a
ld a, h
ld [H_VBCOPYDOUBLEDEST + 1], a
ld hl, [sp + 0]
ld a, l
ld [H_VBCOPYDOUBLESRC], a
ld a, h
ld [H_VBCOPYDOUBLESRC + 1], a
ld a, [H_SPTEMP]
ld h, a
ld a, [H_SPTEMP + 1]
ld l, a
ld sp, hl
ret
VBlankCopy::
; Copy [H_VBCOPYSIZE] 2bpp tiles
; from H_VBCOPYSRC to H_VBCOPYDEST.
; Source and destination addresses
; are updated, so transfer can
; continue in subsequent calls.
ld a, [H_VBCOPYSIZE]
and a
ret z
ld hl, [sp + 0]
ld a, h
ld [H_SPTEMP], a
ld a, l
ld [H_SPTEMP + 1], a
ld a, [H_VBCOPYSRC]
ld l, a
ld a, [H_VBCOPYSRC + 1]
ld h, a
ld sp, hl
ld a, [H_VBCOPYDEST]
ld l, a
ld a, [H_VBCOPYDEST + 1]
ld h, a
ld a, [H_VBCOPYSIZE]
ld b, a
xor a ; transferred
ld [H_VBCOPYSIZE], a
.loop
rept 7
pop de
ld [hl], e
inc l
ld [hl], d
inc l
endr
pop de
ld [hl], e
inc l
ld [hl], d
inc hl
dec b
jr nz, .loop
ld a, l
ld [H_VBCOPYDEST], a
ld a, h
ld [H_VBCOPYDEST + 1], a
ld hl, [sp + 0]
ld a, l
ld [H_VBCOPYSRC], a
ld a, h
ld [H_VBCOPYSRC + 1], a
ld a, [H_SPTEMP]
ld h, a
ld a, [H_SPTEMP + 1]
ld l, a
ld sp, hl
ret
UpdateMovingBgTiles::
; Animate water and flower
; tiles in the overworld.
ld a, [$ffd7]
and a
ret z
ld a, [$ffd8]
inc a
ld [$ffd8], a
cp $14
2014-05-25 17:26:42 +00:00
ret c
cp $15
2014-05-25 17:26:42 +00:00
jr z, .flower
2014-05-29 08:31:46 +00:00
ld hl, vTileset + $14 * $10
2014-05-25 17:26:42 +00:00
ld c, $10
ld a, [wd085]
2014-05-25 17:26:42 +00:00
inc a
and 7
ld [wd085], a
2014-05-25 17:26:42 +00:00
and 4
jr nz, .left
.right
ld a, [hl]
rrca
ld [hli], a
dec c
jr nz, .right
jr .done
.left
ld a, [hl]
rlca
ld [hli], a
dec c
jr nz, .left
.done
ld a, [$ffd7]
rrca
ret nc
xor a
ld [$ffd8], a
ret
.flower
xor a
ld [$ffd8], a
ld a, [wd085]
2014-05-25 17:26:42 +00:00
and 3
cp 2
ld hl, FlowerTile1
jr c, .copy
ld hl, FlowerTile2
jr z, .copy
ld hl, FlowerTile3
.copy
2014-05-29 08:31:46 +00:00
ld de, vTileset + $3 * $10
2014-05-25 17:26:42 +00:00
ld c, $10
.loop
ld a, [hli]
ld [de], a
inc de
dec c
jr nz, .loop
ret
FlowerTile1: INCBIN "gfx/tilesets/flower/flower1.2bpp"
FlowerTile2: INCBIN "gfx/tilesets/flower/flower2.2bpp"
FlowerTile3: INCBIN "gfx/tilesets/flower/flower3.2bpp"
SoftReset::
call StopAllSounds
call GBPalWhiteOut
ld c, $20
call DelayFrames
; fallthrough
Init::
; Program init.
rLCDC_DEFAULT EQU %11100011
; * LCD enabled
; * Window tile map at $9C00
; * Window display enabled
; * BG and window tile data at $8800
; * BG tile map at $9800
; * 8x8 OBJ size
; * OBJ display enabled
; * BG display enabled
di
xor a
ld [rIF], a
ld [rIE], a
ld [$ff43], a
ld [$ff42], a
ld [$ff01], a
ld [$ff02], a
ld [$ff4b], a
ld [$ff4a], a
ld [$ff06], a
ld [$ff07], a
ld [$ff47], a
ld [$ff48], a
ld [$ff49], a
ld a, rLCDC_ENABLE_MASK
ld [rLCDC], a
call DisableLCD
ld sp, wStack
ld hl, $c000 ; start of WRAM
2014-05-25 17:26:42 +00:00
ld bc, $2000 ; size of WRAM
.loop
ld [hl], 0
inc hl
dec bc
ld a, b
or c
jr nz, .loop
call ClearVram
ld hl, $ff80
ld bc, $ffff - $ff80
call FillMemory
call ClearSprites
ld a, Bank(WriteDMACodeToHRAM)
ld [H_LOADEDROMBANK], a
ld [MBC3RomBank], a
call WriteDMACodeToHRAM
xor a
ld [$ffd7], a
ld [$ff41], a
ld [$ffae], a
ld [$ffaf], a
ld [$ff0f], a
ld a, 1 << VBLANK + 1 << TIMER + 1 << SERIAL
ld [rIE], a
ld a, 144 ; move the window off-screen
ld [$ffb0], a
ld [rWY], a
ld a, 7
ld [rWX], a
ld a, $ff
ld [$ffaa], a
2014-05-29 08:31:46 +00:00
ld h, vBGMap0 / $100
2014-05-25 17:26:42 +00:00
call ClearBgMap
2014-05-29 08:31:46 +00:00
ld h, vBGMap1 / $100
2014-05-25 17:26:42 +00:00
call ClearBgMap
ld a, rLCDC_DEFAULT
ld [rLCDC], a
2014-05-25 17:51:53 +00:00
ld a, 16
ld [hSoftReset], a
2014-05-25 17:26:42 +00:00
call StopAllSounds
ei
ld a, $40 ; PREDEF_SGB_BORDER
call Predef
ld a, $1f
ld [wc0ef], a
ld [wc0f0], a
2014-05-25 17:26:42 +00:00
ld a, $9c
ld [$ffbd], a
xor a
ld [$ffbc], a
dec a
ld [wcfcb], a
2014-05-25 17:26:42 +00:00
ld a, $32 ; PREDEF_INTRO
call Predef
call DisableLCD
call ClearVram
call GBPalNormal
call ClearSprites
ld a, rLCDC_DEFAULT
ld [rLCDC], a
jp SetDefaultNamesBeforeTitlescreen
ClearVram:
ld hl, $8000
ld bc, $2000
xor a
jp FillMemory
StopAllSounds::
ld a, Bank(Func_9876)
ld [wc0ef], a
ld [wc0f0], a
2014-05-25 17:26:42 +00:00
xor a
ld [wMusicHeaderPointer], a
ld [wc0ee], a
ld [wcfca], a
2014-05-25 17:26:42 +00:00
dec a
jp PlaySound
VBlank::
push af
push bc
push de
push hl
ld a, [H_LOADEDROMBANK]
ld [wd122], a
2014-05-25 17:26:42 +00:00
ld a, [$ffae]
ld [rSCX], a
ld a, [$ffaf]
ld [rSCY], a
ld a, [wd0a0]
2014-05-25 17:26:42 +00:00
and a
jr nz, .ok
ld a, [$ffb0]
ld [rWY], a
.ok
call AutoBgMapTransfer
call VBlankCopyBgMap
call RedrawExposedScreenEdge
call VBlankCopy
call VBlankCopyDouble
call UpdateMovingBgTiles
call $ff80 ; hOAMDMA
ld a, Bank(PrepareOAMData)
ld [H_LOADEDROMBANK], a
ld [MBC3RomBank], a
call PrepareOAMData
; VBlank-sensitive operations end.
call Random
ld a, [H_VBLANKOCCURRED]
and a
jr z, .vblanked
xor a
ld [H_VBLANKOCCURRED], a
.vblanked
ld a, [H_FRAMECOUNTER]
and a
jr z, .decced
dec a
ld [H_FRAMECOUNTER], a
.decced
call Func_28cb
ld a, [wc0ef] ; music ROM bank
2014-05-25 17:26:42 +00:00
ld [H_LOADEDROMBANK], a
ld [MBC3RomBank], a
cp BANK(Func_9103)
jr nz, .notbank2
.bank2
call Func_9103
jr .afterMusic
.notbank2
cp 8
jr nz, .bank1F
.bank8
call Func_2136e
call Func_21879
jr .afterMusic
.bank1F
call Func_7d177
.afterMusic
callba Func_18dee ; keep track of time played
ld a, [$fff9]
and a
call z, ReadJoypad
ld a, [wd122]
2014-05-25 17:26:42 +00:00
ld [H_LOADEDROMBANK], a
ld [MBC3RomBank], a
pop hl
pop de
pop bc
pop af
reti
DelayFrame::
; Wait for the next vblank interrupt.
; As a bonus, this saves battery.
NOT_VBLANKED EQU 1
ld a, NOT_VBLANKED
ld [H_VBLANKOCCURRED], a
.halt
halt
2014-05-25 17:26:42 +00:00
ld a, [H_VBLANKOCCURRED]
and a
jr nz, .halt
ret
; These routines manage gradual fading
; (e.g., entering a doorway)
LoadGBPal::
ld a, [wd35d] ;tells if cur.map is dark (requires HM5_FLASH?)
ld b, a
ld hl, FadePal4
ld a, l
2014-05-25 17:26:42 +00:00
sub b
ld l, a
jr nc, .ok
2014-05-25 17:26:42 +00:00
dec h
.ok
ld a, [hli]
ld [rBGP], a
ld a, [hli]
ld [rOBP0], a
ld a, [hli]
ld [rOBP1], a
2014-05-25 17:26:42 +00:00
ret
GBFadeOut1::
ld hl, FadePal1
ld b, 4
2014-05-25 17:26:42 +00:00
jr GBFadeOutCommon
GBFadeOut2::
ld hl, FadePal6
ld b, 3
2014-05-25 17:26:42 +00:00
GBFadeOutCommon::
ld a, [hli]
ld [rBGP], a
ld a, [hli]
ld [rOBP0], a
ld a, [hli]
ld [rOBP1], a
ld c, 8
2014-05-25 17:26:42 +00:00
call DelayFrames
dec b
jr nz, GBFadeOutCommon
2014-05-25 17:26:42 +00:00
ret
GBFadeIn1::
ld hl, FadePal4 + 2
ld b, 4
2014-05-25 17:26:42 +00:00
jr GBFadeInCommon
GBFadeIn2::
ld hl, FadePal7 + 2
ld b, 3
GBFadeInCommon::
ld a, [hld]
ld [rOBP1], a
ld a, [hld]
ld [rOBP0], a
ld a, [hld]
ld [rBGP], a
ld c, 8
2014-05-25 17:26:42 +00:00
call DelayFrames
dec b
jr nz, GBFadeInCommon
2014-05-25 17:26:42 +00:00
ret
FadePal1:: db %11111111, %11111111, %11111111
FadePal2:: db %11111110, %11111110, %11111000
FadePal3:: db %11111001, %11100100, %11100100
FadePal4:: db %11100100, %11010000, %11100000
; rBGP rOBP0 rOBP1
FadePal5:: db %11100100, %11010000, %11100000
FadePal6:: db %10010000, %10000000, %10010000
FadePal7:: db %01000000, %01000000, %01000000
FadePal8:: db %00000000, %00000000, %00000000
2014-05-25 17:26:42 +00:00
Serial:: ; 2125 (0:2125)
push af
push bc
push de
push hl
ld a, [$ffaa]
inc a
jr z, .asm_2142
ld a, [$ff01]
ld [$ffad], a
ld a, [$ffac]
ld [$ff01], a
ld a, [$ffaa]
cp $2
jr z, .asm_2162
ld a, $80
ld [$ff02], a
jr .asm_2162
.asm_2142
ld a, [$ff01]
ld [$ffad], a
ld [$ffaa], a
cp $2
jr z, .asm_215f
xor a
ld [$ff01], a
ld a, $3
ld [rDIV], a ; $ff04
.asm_2153
ld a, [rDIV] ; $ff04
bit 7, a
jr nz, .asm_2153
ld a, $80
ld [$ff02], a
jr .asm_2162
.asm_215f
xor a
ld [$ff01], a
.asm_2162
ld a, $1
ld [$ffa9], a
ld a, $fe
ld [$ffac], a
pop hl
pop de
pop bc
pop af
reti
Func_216f:: ; 216f (0:216f)
ld a, $1
ld [$ffab], a
.asm_2173
ld a, [hl]
ld [$ffac], a
call Func_219a
push bc
ld b, a
inc hl
ld a, $30
.asm_217e
dec a
jr nz, .asm_217e
ld a, [$ffab]
and a
ld a, b
pop bc
jr z, .asm_2192
dec hl
cp $fd
jr nz, .asm_2173
xor a
ld [$ffab], a
jr .asm_2173
.asm_2192
ld [de], a
inc de
dec bc
ld a, b
or c
jr nz, .asm_2173
ret
Func_219a:: ; 219a (0:219a)
xor a
ld [$ffa9], a
ld a, [$ffaa]
cp $2
jr nz, .asm_21a7
ld a, $81
ld [$ff02], a
.asm_21a7
ld a, [$ffa9]
and a
jr nz, .asm_21f1
ld a, [$ffaa]
cp $1
jr nz, .asm_21cc
call Func_2237
jr z, .asm_21cc
call Func_2231
push hl
ld hl, wcc48
2014-05-25 17:26:42 +00:00
inc [hl]
jr nz, .asm_21c3
dec hl
inc [hl]
.asm_21c3
pop hl
call Func_2237
jr nz, .asm_21a7
jp Func_223f
.asm_21cc
ld a, [rIE] ; $ffff
and $f
cp $8
jr nz, .asm_21a7
ld a, [W_NUMHITS] ; wd074
2014-05-25 17:26:42 +00:00
dec a
ld [W_NUMHITS], a ; wd074
2014-05-25 17:26:42 +00:00
jr nz, .asm_21a7
ld a, [wd075]
2014-05-25 17:26:42 +00:00
dec a
ld [wd075], a
2014-05-25 17:26:42 +00:00
jr nz, .asm_21a7
ld a, [$ffaa]
cp $1
jr z, .asm_21f1
ld a, $ff
.asm_21ee
dec a
jr nz, .asm_21ee
.asm_21f1
xor a
ld [$ffa9], a
ld a, [rIE] ; $ffff
and $f
sub $8
jr nz, .asm_2204
ld [W_NUMHITS], a ; wd074
2014-05-25 17:26:42 +00:00
ld a, $50
ld [wd075], a
2014-05-25 17:26:42 +00:00
.asm_2204
ld a, [$ffad]
cp $fe
ret nz
call Func_2237
jr z, .asm_221f
push hl
ld hl, wcc48
2014-05-25 17:26:42 +00:00
ld a, [hl]
dec a
ld [hld], a
inc a
jr nz, .asm_2219
dec [hl]
.asm_2219
pop hl
call Func_2237
jr z, Func_223f
.asm_221f
ld a, [rIE] ; $ffff
and $f
cp $8
ld a, $fe
ret z
ld a, [hl]
ld [$ffac], a
call DelayFrame
jp Func_219a
Func_2231:: ; 2231 (0:2231)
ld a, $f
.asm_2233
dec a
jr nz, .asm_2233
ret
Func_2237:: ; 2237 (0:2237)
push hl
ld hl, wcc47
2014-05-25 17:26:42 +00:00
ld a, [hli]
or [hl]
pop hl
ret
Func_223f:: ; 223f (0:223f)
dec a
ld [wcc47], a
ld [wcc48], a
2014-05-25 17:26:42 +00:00
ret
Func_2247:: ; 2247 (0:2247)
ld hl, wcc42
ld de, wcc3d
2014-05-25 17:26:42 +00:00
ld c, $2
ld a, $1
ld [$ffab], a
.asm_2253
call DelayFrame
ld a, [hl]
ld [$ffac], a
call Func_219a
ld b, a
inc hl
ld a, [$ffab]
and a
ld a, $0
ld [$ffab], a
jr nz, .asm_2253
ld a, b
ld [de], a
inc de
dec c
jr nz, .asm_2253
ret
Func_226e:: ; 226e (0:226e)
call SaveScreenTilesToBuffer1
callab PrintWaitingText
call Func_227f
jp LoadScreenTilesFromBuffer1
Func_227f:: ; 227f (0:227f)
ld a, $ff
ld [wcc3e], a
2014-05-25 17:26:42 +00:00
.asm_2284
call Func_22c3
call DelayFrame
call Func_2237
jr z, .asm_22a0
push hl
ld hl, wcc48
2014-05-25 17:26:42 +00:00
dec [hl]
jr nz, .asm_229f
dec hl
dec [hl]
jr nz, .asm_229f
pop hl
xor a
jp Func_223f
.asm_229f
pop hl
.asm_22a0
ld a, [wcc3e]
2014-05-25 17:26:42 +00:00
inc a
jr z, .asm_2284
ld b, $a
.asm_22a8
call DelayFrame
call Func_22c3
dec b
jr nz, .asm_22a8
ld b, $a
.asm_22b3
call DelayFrame
call Func_22ed
dec b
jr nz, .asm_22b3
ld a, [wcc3e]
ld [wcc3d], a
2014-05-25 17:26:42 +00:00
ret
Func_22c3:: ; 22c3 (0:22c3)
call asm_22d7
ld a, [wcc42]
2014-05-25 17:26:42 +00:00
add $60
ld [$ffac], a
ld a, [$ffaa]
cp $2
jr nz, asm_22d7
ld a, $81
ld [$ff02], a
asm_22d7:: ; 22d7 (0:22d7)
ld a, [$ffad]
ld [wcc3d], a
2014-05-25 17:26:42 +00:00
and $f0
cp $60
ret nz
xor a
ld [$ffad], a
ld a, [wcc3d]
2014-05-25 17:26:42 +00:00
and $f
ld [wcc3e], a
2014-05-25 17:26:42 +00:00
ret
Func_22ed:: ; 22ed (0:22ed)
xor a
ld [$ffac], a
ld a, [$ffaa]
cp $2
ret nz
ld a, $81
ld [$ff02], a
ret
Func_22fa:: ; 22fa (0:22fa)
ld a, $2
ld [$ff01], a
xor a
ld [$ffad], a
ld a, $80
ld [$ff02], a
ret
; timer interrupt is apparently not invoked anyway
Timer:: ; 2306 (0:2306)
reti
Func_2307:: ; 2307 (0:2307)
call WaitForSoundToFinish
xor a
ld c, a
ld d, a
ld [wcfca], a
2014-05-25 17:26:42 +00:00
jr asm_2324
Func_2312:: ; 2312 (0:2312)
ld c, $a
ld d, $0
ld a, [wd72e]
2014-05-25 17:26:42 +00:00
bit 5, a
jr z, asm_2324
xor a
ld [wcfca], a
2014-05-25 17:26:42 +00:00
ld c, $8
ld d, c
asm_2324:: ; 2324 (0:2324)
ld a, [wd700]
2014-05-25 17:26:42 +00:00
and a
jr z, .asm_2343
cp $2
jr z, .asm_2332
ld a, MUSIC_BIKE_RIDING
jr .asm_2334
.asm_2332
ld a, MUSIC_SURFING
.asm_2334
ld b, a
ld a, d
and a
ld a, Bank(Func_7d8ea)
jr nz, .asm_233e
ld [wc0ef], a
2014-05-25 17:26:42 +00:00
.asm_233e
ld [wc0f0], a
2014-05-25 17:26:42 +00:00
jr .asm_234c
.asm_2343
ld a, [wd35b]
2014-05-25 17:26:42 +00:00
ld b, a
call Func_2385
jr c, .asm_2351
.asm_234c
ld a, [wcfca]
2014-05-25 17:26:42 +00:00
cp b
ret z
.asm_2351
ld a, c
ld [wMusicHeaderPointer], a
ld a, b
ld [wcfca], a
ld [wc0ee], a
2014-05-25 17:26:42 +00:00
jp PlaySound
Func_235f:: ; 235f (0:235f)
ld a, [wc0ef]
2014-05-25 17:26:42 +00:00
ld b, a
cp $2
jr nz, .checkForBank08
.bank02
ld hl, Func_9103
jr .asm_2378
.checkForBank08
cp $8
jr nz, .bank1F
.bank08
ld hl, Func_21879
jr .asm_2378
.bank1F
ld hl, Func_7d177
.asm_2378
ld c, $6
.asm_237a
push bc
push hl
call Bankswitch
pop hl
pop bc
dec c
jr nz, .asm_237a
ret
Func_2385:: ; 2385 (0:2385)
ld a, [wd35c]
2014-05-25 17:26:42 +00:00
ld e, a
ld a, [wc0ef]
2014-05-25 17:26:42 +00:00
cp e
jr nz, .asm_2394
ld [wc0f0], a
2014-05-25 17:26:42 +00:00
and a
ret
.asm_2394
ld a, c
and a
ld a, e
jr nz, .asm_239c
ld [wc0ef], a
2014-05-25 17:26:42 +00:00
.asm_239c
ld [wc0f0], a
2014-05-25 17:26:42 +00:00
scf
ret
PlayMusic:: ; 23a1 (0:23a1)
ld b, a
ld [wc0ee], a
2014-05-25 17:26:42 +00:00
xor a
ld [wMusicHeaderPointer], a
ld a, c
ld [wc0ef], a
ld [wc0f0], a
2014-05-25 17:26:42 +00:00
ld a, b
; plays music specified by a. If value is $ff, music is stopped
PlaySound:: ; 23b1 (0:23b1)
push hl
push de
push bc
ld b, a
ld a, [wc0ee]
2014-05-25 17:26:42 +00:00
and a
jr z, .asm_23c8
xor a
ld [wc02a], a
ld [wc02b], a
ld [wc02c], a
ld [wc02d], a
2014-05-25 17:26:42 +00:00
.asm_23c8
ld a, [wMusicHeaderPointer]
and a
jr z, .asm_23e3
ld a, [wc0ee]
2014-05-25 17:26:42 +00:00
and a
jr z, .asm_2425
xor a
ld [wc0ee], a
ld a, [wcfca]
2014-05-25 17:26:42 +00:00
cp $ff
jr nz, .asm_2414
xor a
ld [wMusicHeaderPointer], a
.asm_23e3
xor a
ld [wc0ee], a
2014-05-25 17:26:42 +00:00
ld a, [H_LOADEDROMBANK]
ld [$ffb9], a
ld a, [wc0ef]
2014-05-25 17:26:42 +00:00
ld [H_LOADEDROMBANK], a
ld [$2000], a
cp $2
jr nz, .checkForBank08
.bank02
ld a, b
call Func_9876
jr .asm_240b
.checkForBank08
cp $8
jr nz, .bank1F
.bank08
ld a, b
call Func_22035
jr .asm_240b
.bank1F
ld a, b
call Func_7d8ea
.asm_240b
ld a, [$ffb9]
ld [H_LOADEDROMBANK], a
ld [$2000], a
jr .asm_2425
.asm_2414
ld a, b
ld [wcfca], a
2014-05-25 17:26:42 +00:00
ld a, [wMusicHeaderPointer]
ld [wcfc8], a
ld [wcfc9], a
2014-05-25 17:26:42 +00:00
ld a, b
ld [wMusicHeaderPointer], a
.asm_2425
pop bc
pop de
pop hl
ret
UpdateSprites:: ; 2429 (0:2429)
ld a, [wcfcb]
2014-05-25 17:26:42 +00:00
dec a
ret nz
ld a, [H_LOADEDROMBANK]
push af
ld a, Bank(_UpdateSprites)
ld [H_LOADEDROMBANK], a
ld [$2000], a
call _UpdateSprites
pop af
ld [H_LOADEDROMBANK], a
ld [$2000], a
ret
INCLUDE "data/mart_inventories.asm"
TextScriptEndingChar:: ; 24d6 (0:24d6)
db "@"
TextScriptEnd:: ; 24d7 (0:24d7)
ld hl,TextScriptEndingChar
ret
ExclamationText:: ; 24db (0:24db)
TX_FAR _ExclamationText
db "@"
GroundRoseText:: ; 24e0 (0:24e0)
TX_FAR _GroundRoseText
db "@"
BoulderText:: ; 24e5 (0:24e5)
TX_FAR _BoulderText
db "@"
MartSignText:: ; 24ea (0:24ea)
TX_FAR _MartSignText
db "@"
PokeCenterSignText:: ; 24ef (0:24ef)
TX_FAR _PokeCenterSignText
db "@"
Predef5CText:: ; 24f4 (0:24f4)
; XXX better label (what does predef $5C do?)
db $08 ; asm
ld a, $5c
call Predef
jp TextScriptEnd
; bankswitches and runs _UncompressSpriteData
; bank is given in a, sprite input stream is pointed to in W_SPRITEINPUTPTR
UncompressSpriteData:: ; 24fd (0:24fd)
ld b, a
ld a, [H_LOADEDROMBANK]
push af
ld a, b
ld [H_LOADEDROMBANK], a
ld [$2000], a
ld a, $a
ld [$0], a
xor a
ld [$4000], a
call _UncompressSpriteData
pop af
ld [H_LOADEDROMBANK], a
ld [$2000], a
ret
; initializes necessary data to load a sprite and runs UncompressSpriteDataLoop
_UncompressSpriteData:: ; 251a (0:251a)
ld hl, S_SPRITEBUFFER1
ld c, (2*SPRITEBUFFERSIZE) % $100
ld b, (2*SPRITEBUFFERSIZE) / $100
xor a
call FillMemory ; clear sprite buffer 1 and 2
ld a, $1
ld [W_SPRITEINPUTBITCOUNTER], a
ld a, $3
ld [W_SPRITEOUTPUTBITOFFSET], a
xor a
ld [W_SPRITECURPOSX], a
ld [W_SPRITECURPOSY], a
ld [W_SPRITELOADFLAGS], a ; wd0a8
2014-05-25 17:26:42 +00:00
call ReadNextInputByte ; first byte of input determines sprite width (high nybble) and height (low nybble) in tiles (8x8 pixels)
ld b, a
and $f
add a
add a
add a
ld [W_SPRITEHEIGHT], a
ld a, b
swap a
and $f
add a
add a
add a
ld [W_SPRITEWITDH], a
call ReadNextInputBit
ld [W_SPRITELOADFLAGS], a ; initialite bit1 to 0 and bit0 to the first input bit
; this will load two chunks of data to S_SPRITEBUFFER1 and S_SPRITEBUFFER2
; bit 0 decides in which one the first chunk is placed
; fall through
; uncompresses a chunk from the sprite input data stream (pointed to at wd0da) into S_SPRITEBUFFER1 or S_SPRITEBUFFER2
2014-05-25 17:26:42 +00:00
; each chunk is a 1bpp sprite. A 2bpp sprite consist of two chunks which are merged afterwards
; note that this is an endless loop which is terminated during a call to MoveToNextBufferPosition by manipulating the stack
UncompressSpriteDataLoop:: ; 2556 (0:2556)
ld hl, S_SPRITEBUFFER1
ld a, [W_SPRITELOADFLAGS] ; wd0a8
2014-05-25 17:26:42 +00:00
bit 0, a
jr z, .useSpriteBuffer1 ; check which buffer to use
ld hl, S_SPRITEBUFFER2
.useSpriteBuffer1
call StoreSpriteOutputPointer
ld a, [W_SPRITELOADFLAGS] ; wd0a8
2014-05-25 17:26:42 +00:00
bit 1, a
jr z, .startDecompression ; check if last iteration
call ReadNextInputBit ; if last chunk, read 1-2 bit unpacking mode
and a
jr z, .unpackingMode0 ; 0 -> mode 0
call ReadNextInputBit ; 1 0 -> mode 1
inc a ; 1 1 -> mode 2
.unpackingMode0
ld [W_SPRITEUNPACKMODE], a
.startDecompression
call ReadNextInputBit
and a
jr z, .readRLEncodedZeros ; if first bit is 0, the input starts with zeroes, otherwise with (non-zero) input
.readNextInput
call ReadNextInputBit
ld c, a
call ReadNextInputBit
sla c
or c ; read next two bits into c
and a
jr z, .readRLEncodedZeros ; 00 -> RLEncoded zeroes following
call WriteSpriteBitsToBuffer ; otherwise write input to output and repeat
call MoveToNextBufferPosition
jr .readNextInput
.readRLEncodedZeros
ld c, $0 ; number of zeroes it length encoded, the number
.countConsecutiveOnesLoop ; of consecutive ones determines the number of bits the number has
call ReadNextInputBit
and a
jr z, .countConsecutiveOnesFinished
inc c
jr .countConsecutiveOnesLoop
.countConsecutiveOnesFinished
ld a, c
add a
ld hl, LengthEncodingOffsetList
add l
ld l, a
jr nc, .noCarry
inc h
.noCarry
ld a, [hli] ; read offset that is added to the number later on
ld e, a ; adding an offset of 2^length - 1 makes every integer uniquely
ld d, [hl] ; representable in the length encoding and saves bits
push de
inc c
ld e, $0
ld d, e
.readNumberOfZerosLoop ; reads the next c+1 bits of input
call ReadNextInputBit
or e
ld e, a
dec c
jr z, .readNumberOfZerosDone
sla e
rl d
jr .readNumberOfZerosLoop
.readNumberOfZerosDone
pop hl ; add the offset
add hl, de
ld e, l
ld d, h
.writeZerosLoop
ld b, e
xor a ; write 00 to buffer
call WriteSpriteBitsToBuffer
ld e, b
call MoveToNextBufferPosition
dec de
ld a, d
and a
jr nz, .continueLoop
ld a, e
and a
.continueLoop
jr nz, .writeZerosLoop
jr .readNextInput
; moves output pointer to next position
; also cancels the calling function if the all output is done (by removing the return pointer from stack)
; and calls postprocessing functions according to the unpack mode
MoveToNextBufferPosition:: ; 25d8 (0:25d8)
ld a, [W_SPRITEHEIGHT]
ld b, a
ld a, [W_SPRITECURPOSY]
inc a
cp b
jr z, .curColumnDone
ld [W_SPRITECURPOSY], a
ld a, [W_SPRITEOUTPUTPTR]
inc a
ld [W_SPRITEOUTPUTPTR], a
ret nz
ld a, [W_SPRITEOUTPUTPTR+1]
inc a
ld [W_SPRITEOUTPUTPTR+1], a
ret
.curColumnDone
xor a
ld [W_SPRITECURPOSY], a
ld a, [W_SPRITEOUTPUTBITOFFSET]
and a
jr z, .bitOffsetsDone
dec a
ld [W_SPRITEOUTPUTBITOFFSET], a
ld hl, W_SPRITEOUTPUTPTRCACHED
ld a, [hli]
ld [W_SPRITEOUTPUTPTR], a
ld a, [hl]
ld [W_SPRITEOUTPUTPTR+1], a
ret
.bitOffsetsDone
ld a, $3
ld [W_SPRITEOUTPUTBITOFFSET], a
ld a, [W_SPRITECURPOSX]
add $8
ld [W_SPRITECURPOSX], a
ld b, a
ld a, [W_SPRITEWITDH]
cp b
jr z, .allColumnsDone
ld a, [W_SPRITEOUTPUTPTR]
ld l, a
ld a, [W_SPRITEOUTPUTPTR+1]
ld h, a
inc hl
jp StoreSpriteOutputPointer
.allColumnsDone
pop hl
xor a
ld [W_SPRITECURPOSX], a
ld a, [W_SPRITELOADFLAGS] ; wd0a8
2014-05-25 17:26:42 +00:00
bit 1, a
jr nz, .done ; test if there is one more sprite to go
xor $1
set 1, a
ld [W_SPRITELOADFLAGS], a ; wd0a8
2014-05-25 17:26:42 +00:00
jp UncompressSpriteDataLoop
.done
jp UnpackSprite
; writes 2 bits (from a) to the output buffer (pointed to from W_SPRITEOUTPUTPTR)
WriteSpriteBitsToBuffer:: ; 2649 (0:2649)
ld e, a
ld a, [W_SPRITEOUTPUTBITOFFSET]
and a
jr z, .offset0
cp $2
jr c, .offset1
jr z, .offset2
rrc e ; offset 3
rrc e
jr .offset0
.offset1
sla e
sla e
jr .offset0
.offset2
swap e
.offset0
ld a, [W_SPRITEOUTPUTPTR]
ld l, a
ld a, [W_SPRITEOUTPUTPTR+1]
ld h, a
ld a, [hl]
or e
ld [hl], a
ret
; reads next bit from input stream and returns it in a
ReadNextInputBit:: ; 2670 (0:2670)
ld a, [W_SPRITEINPUTBITCOUNTER]
dec a
jr nz, .curByteHasMoreBitsToRead
call ReadNextInputByte
ld [W_SPRITEINPUTCURBYTE], a
ld a, $8
.curByteHasMoreBitsToRead
ld [W_SPRITEINPUTBITCOUNTER], a
ld a, [W_SPRITEINPUTCURBYTE]
rlca
ld [W_SPRITEINPUTCURBYTE], a
and $1
ret
; reads next byte from input stream and returns it in a
ReadNextInputByte:: ; 268b (0:268b)
ld a, [W_SPRITEINPUTPTR]
ld l, a
ld a, [W_SPRITEINPUTPTR+1]
ld h, a
ld a, [hli]
ld b, a
ld a, l
ld [W_SPRITEINPUTPTR], a
ld a, h
ld [W_SPRITEINPUTPTR+1], a
ld a, b
ret
; the nth item is 2^n - 1
LengthEncodingOffsetList:: ; 269f (0:269f)
dw %0000000000000001
dw %0000000000000011
dw %0000000000000111
dw %0000000000001111
dw %0000000000011111
dw %0000000000111111
dw %0000000001111111
dw %0000000011111111
dw %0000000111111111
dw %0000001111111111
dw %0000011111111111
dw %0000111111111111
dw %0001111111111111
dw %0011111111111111
dw %0111111111111111
dw %1111111111111111
; unpacks the sprite data depending on the unpack mode
UnpackSprite:: ; 26bf (0:26bf)
ld a, [W_SPRITEUNPACKMODE]
cp $2
jp z, UnpackSpriteMode2
and a
jp nz, XorSpriteChunks
ld hl, S_SPRITEBUFFER1
call SpriteDifferentialDecode
ld hl, S_SPRITEBUFFER2
; fall through
; decodes differential encoded sprite data
; input bit value 0 preserves the current bit value and input bit value 1 toggles it (starting from initial value 0).
SpriteDifferentialDecode:: ; 26d4 (0:26d4)
xor a
ld [W_SPRITECURPOSX], a
ld [W_SPRITECURPOSY], a
call StoreSpriteOutputPointer
ld a, [W_SPRITEFLIPPED]
and a
jr z, .notFlipped
ld hl, DecodeNybble0TableFlipped
ld de, DecodeNybble1TableFlipped
jr .storeDecodeTablesPointers
.notFlipped
ld hl, DecodeNybble0Table
ld de, DecodeNybble1Table
.storeDecodeTablesPointers
ld a, l
ld [W_SPRITEDECODETABLE0PTR], a
ld a, h
ld [W_SPRITEDECODETABLE0PTR+1], a
ld a, e
ld [W_SPRITEDECODETABLE1PTR], a
ld a, d
ld [W_SPRITEDECODETABLE1PTR+1], a
ld e, $0 ; last decoded nybble, initialized to 0
.decodeNextByteLoop
ld a, [W_SPRITEOUTPUTPTR]
ld l, a
ld a, [W_SPRITEOUTPUTPTR+1]
ld h, a
ld a, [hl]
ld b, a
swap a
and $f
call DifferentialDecodeNybble ; decode high nybble
swap a
ld d, a
ld a, b
and $f
call DifferentialDecodeNybble ; decode low nybble
or d
ld b, a
ld a, [W_SPRITEOUTPUTPTR]
ld l, a
ld a, [W_SPRITEOUTPUTPTR+1]
ld h, a
ld a, b
ld [hl], a ; write back decoded data
ld a, [W_SPRITEHEIGHT]
add l ; move on to next column
jr nc, .noCarry
inc h
.noCarry
ld [W_SPRITEOUTPUTPTR], a
ld a, h
ld [W_SPRITEOUTPUTPTR+1], a
ld a, [W_SPRITECURPOSX]
add $8
ld [W_SPRITECURPOSX], a
ld b, a
ld a, [W_SPRITEWITDH]
cp b
jr nz, .decodeNextByteLoop ; test if current row is done
xor a
ld e, a
ld [W_SPRITECURPOSX], a
ld a, [W_SPRITECURPOSY] ; move on to next row
inc a
ld [W_SPRITECURPOSY], a
ld b, a
ld a, [W_SPRITEHEIGHT]
cp b
jr z, .done ; test if all rows finished
ld a, [W_SPRITEOUTPUTPTRCACHED]
ld l, a
ld a, [W_SPRITEOUTPUTPTRCACHED+1]
ld h, a
inc hl
call StoreSpriteOutputPointer
jr .decodeNextByteLoop
.done
xor a
ld [W_SPRITECURPOSY], a
ret
; decodes the nybble stored in a. Last decoded data is assumed to be in e (needed to determine if initial value is 0 or 1)
DifferentialDecodeNybble:: ; 276d (0:276d)
srl a ; c=a%2, a/=2
ld c, $0
jr nc, .evenNumber
ld c, $1
.evenNumber
ld l, a
ld a, [W_SPRITEFLIPPED]
and a
jr z, .notFlipped ; determine if initial value is 0 or one
bit 3, e ; if flipped, consider MSB of last data
jr .selectLookupTable
.notFlipped
bit 0, e ; else consider LSB
.selectLookupTable
ld e, l
jr nz, .initialValue1 ; load the appropriate table
ld a, [W_SPRITEDECODETABLE0PTR]
ld l, a
ld a, [W_SPRITEDECODETABLE0PTR+1]
jr .tableLookup
.initialValue1
ld a, [W_SPRITEDECODETABLE1PTR]
ld l, a
ld a, [W_SPRITEDECODETABLE1PTR+1]
.tableLookup
ld h, a
ld a, e
add l
ld l, a
jr nc, .noCarry
inc h
.noCarry
ld a, [hl]
bit 0, c
jr nz, .selectLowNybble
swap a ; select high nybble
.selectLowNybble
and $f
ld e, a ; update last decoded data
ret
DecodeNybble0Table:: ; 27a7 (0:27a7)
dn $0, $1
dn $3, $2
dn $7, $6
dn $4, $5
dn $f, $e
dn $c, $d
dn $8, $9
dn $b, $a
DecodeNybble1Table:: ; 27af (0:27af)
dn $f, $e
dn $c, $d
dn $8, $9
dn $b, $a
dn $0, $1
dn $3, $2
dn $7, $6
dn $4, $5
DecodeNybble0TableFlipped:: ; 27b7 (0:27b7)
dn $0, $8
dn $c, $4
dn $e, $6
dn $2, $a
dn $f, $7
dn $3, $b
dn $1, $9
dn $d, $5
DecodeNybble1TableFlipped:: ; 27bf (0:27bf)
dn $f, $7
dn $3, $b
dn $1, $9
dn $d, $5
dn $0, $8
dn $c, $4
dn $e, $6
dn $2, $a
; combines the two loaded chunks with xor (the chunk loaded second is the destination). The source chunk is differeintial decoded beforehand.
XorSpriteChunks:: ; 27c7 (0:27c7)
xor a
ld [W_SPRITECURPOSX], a
ld [W_SPRITECURPOSY], a
call ResetSpriteBufferPointers
ld a, [W_SPRITEOUTPUTPTR] ; points to buffer 1 or 2, depending on flags
ld l, a
ld a, [W_SPRITEOUTPUTPTR+1]
ld h, a
call SpriteDifferentialDecode ; decode buffer 1 or 2, depending on flags
call ResetSpriteBufferPointers
ld a, [W_SPRITEOUTPUTPTR] ; source buffer, points to buffer 1 or 2, depending on flags
ld l, a
ld a, [W_SPRITEOUTPUTPTR+1]
ld h, a
ld a, [W_SPRITEOUTPUTPTRCACHED] ; destination buffer, points to buffer 2 or 1, depending on flags
ld e, a
ld a, [W_SPRITEOUTPUTPTRCACHED+1]
ld d, a
.xorChunksLoop
ld a, [W_SPRITEFLIPPED]
and a
jr z, .notFlipped
push de
ld a, [de]
ld b, a
swap a
and $f
call ReverseNybble ; if flipped reverse the nybbles in the destination buffer
swap a
ld c, a
ld a, b
and $f
call ReverseNybble
or c
pop de
ld [de], a
.notFlipped
ld a, [hli]
ld b, a
ld a, [de]
xor b
ld [de], a
inc de
ld a, [W_SPRITECURPOSY]
inc a
ld [W_SPRITECURPOSY], a ; go to next row
ld b, a
ld a, [W_SPRITEHEIGHT]
cp b
jr nz, .xorChunksLoop ; test if column finished
xor a
ld [W_SPRITECURPOSY], a
ld a, [W_SPRITECURPOSX]
add $8
ld [W_SPRITECURPOSX], a ; go to next column
ld b, a
ld a, [W_SPRITEWITDH]
cp b
jr nz, .xorChunksLoop ; test if all columns finished
xor a
ld [W_SPRITECURPOSX], a
ret
; reverses the bits in the nybble given in register a
ReverseNybble:: ; 2837 (0:2837)
ld de, NybbleReverseTable
add e
ld e, a
jr nc, .asm_283f
inc d
.asm_283f
ld a, [de]
ret
; resets sprite buffer pointers to buffer 1 and 2, depending on W_SPRITELOADFLAGS
ResetSpriteBufferPointers:: ; 2841 (0:2841)
ld a, [W_SPRITELOADFLAGS] ; wd0a8
2014-05-25 17:26:42 +00:00
bit 0, a
jr nz, .buffer2Selected
ld de, S_SPRITEBUFFER1
ld hl, S_SPRITEBUFFER2
jr .storeBufferPointers
.buffer2Selected
ld de, S_SPRITEBUFFER2
ld hl, S_SPRITEBUFFER1
.storeBufferPointers
ld a, l
ld [W_SPRITEOUTPUTPTR], a
ld a, h
ld [W_SPRITEOUTPUTPTR+1], a
ld a, e
ld [W_SPRITEOUTPUTPTRCACHED], a
ld a, d
ld [W_SPRITEOUTPUTPTRCACHED+1], a
ret
; maps each nybble to its reverse
NybbleReverseTable:: ; 2867 (0:2867)
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:: ; 2877 (0:2877)
call ResetSpriteBufferPointers
ld a, [W_SPRITEFLIPPED]
push af
xor a
ld [W_SPRITEFLIPPED], a ; temporarily clear flipped flag for decoding the destination chunk
ld a, [W_SPRITEOUTPUTPTRCACHED]
ld l, a
ld a, [W_SPRITEOUTPUTPTRCACHED+1]
ld h, a
call SpriteDifferentialDecode
call ResetSpriteBufferPointers
pop af
ld [W_SPRITEFLIPPED], a
jp XorSpriteChunks
; stores hl into the output pointers
StoreSpriteOutputPointer:: ; 2897 (0:2897)
ld a, l
ld [W_SPRITEOUTPUTPTR], a
ld [W_SPRITEOUTPUTPTRCACHED], a
ld a, h
ld [W_SPRITEOUTPUTPTR+1], a
ld [W_SPRITEOUTPUTPTRCACHED+1], a
ret
ResetPlayerSpriteData:: ; 28a6 (0:28a6)
ld hl, wSpriteStateData1
call ResetPlayerSpriteData_ClearSpriteData
ld hl, wSpriteStateData2
call ResetPlayerSpriteData_ClearSpriteData
ld a, $1
ld [wSpriteStateData1], a
ld [wSpriteStateData2 + $0e], a
ld hl, wSpriteStateData1 + 4
2014-05-25 17:26:42 +00:00
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:: ; 28c4 (0:28c4)
ld bc, $10
xor a
jp FillMemory
Func_28cb:: ; 28cb (0:28cb)
ld a, [wMusicHeaderPointer]
and a
jr nz, .asm_28dc
ld a, [wd72c]
2014-05-25 17:26:42 +00:00
bit 1, a
ret nz
ld a, $77
ld [$ff24], a
ret
.asm_28dc
ld a, [wcfc9]
2014-05-25 17:26:42 +00:00
and a
jr z, .asm_28e7
dec a
ld [wcfc9], a
2014-05-25 17:26:42 +00:00
ret
.asm_28e7
ld a, [wcfc8]
ld [wcfc9], a
2014-05-25 17:26:42 +00:00
ld a, [$ff24]
and a
jr z, .asm_2903
ld b, a
and $f
dec a
ld c, a
ld a, b
and $f0
swap a
dec a
swap a
or c
ld [$ff24], a
ret
.asm_2903
ld a, [wMusicHeaderPointer]
ld b, a
xor a
ld [wMusicHeaderPointer], a
ld a, $ff
ld [wc0ee], a
2014-05-25 17:26:42 +00:00
call PlaySound
ld a, [wc0f0]
ld [wc0ef], a
2014-05-25 17:26:42 +00:00
ld a, b
ld [wc0ee], a
2014-05-25 17:26:42 +00:00
jp PlaySound
; this function is used to display sign messages, sprite dialog, etc.
; INPUT: [$ff8c] = sprite ID or text ID
DisplayTextID:: ; 2920 (0:2920)
ld a,[H_LOADEDROMBANK]
push af
callba DisplayTextIDInit ; initialization
ld hl,wcf11
2014-05-25 17:26:42 +00:00
bit 0,[hl]
res 0,[hl]
jr nz,.skipSwitchToMapBank
ld a,[W_CURMAP]
call SwitchToMapRomBank
.skipSwitchToMapBank
ld a,30 ; half a second
ld [H_FRAMECOUNTER],a ; used as joypad poll timer
ld hl,W_MAPTEXTPTR
ld a,[hli]
ld h,[hl]
ld l,a ; hl = map text pointer
ld d,$00
ld a,[$ff8c] ; text ID
ld [wcf13],a
2014-05-25 17:26:42 +00:00
and a
jp z,DisplayStartMenu
cp a,$d3 ; safari game over
jp z,DisplaySafariGameOverText
cp a,$d0 ; fainted
jp z,DisplayPokemonFaintedText
cp a,$d1 ; blacked out
jp z,DisplayPlayerBlackedOutText
cp a,$d2 ; repel wore off
jp z,DisplayRepelWoreOffText
ld a,[W_NUMSPRITES] ; number of sprites
2014-05-25 17:26:42 +00:00
ld e,a
ld a,[$ff8c] ; sprite ID
cp e
jr z,.spriteHandling
jr nc,.skipSpriteHandling
.spriteHandling
; get the text ID of the sprite
push hl
push de
push bc
callba Func_13074 ; update the graphics of the sprite the player is talking to (to face the right direction)
pop bc
pop de
ld hl,W_MAPSPRITEDATA ; NPC text entries
ld a,[$ff8c]
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
cp a,$fe ; Pokemart NPC
jp z,DisplayPokemartDialogue
cp a,$ff ; Pokemon Center NPC
jp z,DisplayPokemonCenterDialogue
cp a,$fc ; Item Storage PC
jp z,FuncTX_ItemStoragePC
cp a,$fd ; Bill's PC
jp z,FuncTX_BillsPC
cp a,$f9 ; Pokemon Center PC
jp z,FuncTX_PokemonCenterPC
cp a,$f5 ; Vending Machine
jr nz,.notVendingMachine
callba VendingMachineMenu ; jump banks to vending machine routine
jr AfterDisplayingTextID
.notVendingMachine
cp a,$f7 ; slot machine
jp z,FuncTX_SlotMachine
cp a,$f6 ; cable connection NPC in Pokemon Center
jr nz,.notSpecialCase
callab CableClubNPC
jr AfterDisplayingTextID
.notSpecialCase
call Func_3c59 ; display the text
ld a,[wcc3c]
2014-05-25 17:26:42 +00:00
and a
jr nz,HoldTextDisplayOpen
AfterDisplayingTextID:: ; 29d6 (0:29d6)
ld a,[wcc47]
2014-05-25 17:26:42 +00:00
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:: ; 29df (0:29df)
2014-05-25 18:21:48 +00:00
call Joypad
2014-05-25 17:51:53 +00:00
ld a,[hJoyHeld]
2014-05-25 17:26:42 +00:00
bit 0,a ; is the A button being pressed?
jr nz,HoldTextDisplayOpen
CloseTextDisplay:: ; 29e8 (0:29e8)
ld a,[W_CURMAP]
call SwitchToMapRomBank
ld a,$90
ld [$ffb0],a ; move the window off the screen
call DelayFrame
call LoadGBPal
xor a
ld [H_AUTOBGTRANSFERENABLED],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,wSpriteStateData2 + $19
2014-05-25 17:26:42 +00:00
ld c,$0f
ld de,$0010
.restoreSpriteFacingDirectionLoop
ld a,[hl]
dec h
ld [hl],a
inc h
add hl,de
dec c
jr nz,.restoreSpriteFacingDirectionLoop
ld a,BANK(InitMapSprites)
ld [H_LOADEDROMBANK],a
ld [$2000],a
call InitMapSprites ; reload sprite tile pattern data (since it was partially overwritten by text tile patterns)
ld hl,wcfc4
2014-05-25 17:26:42 +00:00
res 0,[hl]
ld a,[wd732]
2014-05-25 17:26:42 +00:00
bit 3,a
call z,LoadPlayerSpriteGraphics
call LoadCurrentMapView
pop af
ld [H_LOADEDROMBANK],a
ld [$2000],a
jp UpdateSprites ; move sprites
DisplayPokemartDialogue:: ; 2a2e (0:2a2e)
push hl
ld hl,PokemartGreetingText
call PrintText
pop hl
inc hl
call LoadItemList
ld a,$02
ld [wListMenuID],a ; selects between subtypes of menus
2014-05-25 17:26:42 +00:00
ld a,[H_LOADEDROMBANK]
push af
ld a,Bank(DisplayPokemartDialogue_)
ld [H_LOADEDROMBANK],a
ld [$2000],a
call DisplayPokemartDialogue_
pop af
ld [H_LOADEDROMBANK],a
ld [$2000],a
jp AfterDisplayingTextID
PokemartGreetingText:: ; 2a55 (0:2a55)
TX_FAR _PokemartGreetingText
db "@"
LoadItemList:: ; 2a5a (0:2a5a)
ld a,$01
ld [wcfcb],a
2014-05-25 17:26:42 +00:00
ld a,h
ld [wd128],a
2014-05-25 17:26:42 +00:00
ld a,l
ld [wd129],a
ld de,wStringBuffer2 + 11
2014-05-25 17:26:42 +00:00
.loop
ld a,[hli]
ld [de],a
inc de
cp a,$ff
jr nz,.loop
ret
DisplayPokemonCenterDialogue:: ; 2a72 (0:2a72)
xor a
ld [$ff8b],a
ld [$ff8c],a
ld [$ff8d],a
inc hl
ld a,[H_LOADEDROMBANK]
push af
ld a,Bank(DisplayPokemonCenterDialogue_)
ld [H_LOADEDROMBANK],a
ld [$2000],a
call DisplayPokemonCenterDialogue_
pop af
ld [H_LOADEDROMBANK],a
ld [$2000],a
jp AfterDisplayingTextID
DisplaySafariGameOverText:: ; 2a90 (0:2a90)
callab PrintSafariGameOverText
jp AfterDisplayingTextID
DisplayPokemonFaintedText:: ; 2a9b (0:2a9b)
ld hl,PokemonFaintedText
call PrintText
jp AfterDisplayingTextID
PokemonFaintedText:: ; 2aa4 (0:2aa4)
TX_FAR _PokemonFaintedText
db "@"
DisplayPlayerBlackedOutText:: ; 2aa9 (0:2aa9)
ld hl,PlayerBlackedOutText
call PrintText
ld a,[wd732]
2014-05-25 17:26:42 +00:00
res 5,a
ld [wd732],a
2014-05-25 17:26:42 +00:00
jp HoldTextDisplayOpen
PlayerBlackedOutText:: ; 2aba (0:2aba)
TX_FAR _PlayerBlackedOutText
db "@"
DisplayRepelWoreOffText:: ; 2abf (0:2abf)
ld hl,RepelWoreOffText
call PrintText
jp AfterDisplayingTextID
RepelWoreOffText:: ; 2ac8 (0:2ac8)
TX_FAR _RepelWoreOffText
db "@"
INCLUDE "engine/menu/start_menu.asm"
; 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:
; [wd11e] = number of set bits
2014-05-25 17:26:42 +00:00
CountSetBits:: ; 2b7f (0:2b7f)
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 [wd11e],a ; store number of set bits
2014-05-25 17:26:42 +00:00
ret
; subtracts the amount the player paid from their money
; sets carry flag if there is enough money and unsets carry flag if not
SubtractAmountPaidFromMoney:: ; 2b96 (0:2b96)
ld b,BANK(SubtractAmountPaidFromMoney_)
ld hl,SubtractAmountPaidFromMoney_
jp Bankswitch
; adds the amount the player sold to their money
AddAmountSoldToMoney:: ; 2b9e (0:2b9e)
ld de,wPlayerMoney + 2
ld hl,$ffa1 ; total price of items
ld c,3 ; length of money in bytes
ld a,$0b
call Predef ; add total price to money
ld a,$13
ld [wd125],a
2014-05-25 17:26:42 +00:00
call DisplayTextBoxID ; redraw money text box
ld a, (SFX_02_5a - SFX_Headers_02) / 3
call PlaySoundWaitForCurrent ; play sound
jp WaitForSoundToFinish ; wait until sound is done playing
; 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
; [wcf96] = quantity to remove
2014-05-25 17:26:42 +00:00
RemoveItemFromInventory:: ; 2bbb (0:2bbb)
ld a,[H_LOADEDROMBANK]
push af
ld a,BANK(RemoveItemFromInventory_)
ld [H_LOADEDROMBANK],a
ld [$2000],a
call RemoveItemFromInventory_
pop af
ld [H_LOADEDROMBANK],a
ld [$2000],a
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
; [wcf96] = item quantity
2014-05-25 17:26:42 +00:00
; sets carry flag if successful, unsets carry flag if unsuccessful
AddItemToInventory:: ; 2bcf (0:2bcf)
push bc
ld a,[H_LOADEDROMBANK]
push af
ld a,BANK(AddItemToInventory_)
ld [H_LOADEDROMBANK],a
ld [$2000],a
call AddItemToInventory_
pop bc
ld a,b
ld [H_LOADEDROMBANK],a
ld [$2000],a
pop bc
ret
; INPUT:
; [wListMenuID] = list menu ID
; [wcf8b] = address of the list (2 bytes)
2014-05-25 17:26:42 +00:00
DisplayListMenuID:: ; 2be6 (0:2be6)
xor a
ld [H_AUTOBGTRANSFERENABLED],a ; disable auto-transfer
ld a,1
ld [$ffb7],a ; joypad state update flag
ld a,[W_BATTLETYPE]
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(OldManItemList)
.bankswitch
call BankswitchHome
ld hl,wd730
2014-05-25 17:26:42 +00:00
set 6,[hl] ; turn off letter printing delay
xor a
ld [wcc35],a ; 0 means no item is currently being swapped
ld [wd12a],a
ld a,[wcf8b]
2014-05-25 17:26:42 +00:00
ld l,a
ld a,[wcf8c]
2014-05-25 17:26:42 +00:00
ld h,a ; hl = address of the list
ld a,[hl]
ld [wd12a],a ; [wd12a] = number of list entries
2014-05-25 17:26:42 +00:00
ld a,$0d ; list menu text box ID
ld [wd125],a
2014-05-25 17:26:42 +00:00
call DisplayTextBoxID ; draw the menu text box
call UpdateSprites ; move sprites
FuncCoord 4,2 ; coordinates of upper left corner of menu text box
ld hl,Coord
ld de,$090e ; height and width of menu text box
ld a,[wListMenuID]
and a ; is it a PC pokemon list?
jr nz,.skipMovingSprites
call UpdateSprites ; move sprites
.skipMovingSprites
ld a,1 ; max menu item ID is 1 if the list has less than 2 entries
ld [wcc37],a
ld a,[wd12a]
2014-05-25 17:26:42 +00:00
cp a,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,%00000111 ; A button, B button, Select button
ld [wMenuWatchedKeys],a
ld c,10
call DelayFrames
DisplayListMenuIDLoop:: ; 2c53 (0:2c53)
xor a
ld [H_AUTOBGTRANSFERENABLED],a ; disable transfer
call PrintListMenuEntries
ld a,1
ld [H_AUTOBGTRANSFERENABLED],a ; enable transfer
call Delay3
ld a,[W_BATTLETYPE]
and a ; is it the Old Man battle?
jr z,.notOldManBattle
.oldManBattle
ld a,"▶"
FuncCoord 5,4
ld [Coord],a ; place menu cursor in front of first menu entry
ld c,80
call DelayFrames
xor a
ld [wCurrentMenuItem],a
ld hl,Coord
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
ld a,$01
ld [wd12e],a
ld [wd12d],a
2014-05-25 17:26:42 +00:00
xor a
ld [wcc37],a
2014-05-25 17:26:42 +00:00
ld a,[wCurrentMenuItem]
ld c,a
ld a,[wListScrollOffset]
add c
ld c,a
ld a,[wd12a] ; number of list entries
2014-05-25 17:26:42 +00:00
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 a,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,[wcf8b]
2014-05-25 17:26:42 +00:00
ld l,a
ld a,[wcf8c]
2014-05-25 17:26:42 +00:00
ld h,a
inc hl ; hl = beginning of list entries
ld b,0
add hl,bc
ld a,[hl]
ld [wcf91],a
2014-05-25 17:26:42 +00:00
ld a,[wListMenuID]
and a ; is it a PC pokemon list?
jr z,.pokemonList
push hl
call GetItemPrice
pop hl
ld a,[wListMenuID]
cp a,ITEMLISTMENU
jr nz,.skipGettingQuantity
; if it's an item menu
inc hl
ld a,[hl] ; a = item quantity
ld [wcf97],a
2014-05-25 17:26:42 +00:00
.skipGettingQuantity
ld a,[wcf91]
ld [wd0b5],a
2014-05-25 17:26:42 +00:00
ld a,$01
ld [wPredefBank],a
2014-05-25 17:26:42 +00:00
call GetName
jr .storeChosenEntry
.pokemonList
ld hl,W_NUMINPARTY
ld a,[wcf8b]
2014-05-25 17:26:42 +00:00
cp l ; is it a list of party pokemon or box pokemon?
ld hl,W_PARTYMON1NAME
jr z,.getPokemonName
ld hl, W_BOXMON1NAME ; 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
2014-05-25 17:26:42 +00:00
ld a,$01
ld [wd12e],a
2014-05-25 17:26:42 +00:00
ld a,[wCurrentMenuItem]
ld [wd12d],a
2014-05-25 17:26:42 +00:00
xor a
ld [$ffb7],a ; joypad state update flag
ld hl,wd730
2014-05-25 17:26:42 +00:00
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 a,3
ld b,a
ld a,[wd12a] ; number of list entries
2014-05-25 17:26:42 +00:00
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:: ; 2d57 (0:2d57)
; text box dimensions/coordinates for just quantity
FuncCoord 15,9
ld hl,Coord
ld b,1 ; height
ld c,3 ; width
ld a,[wListMenuID]
cp a,PRICEDITEMLISTMENU
jr nz,.drawTextBox
; text box dimensions/coordinates for quantity and price
FuncCoord 7,9
ld hl,Coord
ld b,1 ; height
ld c,11 ; width
.drawTextBox
call TextBoxBorder
FuncCoord 16,10
ld hl,Coord
ld a,[wListMenuID]
cp a,PRICEDITEMLISTMENU
jr nz,.printInitialQuantity
FuncCoord 8,10
ld hl,Coord
.printInitialQuantity
ld de,InitialQuantityText
call PlaceString
xor a
ld [wcf96],a ; initialize current quantity to 0
2014-05-25 17:26:42 +00:00
jp .incrementQuantity
.waitForKeyPressLoop
2014-05-25 18:21:48 +00:00
call JoypadLowSensitivity
2014-05-25 17:51:53 +00:00
ld a,[hJoyPressed] ; newly pressed buttons
2014-05-25 17:26:42 +00:00
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,[wcf97] ; max quantity
2014-05-25 17:26:42 +00:00
inc a
ld b,a
ld hl,wcf96 ; current quantity
2014-05-25 17:26:42 +00:00
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,wcf96 ; current quantity
2014-05-25 17:26:42 +00:00
dec [hl]
jr nz,.handleNewQuantity
; wrap to the max quantity if the player goes below 1
ld a,[wcf97] ; max quantity
2014-05-25 17:26:42 +00:00
ld [hl],a
.handleNewQuantity
FuncCoord 17,10
ld hl,Coord
ld a,[wListMenuID]
cp a,PRICEDITEMLISTMENU
jr nz,.printQuantity
.printPrice
ld c,$03
ld a,[wcf96]
2014-05-25 17:26:42 +00:00
ld b,a
ld hl,$ff9f ; 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,$ffa1
ld hl,$ff8d
push bc
ld a,$0b
call Predef ; add the individual price to the current sum
pop bc
dec b
jr nz,.addLoop
ld a,[$ff8e]
and a ; should the price be halved (for selling items)?
jr z,.skipHalvingPrice
xor a
ld [$ffa2],a
ld [$ffa3],a
ld a,$02
ld [$ffa4],a
ld a,$0d
call Predef ; halves the price
; store the halved price
ld a,[$ffa2]
ld [$ff9f],a
ld a,[$ffa3]
ld [$ffa0],a
ld a,[$ffa4]
ld [$ffa1],a
.skipHalvingPrice
FuncCoord 12,10
ld hl,Coord
ld de,SpacesBetweenQuantityAndPriceText
call PlaceString
ld de,$ff9f ; total price
ld c,$a3
call PrintBCDNumber
FuncCoord 9,10
ld hl,Coord
.printQuantity
ld de,wcf96 ; current quantity
2014-05-25 17:26:42 +00:00
ld bc,$8102 ; print leading zeroes, 1 byte, 2 digits
call PrintNumber
jp .waitForKeyPressLoop
.buttonAPressed ; the player chose to make the transaction
xor a
ld [wcc35],a ; 0 means no item is currently being swapped
2014-05-25 17:26:42 +00:00
ret
.buttonBPressed ; the player chose to cancel the transaction
xor a
ld [wcc35],a ; 0 means no item is currently being swapped
2014-05-25 17:26:42 +00:00
ld a,$ff
ret
InitialQuantityText:: ; 2e30 (0:2e30)
db "×01@"
SpacesBetweenQuantityAndPriceText:: ; 2e34 (0:2e34)
db " @"
ExitListMenu:: ; 2e3b (0:2e3b)
ld a,[wCurrentMenuItem]
ld [wd12d],a
2014-05-25 17:26:42 +00:00
ld a,$02
ld [wd12e],a
ld [wcc37],a
2014-05-25 17:26:42 +00:00
xor a
ld [$ffb7],a
ld hl,wd730
2014-05-25 17:26:42 +00:00
res 6,[hl]
call BankswitchBack
xor a
ld [wcc35],a ; 0 means no item is currently being swapped
2014-05-25 17:26:42 +00:00
scf
ret
PrintListMenuEntries:: ; 2e5a (0:2e5a)
FuncCoord 5, 3
2014-05-25 17:26:42 +00:00
ld hl,Coord
ld b,$09
ld c,$0e
call ClearScreenArea
ld a,[wcf8b]
2014-05-25 17:26:42 +00:00
ld e,a
ld a,[wcf8c]
2014-05-25 17:26:42 +00:00
ld d,a
inc de ; de = beginning of list entries
ld a,[wListScrollOffset]
ld c,a
ld a,[wListMenuID]
cp a,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
FuncCoord 6,4 ; coordinates of first list entry name
ld hl,Coord
ld b,4 ; print 4 names
.loop
ld a,b
ld [wWhichPokemon],a
ld a,[de]
ld [wd11e],a
2014-05-25 17:26:42 +00:00
cp a,$ff
jp z,.printCancelMenuItem
push bc
push de
push hl
push hl
push de
ld a,[wListMenuID]
and a
jr z,.pokemonPCMenu
cp a,$01
jr z,.movesMenu
.itemMenu
call GetItemName
jr .placeNameString
.pokemonPCMenu
push hl
ld hl,W_NUMINPARTY
ld a,[wcf8b]
2014-05-25 17:26:42 +00:00
cp l ; is it a list of party pokemon or box pokemon?
ld hl,W_PARTYMON1NAME
jr z,.getPokemonName
ld hl, W_BOXMON1NAME ; 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,[wcf93]
2014-05-25 17:26:42 +00:00
and a ; should prices be printed?
jr z,.skipPrintingItemPrice
.printItemPrice
push hl
ld a,[de]
ld de,ItemPrices
ld [wcf91],a
2014-05-25 17:26:42 +00:00
call GetItemPrice ; get price
pop hl
ld bc,20 + 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
jr nz,.skipPrintingPokemonLevel
.printPokemonLevel
ld a,[wd11e]
2014-05-25 17:26:42 +00:00
push af
push hl
ld hl,W_NUMINPARTY
ld a,[wcf8b]
2014-05-25 17:26:42 +00:00
cp l ; is it a list of party pokemon or box pokemon?
ld a,$00
jr z,.next
ld a,$02
.next
ld [wcc49],a
2014-05-25 17:26:42 +00:00
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 ; load pokemon info
ld a,[wcc49]
2014-05-25 17:26:42 +00:00
and a ; is it a list of party pokemon or box pokemon?
jr z,.skipCopyingLevel
.copyLevel
ld a,[wcf9b]
ld [wcfb9],a
2014-05-25 17:26:42 +00:00
.skipCopyingLevel
pop hl
ld bc,$001c
add hl,bc
call PrintLevel ; print level
pop af
ld [wd11e],a
2014-05-25 17:26:42 +00:00
.skipPrintingPokemonLevel
pop hl
pop de
inc de
ld a,[wListMenuID]
cp a,ITEMLISTMENU
jr nz,.nextListEntry
.printItemQuantity
ld a,[wd11e]
ld [wcf91],a
2014-05-25 17:26:42 +00:00
call IsKeyItem ; check if item is unsellable
ld a,[wd124]
2014-05-25 17:26:42 +00:00
and a ; is the item unsellable?
jr nz,.skipPrintingItemQuantity ; if so, don't print the quantity
push hl
ld bc,20 + 8 ; 1 row down and 8 columns right
add hl,bc
ld a,"×"
ldi [hl],a
ld a,[wd11e]
2014-05-25 17:26:42 +00:00
push af
ld a,[de]
ld [wcf97],a
2014-05-25 17:26:42 +00:00
push de
ld de,wd11e
2014-05-25 17:26:42 +00:00
ld [de],a
ld bc,$0102
call PrintNumber
pop de
pop af
ld [wd11e],a
2014-05-25 17:26:42 +00:00
pop hl
.skipPrintingItemQuantity
inc de
pop bc
inc c
push bc
inc c
ld a,[wcc35] ; ID of item chosen for swapping (counts from 1)
2014-05-25 17:26:42 +00:00
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,$ec ; unfilled right arrow menu cursor to indicate an item being swapped
ld [hli],a
.nextListEntry
ld bc,2 * 20 ; 2 rows
add hl,bc
pop bc
inc c
dec b
jp nz,.loop
ld bc,-8
add hl,bc
ld a,$ee ; down arrow
ld [hl],a
ret
.printCancelMenuItem
ld de,ListMenuCancelText
jp PlaceString
ListMenuCancelText:: ; 2f97 (0:2f97)
db "CANCEL@"
GetMonName:: ; 2f9e (0:2f9e)
push hl
ld a,[H_LOADEDROMBANK]
push af
ld a,BANK(MonsterNames) ; 07
ld [H_LOADEDROMBANK],a
ld [$2000],a
ld a,[wd11e]
2014-05-25 17:26:42 +00:00
dec a
ld hl,MonsterNames ; 421E
ld c,10
ld b,0
call AddNTimes
ld de,wcd6d
2014-05-25 17:26:42 +00:00
push de
ld bc,10
call CopyData
ld hl,wcd77
2014-05-25 17:26:42 +00:00
ld [hl], "@"
pop de
pop af
ld [H_LOADEDROMBANK],a
ld [$2000],a
pop hl
ret
GetItemName:: ; 2fcf (0:2fcf)
; given an item ID at [wd11e], store the name of the item into a string
; starting at wcd6d
2014-05-25 17:26:42 +00:00
push hl
push bc
ld a,[wd11e]
2014-05-25 17:26:42 +00:00
cp HM_01 ; is this a TM/HM?
jr nc,.Machine
ld [wd0b5],a
2014-05-25 17:26:42 +00:00
ld a,ITEM_NAME
ld [W_LISTTYPE],a
ld a,BANK(ItemNames)
ld [wPredefBank],a
2014-05-25 17:26:42 +00:00
call GetName
jr .Finish
.Machine
call GetMachineName
.Finish
ld de,wcd6d ; pointer to where item name is stored in RAM
2014-05-25 17:26:42 +00:00
pop bc
pop hl
ret
GetMachineName:: ; 2ff3 (0:2ff3)
; copies the name of the TM/HM in [wd11e] to wcd6d
2014-05-25 17:26:42 +00:00
push hl
push de
push bc
ld a,[wd11e]
2014-05-25 17:26:42 +00:00
push af
cp TM_01 ; is this a TM? [not HM]
jr nc,.WriteTM
; if HM, then write "HM" and add 5 to the item ID, so we can reuse the
; TM printing code
add 5
ld [wd11e],a
2014-05-25 17:26:42 +00:00
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
2014-05-25 17:26:42 +00:00
call CopyData
; now get the machine number and convert it to text
ld a,[wd11e]
2014-05-25 17:26:42 +00:00
sub TM_01 - 1
ld b,$F6 ; "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,$F6 ; "0"
add b
ld [de],a
inc de
ld a,"@"
ld [de],a
pop af
ld [wd11e],a
2014-05-25 17:26:42 +00:00
pop bc
pop de
pop hl
ret
TechnicalPrefix:: ; 303c (0:303c)
db "TM"
HiddenPrefix:: ; 303e (0:303e)
db "HM"
; sets carry if item is HM, clears carry if item is not HM
; Input: a = item ID
IsItemHM:: ; 3040 (0:3040)
cp a,HM_01
jr c,.notHM
cp a,TM_01
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:: ; 3049 (0:3049)
ld hl,HMMoves
ld de,1
jp IsInArray
HMMoves:: ; 3052 (0:3052)
db CUT,FLY,SURF,STRENGTH,FLASH
db $ff ; terminator
GetMoveName:: ; 3058 (0:3058)
push hl
ld a,MOVE_NAME
ld [W_LISTTYPE],a
ld a,[wd11e]
ld [wd0b5],a
2014-05-25 17:26:42 +00:00
ld a,BANK(MoveNames)
ld [wPredefBank],a
2014-05-25 17:26:42 +00:00
call GetName
ld de,wcd6d ; pointer to where move name is stored in RAM
2014-05-25 17:26:42 +00:00
pop hl
ret
; reloads text box tile patterns, current map view, and tileset tile patterns
ReloadMapData:: ; 3071 (0:3071)
ld a,[H_LOADEDROMBANK]
push af
ld a,[W_CURMAP]
call SwitchToMapRomBank
call DisableLCD
call LoadTextBoxTilePatterns
call LoadCurrentMapView
call LoadTilesetTilePatternData
call EnableLCD
pop af
ld [H_LOADEDROMBANK],a
ld [$2000],a
ret
; reloads tileset tile patterns
ReloadTilesetTilePatterns:: ; 3090 (0:3090)
ld a,[H_LOADEDROMBANK]
push af
ld a,[W_CURMAP]
call SwitchToMapRomBank
call DisableLCD
call LoadTilesetTilePatternData
call EnableLCD
pop af
ld [H_LOADEDROMBANK],a
ld [$2000],a
ret
; shows the town map and lets the player choose a destination to fly to
ChooseFlyDestination:: ; 30a9 (0:30a9)
ld hl,wd72e
2014-05-25 17:26:42 +00:00
res 4,[hl]
ld b, BANK(LoadTownMap_Fly)
ld hl, LoadTownMap_Fly
jp Bankswitch
; causes the text box to close waithout waiting for a button press after displaying text
DisableWaitingAfterTextDisplay:: ; 30b6 (0:30b6)
ld a,$01
ld [wcc3c],a
2014-05-25 17:26:42 +00:00
ret
; uses an item
; UseItem is used with dummy items to perform certain other functions as well
; INPUT:
; [wcf91] = item ID
2014-05-25 17:26:42 +00:00
; OUTPUT:
; [wcd6a] = success
2014-05-25 17:26:42 +00:00
; 00: unsucessful
; 01: successful
; 02: not able to be used right now, no extra menu displayed (only certain items use this)
UseItem:: ; 30bc (0:30bc)
ld b,BANK(UseItem_)
ld hl,UseItem_
jp Bankswitch
; 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
; [wcf96] = quantity to toss
2014-05-25 17:26:42 +00:00
; OUTPUT:
; clears carry flag if the item is tossed, sets carry flag if not
TossItem:: ; 30c4 (0:30c4)
ld a,[H_LOADEDROMBANK]
push af
ld a,BANK(TossItem_)
ld [H_LOADEDROMBANK],a
ld [$2000],a
call TossItem_
pop de
ld a,d
ld [H_LOADEDROMBANK],a
ld [$2000],a
ret
; checks if an item is a key item
; INPUT:
; [wcf91] = item ID
2014-05-25 17:26:42 +00:00
; OUTPUT:
; [wd124] = result
2014-05-25 17:26:42 +00:00
; 00: item is not key item
; 01: item is key item
IsKeyItem:: ; 30d9 (0:30d9)
push hl
push de
push bc
callba IsKeyItem_
pop bc
pop de
pop hl
ret
; function to draw various text boxes
; INPUT:
; [wd125] = text box ID
2014-05-25 17:26:42 +00:00
DisplayTextBoxID:: ; 30e8 (0:30e8)
ld a,[H_LOADEDROMBANK]
push af
ld a,BANK(DisplayTextBoxID_)
ld [H_LOADEDROMBANK],a
ld [$2000],a
call DisplayTextBoxID_
pop bc
ld a,b
ld [H_LOADEDROMBANK],a
ld [$2000],a
ret
Func_30fd:: ; 30fd (0:30fd)
ld a, [wcc57]
2014-05-25 17:26:42 +00:00
and a
ret nz
ld a, [wd736]
2014-05-25 17:26:42 +00:00
bit 1, a
ret nz
ld a, [wd730]
2014-05-25 17:26:42 +00:00
and $80
ret
Func_310e:: ; 310e (0:310e)
ld hl, wd736
2014-05-25 17:26:42 +00:00
bit 0, [hl]
res 0, [hl]
jr nz, .asm_3146
ld a, [wcc57]
2014-05-25 17:26:42 +00:00
and a
ret z
dec a
add a
ld d, $0
ld e, a
ld hl, .pointerTable_3140
add hl, de
ld a, [hli]
ld h, [hl]
ld l, a
ld a, [H_LOADEDROMBANK]
push af
ld a, [wcc58]
2014-05-25 17:26:42 +00:00
ld [H_LOADEDROMBANK], a
ld [$2000], a
ld a, [wcf10]
2014-05-25 17:26:42 +00:00
call CallFunctionInTable
pop af
ld [H_LOADEDROMBANK], a
ld [$2000], a
ret
.pointerTable_3140
dw PointerTable_1a442
dw PointerTable_1a510
dw PointerTable_1a57d
.asm_3146
ld b, BANK(Func_1a3e0)
ld hl, Func_1a3e0
jp Bankswitch
Func_314e:: ; 314e (0:314e)
ld b, BANK(Func_1a41d)
ld hl, Func_1a41d
jp Bankswitch
Func_3156:: ; 3156 (0:3156)
ret
; stores hl in [W_TRAINERHEADERPTR]
StoreTrainerHeaderPointer:: ; 3157 (0:3157)
ld a, h
ld [W_TRAINERHEADERPTR], a
ld a, l
ld [W_TRAINERHEADERPTR+1], a
ret
; executes the current map script from the function pointer array provided in hl.
; a: map script index to execute (unless overridden by [wd733] bit 4)
2014-05-25 17:26:42 +00:00
ExecuteCurMapScriptInTable:: ; 3160 (0:3160)
push af
push de
call StoreTrainerHeaderPointer
pop hl
pop af
push hl
ld hl, W_FLAGS_D733
bit 4, [hl]
res 4, [hl]
jr z, .useProvidedIndex ; test if map script index was overridden manually
ld a, [W_CURMAPSCRIPT]
.useProvidedIndex
pop hl
ld [W_CURMAPSCRIPT], a
call CallFunctionInTable
ld a, [W_CURMAPSCRIPT]
ret
LoadGymLeaderAndCityName:: ; 317f (0:317f)
push de
ld de, wGymCityName
ld bc, $11
call CopyData ; load city name
pop hl
ld de, wGymLeaderName
ld bc, $b
jp CopyData ; load gym leader name
; reads specific information from trainer header (pointed to at W_TRAINERHEADERPTR)
; 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:: ; 3193 (0:3193)
push de
push af
ld d, $0
ld e, a
ld hl, W_TRAINERHEADERPTR
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::
ld a, $10 ; FlagActionPredef
jp Predef
; direct talking to a trainer (rather than getting seen by one)
TalkToTrainer:: ; 31cc (0:31cc)
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, $2
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 ; 0x31ed
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 PreBattleSaveRegisters
ld hl, W_FLAGS_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 being engaged by another trainer
ret nz
call EngageMapTrainer
ld hl, W_CURMAPSCRIPT
inc [hl] ; progress map script index (assuming it was 0 before) to start pre-battle routines
jp Func_325d
; checks if any trainers are seeing the player and wanting to fight
CheckFightingMapTrainers:: ; 3219 (0:3219)
call CheckForEngagingTrainers
ld a, [wcf13]
2014-05-25 17:26:42 +00:00
cp $ff
jr nz, .trainerEngaging
xor a
ld [wcf13], a
2014-05-25 17:26:42 +00:00
ld [wTrainerHeaderFlagBit], a
ret
.trainerEngaging
ld hl, W_FLAGS_D733
set 3, [hl]
ld [wcd4f], a
2014-05-25 17:26:42 +00:00
xor a
ld [wcd50], a
2014-05-25 17:26:42 +00:00
ld a, $4c
call Predef
ld a, D_RIGHT | D_LEFT | D_UP | D_DOWN
2014-05-25 17:51:53 +00:00
ld [wJoyIgnore], a
2014-05-25 17:26:42 +00:00
xor a
ldh [$b4], a
call TrainerWalkUpToPlayer_Bank0
ld hl, W_CURMAPSCRIPT
inc [hl] ; progress to battle phase 1 (engaging)
ret
Func_324c:: ; 324c (0:324c)
ld a, [wd730]
2014-05-25 17:26:42 +00:00
and $1
ret nz
2014-05-25 17:51:53 +00:00
ld [wJoyIgnore], a
ld a, [wcf13]
2014-05-25 17:26:42 +00:00
ld [H_DOWNARROWBLINKCNT2], a ; $ff8c
call DisplayTextID
Func_325d:: ; 325d (0:325d)
xor a
2014-05-25 17:51:53 +00:00
ld [wJoyIgnore], a
2014-05-25 17:26:42 +00:00
call InitBattleEnemyParameters
ld hl, wd72d
2014-05-25 17:26:42 +00:00
set 6, [hl]
set 7, [hl]
ld hl, wd72e
2014-05-25 17:26:42 +00:00
set 1, [hl]
ld hl, W_CURMAPSCRIPT
inc [hl] ; progress to battle phase 2 (battling)
ret
EndTrainerBattle:: ; 3275 (0:3275)
ld hl, wd126
2014-05-25 17:26:42 +00:00
set 5, [hl]
set 6, [hl]
ld hl, wd72d
2014-05-25 17:26:42 +00:00
res 7, [hl]
ld hl, wFlags_0xcd60
res 0, [hl] ; player is no longer engaged by any trainer
ld a, [W_ISINBATTLE] ; W_ISINBATTLE
2014-05-25 17:26:42 +00:00
cp $ff
jp z, ResetButtonPressedAndMapScript
ld a, $2
call ReadTrainerHeaderInfo
ld a, [wTrainerHeaderFlagBit]
ld c, a
ld b, $1
call TrainerFlagAction ; flag trainer as fought
ld a, [W_ENEMYMONORTRAINERCLASS]
cp $c8
jr nc, .skipRemoveSprite ; test if trainer was fought (in that case skip removing the corresponding sprite)
ld hl, W_MISSABLEOBJECTLIST
ld de, $2
ld a, [wcf13]
2014-05-25 17:26:42 +00:00
call IsInArray ; search for sprite ID
inc hl
ld a, [hl]
ld [wcc4d], a ; load corresponding missable object index and remove it
2014-05-25 17:26:42 +00:00
ld a, $11
call Predef ; indirect jump to RemoveMissableObject (f1d7 (3:71d7))
.skipRemoveSprite
ld hl, wd730
2014-05-25 17:26:42 +00:00
bit 4, [hl]
res 4, [hl]
ret nz
ResetButtonPressedAndMapScript:: ; 32c1 (0:32c1)
xor a
2014-05-25 17:51:53 +00:00
ld [wJoyIgnore], a
ld [hJoyHeld], a
ld [hJoyPressed], a
ld [hJoyReleased], a
2014-05-25 17:26:42 +00:00
ld [W_CURMAPSCRIPT], a ; reset battle status
ret
; calls TrainerWalkUpToPlayer
TrainerWalkUpToPlayer_Bank0:: ; 32cf (0:32cf)
ld b, BANK(TrainerWalkUpToPlayer)
ld hl, TrainerWalkUpToPlayer
jp Bankswitch
; sets opponent type and mon set/lvl based on the engaging trainer data
InitBattleEnemyParameters:: ; 32d7 (0:32d7)
ld a, [wEngagedTrainerClass]
ld [W_CUROPPONENT], a ; wd059
2014-05-25 17:26:42 +00:00
ld [W_ENEMYMONORTRAINERCLASS], a
cp $c8
ld a, [wEngagedTrainerSet] ; wcd2e
2014-05-25 17:26:42 +00:00
jr c, .noTrainer
ld [W_TRAINERNO], a ; wd05d
2014-05-25 17:26:42 +00:00
ret
.noTrainer
ld [W_CURENEMYLVL], a ; W_CURENEMYLVL
2014-05-25 17:26:42 +00:00
ret
Func_32ef:: ; 32ef (0:32ef)
ld hl, Func_567f9
jr asm_3301
Func_32f4:: ; 32f4 (0:32f4)
ld hl, Func_56819
jr asm_3301 ; 0x32f7 $8
Func_32f9:: ; 32f9 (0:32f9)
ld hl, Func_5683d
jr asm_3301
Func_32fe:: ; 32fe (0:32fe)
ld hl, Func_5685d
asm_3301:: ; 3301 (0:3301)
ld b, BANK(Func_567f9) ; BANK(Func_56819), BANK(Func_5683d), BANK(Func_5685d)
jp Bankswitch ; indirect jump to one of the four functions
CheckForEngagingTrainers:: ; 3306 (0:3306)
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 [wcf13], a ; store trainer flag's bit
2014-05-25 17:26:42 +00:00
ld [wTrainerHeaderFlagBit], a
cp $ff
ret z
ld a, $2
call ReadTrainerHeaderInfo ; read trainer flag's byte ptr
ld b, $2
ld a, [wTrainerHeaderFlagBit]
ld c, a
call TrainerFlagAction ; read trainer flag
ld a, c
and a
jr nz, .trainerAlreadyFought
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, [wcf13]
2014-05-25 17:26:42 +00:00
swap a
ld [wTrainerSpriteOffset], a ; wWhichTrade
2014-05-25 17:26:42 +00:00
ld a, $39
call Predef ; indirect jump to CheckEngagePlayer (5690f (15:690f))
pop de
pop hl
ld a, [wTrainerSpriteOffset] ; wWhichTrade
2014-05-25 17:26:42 +00:00
and a
ret nz ; break if the trainer is engaging
.trainerAlreadyFought
ld hl, $c
add hl, de
ld d, h
ld e, l
jr .trainerLoop
; saves loaded rom bank and hl as well as de registers
PreBattleSaveRegisters:: ; 3354 (0:3354)
ld a, [H_LOADEDROMBANK]
ld [W_PBSTOREDROMBANK], a
ld a, h
ld [W_PBSTOREDREGISTERH], a
ld a, l
ld [W_PBSTOREDREGISTERL], a
ld a, d
ld [W_PBSTOREDREGISTERD], a
ld a, e
ld [W_PBSTOREDREGISTERE], a
ret
; loads data of some trainer on the current map and plays pre-battle music
; [wcf13]: sprite ID of trainer who is engaged
2014-05-25 17:26:42 +00:00
EngageMapTrainer:: ; 336a (0:336a)
ld hl, W_MAPSPRITEEXTRADATA
ld d, $0
ld a, [wcf13]
2014-05-25 17:26:42 +00:00
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 [wEnemyMonAttackMod], a ; wcd2e
2014-05-25 17:26:42 +00:00
jp PlayTrainerMusic
Func_3381:: ; 3381 (0:3381)
push hl
ld hl, wd72d
2014-05-25 17:26:42 +00:00
bit 7, [hl]
res 7, [hl]
pop hl
ret z
ld a, [H_LOADEDROMBANK]
push af
ld a, [W_PBSTOREDROMBANK]
ld [H_LOADEDROMBANK], a
ld [$2000], a
push hl
callba SaveTrainerName
ld hl, TrainerNameText
call PrintText
pop hl
pop af
ld [H_LOADEDROMBANK], a
ld [$2000], a
callba Func_1a5e7
jp WaitForSoundToFinish
Func_33b7:: ; 33b7 (0:33b7)
ld a, [wcf0b]
2014-05-25 17:26:42 +00:00
and a
jr nz, .asm_33c6
ld a, [W_PBSTOREDREGISTERH]
ld h, a
ld a, [W_PBSTOREDREGISTERL]
ld l, a
ret
.asm_33c6
ld a, [W_PBSTOREDREGISTERD]
ld h, a
ld a, [W_PBSTOREDREGISTERE]
ld l, a
ret
TrainerNameText:: ; 33cf (0:33cf)
TX_FAR _TrainerNameText
db $08
Func_33d4:: ; 33d4 (0:33d4)
call Func_33b7
call TextCommandProcessor
jp TextScriptEnd
Func_33dd:: ; 33dd (0:33dd)
ld a, [wFlags_0xcd60]
bit 0, a
ret nz
call EngageMapTrainer
xor a
ret
PlayTrainerMusic:: ; 33e8 (0:33e8)
ld a, [wEngagedTrainerClass]
cp $c8 + SONY1
ret z
cp $c8 + SONY2
ret z
cp $c8 + SONY3
ret z
ld a, [W_GYMLEADERNO] ; W_GYMLEADERNO
2014-05-25 17:26:42 +00:00
and a
ret nz
xor a
ld [wMusicHeaderPointer], a
ld a, $ff
call PlaySound ; stop music
ld a, BANK(Music_MeetEvilTrainer)
ld [wc0ef], a
ld [wc0f0], a
2014-05-25 17:26:42 +00:00
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 [wc0ee], a
2014-05-25 17:26:42 +00:00
jp PlaySound
INCLUDE "data/trainer_types.asm"
Func_3442:: ; 3442 (0:3442)
ld a, [hli]
cp $ff
ret z
cp b
jr nz, .asm_345b
ld a, [hli]
cp c
jr nz, .asm_345c
ld a, [hli]
ld d, [hl]
ld e, a
ld hl, wccd3
2014-05-25 17:26:42 +00:00
call DecodeRLEList
dec a
ld [wcd38], a
2014-05-25 17:26:42 +00:00
ret
.asm_345b
inc hl
.asm_345c
inc hl
inc hl
jr Func_3442
FuncTX_ItemStoragePC:: ; 3460 (0:3460)
call SaveScreenTilesToBuffer2
ld b, BANK(PlayerPC)
ld hl, PlayerPC
jr bankswitchAndContinue
FuncTX_BillsPC:: ; 346a (0:346a)
call SaveScreenTilesToBuffer2
ld b, BANK(Func_214c2)
ld hl, Func_214c2
jr bankswitchAndContinue
FuncTX_SlotMachine:: ; 3474 (0:3474)
; XXX find a better name for this function
; special_F7
ld b,BANK(CeladonPrizeMenu)
ld hl,CeladonPrizeMenu
bankswitchAndContinue:: ; 3479 (0:3479)
call Bankswitch
jp HoldTextDisplayOpen ; continue to main text-engine function
FuncTX_PokemonCenterPC:: ; 347f (0:347f)
ld b, BANK(ActivatePC)
ld hl, ActivatePC
jr bankswitchAndContinue
Func_3486:: ; 3486 (0:3486)
xor a
ld [wcd3b], a
ld [wSpriteStateData2 + $06], a
ld hl, wd730
2014-05-25 17:26:42 +00:00
set 7, [hl]
ret
IsItemInBag:: ; 3493 (0:3493)
; 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
ld a,$1C
call Predef
ld a,b
and a
ret
DisplayPokedex:: ; 349b (0:349b)
ld [wd11e], a
2014-05-25 17:26:42 +00:00
ld b, BANK(Func_7c18)
ld hl, Func_7c18
jp Bankswitch
Func_34a6:: ; 34a6 (0:34a6)
call Func_34ae
ld c, $6
jp DelayFrames
Func_34ae:: ; 34ae (0:34ae)
ld a, $9
ld [H_DOWNARROWBLINKCNT1], a ; $ff8b
call Func_34fc
ld a, [$ff8d]
ld [hl], a
ret
Func_34b9:: ; 34b9 (0:34b9)
ld de, $fff9
add hl, de
ld [hl], a
ret
; tests if the player's coordinates are in a specified array
; INPUT:
; hl = address of array
; OUTPUT:
; [wWhichTrade] = if there is match, the matching array index
2014-05-25 17:26:42 +00:00
; sets carry if the coordinates are in the array, clears carry if not
ArePlayerCoordsInArray:: ; 34bf (0:34bf)
ld a,[W_YCOORD]
ld b,a
ld a,[W_XCOORD]
ld c,a
; fallthrough
CheckCoords:: ; 34c7 (0:34c7)
xor a
ld [wWhichTrade],a
2014-05-25 17:26:42 +00:00
.loop
ld a,[hli]
cp a,$ff ; reached terminator?
jr z,.notInArray
push hl
ld hl,wWhichTrade
2014-05-25 17:26:42 +00:00
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
; ff8c = which boulder to check? XXX
; OUTPUT:
; [wWhichTrade] = if there is match, the matching array index
2014-05-25 17:26:42 +00:00
; sets carry if the coordinates are in the array, clears carry if not
CheckBoulderCoords:: ; 34e4 (0:34e4)
push hl
ld hl, wSpriteStateData2 + $04
2014-05-25 17:26:42 +00:00
ld a, [$ff8c]
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
Func_34fc:: ; 34fc (0:34fc)
ld h, $c1
jr asm_3502
Func_3500:: ; 3500 (0:3500)
ld h, $c2
asm_3502:: ; 3502 (0:3502)
ld a, [H_DOWNARROWBLINKCNT1] ; $ff8b
ld b, a
ld a, [H_DOWNARROWBLINKCNT2] ; $ff8c
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:: ; 350c (0:350c)
xor a
ld [wRLEByteCount], a ; count written bytes here
.listLoop
ld a, [de]
cp $ff
jr z, .endOfList
ld [H_DOWNARROWBLINKCNT1], 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
ld a, [H_DOWNARROWBLINKCNT1] ; $ff8b
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 [$FF8C] to $FE and byte 2 to [$FF8D]
SetSpriteMovementBytesToFE:: ; 3533 (0:3533)
push hl
call GetSpriteMovementByte1Pointer
ld [hl], $fe
call GetSpriteMovementByte2Pointer
ld a, [$ff8d]
ld [hl], a
pop hl
ret
; sets both movement bytes for sprite [$FF8C] to $FF
SetSpriteMovementBytesToFF:: ; 3541 (0:3541)
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 [$FF8C] in hl
GetSpriteMovementByte1Pointer:: ; 354e (0:354e)
ld h,$C2
ld a,[$FF8C] ; the sprite to move
swap a
add a,6
ld l,a
ret
; returns the sprite movement byte 2 pointer for sprite [$FF8C] in hl
GetSpriteMovementByte2Pointer:: ; 3558 (0:3558)
push de
ld hl,W_MAPSPRITEDATA
ld a,[$FF8C] ; the sprite to move
dec a
add a
ld d,0
ld e,a
add hl,de
pop de
ret
GetTrainerInformation:: ; 3566 (0:3566)
call GetTrainerName
ld a, [W_ISLINKBATTLE] ; W_ISLINKBATTLE
2014-05-25 17:26:42 +00:00
and a
jr nz, .linkBattle
ld a, Bank(TrainerPicAndMoneyPointers)
call BankswitchHome
ld a, [W_TRAINERCLASS] ; wd031
2014-05-25 17:26:42 +00:00
dec a
ld hl, TrainerPicAndMoneyPointers
ld bc, $5
call AddNTimes
ld de, wd033
2014-05-25 17:26:42 +00:00
ld a, [hli]
ld [de], a
inc de
ld a, [hli]
ld [de], a
ld de, wd046
2014-05-25 17:26:42 +00:00
ld a, [hli]
ld [de], a
inc de
ld a, [hli]
ld [de], a
jp BankswitchBack
.linkBattle
ld hl, wd033
2014-05-25 17:26:42 +00:00
ld de, RedPicFront
ld [hl], e
inc hl
ld [hl], d
ret
GetTrainerName:: ; 359e (0:359e)
ld b, BANK(GetTrainerName_)
ld hl, GetTrainerName_
jp Bankswitch
2014-05-26 00:27:02 +00:00
HasEnoughMoney::
; Check if the player has at least as much
; money as the 3-byte BCD value at $ff9f.
ld de, wPlayerMoney
2014-05-25 17:26:42 +00:00
ld hl, $ff9f
2014-05-26 00:27:02 +00:00
ld c, 3
2014-05-25 17:26:42 +00:00
jp StringCmp
2014-05-26 00:27:02 +00:00
HasEnoughCoins::
; Check if the player has at least as many
; coins as the 2-byte BCD value at $ffa0.
2014-05-25 17:26:42 +00:00
ld de, wPlayerCoins
ld hl, $ffa0
2014-05-26 00:27:02 +00:00
ld c, 2
2014-05-25 17:26:42 +00:00
jp StringCmp
2014-05-26 00:27:02 +00:00
2014-05-25 17:26:42 +00:00
BankswitchHome:: ; 35bc (0:35bc)
; switches to bank # in a
; Only use this when in the home bank!
ld [wcf09],a
2014-05-25 17:26:42 +00:00
ld a,[H_LOADEDROMBANK]
ld [wcf08],a
ld a,[wcf09]
2014-05-25 17:26:42 +00:00
ld [H_LOADEDROMBANK],a
ld [$2000],a
ret
BankswitchBack:: ; 35cd (0:35cd)
; returns from BankswitchHome
ld a,[wcf08]
2014-05-25 17:26:42 +00:00
ld [H_LOADEDROMBANK],a
ld [$2000],a
ret
Bankswitch:: ; 35d6 (0:35d6)
; self-contained bankswitch, use this when not in the home bank
; switches to the bank in b
ld a,[H_LOADEDROMBANK]
push af
ld a,b
ld [H_LOADEDROMBANK],a
ld [$2000],a
ld bc,.Return
push bc
jp [hl]
.Return
pop bc
ld a,b
ld [H_LOADEDROMBANK],a
ld [$2000],a
ret
; displays yes/no choice
; yes -> set carry
YesNoChoice:: ; 35ec (0:35ec)
call SaveScreenTilesToBuffer1
call InitYesNoTextBoxParameters
jr DisplayYesNoChoice
Func_35f4:: ; 35f4 (0:35f4)
ld a, $14
ld [wd125], a
2014-05-25 17:26:42 +00:00
call InitYesNoTextBoxParameters
jp DisplayTextBoxID
InitYesNoTextBoxParameters:: ; 35ff (0:35ff)
xor a
ld [wd12c], a
FuncCoord 14, 7
2014-05-25 17:26:42 +00:00
ld hl, Coord
ld bc, $80f
ret
YesNoChoicePokeCenter:: ; 360a (0:360a)
call SaveScreenTilesToBuffer1
ld a, $6
ld [wd12c], a
FuncCoord 11, 6
2014-05-25 17:26:42 +00:00
ld hl, Coord
ld bc, $80c
jr DisplayYesNoChoice
Func_361a:: ; 361a (0:361a)
call SaveScreenTilesToBuffer1
ld a, $3
ld [wd12c], a
FuncCoord 12, 7
2014-05-25 17:26:42 +00:00
ld hl, Coord
ld bc, $080d
DisplayYesNoChoice:: ; 3628 (0:3628)
ld a, $14
ld [wd125], a
2014-05-25 17:26:42 +00:00
call DisplayTextBoxID
jp LoadScreenTilesFromBuffer1
; calculates the difference |a-b|, setting carry flag if a<b
CalcDifference:: ; 3633 (0:3633)
sub b
ret nc
cpl
add $1
scf
ret
MoveSprite:: ; 363a (0:363a)
; move the sprite [$FF8C] with the movement pointed to by de
; actually only copies the movement data to wcc5b for later
2014-05-25 17:26:42 +00:00
call SetSpriteMovementBytesToFF
MoveSprite_:: ; 363d (0:363d)
push hl
push bc
call GetSpriteMovementByte1Pointer
xor a
ld [hl],a
ld hl,wcc5b
2014-05-25 17:26:42 +00:00
ld c,0
.loop
ld a,[de]
ld [hli],a
inc de
inc c
cp a,$FF ; have we reached the end of the movement data?
jr nz,.loop
ld a,c
ld [wcf0f],a ; number of steps taken
2014-05-25 17:26:42 +00:00
pop bc
ld hl,wd730
2014-05-25 17:26:42 +00:00
set 0,[hl]
pop hl
xor a
ld [wcd3b],a
ld [wccd3],a
2014-05-25 17:26:42 +00:00
dec a
2014-05-25 17:51:53 +00:00
ld [wJoyIgnore],a
ld [wcd3a],a
2014-05-25 17:26:42 +00:00
ret
Func_366b:: ; 366b (0:366b)
push hl
ld hl, $ffe7
xor a
ld [hld], a
ld a, [hld]
and a
jr z, .asm_367e
ld a, [hli]
.asm_3676
sub [hl]
jr c, .asm_367e
inc hl
inc [hl]
dec hl
jr .asm_3676
.asm_367e
pop hl
ret
; copies the tile patterns for letters and numbers into VRAM
LoadFontTilePatterns:: ; 3680 (0:3680)
ld a,[rLCDC]
bit 7,a ; is the LCD enabled?
jr nz,.lcdEnabled
.lcdDisabled
ld hl,FontGraphics
2014-05-29 08:31:46 +00:00
ld de,vFont
2014-05-25 17:26:42 +00:00
ld bc,$400
ld a,BANK(FontGraphics)
jp FarCopyDataDouble ; if LCD is off, transfer all at once
.lcdEnabled
ld de,FontGraphics
2014-05-29 08:31:46 +00:00
ld hl,vFont
2014-05-25 17:26:42 +00:00
ld bc,(BANK(FontGraphics) << 8 | $80)
jp CopyVideoDataDouble ; if LCD is on, transfer during V-blank
; copies the text box tile patterns into VRAM
LoadTextBoxTilePatterns:: ; 36a0 (0:36a0)
ld a,[rLCDC]
bit 7,a ; is the LCD enabled?
jr nz,.lcdEnabled
.lcdDisabled
ld hl,TextBoxGraphics
2014-05-29 08:31:46 +00:00
ld de,vChars2 + $600
ld bc,$200
2014-05-25 17:26:42 +00:00
ld a,BANK(TextBoxGraphics)
jp FarCopyData2 ; if LCD is off, transfer all at once
.lcdEnabled
ld de,TextBoxGraphics
2014-05-29 08:31:46 +00:00
ld hl,vChars2 + $600
2014-05-25 17:26:42 +00:00
ld bc,(BANK(TextBoxGraphics) << 8 | $20)
jp CopyVideoData ; if LCD is on, transfer during V-blank
; copies HP bar and status display tile patterns into VRAM
LoadHpBarAndStatusTilePatterns:: ; 36c0 (0:36c0)
ld a,[rLCDC]
bit 7,a ; is the LCD enabled?
jr nz,.lcdEnabled
.lcdDisabled
ld hl,HpBarAndStatusGraphics
2014-05-29 08:31:46 +00:00
ld de,vChars2 + $620
ld bc,$1e0
2014-05-25 17:26:42 +00:00
ld a,BANK(HpBarAndStatusGraphics)
jp FarCopyData2 ; if LCD is off, transfer all at once
.lcdEnabled
ld de,HpBarAndStatusGraphics
2014-05-29 08:31:46 +00:00
ld hl,vChars2 + $620
2014-05-25 17:26:42 +00:00
ld bc,(BANK(HpBarAndStatusGraphics) << 8 | $1e)
jp CopyVideoData ; if LCD is on, transfer during V-blank
;Fills memory range with the specified byte.
;input registers a = fill_byte, bc = length, hl = address
FillMemory:: ; 36e0 (0:36e0)
push de
ld d, a
.loop
ld a, d
ldi [hl], a
dec bc
ld a, b
or c
jr nz, .loop
pop de
ret
; loads sprite that de points to
; bank of sprite is given in a
UncompressSpriteFromDE:: ; 36eb (0:36eb)
ld hl, W_SPRITEINPUTPTR
ld [hl], e
inc hl
ld [hl], d
jp UncompressSpriteData
SaveScreenTilesToBuffer2:: ; 36f4 (0:36f4)
ld hl, wTileMap
ld de, wTileMapBackup2
ld bc, $168
call CopyData
ret
LoadScreenTilesFromBuffer2:: ; 3701 (0:3701)
call LoadScreenTilesFromBuffer2DisableBGTransfer
ld a, $1
ld [H_AUTOBGTRANSFERENABLED], a ; $ffba
ret
; loads screen tiles stored in wTileMapBackup2 but leaves H_AUTOBGTRANSFERENABLED disabled
LoadScreenTilesFromBuffer2DisableBGTransfer:: ; 3709 (0:3709)
xor a
ld [H_AUTOBGTRANSFERENABLED], a ; $ffba
ld hl, wTileMapBackup2
ld de, wTileMap
ld bc, $168
call CopyData
ret
SaveScreenTilesToBuffer1:: ; 3719 (0:3719)
ld hl, wTileMap
ld de, wTileMapBackup
ld bc, $168
jp CopyData
LoadScreenTilesFromBuffer1:: ; 3725 (0:3725)
xor a
ld [H_AUTOBGTRANSFERENABLED], a ; $ffba
ld hl, wTileMapBackup
ld de, wTileMap
ld bc, $168
call CopyData
ld a, $1
ld [H_AUTOBGTRANSFERENABLED], a ; $ffba
ret
DelayFrames:: ; 3739 (0:3739)
; wait n frames, where n is the value in c
call DelayFrame
dec c
jr nz,DelayFrames
ret
PlaySoundWaitForCurrent:: ; 3740 (0:3740)
push af
call WaitForSoundToFinish
pop af
jp PlaySound
; Wait for sound to finish playing
WaitForSoundToFinish:: ; 3748 (0:3748)
ld a, [wd083]
2014-05-25 17:26:42 +00:00
and $80
ret nz
push hl
.asm_374f
ld hl, wc02a
2014-05-25 17:26:42 +00:00
xor a
or [hl]
inc hl
or [hl]
inc hl
inc hl
or [hl]
jr nz, .asm_374f
pop hl
ret
NamePointers:: ; 375d (0:375d)
dw MonsterNames
dw MoveNames
dw UnusedNames
dw ItemNames
dw W_PARTYMON1OT ; player's OT names list
dw W_ENEMYMON1OT ; enemy's OT names list
dw TrainerNames
GetName:: ; 376b (0:376b)
; arguments:
; [wd0b5] = which name
; [wd0b6] = which list (W_LISTTYPE)
; [wPredefBank] = bank of list
2014-05-25 17:26:42 +00:00
;
; returns pointer to name in de
ld a,[wd0b5]
ld [wd11e],a
2014-05-25 17:26:42 +00:00
cp a,$C4 ;it's TM/HM
jp nc,GetMachineName
ld a,[H_LOADEDROMBANK]
push af
push hl
push bc
push de
ld a,[W_LISTTYPE] ;List3759_entrySelector
dec a
jr nz,.otherEntries
;1 = MON_NAMES
call GetMonName
ld hl,11
add hl,de
ld e,l
ld d,h
jr .gotPtr
.otherEntries ; $378d
;2-7 = OTHER ENTRIES
ld a,[wPredefBank]
2014-05-25 17:26:42 +00:00
ld [H_LOADEDROMBANK],a
ld [$2000],a
ld a,[W_LISTTYPE] ;VariousNames' entryID
dec a
add a
ld d,0
ld e,a
jr nc,.skip
inc d
.skip ; $37a0
ld hl,NamePointers
add hl,de
ld a,[hli]
ld [$ff96],a
ld a,[hl]
ld [$ff95],a
ld a,[$ff95]
ld h,a
ld a,[$ff96]
ld l,a
ld a,[wd0b5]
2014-05-25 17:26:42 +00:00
ld b,a
ld c,0
.nextName
ld d,h
ld e,l
.nextChar
ld a,[hli]
cp a, "@"
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
2014-05-25 17:26:42 +00:00
ld bc,$0014
call CopyData
.gotPtr ; $37cd
ld a,e
ld [wcf8d],a
2014-05-25 17:26:42 +00:00
ld a,d
ld [wcf8e],a
2014-05-25 17:26:42 +00:00
pop de
pop bc
pop hl
pop af
ld [H_LOADEDROMBANK],a
ld [$2000],a
ret
GetItemPrice:: ; 37df (0:37df)
ld a, [H_LOADEDROMBANK]
push af
ld a, [wListMenuID] ; wListMenuID
2014-05-25 17:26:42 +00:00
cp $1
ld a, $1 ; hardcoded Bank
jr nz, .asm_37ed
ld a, $f ; hardcoded Bank
.asm_37ed
ld [H_LOADEDROMBANK], a
ld [$2000], a
ld hl, wcf8f
2014-05-25 17:26:42 +00:00
ld a, [hli]
ld h, [hl]
ld l, a
ld a, [wcf91]
2014-05-25 17:26:42 +00:00
cp HM_01
jr nc, .asm_3812
ld bc, $3
.asm_3802
add hl, bc
dec a
jr nz, .asm_3802
dec hl
ld a, [hld]
ld [$ff8d], a
ld a, [hld]
ld [H_DOWNARROWBLINKCNT2], a ; $ff8c
ld a, [hl]
ld [H_DOWNARROWBLINKCNT1], a ; $ff8b
jr .asm_381c
.asm_3812
ld a, Bank(GetMachinePrice)
ld [H_LOADEDROMBANK], a
ld [$2000], a
call GetMachinePrice
.asm_381c
ld de, H_DOWNARROWBLINKCNT1 ; $ff8b
pop af
ld [H_LOADEDROMBANK], a
ld [$2000], a
ret
; copies a string from [de] to [wcf4b]
2014-05-25 17:26:42 +00:00
CopyStringToCF4B:: ; 3826 (0:3826)
ld hl, wcf4b
2014-05-25 17:26:42 +00:00
; fall through
; copies a string from [de] to [hl]
CopyString:: ; 3829 (0:3829)
ld a, [de]
inc de
ld [hli], a
cp "@"
jr nz, CopyString
ret
; this function is used when lower button sensitivity is wanted (e.g. menus)
; OUTPUT: [$ffb5] = pressed buttons in usual format
; there are two flags that control its functionality, [$ffb6] and [$ffb7]
; there are esentially three modes of operation
; 1. Get newly pressed buttons only
; ([$ffb7] == 0, [$ffb6] == any)
2014-05-25 17:51:53 +00:00
; Just copies [hJoyPressed] to [$ffb5].
2014-05-25 17:26:42 +00:00
; 2. Get currently pressed buttons at low sample rate with delay
; ([$ffb7] == 1, [$ffb6] != 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.
; ([$ffb7] == 1, [$ffb6] == 0)
2014-05-25 18:21:48 +00:00
JoypadLowSensitivity:: ; 3831 (0:3831)
call Joypad
2014-05-25 17:26:42 +00:00
ld a,[$ffb7] ; flag
and a ; get all currently pressed buttons or only newly pressed buttons?
2014-05-25 17:51:53 +00:00
ld a,[hJoyPressed] ; newly pressed buttons
2014-05-25 17:26:42 +00:00
jr z,.storeButtonState
2014-05-25 17:51:53 +00:00
ld a,[hJoyHeld] ; all currently pressed buttons
2014-05-25 17:26:42 +00:00
.storeButtonState
ld [$ffb5],a
2014-05-25 17:51:53 +00:00
ld a,[hJoyPressed] ; newly pressed buttons
2014-05-25 17:26:42 +00:00
and a ; have any buttons been newly pressed since last check?
jr z,.noNewlyPressedButtons
.newlyPressedButtons
ld a,30 ; half a second delay
ld [H_FRAMECOUNTER],a
ret
.noNewlyPressedButtons
ld a,[H_FRAMECOUNTER]
and a ; is the delay over?
jr z,.delayOver
.delayNotOver
xor a
ld [$ffb5],a ; report no buttons as pressed
ret
.delayOver
; if [$ffb6] = 0 and A or B is pressed, report no buttons as pressed
2014-05-25 17:51:53 +00:00
ld a,[hJoyHeld]
2014-05-25 17:26:42 +00:00
and a,%00000011 ; A and B buttons
jr z,.setShortDelay
ld a,[$ffb6] ; flag
and a
jr nz,.setShortDelay
xor a
ld [$ffb5],a
.setShortDelay
ld a,5 ; 1/12 of a second delay
ld [H_FRAMECOUNTER],a
ret
WaitForTextScrollButtonPress:: ; 3865 (0:3865)
ld a, [H_DOWNARROWBLINKCNT1] ; $ff8b
push af
ld a, [H_DOWNARROWBLINKCNT2] ; $ff8c
push af
xor a
ld [H_DOWNARROWBLINKCNT1], a ; $ff8b
ld a, $6
ld [H_DOWNARROWBLINKCNT2], a ; $ff8c
.asm_3872
push hl
ld a, [wd09b]
2014-05-25 17:26:42 +00:00
and a
jr z, .asm_387c
call Func_716c6
.asm_387c
FuncCoord 18, 16
2014-05-25 17:26:42 +00:00
ld hl, Coord
call HandleDownArrowBlinkTiming
pop hl
2014-05-25 18:21:48 +00:00
call JoypadLowSensitivity
2014-05-25 17:26:42 +00:00
ld a, $2d
call Predef ; indirect jump to Func_5a5f (5a5f (1:5a5f))
ld a, [$ffb5]
and A_BUTTON | B_BUTTON
jr z, .asm_3872
pop af
ld [H_DOWNARROWBLINKCNT2], a ; $ff8c
pop af
ld [H_DOWNARROWBLINKCNT1], a ; $ff8b
ret
; (unlass in link battle) waits for A or B being pressed and outputs the scrolling sound effect
ManualTextScroll:: ; 3898 (0:3898)
ld a, [W_ISLINKBATTLE] ; W_ISLINKBATTLE
2014-05-25 17:26:42 +00:00
cp $4
jr z, .inLinkBattle
call WaitForTextScrollButtonPress
ld a, (SFX_02_40 - SFX_Headers_02) / 3
jp PlaySound
.inLinkBattle
ld c, $41
jp DelayFrames
; function to do multiplication
; all values are big endian
; INPUT
; FF96-FF98 = multiplicand
; FF99 = multiplier
; OUTPUT
; FF95-FF98 = product
Multiply:: ; 38ac (0:38ac)
push hl
push bc
callab _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:: ; 38b9 (0:38b9)
push hl
push de
push bc
ld a,[H_LOADEDROMBANK]
push af
ld a,Bank(_Divide)
ld [H_LOADEDROMBANK],a
ld [$2000],a
call _Divide
pop af
ld [H_LOADEDROMBANK],a
ld [$2000],a
pop bc
pop de
pop hl
ret
; 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 [wd358] flags.
2014-05-25 17:26:42 +00:00
PrintLetterDelay:: ; 38d3 (0:38d3)
ld a,[wd730]
2014-05-25 17:26:42 +00:00
bit 6,a
ret nz
ld a,[wd358]
2014-05-25 17:26:42 +00:00
bit 1,a
ret z
push hl
push de
push bc
ld a,[wd358]
2014-05-25 17:26:42 +00:00
bit 0,a
jr z,.waitOneFrame
ld a,[W_OPTIONS]
2014-05-25 17:26:42 +00:00
and a,$0f
ld [H_FRAMECOUNTER],a
jr .checkButtons
.waitOneFrame
ld a,1
ld [H_FRAMECOUNTER],a
.checkButtons
2014-05-25 18:21:48 +00:00
call Joypad
2014-05-25 17:51:53 +00:00
ld a,[hJoyHeld]
2014-05-25 17:26:42 +00:00
.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
ld a,[H_FRAMECOUNTER]
and a
jr nz,.checkButtons
.done
pop bc
pop de
pop hl
ret
; Copies [hl, bc) to [de, bc - hl).
; In other words, the source data is from hl up to but not including bc,
; and the destination is de.
CopyDataUntil:: ; 3913 (0:3913)
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.
; [wcf95] == 0 specifies the party.
; [wcf95] != 0 specifies the current box.
2014-05-25 17:26:42 +00:00
RemovePokemon:: ; 391f (0:391f)
ld hl, _RemovePokemon
ld b, BANK(_RemovePokemon)
jp Bankswitch
AddPokemonToParty:: ; 3927 (0:3927)
push hl
push de
push bc
callba _AddPokemonToParty
pop bc
pop de
pop hl
ret
; calculates all 5 stats of current mon and writes them to [de]
CalcStats:: ; 3936 (0:3936)
ld c, $0
.statsLoop
inc c
call CalcStat
ld a, [H_MULTIPLICAND+1]
ld [de], a
inc de
ld a, [H_MULTIPLICAND+2]
ld [de], a
inc de
ld a, c
cp $5
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:: ; 394a (0:394a)
push hl
push de
push bc
ld a, b
ld d, a
push hl
ld hl, W_MONHEADER
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
ld [H_MULTIPLICAND], a
ld [H_MULTIPLICAND+1], a
inc b ; increment current stat exp bonus
ld a, b
cp $ff
jr z, .statExpDone
ld [H_MULTIPLICAND+2], a
ld [H_MULTIPLIER], a
call Multiply
ld a, [hld]
ld d, a
ld a, [$ff98]
sub d
ld a, [hli]
ld d, a
ld a, [$ff97]
sbc d ; test if (current stat exp bonus)^2 < stat exp
jr c, .statExpLoop
.statExpDone
srl c
pop hl
push bc
ld bc, $b ; skip to stat IV values
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 ; da = (Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4
.noCarry2
ld [H_MULTIPLICAND+2], a
ld a, d
ld [H_MULTIPLICAND+1], a
xor a
ld [H_MULTIPLICAND], a
ld a, [W_CURENEMYLVL] ; W_CURENEMYLVL
2014-05-25 17:26:42 +00:00
ld [H_MULTIPLIER], a
call Multiply ; ((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level
ld a, [H_MULTIPLICAND]
ld [H_DIVIDEND], a
ld a, [H_MULTIPLICAND+1]
ld [H_DIVIDEND+1], a
ld a, [H_MULTIPLICAND+2]
ld [H_DIVIDEND+2], a
ld a, $64
ld [H_DIVISOR], 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
jr nz, .notHPStat
ld a, [W_CURENEMYLVL] ; W_CURENEMYLVL
2014-05-25 17:26:42 +00:00
ld b, a
ld a, [H_MULTIPLICAND+2]
add b
ld [H_MULTIPLICAND+2], a
jr nc, .noCarry3
ld a, [H_MULTIPLICAND+1]
inc a
ld [H_MULTIPLICAND+1], a ; HP: (((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level) / 100 + Level
.noCarry3
ld a, $a
.notHPStat
ld b, a
ld a, [H_MULTIPLICAND+2]
add b
ld [H_MULTIPLICAND+2], a
jr nc, .noCarry4
ld a, [H_MULTIPLICAND+1]
inc a ; non-HP: (((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level) / 100 + 5
ld [H_MULTIPLICAND+1], a ; HP: (((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level) / 100 + Level + 10
.noCarry4
ld a, [H_MULTIPLICAND+1] ; check for overflow (>999)
cp $4
jr nc, .overflow
cp $3
jr c, .noOverflow
ld a, [H_MULTIPLICAND+2]
cp $e8
jr c, .noOverflow
.overflow
ld a, $3 ; overflow: cap at 999
ld [H_MULTIPLICAND+1], a
ld a, $e7
ld [H_MULTIPLICAND+2], a
.noOverflow
pop bc
pop de
pop hl
ret
AddEnemyMonToPlayerParty:: ; 3a53 (0:3a53)
ld a, [H_LOADEDROMBANK]
push af
ld a, BANK(_AddEnemyMonToPlayerParty)
ld [H_LOADEDROMBANK], a
ld [$2000], a
call _AddEnemyMonToPlayerParty
pop bc
ld a, b
ld [H_LOADEDROMBANK], a
ld [$2000], a
ret
Func_3a68:: ; 3a68 (0:3a68)
ld a, [H_LOADEDROMBANK]
push af
ld a, BANK(Func_f51e)
ld [H_LOADEDROMBANK], a
ld [$2000], a
call Func_f51e
pop bc
ld a, b
ld [H_LOADEDROMBANK], a
ld [$2000], a
ret
; skips a text entries, each of size $b (like trainer name, OT name, rival name, ...)
; hl: base pointer, will be incremented by $b * a
SkipFixedLengthTextEntries:: ; 3a7d (0:3a7d)
and a
ret z
ld bc, $b
.skipLoop
add hl, bc
dec a
jr nz, .skipLoop
ret
AddNTimes:: ; 3a87 (0:3a87)
; add bc to hl a times
and a
ret z
.loop
add hl,bc
dec a
jr nz,.loop
ret
; Compare strings, c bytes in length, at de and hl.
; Often used to compare big endian numbers in battle calculations.
StringCmp:: ; 3a8e (0:3a8e)
ld a,[de]
cp [hl]
ret nz
inc de
inc hl
dec c
jr nz,StringCmp
ret
; 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:: ; 3a97 (0:3a97)
2014-05-27 18:08:52 +00:00
ld h,wOAMBuffer / $100
2014-05-25 17:26:42 +00:00
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
HandleMenuInput:: ; 3abe (0:3abe)
xor a
ld [wd09b],a
2014-05-25 17:26:42 +00:00
HandleMenuInputPokemonSelection:: ; 3ac2 (0:3ac2)
ld a,[H_DOWNARROWBLINKCNT1]
push af
ld a,[H_DOWNARROWBLINKCNT2]
push af ; save existing values on stack
xor a
ld [H_DOWNARROWBLINKCNT1],a ; blinking down arrow timing value 1
ld a,$06
ld [H_DOWNARROWBLINKCNT2],a ; blinking down arrow timing value 2
.loop1
xor a
ld [W_SUBANIMTRANSFORM],a ; counter for pokemon shaking animation
2014-05-25 17:26:42 +00:00
call PlaceMenuCursor
call Delay3
.loop2
push hl
ld a,[wd09b]
2014-05-25 17:26:42 +00:00
and a ; is it a pokemon selection menu?
jr z,.getJoypadState
callba AnimatePartyMon ; shake mini sprite of selected pokemon
.getJoypadState
pop hl
2014-05-25 18:21:48 +00:00
call JoypadLowSensitivity
2014-05-25 17:26:42 +00:00
ld a,[$ffb5]
and a ; was a key pressed?
jr nz,.keyPressed
push hl
FuncCoord 18,11 ; coordinates of blinking down arrow in some menus
ld hl,Coord
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
ld [H_DOWNARROWBLINKCNT2],a
pop af
ld [H_DOWNARROWBLINKCNT1],a ; restore previous values
xor a
ld [wMenuWrappingEnabled],a ; disable menu wrapping
ret
.keyPressed
xor a
ld [wcc4b],a
2014-05-25 17:26:42 +00:00
ld a,[$ffb5]
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
ld a,[$ffb5]
and a,%00000011 ; pressed A button or B button?
jr z,.skipPlayingSound
.AButtonOrBButtonPressed
push hl
ld hl,wFlags_0xcd60
bit 5,[hl]
pop hl
jr nz,.skipPlayingSound
ld a,(SFX_02_40 - SFX_Headers_02) / 3
call PlaySound ; play sound
.skipPlayingSound
pop af
ld [H_DOWNARROWBLINKCNT2],a
pop af
ld [H_DOWNARROWBLINKCNT1],a ; restore previous values
xor a
ld [wMenuWrappingEnabled],a ; disable menu wrapping
ld a,[$ffb5]
ret
.noWrappingAround
ld a,[wcc37]
2014-05-25 17:26:42 +00:00
and a ; should we return if the user tried to go past the top or bottom?
jr z,.checkOtherKeys
jr .checkIfAButtonOrBButtonPressed
PlaceMenuCursor:: ; 3b7c (0:3b7c)
ld a,[wTopMenuItemY]
and a ; is the y coordinate 0?
jr z,.adjustForXCoord
ld hl,wTileMap
ld bc,20 ; screen width
.topMenuItemLoop
add hl,bc
dec a
jr nz,.topMenuItemLoop
.adjustForXCoord
ld a,[wTopMenuItemX]
ld b,$00
ld c,a
add hl,bc
push hl
ld a,[wLastMenuItem]
and a ; was the previous menu id 0?
jr z,.checkForArrow1
push af
ld a,[$fff6]
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 a,"▶" ; 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
ld a,[$fff6]
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 a,"▶" ; 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:: ; 3bec (0:3bec)
ld b,a
ld a,[wMenuCursorLocation]
ld l,a
ld a,[wMenuCursorLocation + 1]
ld h,a
ld [hl],$ec ; outline of right arrow
ld a,b
ret
; Replaces the menu cursor with a blank space.
EraseMenuCursor:: ; 3bf9 (0:3bf9)
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 H_DOWNARROWBLINKCNT1 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
; initliazed 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:: ; 3c04 (0:3c04)
ld a,[hl]
ld b,a
ld a,$ee ; down arrow
cp b
jr nz,.downArrowOff
.downArrowOn
ld a,[H_DOWNARROWBLINKCNT1]
dec a
ld [H_DOWNARROWBLINKCNT1],a
ret nz
ld a,[H_DOWNARROWBLINKCNT2]
dec a
ld [H_DOWNARROWBLINKCNT2],a
ret nz
ld a," "
ld [hl],a
ld a,$ff
ld [H_DOWNARROWBLINKCNT1],a
ld a,$06
ld [H_DOWNARROWBLINKCNT2],a
ret
.downArrowOff
ld a,[H_DOWNARROWBLINKCNT1]
and a
ret z
dec a
ld [H_DOWNARROWBLINKCNT1],a
ret nz
dec a
ld [H_DOWNARROWBLINKCNT1],a
ld a,[H_DOWNARROWBLINKCNT2]
dec a
ld [H_DOWNARROWBLINKCNT2],a
ret nz
ld a,$06
ld [H_DOWNARROWBLINKCNT2],a
ld a,$ee ; down arrow
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 [wcc47] is set).
2014-05-25 17:26:42 +00:00
EnableAutoTextBoxDrawing:: ; 3c3c (0:3c3c)
xor a
jr AutoTextBoxDrawingCommon
DisableAutoTextBoxDrawing:: ; 3c3f (0:3c3f)
ld a,$01
AutoTextBoxDrawingCommon:: ; 3c41 (0:3c41)
ld [wcf0c],a ; control text box drawing
2014-05-25 17:26:42 +00:00
xor a
ld [wcc3c],a ; make DisplayTextID wait for button press
2014-05-25 17:26:42 +00:00
ret
PrintText:: ; 3c49 (0:3c49)
; given a pointer in hl, print the text there
push hl
ld a,1
ld [wd125],a
2014-05-25 17:26:42 +00:00
call DisplayTextBoxID
call UpdateSprites
call Delay3
pop hl
Func_3c59:: ; 3c59 (0:3c59)
FuncCoord 1,14
ld bc,Coord
2014-05-25 17:26:42 +00:00
jp TextCommandProcessor
; converts a big-endian binary number into decimal and prints it
; INPUT:
; b = flags and number of bytes
; bit 7: if set, print leading zeroes
; if unset, do not print leading zeroes
; bit 6: if set, left-align the string (do not pad empty digits with spaces)
; if unset, right-align the string
; bits 4-5: unused
; bits 0-3: number of bytes (only 1 - 3 bytes supported)
; c = number of decimal digits
; de = address of the number (big-endian)
PrintNumber:: ; 3c5f (0:3c5f)
push bc
xor a
ld [H_PASTLEADINGZEROES],a
ld [H_NUMTOPRINT],a
ld [H_NUMTOPRINT + 1],a
ld a,b
and a,%00001111
cp a,1
jr z,.oneByte
cp a,2
jr z,.twoBytes
.threeBytes
ld a,[de]
ld [H_NUMTOPRINT],a
inc de
ld a,[de]
ld [H_NUMTOPRINT + 1],a
inc de
ld a,[de]
ld [H_NUMTOPRINT + 2],a
jr .checkNumDigits
.twoBytes
ld a,[de]
ld [H_NUMTOPRINT + 1],a
inc de
ld a,[de]
ld [H_NUMTOPRINT + 2],a
jr .checkNumDigits
.oneByte
ld a,[de]
ld [H_NUMTOPRINT + 2],a
.checkNumDigits
push de
ld d,b
ld a,c
ld b,a
xor a
ld c,a
ld a,b ; a = number of decimal digits
cp a,2
jr z,.tensPlace
cp a,3
jr z,.hundredsPlace
cp a,4
jr z,.thousandsPlace
cp a,5
jr z,.tenThousandsPlace
cp a,6
jr z,.hundredThousandsPlace
.millionsPlace
ld a,1000000 >> 16
ld [H_POWEROFTEN],a
ld a,(1000000 >> 8) & $FF
ld [H_POWEROFTEN + 1],a
ld a,1000000 & $FF
ld [H_POWEROFTEN + 2],a
call PrintNumber_PrintDigit
call PrintNumber_AdvancePointer
.hundredThousandsPlace
ld a,100000 >> 16
ld [H_POWEROFTEN],a
ld a,(100000 >> 8) & $FF
ld [H_POWEROFTEN + 1],a
ld a,100000 & $FF
ld [H_POWEROFTEN + 2],a
call PrintNumber_PrintDigit
call PrintNumber_AdvancePointer
.tenThousandsPlace
xor a
ld [H_POWEROFTEN],a
ld a,10000 >> 8
ld [H_POWEROFTEN + 1],a
ld a,10000 & $FF
ld [H_POWEROFTEN + 2],a
call PrintNumber_PrintDigit
call PrintNumber_AdvancePointer
.thousandsPlace
xor a
ld [H_POWEROFTEN],a
ld a,1000 >> 8
ld [H_POWEROFTEN + 1],a
ld a,1000 & $FF
ld [H_POWEROFTEN + 2],a
call PrintNumber_PrintDigit
call PrintNumber_AdvancePointer
.hundredsPlace
xor a
ld [H_POWEROFTEN],a
xor a
ld [H_POWEROFTEN + 1],a
ld a,100
ld [H_POWEROFTEN + 2],a
call PrintNumber_PrintDigit
call PrintNumber_AdvancePointer
.tensPlace
ld c,00
ld a,[H_NUMTOPRINT + 2]
.loop
cp a,10
jr c,.underflow
sub a,10
inc c
jr .loop
.underflow
ld b,a
ld a,[H_PASTLEADINGZEROES]
or c
ld [H_PASTLEADINGZEROES],a
jr nz,.pastLeadingZeroes
call PrintNumber_PrintLeadingZero
jr .advancePointer
.pastLeadingZeroes
ld a,"0"
add c
ld [hl],a
.advancePointer
call PrintNumber_AdvancePointer
.onesPlace
ld a,"0"
add b
ld [hli],a
pop de
dec de
pop bc
ret
; prints a decimal digit
; This works by repeatedely subtracting a power of ten until the number becomes negative.
; The number of subtractions it took in order to make the number negative is the digit for the current number place.
; The last value that the number had before becoming negative is kept as the new value of the number.
; A more succinct description is that the number is divided by a power of ten
; and the quotient becomes the digit while the remainder is stored as the new value of the number.
PrintNumber_PrintDigit:: ; 3d25 (0:3d25)
ld c,0 ; counts number of loop iterations to determine the decimal digit
.loop
ld a,[H_POWEROFTEN]
ld b,a
ld a,[H_NUMTOPRINT]
ld [H_SAVEDNUMTOPRINT],a
cp b
jr c,.underflow0
sub b
ld [H_NUMTOPRINT],a
ld a,[H_POWEROFTEN + 1]
ld b,a
ld a,[H_NUMTOPRINT + 1]
ld [H_SAVEDNUMTOPRINT + 1],a
cp b
jr nc,.noBorrowForByte1
.byte1BorrowFromByte0
ld a,[H_NUMTOPRINT]
or a,0
jr z,.underflow1
dec a
ld [H_NUMTOPRINT],a
ld a,[H_NUMTOPRINT + 1]
.noBorrowForByte1
sub b
ld [H_NUMTOPRINT + 1],a
ld a,[H_POWEROFTEN + 2]
ld b,a
ld a,[H_NUMTOPRINT + 2]
ld [H_SAVEDNUMTOPRINT + 2],a
cp b
jr nc,.noBorrowForByte2
.byte2BorrowFromByte1
ld a,[H_NUMTOPRINT + 1]
and a
jr nz,.finishByte2BorrowFromByte1
.byte2BorrowFromByte0
ld a,[H_NUMTOPRINT]
and a
jr z,.underflow2
dec a
ld [H_NUMTOPRINT],a
xor a
.finishByte2BorrowFromByte1
dec a
ld [H_NUMTOPRINT + 1],a
ld a,[H_NUMTOPRINT + 2]
.noBorrowForByte2
sub b
ld [H_NUMTOPRINT + 2],a
inc c
jr .loop
.underflow2
ld a,[H_SAVEDNUMTOPRINT + 1]
ld [H_NUMTOPRINT + 1],a
.underflow1
ld a,[H_SAVEDNUMTOPRINT]
ld [H_NUMTOPRINT],a
.underflow0
ld a,[H_PASTLEADINGZEROES]
or c
jr z,PrintNumber_PrintLeadingZero
ld a,"0"
add c
ld [hl],a
ld [H_PASTLEADINGZEROES],a
ret
; prints a leading zero unless they are turned off in the flags
PrintNumber_PrintLeadingZero:: ; 3d83 (0:3d83)
bit 7,d ; print leading zeroes?
ret z
ld [hl],"0"
ret
; increments the pointer unless leading zeroes are not being printed,
; the number is left-aligned, and no nonzero digits have been printed yet
PrintNumber_AdvancePointer:: ; 3d89 (0:3d89)
bit 7,d ; print leading zeroes?
jr nz,.incrementPointer
bit 6,d ; left alignment or right alignment?
jr z,.incrementPointer
ld a,[H_PASTLEADINGZEROES]
and a
ret z
.incrementPointer
inc hl
ret
; calls a function from a table of function pointers
; INPUT:
; a = index within table
; hl = address of function pointer table
CallFunctionInTable:: ; 3d97 (0:3d97)
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
Func_3dbe:: ; 3dbe (0:3dbe)
call ClearSprites
ld a, $1
ld [wcfcb], a
2014-05-25 17:26:42 +00:00
call Func_3e08
call LoadScreenTilesFromBuffer2
call LoadTextBoxTilePatterns
call GoPAL_SET_CF1C
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
ld [rBGP], a
ld a, %11010000 ; 3100
ld [rOBP0], a
ret
GBPalWhiteOut::
; White out all palettes.
xor a
ld [rBGP],a
ld [rOBP0],a
ld [rOBP1],a
ret
GoPAL_SET_CF1C:: ; 3ded (0:3ded)
ld b,$ff
GoPAL_SET:: ; 3def (0:3def)
ld a,[wcf1b]
2014-05-25 17:26:42 +00:00
and a
ret z
ld a,$45
jp Predef
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
Func_3e08:: ; 3e08 (0:3e08)
ld hl, wcfc4
2014-05-25 17:26:42 +00:00
ld a, [hl]
push af
res 0, [hl]
push hl
xor a
ld [W_SPRITESETID], a ; W_SPRITESETID
2014-05-25 17:26:42 +00:00
call DisableLCD
callba InitMapSprites
call EnableLCD
pop hl
pop af
ld [hl], a
call LoadPlayerSpriteGraphics
call LoadFontTilePatterns
jp UpdateSprites
GiveItem::
; Give player quantity c of item b,
; and copy the item's name to wcf4b.
2014-05-25 17:26:42 +00:00
; Return carry on success.
ld a, b
ld [wd11e], a
ld [wcf91], a
2014-05-25 17:26:42 +00:00
ld a, c
ld [wcf96], a
2014-05-25 17:26:42 +00:00
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
2014-05-25 17:26:42 +00:00
ld a, c
ld [W_CURENEMYLVL], a
2014-05-25 17:26:42 +00:00
xor a
ld [wcc49], a
2014-05-25 17:26:42 +00:00
ld b, BANK(_GivePokemon)
ld hl, _GivePokemon
jp Bankswitch
Random::
; Return a random number in a.
; For battles, use BattleRandom.
push hl
push de
push bc
callba Random_
ld a,[hRandomAdd]
pop bc
pop de
pop hl
ret
Predef::
; Call predefined function a.
; To preserve other registers, have the
; destination call GetPredefRegisters.
; Save the predef id for GetPredefPointer.
ld [wPredefID], a
; A hack for LoadDestinationWarpPosition.
; See Func_c754 (predef $19).
ld a, [H_LOADEDROMBANK]
ld [wPredefParentBank], a
push af
ld a, BANK(GetPredefPointer)
ld [H_LOADEDROMBANK], a
ld [$2000], a
call GetPredefPointer
ld a, [wPredefBank]
ld [H_LOADEDROMBANK], a
ld [$2000], a
ld de, .done
push de
jp [hl]
.done
pop af
ld [H_LOADEDROMBANK], a
ld [$2000], a
ret
GetPredefRegisters::
; Restore the contents of register pairs
; when GetPredefPointer was called.
ld a, [wPredefRegisters + 0]
ld h, a
ld a, [wPredefRegisters + 1]
ld l, a
ld a, [wPredefRegisters + 2]
ld d, a
ld a, [wPredefRegisters + 3]
ld e, a
ld a, [wPredefRegisters + 4]
ld b, a
ld a, [wPredefRegisters + 5]
ld c, a
ret
Func_3ead:: ; 3ead (0:3ead)
ld b, BANK(CinnabarGymQuiz_1eb0a)
ld hl, CinnabarGymQuiz_1eb0a
jp Bankswitch
Func_3eb5:: ; 3eb5 (0:3eb5)
ld a, [H_LOADEDROMBANK]
push af
2014-05-25 17:51:53 +00:00
ld a, [hJoyHeld]
2014-05-25 17:26:42 +00:00
bit 0, a
jr z, .asm_3eea
ld a, Bank(Func_469a0)
ld [$2000], a
ld [H_LOADEDROMBANK], a
call Func_469a0
ld a, [$ffee]
and a
jr nz, .asm_3edd
ld a, [wTrainerEngageDistance]
2014-05-25 17:26:42 +00:00
ld [$2000], a
ld [H_LOADEDROMBANK], a
ld de, .asm_3eda
push de
jp [hl]
.asm_3eda
xor a
jr .asm_3eec
.asm_3edd
callba PrintBookshelfText
ld a, [$ffdb]
and a
jr z, .asm_3eec
.asm_3eea
ld a, $ff
.asm_3eec
ld [$ffeb], a
pop af
ld [$2000], a
ld [H_LOADEDROMBANK], a
ret
PrintPredefTextID:: ; 3ef5 (0:3ef5)
ld [H_DOWNARROWBLINKCNT2], a ; $ff8c
ld hl, PointerTable_3f22
call Func_3f0f
ld hl, wcf11
2014-05-25 17:26:42 +00:00
set 0, [hl]
call DisplayTextID
Func_3f05:: ; 3f05 (0:3f05)
ld hl, W_MAPTEXTPTR ; wd36c
2014-05-25 17:26:42 +00:00
ld a, [$ffec]
ld [hli], a
ld a, [$ffed]
ld [hl], a
ret
Func_3f0f:: ; 3f0f (0:3f0f)
ld a, [W_MAPTEXTPTR] ; wd36c
2014-05-25 17:26:42 +00:00
ld [$ffec], a
ld a, [W_MAPTEXTPTR + 1]
2014-05-25 17:26:42 +00:00
ld [$ffed], a
ld a, l
ld [W_MAPTEXTPTR], a ; wd36c
2014-05-25 17:26:42 +00:00
ld a, h
ld [W_MAPTEXTPTR + 1], a
2014-05-25 17:26:42 +00:00
ret
PointerTable_3f22:: ; 3f22 (0:3f22)
dw CardKeySuccessText ; id = 01
dw CardKeyFailText ; id = 02
dw RedBedroomPC ; id = 03
dw RedBedroomSNESText ; id = 04
dw PushStartText ; id = 05
dw SaveOptionText ; id = 06
dw StrengthsAndWeaknessesText ; id = 07
dw OakLabEmailText ; id = 08
dw AerodactylFossilText ; id = 09
dw Route15UpstairsBinocularsText ; id = 0A
dw KabutopsFossilText ; id = 0B
dw GymStatueText1 ; id = 0C
dw GymStatueText2 ; id = 0D
dw BookcaseText ; id = 0E
dw ViridianCityPokecenterBenchGuyText ; id = 0F
dw PewterCityPokecenterBenchGuyText ; id = 10
dw CeruleanCityPokecenterBenchGuyText ; id = 11
dw LavenderCityPokecenterBenchGuyText ; id = 12
dw VermilionCityPokecenterBenchGuyText ; id = 13
dw CeladonCityPokecenterBenchGuyText ; id = 14
dw CeladonCityHotelText ; id = 15
dw FuchsiaCityPokecenterBenchGuyText ; id = 16
dw CinnabarIslandPokecenterBenchGuyText ; id = 17
dw SaffronCityPokecenterBenchGuyText ; id = 18
dw MtMoonPokecenterBenchGuyText ; id = 19
dw RockTunnelPokecenterBenchGuyText ; id = 1A
dw UnusedBenchGuyText1 ; id = 1B
dw UnusedBenchGuyText2 ; id = 1C
dw UnusedBenchGuyText3 ; id = 1D
dw TerminatorText_62508 ; id = 1E
dw PredefText1f ; id = 1F
dw ViridianSchoolNotebook ; id = 20
dw ViridianSchoolBlackboard ; id = 21
dw JustAMomentText ; id = 22
dw PredefText23 ; id = 23
dw FoundHiddenItemText ; id = 24
dw HiddenItemBagFullText ; id = 25
dw VermilionGymTrashText ; id = 26
dw IndigoPlateauHQText ; id = 27
dw GameCornerOutOfOrderText ; id = 28
dw GameCornerOutToLunchText ; id = 29
dw GameCornerSomeonesKeysText ; id = 2A
dw FoundHiddenCoinsText ; id = 2B
dw DroppedHiddenCoinsText ; id = 2C
dw BillsHouseMonitorText ; id = 2D
dw BillsHouseInitiatedText ; id = 2E
dw BillsHousePokemonList ; id = 2F
dw MagazinesText ; id = 30
dw CinnabarGymQuiz ; id = 31
dw GameCornerNoCoinsText ; id = 32
dw GameCornerCoinCaseText ; id = 33
dw LinkCableHelp ; id = 34
dw TMNotebook ; id = 35
dw FightingDojoText ; id = 36
dw FightingDojoText_52a10 ; id = 37
dw FightingDojoText_52a1d ; id = 38
dw NewBicycleText ; id = 39
dw IndigoPlateauStatues ; id = 3A
dw VermilionGymTrashSuccesText1 ; id = 3B
dw VermilionGymTrashSuccesText2 ; id = 3C
dw VermilionGymTrashSuccesText3 ; id = 3D
dw VermilionGymTrashFailText ; id = 3E
dw TownMapText ; id = 3F
dw BookOrSculptureText ; id = 40
dw ElevatorText ; id = 41
dw PokemonStuffText ; id = 42