ref: 96db7d1cd78232f345eb74bc2c91ad5698d1b11f
parent: 3f61e9bd0e07a7930b81911efb098c105e9d32f8
author: YamaArashi <shadow962@live.com>
date: Thu Jan 26 05:31:04 EST 2012
diasm of some bank 0 code (mostly menu related) hg-commit-id: f22d2b2ca017
--- a/constants.asm
+++ b/constants.asm
@@ -89,9 +89,36 @@
; wram locations
+; coordinates of the position of the cursor for the top menu item (id 0)
+W_TOPMENUITEMY EQU $CC24
+W_TOPMENUITEMX EQU $CC25
+
+; the id of the currently selected menu item
+; the top item has id 0, the one below that has id 1, etc.
+W_CURMENUITEMID EQU $CC26
+
+; the tile that was behind the menu cursor's current location
+W_TILEBEHINDCURSOR EQU $CC27
+
+W_MAXMENUITEMID EQU $CC28 ; id of the bottom menu item
+
+W_MENUWATCHEDKEYS EQU $CC29 ; bit mask of keys that the menu will respond to
+
+W_OLDMENUITEMID EQU $CC2A ; id of previously selected menu item
+
+; how many times should HandleMenuInput poll the joypad state before it returns?
+W_MENUJOYPADPOLLCOUNT EQU $CC34
+
W_PLAYERMOVELISTINDEX EQU $CC2E
W_PLAYERMONNUMBER EQU $CC2F
+; the address of the menu cursor's current location within C3A0-C507
+W_MENUCURSORLOCATION EQU $CC30 ; 2 bytes
+
+; set to 1 if you can go from the bottom to the top or top to bottom of a menu
+; set to 0 if you can't go past the top or bottom of the menu
+W_MENUWRAPPINGENABLED EQU $CC4A
+
; current HP of player and enemy substitutes
W_PLAYERSUBSITUTEHP EQU $CCD7
W_ENEMYSUBSITUTEHP EQU $CCD8
@@ -698,6 +725,10 @@
W_SAFARITIMER1 EQU $D70D ; use 01 for maximum
W_SAFARITIMER2 EQU $D70E ; use F4 for maximum
+
+; counters for blinking down arrow
+H_DOWNARROWBLINKCNT1 EQU $FF8B
+H_DOWNARROWBLINKCNT2 EQU $FF8C
; Note: the following multiplication and division addresses are used for multiple purposes
; and so they overlap with each other
--- a/main.asm
+++ b/main.asm
@@ -4847,7 +4847,338 @@
jr nz,.loop\@
ret
-INCBIN "baserom.gbc",$3A8E,$3C49 - $3A8E
+; Compare strings, c bytes in length, at de and hl.
+; Often used to compare big endian numbers in battle calculations.
+StringCmp: ; 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
+ ld h,$c3
+ 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
+ xor a
+ ld [$d09b],a
+
+HandleMenuInputPokemonSelection: ; 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 [$d08b],a ; counter for pokemon shaking animation
+ call PlaceMenuCursor
+ call Delay3
+.loop2\@
+ push hl
+ ld a,[$d09b]
+ and a ; is it a pokemon selection menu?
+ jr z,.getJoypadState\@
+ ld b,$1c
+ ld hl,$56ff ; shake mini sprite of selected pokemon
+ call Bankswitch
+.getJoypadState\@
+ pop hl
+ call GetJoypadStateLowSensitivity
+ 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 $3c04 ; blink down arrow (if any)
+ pop hl
+ ld a,[W_MENUJOYPADPOLLCOUNT]
+ 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 [W_MENUWRAPPINGENABLED],a ; disable menu wrapping
+ ret
+.keyPressed\@
+ xor a
+ ld [$cc4b],a
+ ld a,[$ffb5]
+ ld b,a
+ bit 6,a ; pressed Up key?
+ jr z,.checkIfDownPressed\@
+.upPressed\@
+ ld a,[W_CURMENUITEMID] ; selected menu item
+ and a ; already at the top of the menu?
+ jr z,.alreadyAtTop\@
+.notAtTop\@
+ dec a
+ ld [W_CURMENUITEMID],a ; move selected menu item up one space
+ jr .checkOtherKeys\@
+.alreadyAtTop\@
+ ld a,[W_MENUWRAPPINGENABLED]
+ and a ; is wrapping around enabled?
+ jr z,.noWrappingAround\@
+ ld a,[W_MAXMENUITEMID]
+ ld [W_CURMENUITEMID],a ; wrap to the bottom of the menu
+ jr .checkOtherKeys\@
+.checkIfDownPressed\@
+ bit 7,a
+ jr z,.checkOtherKeys\@
+.downPressed\@
+ ld a,[W_CURMENUITEMID]
+ inc a
+ ld c,a
+ ld a,[W_MAXMENUITEMID]
+ cp c
+ jr nc,.notAtBottom\@
+.alreadyAtBottom\@
+ ld a,[W_MENUWRAPPINGENABLED]
+ and a ; is wrapping around enabled?
+ jr z,.noWrappingAround\@
+ ld c,$00 ; wrap from bottom to top
+.notAtBottom\@
+ ld a,c
+ ld [W_CURMENUITEMID],a
+.checkOtherKeys\@
+ ld a,[W_MENUWATCHEDKEYS]
+ 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,$cd60
+ bit 5,[hl]
+ pop hl
+ jr nz,.skipPlayingSound\@
+ ld a,$90
+ call $23b1 ; play sound
+.skipPlayingSound\@
+ pop af
+ ld [H_DOWNARROWBLINKCNT2],a
+ pop af
+ ld [H_DOWNARROWBLINKCNT1],a ; restore previous values
+ xor a
+ ld [W_MENUWRAPPINGENABLED],a ; disable menu wrapping
+ ld a,[$ffb5]
+ ret
+.noWrappingAround\@
+ ld a,[$cc37]
+ and a ; should we return if the user tried to go past the top or bottom?
+ jr z,.checkOtherKeys\@
+ jr .checkIfAButtonOrBButtonPressed\@
+
+PlaceMenuCursor: ; 3B7C
+ ld a,[W_TOPMENUITEMY]
+ and a ; is the y coordinate 0?
+ jr z,.adjustForXCoord\@
+ ld hl,$c3a0
+ ld bc,20 ; screen width
+.topMenuItemLoop\@
+ add hl,bc
+ dec a
+ jr nz,.topMenuItemLoop\@
+.adjustForXCoord\@
+ ld a,[W_TOPMENUITEMX]
+ ld b,$00
+ ld c,a
+ add hl,bc
+ push hl
+ ld a,[W_OLDMENUITEMID]
+ 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,$ed ; was an arrow next to the previously selected menu item?
+ jr nz,.skipClearingArrow\@
+.clearArrow\@
+ ld a,[W_TILEBEHINDCURSOR]
+ ld [hl],a
+.skipClearingArrow\@
+ pop hl
+ ld a,[W_CURMENUITEMID]
+ 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,$ed ; has the right arrow already been placed?
+ jr z,.skipSavingTile\@ ; if so, don't lose the saved tile
+ ld [W_TILEBEHINDCURSOR],a ; save tile before overwriting with right arrow
+.skipSavingTile\@
+ ld a,$ed ; place right arrow
+ ld [hl],a
+ ld a,l
+ ld [W_MENUCURSORLOCATION],a
+ ld a,h
+ ld [W_MENUCURSORLOCATION + 1],a
+ ld a,[W_CURMENUITEMID]
+ ld [W_OLDMENUITEMID],a
+ ret
+
+; Used when swapping positions of items in a list menu.
+; The item that the user selects first is marked with an outline of a right arrow
+; to distinguish it from the arrow being used to select the second item.
+PlaceUnfilledArrowMenuCursor: ; 3BEC
+ ld b,a
+ ld a,[W_MENUCURSORLOCATION]
+ ld l,a
+ ld a,[W_MENUCURSORLOCATION + 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
+ ld a,[W_MENUCURSORLOCATION]
+ ld l,a
+ ld a,[W_MENUCURSORLOCATION + 1]
+ ld h,a
+ ld [hl],$7f ; blank space
+ 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
+ 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,$7f ; blank space
+ 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 [$cc47] is set).
+
+EnableAutoTextBoxDrawing: ; 3C3C
+ xor a
+ jr AutoTextBoxDrawingCommon
+
+DisableAutoTextBoxDrawing: ; 3C3F
+ ld a,$01
+
+AutoTextBoxDrawingCommon: ; 3C41
+ ld [$cf0c],a ; control text box drawing
+ xor a
+ ld [$cc3c],a ; make DisplayTextID wait for button press
+ ret
PrintText: ; 3C49
; given a pointer in hl, print the text there