mirror of
https://github.com/pret/pokered.git
synced 2024-10-23 06:58:24 +00:00
10171 lines
196 KiB
NASM
10171 lines
196 KiB
NASM
; 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
|
||
|
||
|
||
ReadJoypad::
|
||
; Poll joypad input.
|
||
; Unlike the hardware register, button
|
||
; presses are indicated by a set bit.
|
||
|
||
ld a, 1 << 5 ; select direction keys
|
||
ld c, 0
|
||
|
||
ld [rJOYP], a
|
||
rept 6
|
||
ld a, [rJOYP]
|
||
endr
|
||
cpl
|
||
and %1111
|
||
swap a
|
||
ld b, a
|
||
|
||
ld a, 1 << 4 ; select button keys
|
||
ld [rJOYP], a
|
||
rept 10
|
||
ld a, [rJOYP]
|
||
endr
|
||
cpl
|
||
and %1111
|
||
or b
|
||
|
||
ld [hJoyInput], a
|
||
|
||
ld a, 1 << 4 + 1 << 5 ; deselect keys
|
||
ld [rJOYP], a
|
||
ret
|
||
|
||
Joypad::
|
||
; Update the joypad state variables:
|
||
; [hJoyReleased] keys released since last time
|
||
; [hJoyPressed] keys pressed since last time
|
||
; [hJoyHeld] currently pressed keys
|
||
homecall _Joypad
|
||
ret
|
||
|
||
|
||
INCLUDE "data/map_header_pointers.asm"
|
||
|
||
HandleMidJump::
|
||
; Handle the player jumping down
|
||
; a ledge in the overworld.
|
||
ld b, BANK(_HandleMidJump)
|
||
ld hl, _HandleMidJump
|
||
jp Bankswitch
|
||
|
||
EnterMap::
|
||
; Load a new map.
|
||
ld a, $ff
|
||
ld [wJoyIgnore], a
|
||
call LoadMapData
|
||
callba Func_c335 ; initialize map variables
|
||
ld hl, wd72c
|
||
bit 0, [hl]
|
||
jr z, .doNotCountSteps
|
||
ld a, 3
|
||
ld [wd13c], a ; some kind of step counter (counts up to 3 steps?)
|
||
.doNotCountSteps
|
||
ld hl, wd72e
|
||
bit 5, [hl] ; did a battle happen immediately before this?
|
||
res 5, [hl] ; unset the "battle just happened" flag
|
||
call z, Func_12e7
|
||
call nz, MapEntryAfterBattle
|
||
ld hl, wd732
|
||
ld a, [hl]
|
||
and 1 << 4 | 1 << 3
|
||
jr z, .didNotFlyOrTeleportIn
|
||
res 3, [hl]
|
||
callba Func_70510 ; display fly/teleport in graphical effect
|
||
call UpdateSprites
|
||
.didNotFlyOrTeleportIn
|
||
callba CheckForceBikeOrSurf ; handle currents in SF islands and forced bike riding in cycling road
|
||
ld hl, wd72d
|
||
res 5, [hl]
|
||
call UpdateSprites
|
||
ld hl, wd126
|
||
set 5, [hl]
|
||
set 6, [hl]
|
||
xor a
|
||
ld [wJoyIgnore], a
|
||
|
||
OverworldLoop::
|
||
call DelayFrame
|
||
OverworldLoopLessDelay::
|
||
call DelayFrame
|
||
call LoadGBPal
|
||
ld a,[wd736]
|
||
bit 6,a ; jumping down a ledge?
|
||
call nz, HandleMidJump
|
||
ld a,[wWalkCounter]
|
||
and a
|
||
jp nz,.moveAhead ; if the player sprite has not yet completed the walking animation
|
||
call JoypadOverworld ; get joypad state (which is possibly simulated)
|
||
callba SafariZoneCheck
|
||
ld a,[wda46]
|
||
and a
|
||
jp nz,WarpFound2
|
||
ld hl,wd72d
|
||
bit 3,[hl]
|
||
res 3,[hl]
|
||
jp nz,WarpFound2
|
||
ld a,[wd732]
|
||
and a,$18
|
||
jp nz,HandleFlyOrTeleportAway
|
||
ld a,[W_CUROPPONENT]
|
||
and a
|
||
jp nz,.newBattle
|
||
ld a,[wd730]
|
||
bit 7,a ; are we simulating button presses?
|
||
jr z,.notSimulating
|
||
ld a,[hJoyHeld]
|
||
jr .checkIfStartIsPressed
|
||
.notSimulating
|
||
ld a,[hJoyPressed]
|
||
.checkIfStartIsPressed
|
||
bit 3,a ; start button
|
||
jr z,.startButtonNotPressed
|
||
; if START is pressed
|
||
xor a
|
||
ld [$ff8c],a ; the $2920 ID for the start menu is 0
|
||
jp .displayDialogue
|
||
.startButtonNotPressed
|
||
bit 0,a ; A button
|
||
jp z,.checkIfDownButtonIsPressed
|
||
; if A is pressed
|
||
ld a,[wd730]
|
||
bit 2,a
|
||
jp nz,.noDirectionButtonsPressed
|
||
call Func_30fd
|
||
jr nz,.checkForOpponent
|
||
call Func_3eb5 ; check for hidden items, PC's, etc.
|
||
ld a,[$ffeb]
|
||
and a
|
||
jp z,OverworldLoop
|
||
call IsSpriteOrSignInFrontOfPlayer ; check for sign or sprite in front of the player
|
||
ld a,[$ff8c] ; $2920 ID for NPC/sign text, if any
|
||
and a
|
||
jp z,OverworldLoop
|
||
.displayDialogue
|
||
ld a,$35
|
||
call Predef ; check what is in front of the player
|
||
call UpdateSprites ; move sprites
|
||
ld a,[wFlags_0xcd60]
|
||
bit 2,a
|
||
jr nz,.checkForOpponent
|
||
bit 0,a
|
||
jr nz,.checkForOpponent
|
||
FuncCoord 8, 9
|
||
ld a,[Coord]
|
||
ld [wcf0e],a
|
||
call DisplayTextID ; display either the start menu or the NPC/sign text
|
||
ld a,[wcc47]
|
||
and a
|
||
jr z,.checkForOpponent
|
||
dec a
|
||
ld a,$00
|
||
ld [wcc47],a
|
||
jr z,.changeMap
|
||
ld a,$52
|
||
call Predef
|
||
ld a,[W_CURMAP]
|
||
ld [wd71a],a
|
||
call Func_62ce
|
||
ld a,[W_CURMAP]
|
||
call SwitchToMapRomBank ; switch to the ROM bank of the current map
|
||
ld hl,W_CURMAPTILESET
|
||
set 7,[hl]
|
||
.changeMap
|
||
jp EnterMap
|
||
.checkForOpponent
|
||
ld a,[W_CUROPPONENT]
|
||
and a
|
||
jp nz,.newBattle
|
||
jp OverworldLoop
|
||
.noDirectionButtonsPressed
|
||
ld hl,wFlags_0xcd60
|
||
res 2,[hl]
|
||
call UpdateSprites ; move sprites
|
||
ld a,$01
|
||
ld [wcc4b],a
|
||
ld a,[wd528] ; the direction that was pressed last time
|
||
and a
|
||
jp z,OverworldLoop
|
||
; if a direction was pressed last time
|
||
ld [wd529],a ; save the last direction
|
||
xor a
|
||
ld [wd528],a ; zero the direction
|
||
jp OverworldLoop
|
||
.checkIfDownButtonIsPressed
|
||
ld a,[hJoyHeld] ; current joypad state
|
||
bit 7,a ; down button
|
||
jr z,.checkIfUpButtonIsPressed
|
||
ld a,$01
|
||
ld [wSpriteStateData1 + 3],a
|
||
ld a,$04
|
||
jr .handleDirectionButtonPress
|
||
.checkIfUpButtonIsPressed
|
||
bit 6,a ; up button
|
||
jr z,.checkIfLeftButtonIsPressed
|
||
ld a,$ff
|
||
ld [wSpriteStateData1 + 3],a
|
||
ld a,$08
|
||
jr .handleDirectionButtonPress
|
||
.checkIfLeftButtonIsPressed
|
||
bit 5,a ; left button
|
||
jr z,.checkIfRightButtonIsPressed
|
||
ld a,$ff
|
||
ld [wSpriteStateData1 + 5],a
|
||
ld a,$02
|
||
jr .handleDirectionButtonPress
|
||
.checkIfRightButtonIsPressed
|
||
bit 4,a ; right button
|
||
jr z,.noDirectionButtonsPressed
|
||
ld a,$01
|
||
ld [wSpriteStateData1 + 5],a
|
||
.handleDirectionButtonPress
|
||
ld [wd52a],a ; new direction
|
||
ld a,[wd730]
|
||
bit 7,a ; are we simulating button presses?
|
||
jr nz,.noDirectionChange ; ignore direction changes if we are
|
||
ld a,[wcc4b]
|
||
and a
|
||
jr z,.noDirectionChange
|
||
ld a,[wd52a] ; new direction
|
||
ld b,a
|
||
ld a,[wd529] ; old direction
|
||
cp b
|
||
jr z,.noDirectionChange
|
||
; the code below is strange
|
||
; it computes whether or not the player did a 180 degree turn, but then overwrites the result
|
||
; also, it does a seemingly pointless loop afterwards
|
||
swap a ; put old direction in upper half
|
||
or b ; put new direction in lower half
|
||
cp a,$48 ; change dir from down to up
|
||
jr nz,.notDownToUp
|
||
ld a,$02
|
||
ld [wd528],a
|
||
jr .oddLoop
|
||
.notDownToUp
|
||
cp a,$84 ; change dir from up to down
|
||
jr nz,.notUpToDown
|
||
ld a,$01
|
||
ld [wd528],a
|
||
jr .oddLoop
|
||
.notUpToDown
|
||
cp a,$12 ; change dir from right to left
|
||
jr nz,.notRightToLeft
|
||
ld a,$04
|
||
ld [wd528],a
|
||
jr .oddLoop
|
||
.notRightToLeft
|
||
cp a,$21 ; change dir from left to right
|
||
jr nz,.oddLoop
|
||
ld a,$08
|
||
ld [wd528],a
|
||
.oddLoop
|
||
ld hl,wFlags_0xcd60
|
||
set 2,[hl]
|
||
ld hl,wcc4b
|
||
dec [hl]
|
||
jr nz,.oddLoop
|
||
ld a,[wd52a]
|
||
ld [wd528],a
|
||
call NewBattle
|
||
jp c,.battleOccurred
|
||
jp OverworldLoop
|
||
.noDirectionChange
|
||
ld a,[wd52a] ; current direction
|
||
ld [wd528],a ; save direction
|
||
call UpdateSprites ; move sprites
|
||
ld a,[wd700]
|
||
cp a,$02 ; surfing
|
||
jr z,.surfing
|
||
; not surfing
|
||
call CollisionCheckOnLand
|
||
jr nc,.noCollision
|
||
push hl
|
||
ld hl,wd736
|
||
bit 2,[hl]
|
||
pop hl
|
||
jp z,OverworldLoop
|
||
push hl
|
||
call ExtraWarpCheck ; sets carry if there is a potential to warp
|
||
pop hl
|
||
jp c,CheckWarpsCollision
|
||
jp OverworldLoop
|
||
.surfing
|
||
call CollisionCheckOnWater
|
||
jp c,OverworldLoop
|
||
.noCollision
|
||
ld a,$08
|
||
ld [wWalkCounter],a
|
||
jr .moveAhead2
|
||
.moveAhead
|
||
ld a,[wd736]
|
||
bit 7,a
|
||
jr z,.noSpinning
|
||
callba LoadSpinnerArrowTiles ; spin while moving
|
||
.noSpinning
|
||
call UpdateSprites ; move sprites
|
||
.moveAhead2
|
||
ld hl,wFlags_0xcd60
|
||
res 2,[hl]
|
||
ld a,[wd700]
|
||
dec a ; riding a bike?
|
||
jr nz,.normalPlayerSpriteAdvancement
|
||
ld a,[wd736]
|
||
bit 6,a ; jumping a ledge?
|
||
jr nz,.normalPlayerSpriteAdvancement
|
||
call BikeSpeedup ; if riding a bike and not jumping a ledge
|
||
.normalPlayerSpriteAdvancement
|
||
call AdvancePlayerSprite
|
||
ld a,[wWalkCounter]
|
||
and a
|
||
jp nz,CheckMapConnections ; it seems like this check will never succeed (the other place where CheckMapConnections is run works)
|
||
; walking animation finished
|
||
ld a,[wd730]
|
||
bit 7,a
|
||
jr nz,.doneStepCounting ; if button presses are being simulated, don't count steps
|
||
; step counting
|
||
ld hl,wd13b ; step counter
|
||
dec [hl]
|
||
ld a,[wd72c]
|
||
bit 0,a
|
||
jr z,.doneStepCounting
|
||
ld hl,wd13c
|
||
dec [hl]
|
||
jr nz,.doneStepCounting
|
||
ld hl,wd72c
|
||
res 0,[hl]
|
||
.doneStepCounting
|
||
ld a,[wd790]
|
||
bit 7,a ; in the safari zone?
|
||
jr z,.notSafariZone
|
||
callba SafariZoneCheckSteps
|
||
ld a,[wda46]
|
||
and a
|
||
jp nz,WarpFound2
|
||
.notSafariZone
|
||
ld a,[W_ISINBATTLE]
|
||
and a
|
||
jp nz,CheckWarpsNoCollision
|
||
ld a,$13
|
||
call Predef ; decrement HP of poisoned pokemon
|
||
ld a,[wd12d]
|
||
and a
|
||
jp nz,HandleBlackOut ; if all pokemon fainted
|
||
.newBattle
|
||
call NewBattle
|
||
ld hl,wd736
|
||
res 2,[hl]
|
||
jp nc,CheckWarpsNoCollision ; check for warps if there was no battle
|
||
.battleOccurred
|
||
ld hl,wd72d
|
||
res 6,[hl]
|
||
ld hl,W_FLAGS_D733
|
||
res 3,[hl]
|
||
ld hl,wd126
|
||
set 5,[hl]
|
||
set 6,[hl]
|
||
xor a
|
||
ld [hJoyHeld],a ; clear joypad state
|
||
ld a,[W_CURMAP]
|
||
cp a,CINNABAR_GYM
|
||
jr nz,.notCinnabarGym
|
||
ld hl,wd79b
|
||
set 7,[hl]
|
||
.notCinnabarGym
|
||
ld hl,wd72e
|
||
set 5,[hl]
|
||
ld a,[W_CURMAP]
|
||
cp a,OAKS_LAB
|
||
jp z,.noFaintCheck
|
||
callab AnyPlayerPokemonAliveCheck ; check if all the player's pokemon fainted
|
||
ld a,d
|
||
and a
|
||
jr z,.allPokemonFainted
|
||
.noFaintCheck
|
||
ld c,$0a
|
||
call DelayFrames
|
||
jp EnterMap
|
||
.allPokemonFainted
|
||
ld a,$ff
|
||
ld [W_ISINBATTLE],a
|
||
call RunMapScript
|
||
jp HandleBlackOut
|
||
|
||
; function to determine if there will be a battle and execute it (either a trainer battle or wild battle)
|
||
; sets carry if a battle occurred and unsets carry if not
|
||
NewBattle:: ; 0683 (0:0683)
|
||
ld a,[wd72d]
|
||
bit 4,a
|
||
jr nz,.noBattle
|
||
call Func_30fd
|
||
jr nz,.noBattle
|
||
ld a,[wd72e]
|
||
bit 4,a
|
||
jr nz,.noBattle
|
||
ld b, BANK(InitBattle)
|
||
ld hl, InitBattle
|
||
jp Bankswitch ; determines if a battle will occur and runs the battle if so
|
||
.noBattle
|
||
and a
|
||
ret
|
||
|
||
; function to make bikes twice as fast as walking
|
||
BikeSpeedup:: ; 06a0 (0:06a0)
|
||
ld a,[wcc57]
|
||
and a
|
||
ret nz
|
||
ld a,[W_CURMAP]
|
||
cp a,ROUTE_17 ; Cycling Road
|
||
jr nz,.goFaster
|
||
ld a,[hJoyHeld] ; current joypad state
|
||
and a,%01110000 ; bit mask for up, left, right buttons
|
||
ret nz
|
||
.goFaster
|
||
jp AdvancePlayerSprite
|
||
|
||
; check if the player has stepped onto a warp after having not collided
|
||
CheckWarpsNoCollision:: ; 06b4 (0:06b4)
|
||
ld a,[wd3ae] ; number of warps
|
||
and a
|
||
jp z,CheckMapConnections
|
||
ld a,[wd3ae] ; number of warps
|
||
ld b,$00
|
||
ld c,a
|
||
ld a,[W_YCOORD]
|
||
ld d,a
|
||
ld a,[W_XCOORD]
|
||
ld e,a
|
||
ld hl,wd3af ; start of warp entries
|
||
CheckWarpsNoCollisionLoop:: ; 06cc (0:06cc)
|
||
ld a,[hli] ; check if the warp's Y position matches
|
||
cp d
|
||
jr nz,CheckWarpsNoCollisionRetry1
|
||
ld a,[hli] ; check if the warp's X position matches
|
||
cp e
|
||
jr nz,CheckWarpsNoCollisionRetry2
|
||
; if a match was found
|
||
push hl
|
||
push bc
|
||
ld hl,wd736
|
||
set 2,[hl]
|
||
callba Func_c49d ; check if the player sprite is standing on a "door" tile
|
||
pop bc
|
||
pop hl
|
||
jr c,WarpFound1 ; if it is, go to 0735
|
||
push hl
|
||
push bc
|
||
call ExtraWarpCheck ; sets carry if the warp is confirmed
|
||
pop bc
|
||
pop hl
|
||
jr nc,CheckWarpsNoCollisionRetry2
|
||
; if the extra check passed
|
||
ld a,[W_FLAGS_D733]
|
||
bit 2,a
|
||
jr nz,WarpFound1
|
||
push de
|
||
push bc
|
||
call Joypad
|
||
pop bc
|
||
pop de
|
||
ld a,[hJoyHeld] ; current joypad state
|
||
and a,%11110000 ; bit mask for directional buttons
|
||
jr z,CheckWarpsNoCollisionRetry2 ; if directional buttons aren't being pressed, do not pass through the warp
|
||
jr WarpFound1
|
||
|
||
; check if the player has stepped onto a warp after having collided
|
||
CheckWarpsCollision:: ; 0706 (0:0706)
|
||
ld a,[wd3ae] ; number of warps
|
||
ld c,a
|
||
ld hl,wd3af ; start of warp entries
|
||
.loop
|
||
ld a,[hli] ; Y coordinate of warp
|
||
ld b,a
|
||
ld a,[W_YCOORD]
|
||
cp b
|
||
jr nz,.retry1
|
||
ld a,[hli] ; X coordinate of warp
|
||
ld b,a
|
||
ld a,[W_XCOORD]
|
||
cp b
|
||
jr nz,.retry2
|
||
ld a,[hli]
|
||
ld [wd42f],a ; save target warp ID
|
||
ld a,[hl]
|
||
ld [$ff8b],a ; save target map
|
||
jr WarpFound2
|
||
.retry1
|
||
inc hl
|
||
.retry2
|
||
inc hl
|
||
inc hl
|
||
dec c
|
||
jr nz,.loop
|
||
jp OverworldLoop
|
||
|
||
CheckWarpsNoCollisionRetry1:: ; 072f (0:072f)
|
||
inc hl
|
||
CheckWarpsNoCollisionRetry2:: ; 0730 (0:0730)
|
||
inc hl
|
||
inc hl
|
||
jp ContinueCheckWarpsNoCollisionLoop
|
||
|
||
WarpFound1:: ; 0735 (0:0735)
|
||
ld a,[hli]
|
||
ld [wd42f],a ; save target warp ID
|
||
ld a,[hli]
|
||
ld [$ff8b],a ; save target map
|
||
|
||
WarpFound2:: ; 073c (0:073c)
|
||
ld a,[wd3ae] ; number of warps
|
||
sub c
|
||
ld [wd73b],a ; save ID of used warp
|
||
ld a,[W_CURMAP]
|
||
ld [wd73c],a
|
||
call CheckIfInOutsideMap
|
||
jr nz,.indoorMaps
|
||
; this is for handling "outside" maps that can't have the 0xFF destination map
|
||
ld a,[W_CURMAP]
|
||
ld [wLastMap],a
|
||
ld a,[W_CURMAPWIDTH]
|
||
ld [wd366],a
|
||
ld a,[$ff8b] ; destination map number
|
||
ld [W_CURMAP],a ; change current map to destination map
|
||
cp a,ROCK_TUNNEL_1
|
||
jr nz,.notRockTunnel
|
||
ld a,$06
|
||
ld [wd35d],a
|
||
call GBFadeIn1
|
||
.notRockTunnel
|
||
call PlayMapChangeSound
|
||
jr .done
|
||
; for maps that can have the 0xFF destination map, which means to return to the outside map; not all these maps are necessarily indoors, though
|
||
.indoorMaps
|
||
ld a,[$ff8b] ; destination map
|
||
cp a,$ff
|
||
jr z,.goBackOutside
|
||
; if not going back to the previous map
|
||
ld [W_CURMAP],a ; current map number
|
||
callba Func_70787 ; check if the warp was a Silph Co. teleporter
|
||
ld a,[wcd5b]
|
||
dec a
|
||
jr nz,.notTeleporter
|
||
; if it's a Silph Co. teleporter
|
||
ld hl,wd732
|
||
set 3,[hl]
|
||
call DoFlyOrTeleportAwayGraphics
|
||
jr .skipMapChangeSound
|
||
.notTeleporter
|
||
call PlayMapChangeSound
|
||
.skipMapChangeSound
|
||
ld hl,wd736
|
||
res 0,[hl]
|
||
res 1,[hl]
|
||
jr .done
|
||
.goBackOutside
|
||
ld a,[wLastMap]
|
||
ld [W_CURMAP],a
|
||
call PlayMapChangeSound
|
||
xor a
|
||
ld [wd35d],a
|
||
.done
|
||
ld hl,wd736
|
||
set 0,[hl]
|
||
call Func_12da
|
||
jp EnterMap
|
||
|
||
ContinueCheckWarpsNoCollisionLoop:: ; 07b5 (0:07b5)
|
||
inc b ; increment warp number
|
||
dec c ; decrement number of warps
|
||
jp nz,CheckWarpsNoCollisionLoop
|
||
|
||
; if no matching warp was found
|
||
CheckMapConnections:: ; 07ba (0:07ba)
|
||
.checkWestMap
|
||
ld a,[W_XCOORD]
|
||
cp a,$ff
|
||
jr nz,.checkEastMap
|
||
ld a,[W_MAPCONN3PTR]
|
||
ld [W_CURMAP],a
|
||
ld a,[wd38f] ; new X coordinate upon entering west map
|
||
ld [W_XCOORD],a
|
||
ld a,[W_YCOORD]
|
||
ld c,a
|
||
ld a,[wd38e] ; Y adjustment upon entering west map
|
||
add c
|
||
ld c,a
|
||
ld [W_YCOORD],a
|
||
ld a,[wd390] ; pointer to upper left corner of map without adjustment for Y position
|
||
ld l,a
|
||
ld a,[wd391]
|
||
ld h,a
|
||
srl c
|
||
jr z,.savePointer1
|
||
.pointerAdjustmentLoop1
|
||
ld a,[wd38d] ; width of connected map
|
||
add a,$06
|
||
ld e,a
|
||
ld d,$00
|
||
ld b,$00
|
||
add hl,de
|
||
dec c
|
||
jr nz,.pointerAdjustmentLoop1
|
||
.savePointer1
|
||
ld a,l
|
||
ld [wd35f],a ; pointer to upper left corner of current tile block map section
|
||
ld a,h
|
||
ld [wd360],a
|
||
jp .loadNewMap
|
||
.checkEastMap
|
||
ld b,a
|
||
ld a,[wd525] ; map width
|
||
cp b
|
||
jr nz,.checkNorthMap
|
||
ld a,[W_MAPCONN4PTR]
|
||
ld [W_CURMAP],a
|
||
ld a,[wd39a] ; new X coordinate upon entering east map
|
||
ld [W_XCOORD],a
|
||
ld a,[W_YCOORD]
|
||
ld c,a
|
||
ld a,[wd399] ; Y adjustment upon entering east map
|
||
add c
|
||
ld c,a
|
||
ld [W_YCOORD],a
|
||
ld a,[wd39b] ; pointer to upper left corner of map without adjustment for Y position
|
||
ld l,a
|
||
ld a,[wd39c]
|
||
ld h,a
|
||
srl c
|
||
jr z,.savePointer2
|
||
.pointerAdjustmentLoop2
|
||
ld a,[wd398]
|
||
add a,$06
|
||
ld e,a
|
||
ld d,$00
|
||
ld b,$00
|
||
add hl,de
|
||
dec c
|
||
jr nz,.pointerAdjustmentLoop2
|
||
.savePointer2
|
||
ld a,l
|
||
ld [wd35f],a ; pointer to upper left corner of current tile block map section
|
||
ld a,h
|
||
ld [wd360],a
|
||
jp .loadNewMap
|
||
.checkNorthMap
|
||
ld a,[W_YCOORD]
|
||
cp a,$ff
|
||
jr nz,.checkSouthMap
|
||
ld a,[W_MAPCONN1PTR]
|
||
ld [W_CURMAP],a
|
||
ld a,[wd378] ; new Y coordinate upon entering north map
|
||
ld [W_YCOORD],a
|
||
ld a,[W_XCOORD]
|
||
ld c,a
|
||
ld a,[wd379] ; X adjustment upon entering north map
|
||
add c
|
||
ld c,a
|
||
ld [W_XCOORD],a
|
||
ld a,[wd37a] ; pointer to upper left corner of map without adjustment for X position
|
||
ld l,a
|
||
ld a,[wd37b]
|
||
ld h,a
|
||
ld b,$00
|
||
srl c
|
||
add hl,bc
|
||
ld a,l
|
||
ld [wd35f],a ; pointer to upper left corner of current tile block map section
|
||
ld a,h
|
||
ld [wd360],a
|
||
jp .loadNewMap
|
||
.checkSouthMap
|
||
ld b,a
|
||
ld a,[wd524]
|
||
cp b
|
||
jr nz,.didNotEnterConnectedMap
|
||
ld a,[W_MAPCONN2PTR]
|
||
ld [W_CURMAP],a
|
||
ld a,[wd383] ; new Y coordinate upon entering south map
|
||
ld [W_YCOORD],a
|
||
ld a,[W_XCOORD]
|
||
ld c,a
|
||
ld a,[wd384] ; X adjustment upon entering south map
|
||
add c
|
||
ld c,a
|
||
ld [W_XCOORD],a
|
||
ld a,[wd385] ; pointer to upper left corner of map without adjustment for X position
|
||
ld l,a
|
||
ld a,[wd386]
|
||
ld h,a
|
||
ld b,$00
|
||
srl c
|
||
add hl,bc
|
||
ld a,l
|
||
ld [wd35f],a ; pointer to upper left corner of current tile block map section
|
||
ld a,h
|
||
ld [wd360],a
|
||
.loadNewMap ; load the connected map that was entered
|
||
call LoadMapHeader
|
||
call Func_2312 ; music
|
||
ld b,$09
|
||
call GoPAL_SET
|
||
; Since the sprite set shouldn't change, this will just update VRAM slots at
|
||
; $C2XE without loading any tile patterns.
|
||
callba InitMapSprites
|
||
call LoadTileBlockMap
|
||
jp OverworldLoopLessDelay
|
||
.didNotEnterConnectedMap
|
||
jp OverworldLoop
|
||
|
||
; function to play a sound when changing maps
|
||
PlayMapChangeSound:: ; 08c9 (0:08c9)
|
||
FuncCoord 8, 8
|
||
ld a,[Coord] ; upper left tile of the 4x4 square the player's sprite is standing on
|
||
cp a,$0b ; door tile in tileset 0
|
||
jr nz,.didNotGoThroughDoor
|
||
ld a,(SFX_02_57 - SFX_Headers_02) / 3
|
||
jr .playSound
|
||
.didNotGoThroughDoor
|
||
ld a,(SFX_02_5c - SFX_Headers_02) / 3
|
||
.playSound
|
||
call PlaySound
|
||
ld a,[wd35d]
|
||
and a
|
||
ret nz
|
||
jp GBFadeIn1
|
||
|
||
CheckIfInOutsideMap:: ; 08e1 (0:08e1)
|
||
; If the player is in an outside map (a town or route), set the z flag
|
||
ld a, [W_CURMAPTILESET]
|
||
and a ; most towns/routes have tileset 0 (OVERWORLD)
|
||
ret z
|
||
cp PLATEAU ; Route 23 / Indigo Plateau
|
||
ret
|
||
|
||
; this function is an extra check that sometimes has to pass in order to warp, beyond just standing on a warp
|
||
; the "sometimes" qualification is necessary because of CheckWarpsNoCollision's behavior
|
||
; depending on the map, either "function 1" or "function 2" is used for the check
|
||
; "function 1" passes when the player is at the edge of the map and is facing towards the outside of the map
|
||
; "function 2" passes when the the tile in front of the player is among a certain set
|
||
; sets carry if the check passes, otherwise clears carry
|
||
ExtraWarpCheck:: ; 08e9 (0:08e9)
|
||
ld a, [W_CURMAP]
|
||
cp SS_ANNE_3
|
||
jr z, .useFunction1
|
||
cp ROCKET_HIDEOUT_1
|
||
jr z, .useFunction2
|
||
cp ROCKET_HIDEOUT_2
|
||
jr z, .useFunction2
|
||
cp ROCKET_HIDEOUT_4
|
||
jr z, .useFunction2
|
||
cp ROCK_TUNNEL_1
|
||
jr z, .useFunction2
|
||
ld a, [W_CURMAPTILESET]
|
||
and a ; outside tileset (OVERWORLD)
|
||
jr z, .useFunction2
|
||
cp SHIP ; S.S. Anne tileset
|
||
jr z, .useFunction2
|
||
cp SHIP_PORT ; Vermilion Port tileset
|
||
jr z, .useFunction2
|
||
cp PLATEAU ; Indigo Plateau tileset
|
||
jr z, .useFunction2
|
||
.useFunction1
|
||
ld hl, Func_c3ff
|
||
jr .doBankswitch
|
||
.useFunction2
|
||
ld hl, Func_c44e
|
||
.doBankswitch
|
||
ld b, BANK(Func_c44e)
|
||
jp Bankswitch
|
||
|
||
MapEntryAfterBattle:: ; 091f (0:091f)
|
||
callba Func_c35f ; function that appears to disable warp testing after collisions if the player is standing on a warp
|
||
ld a,[wd35d]
|
||
and a
|
||
jp z,GBFadeIn2
|
||
jp LoadGBPal
|
||
|
||
HandleBlackOut::
|
||
; For when all the player's pokemon faint.
|
||
; Does not print the "blacked out" message.
|
||
|
||
call GBFadeIn1
|
||
ld a, $08
|
||
call StopMusic
|
||
ld hl, wd72e
|
||
res 5, [hl]
|
||
ld a, Bank(Func_40b0) ; also Bank(Func_62ce) and Bank(Func_5d5f)
|
||
ld [H_LOADEDROMBANK], a
|
||
ld [MBC3RomBank], a
|
||
call Func_40b0
|
||
call Func_62ce
|
||
call Func_2312
|
||
jp Func_5d5f
|
||
|
||
StopMusic::
|
||
ld [wMusicHeaderPointer], a
|
||
ld a, $ff
|
||
ld [wc0ee], a
|
||
call PlaySound
|
||
.wait
|
||
ld a, [wMusicHeaderPointer]
|
||
and a
|
||
jr nz, .wait
|
||
jp StopAllSounds
|
||
|
||
HandleFlyOrTeleportAway::
|
||
call UpdateSprites
|
||
call Delay3
|
||
xor a
|
||
ld [wcf0b], a
|
||
ld [wd700], a
|
||
ld [W_ISINBATTLE], a
|
||
ld [wd35d], a
|
||
ld hl, wd732
|
||
set 2, [hl]
|
||
res 5, [hl]
|
||
call DoFlyOrTeleportAwayGraphics
|
||
ld a, Bank(Func_62ce)
|
||
ld [H_LOADEDROMBANK], a
|
||
ld [$2000], a
|
||
call Func_62ce
|
||
jp Func_5d5f
|
||
|
||
DoFlyOrTeleportAwayGraphics::
|
||
ld b, BANK(_DoFlyOrTeleportAwayGraphics)
|
||
ld hl, _DoFlyOrTeleportAwayGraphics
|
||
jp Bankswitch
|
||
|
||
LoadPlayerSpriteGraphics::
|
||
; Load sprite graphics based on whether the player is standing, biking, or surfing.
|
||
|
||
; 0: standing
|
||
; 1: biking
|
||
; 2: surfing
|
||
|
||
ld a, [wd700]
|
||
dec a
|
||
jr z, .ridingBike
|
||
|
||
ld a, [$ffd7]
|
||
and a
|
||
jr nz, .determineGraphics
|
||
jr .startWalking
|
||
|
||
.ridingBike
|
||
; If the bike can't be used,
|
||
; start walking instead.
|
||
call IsBikeRidingAllowed
|
||
jr c, .determineGraphics
|
||
|
||
.startWalking
|
||
xor a
|
||
ld [wd700], a
|
||
ld [wd11a], a
|
||
jp LoadWalkingPlayerSpriteGraphics
|
||
|
||
.determineGraphics
|
||
ld a, [wd700]
|
||
and a
|
||
jp z, LoadWalkingPlayerSpriteGraphics
|
||
dec a
|
||
jp z, LoadBikePlayerSpriteGraphics
|
||
dec a
|
||
jp z, LoadSurfingPlayerSpriteGraphics
|
||
jp LoadWalkingPlayerSpriteGraphics
|
||
|
||
IsBikeRidingAllowed::
|
||
; The bike can be used on Route 23 and Indigo Plateau,
|
||
; or maps with tilesets in BikeRidingTilesets.
|
||
; Return carry if biking is allowed.
|
||
|
||
ld a, [W_CURMAP]
|
||
cp ROUTE_23
|
||
jr z, .allowed
|
||
cp INDIGO_PLATEAU
|
||
jr z, .allowed
|
||
|
||
ld a, [W_CURMAPTILESET]
|
||
ld b, a
|
||
ld hl, BikeRidingTilesets
|
||
.loop
|
||
ld a, [hli]
|
||
cp b
|
||
jr z, .allowed
|
||
inc a
|
||
jr nz, .loop
|
||
and a
|
||
ret
|
||
|
||
.allowed
|
||
scf
|
||
ret
|
||
|
||
INCLUDE "data/bike_riding_tilesets.asm"
|
||
|
||
; load the tile pattern data of the current tileset into VRAM
|
||
LoadTilesetTilePatternData:: ; 09e8 (0:09e8)
|
||
ld a,[W_TILESETGFXPTR]
|
||
ld l,a
|
||
ld a,[W_TILESETGFXPTR + 1]
|
||
ld h,a
|
||
ld de,vTileset
|
||
ld bc,$600
|
||
ld a,[W_TILESETBANK]
|
||
jp FarCopyData2
|
||
|
||
; this loads the current maps complete tile map (which references blocks, not individual tiles) to C6E8
|
||
; it can also load partial tile maps of connected maps into a border of length 3 around the current map
|
||
LoadTileBlockMap:: ; 09fc (0:09fc)
|
||
; fill C6E8-CBFB with the background tile
|
||
ld hl,wOverworldMap
|
||
ld a,[wd3ad] ; background tile number
|
||
ld d,a
|
||
ld bc,$0514
|
||
.backgroundTileLoop
|
||
ld a,d
|
||
ld [hli],a
|
||
dec bc
|
||
ld a,c
|
||
or b
|
||
jr nz,.backgroundTileLoop
|
||
; load tile map of current map (made of tile block IDs)
|
||
; a 3-byte border at the edges of the map is kept so that there is space for map connections
|
||
ld hl,wOverworldMap
|
||
ld a,[W_CURMAPWIDTH]
|
||
ld [$ff8c],a
|
||
add a,$06 ; border (east and west)
|
||
ld [$ff8b],a ; map width + border
|
||
ld b,$00
|
||
ld c,a
|
||
; make space for north border (next 3 lines)
|
||
add hl,bc
|
||
add hl,bc
|
||
add hl,bc
|
||
ld c,$03
|
||
add hl,bc ; this puts us past the (west) border
|
||
ld a,[W_MAPDATAPTR] ; tile map pointer
|
||
ld e,a
|
||
ld a,[W_MAPDATAPTR + 1]
|
||
ld d,a ; de = tile map pointer
|
||
ld a,[W_CURMAPHEIGHT]
|
||
ld b,a
|
||
.rowLoop ; copy one row each iteration
|
||
push hl
|
||
ld a,[$ff8c] ; map width (without border)
|
||
ld c,a
|
||
.rowInnerLoop
|
||
ld a,[de]
|
||
inc de
|
||
ld [hli],a
|
||
dec c
|
||
jr nz,.rowInnerLoop
|
||
; add the map width plus the border to the base address of the current row to get the next row's address
|
||
pop hl
|
||
ld a,[$ff8b] ; map width + border
|
||
add l
|
||
ld l,a
|
||
jr nc,.noCarry
|
||
inc h
|
||
.noCarry
|
||
dec b
|
||
jr nz,.rowLoop
|
||
.northConnection
|
||
ld a,[W_MAPCONN1PTR]
|
||
cp a,$ff
|
||
jr z,.southConnection
|
||
call SwitchToMapRomBank
|
||
ld a,[wd372]
|
||
ld l,a
|
||
ld a,[wd373]
|
||
ld h,a
|
||
ld a,[wd374]
|
||
ld e,a
|
||
ld a,[wd375]
|
||
ld d,a
|
||
ld a,[wd376]
|
||
ld [$ff8b],a
|
||
ld a,[wd377]
|
||
ld [$ff8c],a
|
||
call LoadNorthSouthConnectionsTileMap
|
||
.southConnection
|
||
ld a,[W_MAPCONN2PTR]
|
||
cp a,$ff
|
||
jr z,.westConnection
|
||
call SwitchToMapRomBank
|
||
ld a,[wd37d]
|
||
ld l,a
|
||
ld a,[wd37e]
|
||
ld h,a
|
||
ld a,[wd37f]
|
||
ld e,a
|
||
ld a,[wd380]
|
||
ld d,a
|
||
ld a,[wd381]
|
||
ld [$ff8b],a
|
||
ld a,[wd382]
|
||
ld [$ff8c],a
|
||
call LoadNorthSouthConnectionsTileMap
|
||
.westConnection
|
||
ld a,[W_MAPCONN3PTR]
|
||
cp a,$ff
|
||
jr z,.eastConnection
|
||
call SwitchToMapRomBank
|
||
ld a,[wd388]
|
||
ld l,a
|
||
ld a,[wd389]
|
||
ld h,a
|
||
ld a,[wd38a]
|
||
ld e,a
|
||
ld a,[wd38b]
|
||
ld d,a
|
||
ld a,[wd38c]
|
||
ld b,a
|
||
ld a,[wd38d]
|
||
ld [$ff8b],a
|
||
call LoadEastWestConnectionsTileMap
|
||
.eastConnection
|
||
ld a,[W_MAPCONN4PTR]
|
||
cp a,$ff
|
||
jr z,.done
|
||
call SwitchToMapRomBank
|
||
ld a,[wd393]
|
||
ld l,a
|
||
ld a,[wd394]
|
||
ld h,a
|
||
ld a,[wd395]
|
||
ld e,a
|
||
ld a,[wd396]
|
||
ld d,a
|
||
ld a,[wd397]
|
||
ld b,a
|
||
ld a,[wd398]
|
||
ld [$ff8b],a
|
||
call LoadEastWestConnectionsTileMap
|
||
.done
|
||
ret
|
||
|
||
LoadNorthSouthConnectionsTileMap:: ; 0ade (0:0ade)
|
||
ld c,$03
|
||
.loop
|
||
push de
|
||
push hl
|
||
ld a,[$ff8b] ; width of connection
|
||
ld b,a
|
||
.innerLoop
|
||
ld a,[hli]
|
||
ld [de],a
|
||
inc de
|
||
dec b
|
||
jr nz,.innerLoop
|
||
pop hl
|
||
pop de
|
||
ld a,[$ff8c] ; width of connected map
|
||
add l
|
||
ld l,a
|
||
jr nc,.noCarry1
|
||
inc h
|
||
.noCarry1
|
||
ld a,[W_CURMAPWIDTH]
|
||
add a,$06
|
||
add e
|
||
ld e,a
|
||
jr nc,.noCarry2
|
||
inc d
|
||
.noCarry2
|
||
dec c
|
||
jr nz,.loop
|
||
ret
|
||
|
||
LoadEastWestConnectionsTileMap:: ; 0b02 (0:0b02)
|
||
push hl
|
||
push de
|
||
ld c,$03
|
||
.innerLoop
|
||
ld a,[hli]
|
||
ld [de],a
|
||
inc de
|
||
dec c
|
||
jr nz,.innerLoop
|
||
pop de
|
||
pop hl
|
||
ld a,[$ff8b] ; width of connected map
|
||
add l
|
||
ld l,a
|
||
jr nc,.noCarry1
|
||
inc h
|
||
.noCarry1
|
||
ld a,[W_CURMAPWIDTH]
|
||
add a,$06
|
||
add e
|
||
ld e,a
|
||
jr nc,.noCarry2
|
||
inc d
|
||
.noCarry2
|
||
dec b
|
||
jr nz,LoadEastWestConnectionsTileMap
|
||
ret
|
||
|
||
; function to check if there is a sign or sprite in front of the player
|
||
; if so, it is stored in [$FF8C]
|
||
; if not, [$FF8C] is set to 0
|
||
IsSpriteOrSignInFrontOfPlayer:: ; 0b23 (0:0b23)
|
||
xor a
|
||
ld [$ff8c],a
|
||
ld a,[wd4b0] ; number of signs in the map
|
||
and a
|
||
jr z,.extendRangeOverCounter
|
||
; if there are signs
|
||
ld a,$35
|
||
call Predef ; get the coordinates in front of the player in de
|
||
ld hl,wd4b1 ; start of sign coordinates
|
||
ld a,[wd4b0] ; number of signs in the map
|
||
ld b,a
|
||
ld c,$00
|
||
.signLoop
|
||
inc c
|
||
ld a,[hli] ; sign Y
|
||
cp d
|
||
jr z,.yCoordMatched
|
||
inc hl
|
||
jr .retry
|
||
.yCoordMatched
|
||
ld a,[hli] ; sign X
|
||
cp e
|
||
jr nz,.retry
|
||
.xCoordMatched
|
||
; found sign
|
||
push hl
|
||
push bc
|
||
ld hl,wd4d1 ; start of sign text ID's
|
||
ld b,$00
|
||
dec c
|
||
add hl,bc
|
||
ld a,[hl]
|
||
ld [$ff8c],a ; store sign text ID
|
||
pop bc
|
||
pop hl
|
||
ret
|
||
.retry
|
||
dec b
|
||
jr nz,.signLoop
|
||
; check if the player is front of a counter in a pokemon center, pokemart, etc. and if so, extend the range at which he can talk to the NPC
|
||
.extendRangeOverCounter
|
||
ld a,$35
|
||
call Predef ; get the tile in front of the player in c
|
||
ld hl,W_TILESETTALKINGOVERTILES ; list of tiles that extend talking range (counter tiles)
|
||
ld b,$03
|
||
ld d,$20 ; talking range in pixels (long range)
|
||
.counterTilesLoop
|
||
ld a,[hli]
|
||
cp c
|
||
jr z,IsSpriteInFrontOfPlayer2 ; jumps if the tile in front of the player is a counter tile
|
||
dec b
|
||
jr nz,.counterTilesLoop
|
||
|
||
; part of the above function, but sometimes its called on its own, when signs are irrelevant
|
||
; the caller must zero [$FF8C]
|
||
IsSpriteInFrontOfPlayer:: ; 0b6b (0:0b6b)
|
||
ld d,$10 ; talking range in pixels (normal range)
|
||
IsSpriteInFrontOfPlayer2:: ; 0b6d (0:0b6d)
|
||
ld bc,$3c40 ; Y and X position of player sprite
|
||
ld a,[wSpriteStateData1 + 9] ; direction the player is facing
|
||
.checkIfPlayerFacingUp
|
||
cp a,$04
|
||
jr nz,.checkIfPlayerFacingDown
|
||
; facing up
|
||
ld a,b
|
||
sub d
|
||
ld b,a
|
||
ld a,$08
|
||
jr .doneCheckingDirection
|
||
.checkIfPlayerFacingDown
|
||
cp a,$00
|
||
jr nz,.checkIfPlayerFacingRight
|
||
; facing down
|
||
ld a,b
|
||
add d
|
||
ld b,a
|
||
ld a,$04
|
||
jr .doneCheckingDirection
|
||
.checkIfPlayerFacingRight
|
||
cp a,$0c
|
||
jr nz,.playerFacingLeft
|
||
; facing right
|
||
ld a,c
|
||
add d
|
||
ld c,a
|
||
ld a,$01
|
||
jr .doneCheckingDirection
|
||
.playerFacingLeft
|
||
; facing left
|
||
ld a,c
|
||
sub d
|
||
ld c,a
|
||
ld a,$02
|
||
.doneCheckingDirection
|
||
ld [wd52a],a
|
||
ld a,[W_NUMSPRITES] ; number of sprites
|
||
and a
|
||
ret z
|
||
; if there are sprites
|
||
ld hl,wSpriteStateData1 + $10
|
||
ld d,a
|
||
ld e,$01
|
||
.spriteLoop
|
||
push hl
|
||
ld a,[hli] ; image (0 if no sprite)
|
||
and a
|
||
jr z,.nextSprite
|
||
inc l
|
||
ld a,[hli] ; sprite visibility
|
||
inc a
|
||
jr z,.nextSprite
|
||
inc l
|
||
ld a,[hli] ; Y location
|
||
cp b
|
||
jr nz,.nextSprite
|
||
inc l
|
||
ld a,[hl] ; X location
|
||
cp c
|
||
jr z,.foundSpriteInFrontOfPlayer
|
||
.nextSprite
|
||
pop hl
|
||
ld a,l
|
||
add a,$10
|
||
ld l,a
|
||
inc e
|
||
dec d
|
||
jr nz,.spriteLoop
|
||
ret
|
||
.foundSpriteInFrontOfPlayer
|
||
pop hl
|
||
ld a,l
|
||
and a,$f0
|
||
inc a
|
||
ld l,a
|
||
set 7,[hl]
|
||
ld a,e
|
||
ld [$ff8c],a ; store sprite ID
|
||
ret
|
||
|
||
; function to check if the player will jump down a ledge and check if the tile ahead is passable (when not surfing)
|
||
; sets the carry flag if there is a collision, and unsets it if there isn't a collision
|
||
CollisionCheckOnLand:: ; 0bd1 (0:0bd1)
|
||
ld a,[wd736]
|
||
bit 6,a ; is the player jumping?
|
||
jr nz,.noCollision
|
||
; if not jumping a ledge
|
||
ld a,[wcd38]
|
||
and a
|
||
jr nz,.noCollision
|
||
ld a,[wd52a] ; the direction that the player is trying to go in
|
||
ld d,a
|
||
ld a,[wSpriteStateData1 + 12] ; the player sprite's collision data (bit field) (set in the sprite movement code)
|
||
and d ; check if a sprite is in the direction the player is trying to go
|
||
jr nz,.collision
|
||
xor a
|
||
ld [$ff8c],a
|
||
call IsSpriteInFrontOfPlayer ; check for sprite collisions again? when does the above check fail to detect a sprite collision?
|
||
ld a,[$ff8c]
|
||
and a ; was there a sprite collision?
|
||
jr nz,.collision
|
||
; if no sprite collision
|
||
ld hl,TilePairCollisionsLand
|
||
call CheckForJumpingAndTilePairCollisions
|
||
jr c,.collision
|
||
call CheckTilePassable
|
||
jr nc,.noCollision
|
||
.collision
|
||
ld a,[wc02a]
|
||
cp a,(SFX_02_5b - SFX_Headers_02) / 3 ; check if collision sound is already playing
|
||
jr z,.setCarry
|
||
ld a,(SFX_02_5b - SFX_Headers_02) / 3
|
||
call PlaySound ; play collision sound (if it's not already playing)
|
||
.setCarry
|
||
scf
|
||
ret
|
||
.noCollision
|
||
and a
|
||
ret
|
||
|
||
; function that checks if the tile in front of the player is passable
|
||
; clears carry if it is, sets carry if not
|
||
CheckTilePassable:: ; 0c10 (0:0c10)
|
||
ld a,$35
|
||
call Predef ; get tile in front of player
|
||
ld a,[wcfc6] ; tile in front of player
|
||
ld c,a
|
||
ld hl,W_TILESETCOLLISIONPTR ; pointer to list of passable tiles
|
||
ld a,[hli]
|
||
ld h,[hl]
|
||
ld l,a ; hl now points to passable tiles
|
||
.loop
|
||
ld a,[hli]
|
||
cp a,$ff
|
||
jr z,.tileNotPassable
|
||
cp c
|
||
ret z
|
||
jr .loop
|
||
.tileNotPassable
|
||
scf
|
||
ret
|
||
|
||
; check if the player is going to jump down a small ledge
|
||
; and check for collisions that only occur between certain pairs of tiles
|
||
; Input: hl - address of directional collision data
|
||
; sets carry if there is a collision and unsets carry if not
|
||
CheckForJumpingAndTilePairCollisions:: ; 0c2a (0:0c2a)
|
||
push hl
|
||
ld a,$35
|
||
call Predef ; get the tile in front of the player
|
||
push de
|
||
push bc
|
||
callba HandleLedges ; check if the player is trying to jump a ledge
|
||
pop bc
|
||
pop de
|
||
pop hl
|
||
and a
|
||
ld a,[wd736]
|
||
bit 6,a ; is the player jumping?
|
||
ret nz
|
||
; if not jumping
|
||
|
||
Func_c44:: ; 0c44 (0:0c44)
|
||
FuncCoord 8, 9
|
||
ld a,[Coord] ; tile the player is on
|
||
ld [wcf0e],a
|
||
|
||
CheckForTilePairCollisions:: ; 0c4a (0:0c4a)
|
||
ld a,[wcfc6] ; tile in front of the player
|
||
ld c,a
|
||
.tilePairCollisionLoop
|
||
ld a,[W_CURMAPTILESET] ; tileset number
|
||
ld b,a
|
||
ld a,[hli]
|
||
cp a,$ff
|
||
jr z,.noMatch
|
||
cp b
|
||
jr z,.tilesetMatches
|
||
inc hl
|
||
.retry
|
||
inc hl
|
||
jr .tilePairCollisionLoop
|
||
.tilesetMatches
|
||
ld a,[wcf0e] ; tile the player is on
|
||
ld b,a
|
||
ld a,[hl]
|
||
cp b
|
||
jr z,.currentTileMatchesFirstInPair
|
||
inc hl
|
||
ld a,[hl]
|
||
cp b
|
||
jr z,.currentTileMatchesSecondInPair
|
||
jr .retry
|
||
.currentTileMatchesFirstInPair
|
||
inc hl
|
||
ld a,[hl]
|
||
cp c
|
||
jr z,.foundMatch
|
||
jr .tilePairCollisionLoop
|
||
.currentTileMatchesSecondInPair
|
||
dec hl
|
||
ld a,[hli]
|
||
cp c
|
||
inc hl
|
||
jr nz,.tilePairCollisionLoop
|
||
.foundMatch
|
||
scf
|
||
ret
|
||
.noMatch
|
||
and a
|
||
ret
|
||
|
||
; FORMAT: tileset number, tile 1, tile 2
|
||
; terminated by 0xFF
|
||
; these entries indicate that the player may not cross between tile 1 and tile 2
|
||
; it's mainly used to simulate differences in elevation
|
||
|
||
TilePairCollisionsLand:: ; 0c7e (0:0c7e)
|
||
db CAVERN, $20, $05
|
||
db CAVERN, $41, $05
|
||
db FOREST, $30, $2E
|
||
db CAVERN, $2A, $05
|
||
db CAVERN, $05, $21
|
||
db FOREST, $52, $2E
|
||
db FOREST, $55, $2E
|
||
db FOREST, $56, $2E
|
||
db FOREST, $20, $2E
|
||
db FOREST, $5E, $2E
|
||
db FOREST, $5F, $2E
|
||
db $FF
|
||
|
||
TilePairCollisionsWater:: ; 0ca0 (0:0ca0)
|
||
db FOREST, $14, $2E
|
||
db FOREST, $48, $2E
|
||
db CAVERN, $14, $05
|
||
db $FF
|
||
|
||
; this builds a tile map from the tile block map based on the current X/Y coordinates of the player's character
|
||
LoadCurrentMapView:: ; 0caa (0:0caa)
|
||
ld a,[H_LOADEDROMBANK]
|
||
push af
|
||
ld a,[W_TILESETBANK] ; tile data ROM bank
|
||
ld [H_LOADEDROMBANK],a
|
||
ld [$2000],a ; switch to ROM bank that contains tile data
|
||
ld a,[wd35f] ; address of upper left corner of current map view
|
||
ld e,a
|
||
ld a,[wd360]
|
||
ld d,a
|
||
ld hl,wTileMapBackup
|
||
ld b,$05
|
||
.rowLoop ; each loop iteration fills in one row of tile blocks
|
||
push hl
|
||
push de
|
||
ld c,$06
|
||
.rowInnerLoop ; loop to draw each tile block of the current row
|
||
push bc
|
||
push de
|
||
push hl
|
||
ld a,[de]
|
||
ld c,a ; tile block number
|
||
call DrawTileBlock
|
||
pop hl
|
||
pop de
|
||
pop bc
|
||
inc hl
|
||
inc hl
|
||
inc hl
|
||
inc hl
|
||
inc de
|
||
dec c
|
||
jr nz,.rowInnerLoop
|
||
; update tile block map pointer to next row's address
|
||
pop de
|
||
ld a,[W_CURMAPWIDTH]
|
||
add a,$06
|
||
add e
|
||
ld e,a
|
||
jr nc,.noCarry
|
||
inc d
|
||
.noCarry
|
||
; update tile map pointer to next row's address
|
||
pop hl
|
||
ld a,$60
|
||
add l
|
||
ld l,a
|
||
jr nc,.noCarry2
|
||
inc h
|
||
.noCarry2
|
||
dec b
|
||
jr nz,.rowLoop
|
||
ld hl,wTileMapBackup
|
||
ld bc,$0000
|
||
.adjustForYCoordWithinTileBlock
|
||
ld a,[W_YBLOCKCOORD]
|
||
and a
|
||
jr z,.adjustForXCoordWithinTileBlock
|
||
ld bc,$0030
|
||
add hl,bc
|
||
.adjustForXCoordWithinTileBlock
|
||
ld a,[W_XBLOCKCOORD]
|
||
and a
|
||
jr z,.copyToVisibleAreaBuffer
|
||
ld bc,$0002
|
||
add hl,bc
|
||
.copyToVisibleAreaBuffer
|
||
ld de,wTileMap ; base address for the tiles that are directly transfered to VRAM during V-blank
|
||
ld b,$12
|
||
.rowLoop2
|
||
ld c,$14
|
||
.rowInnerLoop2
|
||
ld a,[hli]
|
||
ld [de],a
|
||
inc de
|
||
dec c
|
||
jr nz,.rowInnerLoop2
|
||
ld a,$04
|
||
add l
|
||
ld l,a
|
||
jr nc,.noCarry3
|
||
inc h
|
||
.noCarry3
|
||
dec b
|
||
jr nz,.rowLoop2
|
||
pop af
|
||
ld [H_LOADEDROMBANK],a
|
||
ld [$2000],a ; restore previous ROM bank
|
||
ret
|
||
|
||
AdvancePlayerSprite:: ; 0d27 (0:0d27)
|
||
ld a,[wSpriteStateData1 + 3] ; delta Y
|
||
ld b,a
|
||
ld a,[wSpriteStateData1 + 5] ; delta X
|
||
ld c,a
|
||
ld hl,wWalkCounter ; walking animation counter
|
||
dec [hl]
|
||
jr nz,.afterUpdateMapCoords
|
||
; if it's the end of the animation, update the player's map coordinates
|
||
ld a,[W_YCOORD]
|
||
add b
|
||
ld [W_YCOORD],a
|
||
ld a,[W_XCOORD]
|
||
add c
|
||
ld [W_XCOORD],a
|
||
.afterUpdateMapCoords
|
||
ld a,[wWalkCounter] ; walking animation counter
|
||
cp a,$07
|
||
jp nz,.scrollBackgroundAndSprites
|
||
; if this is the first iteration of the animation
|
||
ld a,c
|
||
cp a,$01
|
||
jr nz,.checkIfMovingWest
|
||
; moving east
|
||
ld a,[wd526]
|
||
ld e,a
|
||
and a,$e0
|
||
ld d,a
|
||
ld a,e
|
||
add a,$02
|
||
and a,$1f
|
||
or d
|
||
ld [wd526],a
|
||
jr .adjustXCoordWithinBlock
|
||
.checkIfMovingWest
|
||
cp a,$ff
|
||
jr nz,.checkIfMovingSouth
|
||
; moving west
|
||
ld a,[wd526]
|
||
ld e,a
|
||
and a,$e0
|
||
ld d,a
|
||
ld a,e
|
||
sub a,$02
|
||
and a,$1f
|
||
or d
|
||
ld [wd526],a
|
||
jr .adjustXCoordWithinBlock
|
||
.checkIfMovingSouth
|
||
ld a,b
|
||
cp a,$01
|
||
jr nz,.checkIfMovingNorth
|
||
; moving south
|
||
ld a,[wd526]
|
||
add a,$40
|
||
ld [wd526],a
|
||
jr nc,.adjustXCoordWithinBlock
|
||
ld a,[wd527]
|
||
inc a
|
||
and a,$03
|
||
or a,$98
|
||
ld [wd527],a
|
||
jr .adjustXCoordWithinBlock
|
||
.checkIfMovingNorth
|
||
cp a,$ff
|
||
jr nz,.adjustXCoordWithinBlock
|
||
; moving north
|
||
ld a,[wd526]
|
||
sub a,$40
|
||
ld [wd526],a
|
||
jr nc,.adjustXCoordWithinBlock
|
||
ld a,[wd527]
|
||
dec a
|
||
and a,$03
|
||
or a,$98
|
||
ld [wd527],a
|
||
.adjustXCoordWithinBlock
|
||
ld a,c
|
||
and a
|
||
jr z,.pointlessJump ; mistake?
|
||
.pointlessJump
|
||
ld hl,W_XBLOCKCOORD
|
||
ld a,[hl]
|
||
add c
|
||
ld [hl],a
|
||
cp a,$02
|
||
jr nz,.checkForMoveToWestBlock
|
||
; moved into the tile block to the east
|
||
xor a
|
||
ld [hl],a
|
||
ld hl,wd4e3
|
||
inc [hl]
|
||
ld de,wd35f
|
||
call MoveTileBlockMapPointerEast
|
||
jr .updateMapView
|
||
.checkForMoveToWestBlock
|
||
cp a,$ff
|
||
jr nz,.adjustYCoordWithinBlock
|
||
; moved into the tile block to the west
|
||
ld a,$01
|
||
ld [hl],a
|
||
ld hl,wd4e3
|
||
dec [hl]
|
||
ld de,wd35f
|
||
call MoveTileBlockMapPointerWest
|
||
jr .updateMapView
|
||
.adjustYCoordWithinBlock
|
||
ld hl,W_YBLOCKCOORD
|
||
ld a,[hl]
|
||
add b
|
||
ld [hl],a
|
||
cp a,$02
|
||
jr nz,.checkForMoveToNorthBlock
|
||
; moved into the tile block to the south
|
||
xor a
|
||
ld [hl],a
|
||
ld hl,wd4e2
|
||
inc [hl]
|
||
ld de,wd35f
|
||
ld a,[W_CURMAPWIDTH]
|
||
call MoveTileBlockMapPointerSouth
|
||
jr .updateMapView
|
||
.checkForMoveToNorthBlock
|
||
cp a,$ff
|
||
jr nz,.updateMapView
|
||
; moved into the tile block to the north
|
||
ld a,$01
|
||
ld [hl],a
|
||
ld hl,wd4e2
|
||
dec [hl]
|
||
ld de,wd35f
|
||
ld a,[W_CURMAPWIDTH]
|
||
call MoveTileBlockMapPointerNorth
|
||
.updateMapView
|
||
call LoadCurrentMapView
|
||
ld a,[wSpriteStateData1 + 3] ; delta Y
|
||
cp a,$01
|
||
jr nz,.checkIfMovingNorth2
|
||
; if moving south
|
||
call ScheduleSouthRowRedraw
|
||
jr .scrollBackgroundAndSprites
|
||
.checkIfMovingNorth2
|
||
cp a,$ff
|
||
jr nz,.checkIfMovingEast2
|
||
; if moving north
|
||
call ScheduleNorthRowRedraw
|
||
jr .scrollBackgroundAndSprites
|
||
.checkIfMovingEast2
|
||
ld a,[wSpriteStateData1 + 5] ; delta X
|
||
cp a,$01
|
||
jr nz,.checkIfMovingWest2
|
||
; if moving east
|
||
call ScheduleEastColumnRedraw
|
||
jr .scrollBackgroundAndSprites
|
||
.checkIfMovingWest2
|
||
cp a,$ff
|
||
jr nz,.scrollBackgroundAndSprites
|
||
; if moving west
|
||
call ScheduleWestColumnRedraw
|
||
.scrollBackgroundAndSprites
|
||
ld a,[wSpriteStateData1 + 3] ; delta Y
|
||
ld b,a
|
||
ld a,[wSpriteStateData1 + 5] ; delta X
|
||
ld c,a
|
||
sla b
|
||
sla c
|
||
ld a,[$ffaf]
|
||
add b
|
||
ld [$ffaf],a ; update background scroll Y
|
||
ld a,[$ffae]
|
||
add c
|
||
ld [$ffae],a ; update background scroll X
|
||
; shift all the sprites in the direction opposite of the player's motion
|
||
; so that the player appears to move relative to them
|
||
ld hl,wSpriteStateData1 + $14
|
||
ld a,[W_NUMSPRITES] ; number of sprites
|
||
and a ; are there any sprites?
|
||
jr z,.done
|
||
ld e,a
|
||
.spriteShiftLoop
|
||
ld a,[hl]
|
||
sub b
|
||
ld [hli],a
|
||
inc l
|
||
ld a,[hl]
|
||
sub c
|
||
ld [hl],a
|
||
ld a,$0e
|
||
add l
|
||
ld l,a
|
||
dec e
|
||
jr nz,.spriteShiftLoop
|
||
.done
|
||
ret
|
||
|
||
; the following four functions are used to move the pointer to the upper left
|
||
; corner of the tile block map in the direction of motion
|
||
|
||
MoveTileBlockMapPointerEast:: ; 0e65 (0:0e65)
|
||
ld a,[de]
|
||
add a,$01
|
||
ld [de],a
|
||
ret nc
|
||
inc de
|
||
ld a,[de]
|
||
inc a
|
||
ld [de],a
|
||
ret
|
||
|
||
MoveTileBlockMapPointerWest:: ; 0e6f (0:0e6f)
|
||
ld a,[de]
|
||
sub a,$01
|
||
ld [de],a
|
||
ret nc
|
||
inc de
|
||
ld a,[de]
|
||
dec a
|
||
ld [de],a
|
||
ret
|
||
|
||
MoveTileBlockMapPointerSouth:: ; 0e79 (0:0e79)
|
||
add a,$06
|
||
ld b,a
|
||
ld a,[de]
|
||
add b
|
||
ld [de],a
|
||
ret nc
|
||
inc de
|
||
ld a,[de]
|
||
inc a
|
||
ld [de],a
|
||
ret
|
||
|
||
MoveTileBlockMapPointerNorth:: ; 0e85 (0:0e85)
|
||
add a,$06
|
||
ld b,a
|
||
ld a,[de]
|
||
sub b
|
||
ld [de],a
|
||
ret nc
|
||
inc de
|
||
ld a,[de]
|
||
dec a
|
||
ld [de],a
|
||
ret
|
||
|
||
; the following 6 functions are used to tell the V-blank handler to redraw
|
||
; the portion of the map that was newly exposed due to the player's movement
|
||
|
||
ScheduleNorthRowRedraw:: ; 0e91 (0:0e91)
|
||
FuncCoord 0, 0
|
||
ld hl,Coord
|
||
call ScheduleRowRedrawHelper
|
||
ld a,[wd526]
|
||
ld [H_SCREENEDGEREDRAWADDR],a
|
||
ld a,[wd527]
|
||
ld [H_SCREENEDGEREDRAWADDR + 1],a
|
||
ld a,REDRAWROW
|
||
ld [H_SCREENEDGEREDRAW],a
|
||
ret
|
||
|
||
ScheduleRowRedrawHelper:: ; 0ea6 (0:0ea6)
|
||
ld de,wScreenEdgeTiles
|
||
ld c,$28
|
||
.loop
|
||
ld a,[hli]
|
||
ld [de],a
|
||
inc de
|
||
dec c
|
||
jr nz,.loop
|
||
ret
|
||
|
||
ScheduleSouthRowRedraw:: ; 0eb2 (0:0eb2)
|
||
FuncCoord 0,16
|
||
ld hl,Coord
|
||
call ScheduleRowRedrawHelper
|
||
ld a,[wd526]
|
||
ld l,a
|
||
ld a,[wd527]
|
||
ld h,a
|
||
ld bc,$0200
|
||
add hl,bc
|
||
ld a,h
|
||
and a,$03
|
||
or a,$98
|
||
ld [H_SCREENEDGEREDRAWADDR + 1],a
|
||
ld a,l
|
||
ld [H_SCREENEDGEREDRAWADDR],a
|
||
ld a,REDRAWROW
|
||
ld [H_SCREENEDGEREDRAW],a
|
||
ret
|
||
|
||
ScheduleEastColumnRedraw:: ; 0ed3 (0:0ed3)
|
||
FuncCoord 18,0
|
||
ld hl,Coord
|
||
call ScheduleColumnRedrawHelper
|
||
ld a,[wd526]
|
||
ld c,a
|
||
and a,$e0
|
||
ld b,a
|
||
ld a,c
|
||
add a,18
|
||
and a,$1f
|
||
or b
|
||
ld [H_SCREENEDGEREDRAWADDR],a
|
||
ld a,[wd527]
|
||
ld [H_SCREENEDGEREDRAWADDR + 1],a
|
||
ld a,REDRAWCOL
|
||
ld [H_SCREENEDGEREDRAW],a
|
||
ret
|
||
|
||
ScheduleColumnRedrawHelper:: ; 0ef2 (0:0ef2)
|
||
ld de,wScreenEdgeTiles
|
||
ld c,$12
|
||
.loop
|
||
ld a,[hli]
|
||
ld [de],a
|
||
inc de
|
||
ld a,[hl]
|
||
ld [de],a
|
||
inc de
|
||
ld a,19
|
||
add l
|
||
ld l,a
|
||
jr nc,.noCarry
|
||
inc h
|
||
.noCarry
|
||
dec c
|
||
jr nz,.loop
|
||
ret
|
||
|
||
ScheduleWestColumnRedraw:: ; 0f08 (0:0f08)
|
||
FuncCoord 0,0
|
||
ld hl,Coord
|
||
call ScheduleColumnRedrawHelper
|
||
ld a,[wd526]
|
||
ld [H_SCREENEDGEREDRAWADDR],a
|
||
ld a,[wd527]
|
||
ld [H_SCREENEDGEREDRAWADDR + 1],a
|
||
ld a,REDRAWCOL
|
||
ld [H_SCREENEDGEREDRAW],a
|
||
ret
|
||
|
||
; function to write the tiles that make up a tile block to memory
|
||
; Input: c = tile block ID, hl = destination address
|
||
DrawTileBlock:: ; 0f1d (0:0f1d)
|
||
push hl
|
||
ld a,[W_TILESETBLOCKSPTR] ; pointer to tiles
|
||
ld l,a
|
||
ld a,[W_TILESETBLOCKSPTR + 1]
|
||
ld h,a
|
||
ld a,c
|
||
swap a
|
||
ld b,a
|
||
and a,$f0
|
||
ld c,a
|
||
ld a,b
|
||
and a,$0f
|
||
ld b,a ; bc = tile block ID * 0x10
|
||
add hl,bc
|
||
ld d,h
|
||
ld e,l ; de = address of the tile block's tiles
|
||
pop hl
|
||
ld c,$04 ; 4 loop iterations
|
||
.loop ; each loop iteration, write 4 tile numbers
|
||
push bc
|
||
ld a,[de]
|
||
ld [hli],a
|
||
inc de
|
||
ld a,[de]
|
||
ld [hli],a
|
||
inc de
|
||
ld a,[de]
|
||
ld [hli],a
|
||
inc de
|
||
ld a,[de]
|
||
ld [hl],a
|
||
inc de
|
||
ld bc,$0015
|
||
add hl,bc
|
||
pop bc
|
||
dec c
|
||
jr nz,.loop
|
||
ret
|
||
|
||
; function to update joypad state and simulate button presses
|
||
JoypadOverworld:: ; 0f4d (0:0f4d)
|
||
xor a
|
||
ld [wSpriteStateData1 + 3],a
|
||
ld [wSpriteStateData1 + 5],a
|
||
call RunMapScript
|
||
call Joypad
|
||
ld a,[W_FLAGS_D733]
|
||
bit 3,a ; check if a trainer wants a challenge
|
||
jr nz,.notForcedDownwards
|
||
ld a,[W_CURMAP]
|
||
cp a,ROUTE_17 ; Cycling Road
|
||
jr nz,.notForcedDownwards
|
||
ld a,[hJoyHeld] ; current joypad state
|
||
and a,%11110011 ; bit mask for all directions and A/B
|
||
jr nz,.notForcedDownwards
|
||
ld a,%10000000 ; down pressed
|
||
ld [hJoyHeld],a ; on the cycling road, if there isn't a trainer and the player isn't pressing buttons, simulate a down press
|
||
.notForcedDownwards
|
||
ld a,[wd730]
|
||
bit 7,a
|
||
ret z
|
||
; if simulating button presses
|
||
ld a,[hJoyHeld] ; current joypad state
|
||
ld b,a
|
||
ld a,[wcd3b] ; bit mask for button presses that override simulated ones
|
||
and b
|
||
ret nz ; return if the simulated button presses are overridden
|
||
ld hl,wcd38 ; index of current simulated button press
|
||
dec [hl]
|
||
ld a,[hl]
|
||
cp a,$ff
|
||
jr z,.doneSimulating ; if the end of the simulated button presses has been reached
|
||
ld hl,wccd3 ; base address of simulated button presses
|
||
; add offset to base address
|
||
add l
|
||
ld l,a
|
||
jr nc,.noCarry
|
||
inc h
|
||
.noCarry
|
||
ld a,[hl]
|
||
ld [hJoyHeld],a ; store simulated button press in joypad state
|
||
and a
|
||
ret nz
|
||
ld [hJoyPressed],a
|
||
ld [hJoyReleased],a
|
||
ret
|
||
; if done simulating button presses
|
||
.doneSimulating
|
||
xor a
|
||
ld [wcd3a],a
|
||
ld [wcd38],a
|
||
ld [wccd3],a
|
||
ld [wJoyIgnore],a
|
||
ld [hJoyHeld],a
|
||
ld hl,wd736
|
||
ld a,[hl]
|
||
and a,$f8
|
||
ld [hl],a
|
||
ld hl,wd730
|
||
res 7,[hl]
|
||
ret
|
||
|
||
; function to check the tile ahead to determine if the character should get on land or keep surfing
|
||
; sets carry if there is a collision and clears carry otherwise
|
||
; It seems that this function has a bug in it, but due to luck, it doesn't
|
||
; show up. After detecting a sprite collision, it jumps to the code that
|
||
; checks if the next tile is passable instead of just directly jumping to the
|
||
; "collision detected" code. However, it doesn't store the next tile in c,
|
||
; so the old value of c is used. 2429 is always called before this function,
|
||
; and 2429 always sets c to 0xF0. There is no 0xF0 background tile, so it
|
||
; is considered impassable and it is detected as a collision.
|
||
CollisionCheckOnWater:: ; 0fb7 (0:0fb7)
|
||
ld a,[wd730]
|
||
bit 7,a
|
||
jp nz,.noCollision ; return and clear carry if button presses are being simulated
|
||
ld a,[wd52a] ; the direction that the player is trying to go in
|
||
ld d,a
|
||
ld a,[wSpriteStateData1 + 12] ; the player sprite's collision data (bit field) (set in the sprite movement code)
|
||
and d ; check if a sprite is in the direction the player is trying to go
|
||
jr nz,.checkIfNextTileIsPassable ; bug?
|
||
ld hl,TilePairCollisionsWater
|
||
call CheckForJumpingAndTilePairCollisions
|
||
jr c,.collision
|
||
ld a,$35
|
||
call Predef ; get tile in front of player (puts it in c and [wcfc6])
|
||
ld a,[wcfc6] ; tile in front of player
|
||
cp a,$14 ; water tile
|
||
jr z,.noCollision ; keep surfing if it's a water tile
|
||
cp a,$32 ; either the left tile of the S.S. Anne boarding platform or the tile on eastern coastlines (depending on the current tileset)
|
||
jr z,.checkIfVermilionDockTileset
|
||
cp a,$48 ; tile on right on coast lines in Safari Zone
|
||
jr z,.noCollision ; keep surfing
|
||
; check if the [land] tile in front of the player is passable
|
||
.checkIfNextTileIsPassable
|
||
ld hl,W_TILESETCOLLISIONPTR ; pointer to list of passable tiles
|
||
ld a,[hli]
|
||
ld h,[hl]
|
||
ld l,a
|
||
.loop
|
||
ld a,[hli]
|
||
cp a,$ff
|
||
jr z,.collision
|
||
cp c
|
||
jr z,.stopSurfing ; stop surfing if the tile is passable
|
||
jr .loop
|
||
.collision
|
||
ld a,[wc02a]
|
||
cp a,(SFX_02_5b - SFX_Headers_02) / 3 ; check if collision sound is already playing
|
||
jr z,.setCarry
|
||
ld a,(SFX_02_5b - SFX_Headers_02) / 3
|
||
call PlaySound ; play collision sound (if it's not already playing)
|
||
.setCarry
|
||
scf
|
||
jr .done
|
||
.noCollision
|
||
and a
|
||
.done
|
||
ret
|
||
.stopSurfing
|
||
xor a
|
||
ld [wd700],a
|
||
call LoadPlayerSpriteGraphics
|
||
call Func_2307
|
||
jr .noCollision
|
||
.checkIfVermilionDockTileset
|
||
ld a, [W_CURMAPTILESET] ; tileset
|
||
cp SHIP_PORT ; Vermilion Dock tileset
|
||
jr nz, .noCollision ; keep surfing if it's not the boarding platform tile
|
||
jr .stopSurfing ; if it is the boarding platform tile, stop surfing
|
||
|
||
; function to run the current map's script
|
||
RunMapScript:: ; 101b (0:101b)
|
||
push hl
|
||
push de
|
||
push bc
|
||
callba Func_f225 ; check if the player is pushing a boulder
|
||
ld a,[wFlags_0xcd60]
|
||
bit 1,a ; is the player pushing a boulder?
|
||
jr z,.afterBoulderEffect
|
||
callba Func_f2b5 ; displays dust effect when pushing a boulder
|
||
.afterBoulderEffect
|
||
pop bc
|
||
pop de
|
||
pop hl
|
||
call Func_310e
|
||
ld a,[W_CURMAP] ; current map number
|
||
call SwitchToMapRomBank ; change to the ROM bank the map's data is in
|
||
ld hl,W_MAPSCRIPTPTR
|
||
ld a,[hli]
|
||
ld h,[hl]
|
||
ld l,a
|
||
ld de,.return
|
||
push de
|
||
jp [hl] ; jump to script
|
||
.return
|
||
ret
|
||
|
||
LoadWalkingPlayerSpriteGraphics:: ; 104d (0:104d)
|
||
ld de,RedSprite ; $4180
|
||
ld hl,vNPCSprites
|
||
jr LoadPlayerSpriteGraphicsCommon
|
||
|
||
LoadSurfingPlayerSpriteGraphics:: ; 1055 (0:1055)
|
||
ld de,SeelSprite
|
||
ld hl,vNPCSprites
|
||
jr LoadPlayerSpriteGraphicsCommon
|
||
|
||
LoadBikePlayerSpriteGraphics:: ; 105d (0:105d)
|
||
ld de,RedCyclingSprite
|
||
ld hl,vNPCSprites
|
||
|
||
LoadPlayerSpriteGraphicsCommon:: ; 1063 (0:1063)
|
||
push de
|
||
push hl
|
||
ld bc,(BANK(RedSprite) << 8) + $0c
|
||
call CopyVideoData
|
||
pop hl
|
||
pop de
|
||
ld a,$c0
|
||
add e
|
||
ld e,a
|
||
jr nc,.noCarry
|
||
inc d
|
||
.noCarry
|
||
set 3,h
|
||
ld bc,$050c
|
||
jp CopyVideoData
|
||
|
||
; function to load data from the map header
|
||
LoadMapHeader:: ; 107c (0:107c)
|
||
callba Func_f113
|
||
ld a,[W_CURMAPTILESET]
|
||
ld [wd119],a
|
||
ld a,[W_CURMAP]
|
||
call SwitchToMapRomBank
|
||
ld a,[W_CURMAPTILESET]
|
||
ld b,a
|
||
res 7,a
|
||
ld [W_CURMAPTILESET],a
|
||
ld [$ff8b],a
|
||
bit 7,b
|
||
ret nz
|
||
ld hl,MapHeaderPointers
|
||
ld a,[W_CURMAP]
|
||
sla a
|
||
jr nc,.noCarry1
|
||
inc h
|
||
.noCarry1
|
||
add l
|
||
ld l,a
|
||
jr nc,.noCarry2
|
||
inc h
|
||
.noCarry2
|
||
ld a,[hli]
|
||
ld h,[hl]
|
||
ld l,a ; hl = base of map header
|
||
; copy the first 10 bytes (the fixed area) of the map data to D367-D370
|
||
ld de,W_CURMAPTILESET
|
||
ld c,$0a
|
||
.copyFixedHeaderLoop
|
||
ld a,[hli]
|
||
ld [de],a
|
||
inc de
|
||
dec c
|
||
jr nz,.copyFixedHeaderLoop
|
||
; initialize all the connected maps to disabled at first, before loading the actual values
|
||
ld a,$ff
|
||
ld [W_MAPCONN1PTR],a
|
||
ld [W_MAPCONN2PTR],a
|
||
ld [W_MAPCONN3PTR],a
|
||
ld [W_MAPCONN4PTR],a
|
||
; copy connection data (if any) to WRAM
|
||
ld a,[W_MAPCONNECTIONS]
|
||
ld b,a
|
||
.checkNorth
|
||
bit 3,b
|
||
jr z,.checkSouth
|
||
ld de,W_MAPCONN1PTR
|
||
call CopyMapConnectionHeader
|
||
.checkSouth
|
||
bit 2,b
|
||
jr z,.checkWest
|
||
ld de,W_MAPCONN2PTR
|
||
call CopyMapConnectionHeader
|
||
.checkWest
|
||
bit 1,b
|
||
jr z,.checkEast
|
||
ld de,W_MAPCONN3PTR
|
||
call CopyMapConnectionHeader
|
||
.checkEast
|
||
bit 0,b
|
||
jr z,.getObjectDataPointer
|
||
ld de,W_MAPCONN4PTR
|
||
call CopyMapConnectionHeader
|
||
.getObjectDataPointer
|
||
ld a,[hli]
|
||
ld [wd3a9],a
|
||
ld a,[hli]
|
||
ld [wd3aa],a
|
||
push hl
|
||
ld a,[wd3a9]
|
||
ld l,a
|
||
ld a,[wd3aa]
|
||
ld h,a ; hl = base of object data
|
||
ld de,wd3ad ; background tile ID
|
||
ld a,[hli]
|
||
ld [de],a ; save background tile ID
|
||
.loadWarpData
|
||
ld a,[hli] ; number of warps
|
||
ld [wd3ae],a ; save the number of warps
|
||
and a ; are there any warps?
|
||
jr z,.loadSignData ; if not, skip this
|
||
ld c,a
|
||
ld de,wd3af ; base address of warps
|
||
.warpLoop ; one warp per loop iteration
|
||
ld b,$04
|
||
.warpInnerLoop
|
||
ld a,[hli]
|
||
ld [de],a
|
||
inc de
|
||
dec b
|
||
jr nz,.warpInnerLoop
|
||
dec c
|
||
jr nz,.warpLoop
|
||
.loadSignData
|
||
ld a,[hli] ; number of signs
|
||
ld [wd4b0],a ; save the number of signs
|
||
and a ; are there any signs?
|
||
jr z,.loadSpriteData ; if not, skip this
|
||
ld c,a
|
||
ld de,wd4d1 ; base address of sign text IDs
|
||
ld a,d
|
||
ld [$ff95],a
|
||
ld a,e
|
||
ld [$ff96],a
|
||
ld de,wd4b1 ; base address of sign coordinates
|
||
.signLoop
|
||
ld a,[hli]
|
||
ld [de],a
|
||
inc de
|
||
ld a,[hli]
|
||
ld [de],a
|
||
inc de
|
||
push de
|
||
ld a,[$ff95]
|
||
ld d,a
|
||
ld a,[$ff96]
|
||
ld e,a
|
||
ld a,[hli]
|
||
ld [de],a
|
||
inc de
|
||
ld a,d
|
||
ld [$ff95],a
|
||
ld a,e
|
||
ld [$ff96],a
|
||
pop de
|
||
dec c
|
||
jr nz,.signLoop
|
||
.loadSpriteData
|
||
ld a,[wd72e]
|
||
bit 5,a ; did a battle happen immediately before this?
|
||
jp nz,.finishUp ; if so, skip this because battles don't destroy this data
|
||
ld a,[hli]
|
||
ld [W_NUMSPRITES],a ; save the number of sprites
|
||
push hl
|
||
; zero C110-C1FF and C210-C2FF
|
||
ld hl,wSpriteStateData1 + $10
|
||
ld de,wSpriteStateData2 + $10
|
||
xor a
|
||
ld b,$f0
|
||
.zeroSpriteDataLoop
|
||
ld [hli],a
|
||
ld [de],a
|
||
inc e
|
||
dec b
|
||
jr nz,.zeroSpriteDataLoop
|
||
; initialize all C100-C1FF sprite entries to disabled (other than player's)
|
||
ld hl,wSpriteStateData1 + $12
|
||
ld de,$0010
|
||
ld c,$0f
|
||
.disableSpriteEntriesLoop
|
||
ld [hl],$ff
|
||
add hl,de
|
||
dec c
|
||
jr nz,.disableSpriteEntriesLoop
|
||
pop hl
|
||
ld de,wSpriteStateData1 + $10
|
||
ld a,[W_NUMSPRITES] ; number of sprites
|
||
and a ; are there any sprites?
|
||
jp z,.finishUp ; if there are no sprites, skip the rest
|
||
ld b,a
|
||
ld c,$00
|
||
.loadSpriteLoop
|
||
ld a,[hli]
|
||
ld [de],a ; store picture ID at C1X0
|
||
inc d
|
||
ld a,$04
|
||
add e
|
||
ld e,a
|
||
ld a,[hli]
|
||
ld [de],a ; store Y position at C2X4
|
||
inc e
|
||
ld a,[hli]
|
||
ld [de],a ; store X position at C2X5
|
||
inc e
|
||
ld a,[hli]
|
||
ld [de],a ; store movement byte 1 at C2X6
|
||
ld a,[hli]
|
||
ld [$ff8d],a ; save movement byte 2
|
||
ld a,[hli]
|
||
ld [$ff8e],a ; save text ID and flags byte
|
||
push bc
|
||
push hl
|
||
ld b,$00
|
||
ld hl,W_MAPSPRITEDATA
|
||
add hl,bc
|
||
ld a,[$ff8d]
|
||
ld [hli],a ; store movement byte 2 in byte 0 of sprite entry
|
||
ld a,[$ff8e]
|
||
ld [hl],a ; this appears pointless, since the value is overwritten immediately after
|
||
ld a,[$ff8e]
|
||
ld [$ff8d],a
|
||
and a,$3f
|
||
ld [hl],a ; store text ID in byte 1 of sprite entry
|
||
pop hl
|
||
ld a,[$ff8d]
|
||
bit 6,a
|
||
jr nz,.trainerSprite
|
||
bit 7,a
|
||
jr nz,.itemBallSprite
|
||
jr .regularSprite
|
||
.trainerSprite
|
||
ld a,[hli]
|
||
ld [$ff8d],a ; save trainer class
|
||
ld a,[hli]
|
||
ld [$ff8e],a ; save trainer number (within class)
|
||
push hl
|
||
ld hl,W_MAPSPRITEEXTRADATA
|
||
add hl,bc
|
||
ld a,[$ff8d]
|
||
ld [hli],a ; store trainer class in byte 0 of the entry
|
||
ld a,[$ff8e]
|
||
ld [hl],a ; store trainer number in byte 1 of the entry
|
||
pop hl
|
||
jr .nextSprite
|
||
.itemBallSprite
|
||
ld a,[hli]
|
||
ld [$ff8d],a ; save item number
|
||
push hl
|
||
ld hl,W_MAPSPRITEEXTRADATA
|
||
add hl,bc
|
||
ld a,[$ff8d]
|
||
ld [hli],a ; store item number in byte 0 of the entry
|
||
xor a
|
||
ld [hl],a ; zero byte 1, since it is not used
|
||
pop hl
|
||
jr .nextSprite
|
||
.regularSprite
|
||
push hl
|
||
ld hl,W_MAPSPRITEEXTRADATA
|
||
add hl,bc
|
||
; zero both bytes, since regular sprites don't use this extra space
|
||
xor a
|
||
ld [hli],a
|
||
ld [hl],a
|
||
pop hl
|
||
.nextSprite
|
||
pop bc
|
||
dec d
|
||
ld a,$0a
|
||
add e
|
||
ld e,a
|
||
inc c
|
||
inc c
|
||
dec b
|
||
jp nz,.loadSpriteLoop
|
||
.finishUp
|
||
ld a,$19
|
||
call Predef ; load tileset data
|
||
callab LoadWildData ; load wild pokemon data
|
||
pop hl ; restore hl from before going to the warp/sign/sprite data (this value was saved for seemingly no purpose)
|
||
ld a,[W_CURMAPHEIGHT] ; map height in 4x4 tile blocks
|
||
add a ; double it
|
||
ld [wd524],a ; store map height in 2x2 tile blocks
|
||
ld a,[W_CURMAPWIDTH] ; map width in 4x4 tile blocks
|
||
add a ; double it
|
||
ld [wd525],a ; map width in 2x2 tile blocks
|
||
ld a,[W_CURMAP]
|
||
ld c,a
|
||
ld b,$00
|
||
ld a,[H_LOADEDROMBANK]
|
||
push af
|
||
ld a, BANK(MapSongBanks)
|
||
ld [H_LOADEDROMBANK],a
|
||
ld [$2000],a
|
||
ld hl, MapSongBanks
|
||
add hl,bc
|
||
add hl,bc
|
||
ld a,[hli]
|
||
ld [wd35b],a ; music 1
|
||
ld a,[hl]
|
||
ld [wd35c],a ; music 2
|
||
pop af
|
||
ld [H_LOADEDROMBANK],a
|
||
ld [$2000],a
|
||
ret
|
||
|
||
; function to copy map connection data from ROM to WRAM
|
||
; Input: hl = source, de = destination
|
||
CopyMapConnectionHeader:: ; 1238 (0:1238)
|
||
ld c,$0b
|
||
.loop
|
||
ld a,[hli]
|
||
ld [de],a
|
||
inc de
|
||
dec c
|
||
jr nz,.loop
|
||
ret
|
||
|
||
; function to load map data
|
||
LoadMapData:: ; 1241 (0:1241)
|
||
ld a,[H_LOADEDROMBANK]
|
||
push af
|
||
call DisableLCD
|
||
ld a,$98
|
||
ld [wd527],a
|
||
xor a
|
||
ld [wd526],a
|
||
ld [$ffaf],a
|
||
ld [$ffae],a
|
||
ld [wWalkCounter],a
|
||
ld [wd119],a
|
||
ld [wd11a],a
|
||
ld [W_SPRITESETID],a
|
||
call LoadTextBoxTilePatterns
|
||
call LoadMapHeader
|
||
callba InitMapSprites ; load tile pattern data for sprites
|
||
call LoadTileBlockMap
|
||
call LoadTilesetTilePatternData
|
||
call LoadCurrentMapView
|
||
; copy current map view to VRAM
|
||
ld hl,wTileMap
|
||
ld de,vBGMap0
|
||
ld b,18
|
||
.vramCopyLoop
|
||
ld c,20
|
||
.vramCopyInnerLoop
|
||
ld a,[hli]
|
||
ld [de],a
|
||
inc e
|
||
dec c
|
||
jr nz,.vramCopyInnerLoop
|
||
ld a,32 - 20
|
||
add e
|
||
ld e,a
|
||
jr nc,.noCarry
|
||
inc d
|
||
.noCarry
|
||
dec b
|
||
jr nz,.vramCopyLoop
|
||
ld a,$01
|
||
ld [wcfcb],a
|
||
call EnableLCD
|
||
ld b,$09
|
||
call GoPAL_SET
|
||
call LoadPlayerSpriteGraphics
|
||
ld a,[wd732]
|
||
and a,$18 ; did the player fly or teleport in?
|
||
jr nz,.restoreRomBank
|
||
ld a,[W_FLAGS_D733]
|
||
bit 1,a
|
||
jr nz,.restoreRomBank
|
||
call Func_235f ; music related
|
||
call Func_2312 ; music related
|
||
.restoreRomBank
|
||
pop af
|
||
ld [H_LOADEDROMBANK],a
|
||
ld [$2000],a
|
||
ret
|
||
|
||
; function to switch to the ROM bank that a map is stored in
|
||
; Input: a = map number
|
||
SwitchToMapRomBank:: ; 12bc (0:12bc)
|
||
push hl
|
||
push bc
|
||
ld c,a
|
||
ld b,$00
|
||
ld a,Bank(MapHeaderBanks)
|
||
call BankswitchHome ; switch to ROM bank 3
|
||
ld hl,MapHeaderBanks
|
||
add hl,bc
|
||
ld a,[hl]
|
||
ld [$ffe8],a ; save map ROM bank
|
||
call BankswitchBack
|
||
ld a,[$ffe8]
|
||
ld [H_LOADEDROMBANK],a
|
||
ld [$2000],a ; switch to map ROM bank
|
||
pop bc
|
||
pop hl
|
||
ret
|
||
|
||
Func_12da:: ; 12da (0:12da)
|
||
ld a, $1e
|
||
ld [wd13a], a
|
||
ld hl, wd730
|
||
ld a, [hl]
|
||
or $26
|
||
ld [hl], a
|
||
ret
|
||
|
||
Func_12e7:: ; 12e7 (0:12e7)
|
||
ld hl, wd728
|
||
res 0, [hl]
|
||
ret
|
||
|
||
ForceBikeOrSurf:: ; 12ed (0:12ed)
|
||
ld b, BANK(RedSprite)
|
||
ld hl, LoadPlayerSpriteGraphics
|
||
call Bankswitch
|
||
jp Func_2307 ; update map/player state?
|
||
|
||
; 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
|
||
call JoypadLowSensitivity
|
||
pop bc
|
||
ld a,[hJoyHeld] ; currently pressed buttons
|
||
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
|
||
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]
|
||
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
|
||
; INPUT:
|
||
; [wWhichPokemon] = index of pokemon within party/box
|
||
; [wcc49] = source
|
||
; 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
|
||
LoadMonData:: ; 1372 (0:1372)
|
||
ld hl,LoadMonData_
|
||
ld b,BANK(LoadMonData_)
|
||
jp Bankswitch
|
||
|
||
; writes c to wd0dc+b
|
||
Func_137a:: ; 137a (0:137a)
|
||
ld hl, wd0dc
|
||
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]
|
||
push af
|
||
ld a, [wcf91]
|
||
ld [wd11e], a
|
||
ld a, $3a
|
||
call Predef ; indirect jump to IndexToPokedex (41010 (10:5010))
|
||
ld hl, wd11e
|
||
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
|
||
ret
|
||
.validDexNumber
|
||
push hl
|
||
ld de, vFrontPic
|
||
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
|
||
ld a,[hl]
|
||
ld [wc0f2],a
|
||
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
|
||
set 6,[hl] ; turn off letter printing delay
|
||
xor a
|
||
ld [wcc49],a
|
||
ld [wcc37],a
|
||
ld hl,wTopMenuItemY
|
||
inc a
|
||
ld [hli],a ; top menu item Y
|
||
xor a
|
||
ld [hli],a ; top menu item X
|
||
ld a,[wcc2b]
|
||
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]
|
||
and a
|
||
ld a,%00000011 ; A button and B button
|
||
jr z,.next
|
||
xor a
|
||
ld [wd11f],a
|
||
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
|
||
ld a,$40
|
||
ld [wd09b],a
|
||
call HandleMenuInputPokemonSelection
|
||
call PlaceUnfilledArrowMenuCursor
|
||
ld b,a
|
||
xor a
|
||
ld [wd09b],a
|
||
ld a,[wCurrentMenuItem]
|
||
ld [wcc2b],a
|
||
ld hl,wd730
|
||
res 6,[hl] ; turn on letter printing delay
|
||
ld a,[wcc35]
|
||
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
|
||
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
|
||
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
|
||
PrintLevel:: ; 150b (0:150b)
|
||
ld a,$6e ; ":L" tile ID
|
||
ld [hli],a
|
||
ld c,2 ; number of digits
|
||
ld a,[wcfb9] ; level
|
||
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
|
||
PrintLevelFull:: ; 151b (0:151b)
|
||
ld a,$6e ; ":L" tile ID
|
||
ld [hli],a
|
||
ld c,3 ; number of digits
|
||
ld a,[wcfb9] ; level
|
||
|
||
PrintLevelCommon:: ; 1523 (0:1523)
|
||
ld [wd11e],a
|
||
ld de,wd11e
|
||
ld b,$41 ; no leading zeroes, left-aligned, one byte
|
||
jp PrintNumber
|
||
|
||
Func_152e:: ; 152e (0:152e)
|
||
ld hl,wd0dc
|
||
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)
|
||
; INPUT:
|
||
; [wd0b5] = pokemon ID
|
||
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]
|
||
push af
|
||
ld a,[wd0b5]
|
||
ld [wd11e],a
|
||
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]
|
||
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
|
||
pop af
|
||
ld [wd11e],a
|
||
pop hl
|
||
pop de
|
||
pop bc
|
||
pop af
|
||
ld [H_LOADEDROMBANK],a
|
||
ld [$2000],a
|
||
ret
|
||
|
||
; copy party pokemon's name to wcd6d
|
||
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
|
||
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
|
||
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:: ; 172f (0:172f)
|
||
INCBIN "gfx/tilesets/underground.tilecoll"
|
||
Overworld_Coll:: ; 1735 (0:1735)
|
||
INCBIN "gfx/tilesets/overworld.tilecoll"
|
||
RedsHouse1_Coll::
|
||
RedsHouse2_Coll:: ; 1749 (0:1749)
|
||
INCBIN "gfx/tilesets/reds_house.tilecoll"
|
||
Mart_Coll
|
||
Pokecenter_Coll:: ; 1753 (0:1753)
|
||
INCBIN "gfx/tilesets/pokecenter.tilecoll"
|
||
Dojo_Coll::
|
||
Gym_Coll:: ; 1759 (0:1759)
|
||
INCBIN "gfx/tilesets/gym.tilecoll"
|
||
Forest_Coll:: ; 1765 (0:1765)
|
||
INCBIN "gfx/tilesets/forest.tilecoll"
|
||
House_Coll:: ; 1775 (0:1775)
|
||
INCBIN "gfx/tilesets/house.tilecoll"
|
||
ForestGate_Coll::
|
||
Museum_Coll::
|
||
Gate_Coll:: ; 177f (0:177f)
|
||
INCBIN "gfx/tilesets/gate.tilecoll"
|
||
Ship_Coll:: ; 178a (0:178a)
|
||
INCBIN "gfx/tilesets/ship.tilecoll"
|
||
ShipPort_Coll:: ; 1795 (0:1795)
|
||
INCBIN "gfx/tilesets/ship_port.tilecoll"
|
||
Cemetery_Coll:: ; 179a (0:179a)
|
||
INCBIN "gfx/tilesets/cemetery.tilecoll"
|
||
Interior_Coll:: ; 17a2 (0:17a2)
|
||
INCBIN "gfx/tilesets/interior.tilecoll"
|
||
Cavern_Coll:: ; 17ac (0:17ac)
|
||
INCBIN "gfx/tilesets/cavern.tilecoll"
|
||
Lobby_Coll:: ; 17b8 (0:17b8)
|
||
INCBIN "gfx/tilesets/lobby.tilecoll"
|
||
Mansion_Coll:: ; 17c0 (0:17c0)
|
||
INCBIN "gfx/tilesets/mansion.tilecoll"
|
||
Lab_Coll:: ; 17ca (0:17ca)
|
||
INCBIN "gfx/tilesets/lab.tilecoll"
|
||
Club_Coll:: ; 17d1 (0:17d1)
|
||
INCBIN "gfx/tilesets/club.tilecoll"
|
||
Facility_Coll:: ; 17dd (0:17dd)
|
||
INCBIN "gfx/tilesets/facility.tilecoll"
|
||
Plateau_Coll:: ; 17f0 (0:17f0)
|
||
INCBIN "gfx/tilesets/plateau.tilecoll"
|
||
|
||
; does the same thing as FarCopyData at 009D
|
||
; only difference is that it uses [$ff8b] instead of [wHPBarMaxHP] for a temp value
|
||
; copy bc bytes of data from a:hl to de
|
||
FarCopyData2:: ; 17f7 (0:17f7)
|
||
ld [$ff8b],a
|
||
ld a,[H_LOADEDROMBANK]
|
||
push af
|
||
ld a,[$ff8b]
|
||
ld [H_LOADEDROMBANK],a
|
||
ld [$2000],a
|
||
call CopyData
|
||
pop af
|
||
ld [H_LOADEDROMBANK],a
|
||
ld [$2000],a
|
||
ret
|
||
|
||
; does a far copy but the source is de and the destination is hl
|
||
; copy bc bytes of data from a:de to hl
|
||
FarCopyData3:: ; 180d (0:180d)
|
||
ld [$ff8b],a
|
||
ld a,[H_LOADEDROMBANK]
|
||
push af
|
||
ld a,[$ff8b]
|
||
ld [H_LOADEDROMBANK],a
|
||
ld [$2000],a
|
||
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 [$2000],a
|
||
ret
|
||
|
||
; copies each source byte to the destination twice (next to each other)
|
||
; copy bc source bytes from a:hl to de
|
||
FarCopyDataDouble:: ; 182b (0:182b)
|
||
ld [$ff8b],a
|
||
ld a,[H_LOADEDROMBANK]
|
||
push af
|
||
ld a,[$ff8b]
|
||
ld [H_LOADEDROMBANK],a
|
||
ld [$2000],a
|
||
.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 [$2000],a
|
||
ret
|
||
|
||
; copy (c * 16) bytes from b:de to hl during V-blank
|
||
; transfers up to 128 bytes per V-blank
|
||
CopyVideoData:: ; 1848 (0:1848)
|
||
ld a,[H_AUTOBGTRANSFERENABLED] ; save auto-transfer enabled flag
|
||
push af
|
||
xor a
|
||
ld [H_AUTOBGTRANSFERENABLED],a ; disable auto-transfer while copying
|
||
ld a,[H_LOADEDROMBANK]
|
||
ld [$ff8b],a
|
||
ld a,b
|
||
ld [H_LOADEDROMBANK],a
|
||
ld [$2000],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
|
||
.loop
|
||
ld a,c
|
||
cp a,8 ; are there more than 128 bytes left to copy?
|
||
jr nc,.copyMaxSize ; only copy up to 128 bytes at a time
|
||
.copyRemainder
|
||
ld [H_VBCOPYSIZE],a
|
||
call DelayFrame ; wait for V-blank handler to perform the copy
|
||
ld a,[$ff8b]
|
||
ld [H_LOADEDROMBANK],a
|
||
ld [$2000],a
|
||
pop af
|
||
ld [H_AUTOBGTRANSFERENABLED],a ; restore original auto-transfer enabled flag
|
||
ret
|
||
.copyMaxSize
|
||
ld a,8 ; 128 bytes
|
||
ld [H_VBCOPYSIZE],a
|
||
call DelayFrame ; wait for V-blank handler to perform the copy
|
||
ld a,c
|
||
sub a,8
|
||
ld c,a
|
||
jr .loop
|
||
|
||
; copy (c * 8) source bytes from b:de to hl during V-blank
|
||
; copies each source byte to the destination twice (next to each other)
|
||
; transfers up to 64 source bytes per V-blank
|
||
CopyVideoDataDouble:: ; 1886 (0:1886)
|
||
ld a,[H_AUTOBGTRANSFERENABLED] ; save auto-transfer enabled flag
|
||
push af
|
||
xor a
|
||
ld [H_AUTOBGTRANSFERENABLED],a ; disable auto-transfer while copying
|
||
ld a,[H_LOADEDROMBANK]
|
||
ld [$ff8b],a
|
||
ld a,b
|
||
ld [H_LOADEDROMBANK],a
|
||
ld [$2000],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
|
||
.loop
|
||
ld a,c
|
||
cp a,8 ; are there more than 64 source bytes left to copy?
|
||
jr nc,.copyMaxSize ; only copy up to 64 source bytes at a time
|
||
.copyRemainder
|
||
ld [H_VBCOPYDOUBLESIZE],a
|
||
call DelayFrame ; wait for V-blank handler to perform the copy
|
||
ld a,[$ff8b]
|
||
ld [H_LOADEDROMBANK],a
|
||
ld [$2000],a
|
||
pop af
|
||
ld [H_AUTOBGTRANSFERENABLED],a ; restore original auto-transfer enabled flag
|
||
ret
|
||
.copyMaxSize
|
||
ld a,8 ; 64 source bytes
|
||
ld [H_VBCOPYDOUBLESIZE],a
|
||
call DelayFrame ; wait for V-blank handler to perform the copy
|
||
ld a,c
|
||
sub a,8
|
||
ld c,a
|
||
jr .loop
|
||
|
||
; clears an area of the screen
|
||
; INPUT:
|
||
; hl = address of upper left corner of the area
|
||
; b = height
|
||
; c = width
|
||
ClearScreenArea:: ; 18c4 (0:18c4)
|
||
ld a,$7F ; blank tile
|
||
ld de,20 ; screen width
|
||
.loop
|
||
push hl
|
||
push bc
|
||
.innerLoop
|
||
ld [hli],a
|
||
dec c
|
||
jr nz,.innerLoop
|
||
pop bc
|
||
pop hl
|
||
add hl,de
|
||
dec b
|
||
jr nz,.loop
|
||
ret
|
||
|
||
; copies the screen tile buffer from WRAM to VRAM
|
||
; copying is done in 3 chunks of 6 rows each
|
||
; b: high byte of VRAM destination address ($98 or $9c for window tile map 0 or 1 resp.)
|
||
CopyScreenTileBufferToVRAM:: ; 18d6 (0:18d6)
|
||
ld c, $6
|
||
ld hl, $0000
|
||
ld de, wTileMap
|
||
call InitScreenTileBufferTransferParameters
|
||
call DelayFrame
|
||
ld hl, $600
|
||
ld de, wTileMap + 20 * 6
|
||
call InitScreenTileBufferTransferParameters
|
||
call DelayFrame
|
||
ld hl, $c00
|
||
ld de, wTileMap + 20 * 12
|
||
call InitScreenTileBufferTransferParameters
|
||
jp DelayFrame
|
||
|
||
InitScreenTileBufferTransferParameters:: ; 18fc (0:18fc)
|
||
ld a, d
|
||
ld [H_VBCOPYBGSRC+1], a
|
||
call GetRowColAddressBgMap
|
||
ld a, l
|
||
ld [H_VBCOPYBGDEST], a ; $ffc3
|
||
ld a, h
|
||
ld [H_VBCOPYBGDEST+1], a
|
||
ld a, c
|
||
ld [H_VBCOPYBGNUMROWS], a ; $ffc5
|
||
ld a, e
|
||
ld [H_VBCOPYBGSRC], a ; $ffc1
|
||
ret
|
||
|
||
ClearScreen:: ; 190f (0:190f)
|
||
; clears all tiles in the tilemap,
|
||
; then wait three frames
|
||
ld bc,$0168 ; tilemap size
|
||
inc b
|
||
ld hl,wTileMap ; TILEMAP_START
|
||
ld a,$7F ; $7F is blank tile
|
||
.loop
|
||
ld [hli],a
|
||
dec c
|
||
jr nz,.loop
|
||
dec b
|
||
jr nz,.loop
|
||
jp Delay3
|
||
|
||
TextBoxBorder:: ; 1922 (0:1922)
|
||
; draw a text box
|
||
; upper-left corner at coordinates hl
|
||
; height b
|
||
; width c
|
||
|
||
; first row
|
||
push hl
|
||
ld a,"┌"
|
||
ld [hli],a
|
||
inc a ; horizontal border ─
|
||
call NPlaceChar
|
||
inc a ; upper-right border ┐
|
||
ld [hl],a
|
||
|
||
; middle rows
|
||
pop hl
|
||
ld de,20
|
||
add hl,de ; skip the top row
|
||
|
||
.PlaceRow
|
||
push hl
|
||
ld a,"│"
|
||
ld [hli],a
|
||
ld a," "
|
||
call NPlaceChar
|
||
ld [hl],"│"
|
||
|
||
pop hl
|
||
ld de,20
|
||
add hl,de ; move to next row
|
||
dec b
|
||
jr nz,.PlaceRow
|
||
|
||
; bottom row
|
||
ld a,"└"
|
||
ld [hli],a
|
||
ld a,"─"
|
||
call NPlaceChar
|
||
ld [hl],"┘"
|
||
ret
|
||
;
|
||
NPlaceChar:: ; 194f (0:194f)
|
||
; place a row of width c of identical characters
|
||
ld d,c
|
||
.loop
|
||
ld [hli],a
|
||
dec d
|
||
jr nz,.loop
|
||
ret
|
||
|
||
PlaceString:: ; 1955 (0:1955)
|
||
push hl
|
||
PlaceNextChar:: ; 1956 (0:1956)
|
||
ld a,[de]
|
||
|
||
cp "@"
|
||
jr nz,.PlaceText
|
||
ld b,h
|
||
ld c,l
|
||
pop hl
|
||
ret
|
||
|
||
.PlaceText
|
||
cp $4E
|
||
jr nz,.next
|
||
ld bc,$0028
|
||
ld a,[$FFF6]
|
||
bit 2,a
|
||
jr z,.next2
|
||
ld bc,$14
|
||
.next2
|
||
pop hl
|
||
add hl,bc
|
||
push hl
|
||
jp Next19E8
|
||
|
||
.next
|
||
cp $4F
|
||
jr nz,.next3
|
||
pop hl
|
||
FuncCoord 1, 16
|
||
ld hl,Coord
|
||
push hl
|
||
jp Next19E8
|
||
|
||
.next3 ; Check against a dictionary
|
||
and a
|
||
jp z,Char00
|
||
cp $4C
|
||
jp z,Char4C
|
||
cp $4B
|
||
jp z,Char4B
|
||
cp $51
|
||
jp z,Char51
|
||
cp $49
|
||
jp z,Char49
|
||
cp $52
|
||
jp z,Char52
|
||
cp $53
|
||
jp z,Char53
|
||
cp $54
|
||
jp z,Char54
|
||
cp $5B
|
||
jp z,Char5B
|
||
cp $5E
|
||
jp z,Char5E
|
||
cp $5C
|
||
jp z,Char5C
|
||
cp $5D
|
||
jp z,Char5D
|
||
cp $55
|
||
jp z,Char55
|
||
cp $56
|
||
jp z,Char56
|
||
cp $57
|
||
jp z,Char57
|
||
cp $58
|
||
jp z,Char58
|
||
cp $4A
|
||
jp z,Char4A
|
||
cp $5F
|
||
jp z,Char5F
|
||
cp $59
|
||
jp z,Char59
|
||
cp $5A
|
||
jp z,Char5A
|
||
ld [hli],a
|
||
call PrintLetterDelay
|
||
Next19E8:: ; 19e8 (0:19e8)
|
||
inc de
|
||
jp PlaceNextChar
|
||
|
||
Char00:: ; 19ec (0:19ec)
|
||
ld b,h
|
||
ld c,l
|
||
pop hl
|
||
ld de,Char00Text
|
||
dec de
|
||
ret
|
||
|
||
Char00Text:: ; 0x19f4 “%d ERROR.”
|
||
TX_FAR _Char00Text
|
||
db "@"
|
||
|
||
Char52:: ; 0x19f9 player’s name
|
||
push de
|
||
ld de,W_PLAYERNAME
|
||
jr FinishDTE
|
||
|
||
Char53:: ; 19ff (0:19ff) ; rival’s name
|
||
push de
|
||
ld de,W_RIVALNAME
|
||
jr FinishDTE
|
||
|
||
Char5D:: ; 1a05 (0:1a05) ; TRAINER
|
||
push de
|
||
ld de,Char5DText
|
||
jr FinishDTE
|
||
|
||
Char5C:: ; 1a0b (0:1a0b) ; TM
|
||
push de
|
||
ld de,Char5CText
|
||
jr FinishDTE
|
||
|
||
Char5B:: ; 1a11 (0:1a11) ; PC
|
||
push de
|
||
ld de,Char5BText
|
||
jr FinishDTE
|
||
|
||
Char5E:: ; 1a17 (0:1a17) ; ROCKET
|
||
push de
|
||
ld de,Char5EText
|
||
jr FinishDTE
|
||
|
||
Char54:: ; 1a1d (0:1a1d) ; POKé
|
||
push de
|
||
ld de,Char54Text
|
||
jr FinishDTE
|
||
|
||
Char56:: ; 1a23 (0:1a23) ; ……
|
||
push de
|
||
ld de,Char56Text
|
||
jr FinishDTE
|
||
|
||
Char4A:: ; 1a29 (0:1a29) ; PKMN
|
||
push de
|
||
ld de,Char4AText
|
||
jr FinishDTE
|
||
|
||
Char59:: ; 1a2f (0:1a2f)
|
||
; depending on whose turn it is, print
|
||
; enemy active monster’s name, prefixed with “Enemy ”
|
||
; or
|
||
; player active monster’s name
|
||
; (like Char5A but flipped)
|
||
ld a,[H_WHOSETURN]
|
||
xor 1
|
||
jr MonsterNameCharsCommon
|
||
|
||
Char5A:: ; 1a35 (0:1a35)
|
||
; depending on whose turn it is, print
|
||
; player active monster’s name
|
||
; or
|
||
; enemy active monster’s name, prefixed with “Enemy ”
|
||
ld a,[H_WHOSETURN]
|
||
MonsterNameCharsCommon:: ; 1a37 (0:1a37)
|
||
push de
|
||
and a
|
||
jr nz,.Enemy
|
||
ld de,W_PLAYERMONNAME ; player active monster name
|
||
jr FinishDTE
|
||
|
||
.Enemy ; 1A40
|
||
; print “Enemy ”
|
||
ld de,Char5AText
|
||
call PlaceString
|
||
|
||
ld h,b
|
||
ld l,c
|
||
ld de,W_ENEMYMONNAME ; enemy active monster name
|
||
|
||
FinishDTE:: ; 1a4b (0:1a4b)
|
||
call PlaceString
|
||
ld h,b
|
||
ld l,c
|
||
pop de
|
||
inc de
|
||
jp PlaceNextChar
|
||
|
||
Char5CText:: ; 1a55 (0:1a55)
|
||
db "TM@"
|
||
Char5DText:: ; 1a58 (0:1a58)
|
||
db "TRAINER@"
|
||
Char5BText:: ; 1a60 (0:1a60)
|
||
db "PC@"
|
||
Char5EText:: ; 1a63 (0:1a63)
|
||
db "ROCKET@"
|
||
Char54Text:: ; 1a6a (0:1a6a)
|
||
db "POKé@"
|
||
Char56Text:: ; 1a6f (0:1a6f)
|
||
db "……@"
|
||
Char5AText:: ; 1a72 (0:1a72)
|
||
db "Enemy @"
|
||
Char4AText:: ; 1a79 (0:1a79)
|
||
db $E1,$E2,"@" ; PKMN
|
||
|
||
Char55:: ; 1a7c (0:1a7c)
|
||
push de
|
||
ld b,h
|
||
ld c,l
|
||
ld hl,Char55Text
|
||
call TextCommandProcessor
|
||
ld h,b
|
||
ld l,c
|
||
pop de
|
||
inc de
|
||
jp PlaceNextChar
|
||
|
||
Char55Text:: ; 1a8c (0:1a8c)
|
||
; equivalent to Char4B
|
||
TX_FAR _Char55Text
|
||
db "@"
|
||
|
||
Char5F:: ; 1a91 (0:1a91)
|
||
; ends a Pokédex entry
|
||
ld [hl],"."
|
||
pop hl
|
||
ret
|
||
|
||
Char58:: ; 1a95 (0:1a95)
|
||
ld a,[W_ISLINKBATTLE]
|
||
cp 4
|
||
jp z,Next1AA2
|
||
ld a,$EE
|
||
FuncCoord 18, 16
|
||
ld [Coord],a
|
||
Next1AA2:: ; 1aa2 (0:1aa2)
|
||
call ProtectedDelay3
|
||
call ManualTextScroll
|
||
ld a,$7F
|
||
FuncCoord 18, 16
|
||
ld [Coord],a
|
||
Char57:: ; 1aad (0:1aad)
|
||
pop hl
|
||
ld de,Char58Text
|
||
dec de
|
||
ret
|
||
|
||
Char58Text:: ; 1ab3 (0:1ab3)
|
||
db "@"
|
||
|
||
Char51:: ; 1ab4 (0:1ab4)
|
||
push de
|
||
ld a,$EE
|
||
FuncCoord 18, 16
|
||
ld [Coord],a
|
||
call ProtectedDelay3
|
||
call ManualTextScroll
|
||
FuncCoord 1, 13
|
||
ld hl,Coord
|
||
ld bc,$0412
|
||
call ClearScreenArea
|
||
ld c,$14
|
||
call DelayFrames
|
||
pop de
|
||
FuncCoord 1, 14
|
||
ld hl,Coord
|
||
jp Next19E8
|
||
|
||
Char49:: ; 1ad5 (0:1ad5)
|
||
push de
|
||
ld a,$EE
|
||
FuncCoord 18, 16
|
||
ld [Coord],a
|
||
call ProtectedDelay3
|
||
call ManualTextScroll
|
||
FuncCoord 1, 10
|
||
ld hl,Coord
|
||
ld bc,$0712
|
||
call ClearScreenArea
|
||
ld c,$14
|
||
call DelayFrames
|
||
pop de
|
||
pop hl
|
||
FuncCoord 1, 11
|
||
ld hl,Coord
|
||
push hl
|
||
jp Next19E8
|
||
|
||
Char4B:: ; 1af8 (0:1af8)
|
||
ld a,$EE
|
||
FuncCoord 18, 16
|
||
ld [Coord],a
|
||
call ProtectedDelay3
|
||
push de
|
||
call ManualTextScroll
|
||
pop de
|
||
ld a,$7F
|
||
FuncCoord 18, 16
|
||
ld [Coord],a
|
||
;fall through
|
||
Char4C:: ; 1b0a (0:1b0a)
|
||
push de
|
||
call Next1B18
|
||
call Next1B18
|
||
FuncCoord 1, 16
|
||
ld hl,Coord
|
||
pop de
|
||
jp Next19E8
|
||
|
||
Next1B18:: ; 1b18 (0:1b18)
|
||
FuncCoord 0, 14
|
||
ld hl,Coord
|
||
FuncCoord 0, 13
|
||
ld de,Coord
|
||
ld b,$3C
|
||
.next
|
||
ld a,[hli]
|
||
ld [de],a
|
||
inc de
|
||
dec b
|
||
jr nz,.next
|
||
FuncCoord 1, 16
|
||
ld hl,Coord
|
||
ld a,$7F
|
||
ld b,$12
|
||
.next2
|
||
ld [hli],a
|
||
dec b
|
||
jr nz,.next2
|
||
|
||
; wait five frames
|
||
ld b,5
|
||
.WaitFrame
|
||
call DelayFrame
|
||
dec b
|
||
jr nz,.WaitFrame
|
||
|
||
ret
|
||
|
||
ProtectedDelay3:: ; 1b3a (0:1b3a)
|
||
push bc
|
||
call Delay3
|
||
pop bc
|
||
ret
|
||
|
||
TextCommandProcessor:: ; 1b40 (0:1b40)
|
||
ld a,[wd358]
|
||
push af
|
||
set 1,a
|
||
ld e,a
|
||
ld a,[$fff4]
|
||
xor e
|
||
ld [wd358],a
|
||
ld a,c
|
||
ld [wcc3a],a
|
||
ld a,b
|
||
ld [wcc3b],a
|
||
|
||
NextTextCommand:: ; 1b55 (0:1b55)
|
||
ld a,[hli]
|
||
cp a, "@" ; terminator
|
||
jr nz,.doTextCommand
|
||
pop af
|
||
ld [wd358],a
|
||
ret
|
||
.doTextCommand
|
||
push hl
|
||
cp a,$17
|
||
jp z,TextCommand17
|
||
cp a,$0e
|
||
jp nc,TextCommand0B ; if a != 0x17 and a >= 0xE, go to command 0xB
|
||
; if a < 0xE, use a jump table
|
||
ld hl,TextCommandJumpTable
|
||
push bc
|
||
add a
|
||
ld b,$00
|
||
ld c,a
|
||
add hl,bc
|
||
pop bc
|
||
ld a,[hli]
|
||
ld h,[hl]
|
||
ld l,a
|
||
jp [hl]
|
||
|
||
; draw box
|
||
; 04AAAABBCC
|
||
; AAAA = address of upper left corner
|
||
; BB = height
|
||
; CC = width
|
||
TextCommand04:: ; 1b78 (0:1b78)
|
||
pop hl
|
||
ld a,[hli]
|
||
ld e,a
|
||
ld a,[hli]
|
||
ld d,a
|
||
ld a,[hli]
|
||
ld b,a
|
||
ld a,[hli]
|
||
ld c,a
|
||
push hl
|
||
ld h,d
|
||
ld l,e
|
||
call TextBoxBorder
|
||
pop hl
|
||
jr NextTextCommand
|
||
|
||
; place string inline
|
||
; 00{string}
|
||
TextCommand00:: ; 1b8a (0:1b8a)
|
||
pop hl
|
||
ld d,h
|
||
ld e,l
|
||
ld h,b
|
||
ld l,c
|
||
call PlaceString
|
||
ld h,d
|
||
ld l,e
|
||
inc hl
|
||
jr NextTextCommand
|
||
|
||
; place string from RAM
|
||
; 01AAAA
|
||
; AAAA = address of string
|
||
TextCommand01:: ; 1b97 (0:1b97)
|
||
pop hl
|
||
ld a,[hli]
|
||
ld e,a
|
||
ld a,[hli]
|
||
ld d,a
|
||
push hl
|
||
ld h,b
|
||
ld l,c
|
||
call PlaceString
|
||
pop hl
|
||
jr NextTextCommand
|
||
|
||
; print BCD number
|
||
; 02AAAABB
|
||
; AAAA = address of BCD number
|
||
; BB
|
||
; bits 0-4 = length in bytes
|
||
; bits 5-7 = unknown flags
|
||
TextCommand02:: ; 1ba5 (0:1ba5)
|
||
pop hl
|
||
ld a,[hli]
|
||
ld e,a
|
||
ld a,[hli]
|
||
ld d,a
|
||
ld a,[hli]
|
||
push hl
|
||
ld h,b
|
||
ld l,c
|
||
ld c,a
|
||
call PrintBCDNumber
|
||
ld b,h
|
||
ld c,l
|
||
pop hl
|
||
jr NextTextCommand
|
||
|
||
; repoint destination address
|
||
; 03AAAA
|
||
; AAAA = new destination address
|
||
TextCommand03:: ; 1bb7 (0:1bb7)
|
||
pop hl
|
||
ld a,[hli]
|
||
ld [wcc3a],a
|
||
ld c,a
|
||
ld a,[hli]
|
||
ld [wcc3b],a
|
||
ld b,a
|
||
jp NextTextCommand
|
||
|
||
; repoint destination to second line of dialogue text box
|
||
; 05
|
||
; (no arguments)
|
||
TextCommand05:: ; 1bc5 (0:1bc5)
|
||
pop hl
|
||
FuncCoord 1, 16
|
||
ld bc,Coord ; address of second line of dialogue text box
|
||
jp NextTextCommand
|
||
|
||
; blink arrow and wait for A or B to be pressed
|
||
; 06
|
||
; (no arguments)
|
||
TextCommand06:: ; 1bcc (0:1bcc)
|
||
ld a,[W_ISLINKBATTLE]
|
||
cp a,$04
|
||
jp z,TextCommand0D
|
||
ld a,$ee ; down arrow
|
||
FuncCoord 18, 16
|
||
ld [Coord],a ; place down arrow in lower right corner of dialogue text box
|
||
push bc
|
||
call ManualTextScroll ; blink arrow and wait for A or B to be pressed
|
||
pop bc
|
||
ld a," "
|
||
FuncCoord 18, 16
|
||
ld [Coord],a ; overwrite down arrow with blank space
|
||
pop hl
|
||
jp NextTextCommand
|
||
|
||
; scroll text up one line
|
||
; 07
|
||
; (no arguments)
|
||
TextCommand07:: ; 1be7 (0:1be7)
|
||
ld a," "
|
||
FuncCoord 18, 16
|
||
ld [Coord],a ; place blank space in lower right corner of dialogue text box
|
||
call Next1B18 ; scroll up text
|
||
call Next1B18
|
||
pop hl
|
||
FuncCoord 1, 16
|
||
ld bc,Coord ; address of second line of dialogue text box
|
||
jp NextTextCommand
|
||
|
||
; execute asm inline
|
||
; 08{code}
|
||
TextCommand08:: ; 1bf9 (0:1bf9)
|
||
pop hl
|
||
ld de,NextTextCommand
|
||
push de ; return address
|
||
jp [hl]
|
||
|
||
; print decimal number (converted from binary number)
|
||
; 09AAAABB
|
||
; AAAA = address of number
|
||
; BB
|
||
; bits 0-3 = how many digits to display
|
||
; bits 4-7 = how long the number is in bytes
|
||
TextCommand09:: ; 1bff (0:1bff)
|
||
pop hl
|
||
ld a,[hli]
|
||
ld e,a
|
||
ld a,[hli]
|
||
ld d,a
|
||
ld a,[hli]
|
||
push hl
|
||
ld h,b
|
||
ld l,c
|
||
ld b,a
|
||
and a,$0f
|
||
ld c,a
|
||
ld a,b
|
||
and a,$f0
|
||
swap a
|
||
set 6,a
|
||
ld b,a
|
||
call PrintNumber
|
||
ld b,h
|
||
ld c,l
|
||
pop hl
|
||
jp NextTextCommand
|
||
|
||
; wait half a second if the user doesn't hold A or B
|
||
; 0A
|
||
; (no arguments)
|
||
TextCommand0A:: ; 1c1d (0:1c1d)
|
||
push bc
|
||
call Joypad
|
||
ld a,[hJoyHeld]
|
||
and a,%00000011 ; A and B buttons
|
||
jr nz,.skipDelay
|
||
ld c,30
|
||
call DelayFrames
|
||
.skipDelay
|
||
pop bc
|
||
pop hl
|
||
jp NextTextCommand
|
||
|
||
; plays sounds
|
||
; this actually handles various command ID's, not just 0B
|
||
; (no arguments)
|
||
TextCommand0B:: ; 1c31 (0:1c31)
|
||
pop hl
|
||
push bc
|
||
dec hl
|
||
ld a,[hli]
|
||
ld b,a ; b = command number that got us here
|
||
push hl
|
||
ld hl,TextCommandSounds
|
||
.loop
|
||
ld a,[hli]
|
||
cp b
|
||
jr z,.matchFound
|
||
inc hl
|
||
jr .loop
|
||
.matchFound
|
||
cp a,$14
|
||
jr z,.pokemonCry
|
||
cp a,$15
|
||
jr z,.pokemonCry
|
||
cp a,$16
|
||
jr z,.pokemonCry
|
||
ld a,[hl]
|
||
call PlaySound
|
||
call WaitForSoundToFinish
|
||
pop hl
|
||
pop bc
|
||
jp NextTextCommand
|
||
.pokemonCry
|
||
push de
|
||
ld a,[hl]
|
||
call PlayCry
|
||
pop de
|
||
pop hl
|
||
pop bc
|
||
jp NextTextCommand
|
||
|
||
; format: text command ID, sound ID or cry ID
|
||
TextCommandSounds:: ; 1c64 (0:1c64)
|
||
db $0B,(SFX_02_3a - SFX_Headers_02) / 3
|
||
db $12,(SFX_02_46 - SFX_Headers_02) / 3
|
||
db $0E,(SFX_02_41 - SFX_Headers_02) / 3
|
||
db $0F,(SFX_02_3a - SFX_Headers_02) / 3
|
||
db $10,(SFX_02_3b - SFX_Headers_02) / 3
|
||
db $11,(SFX_02_42 - SFX_Headers_02) / 3
|
||
db $13,(SFX_02_44 - SFX_Headers_02) / 3
|
||
db $14,NIDORINA ; used in OakSpeech
|
||
db $15,PIDGEOT ; used in SaffronCityText12
|
||
db $16,DEWGONG ; unused?
|
||
|
||
; draw ellipses
|
||
; 0CAA
|
||
; AA = number of ellipses to draw
|
||
TextCommand0C:: ; 1c78 (0:1c78)
|
||
pop hl
|
||
ld a,[hli]
|
||
ld d,a
|
||
push hl
|
||
ld h,b
|
||
ld l,c
|
||
.loop
|
||
ld a,$75 ; ellipsis
|
||
ld [hli],a
|
||
push de
|
||
call Joypad
|
||
pop de
|
||
ld a,[hJoyHeld] ; joypad state
|
||
and a,%00000011 ; is A or B button pressed?
|
||
jr nz,.skipDelay ; if so, skip the delay
|
||
ld c,10
|
||
call DelayFrames
|
||
.skipDelay
|
||
dec d
|
||
jr nz,.loop
|
||
ld b,h
|
||
ld c,l
|
||
pop hl
|
||
jp NextTextCommand
|
||
|
||
; wait for A or B to be pressed
|
||
; 0D
|
||
; (no arguments)
|
||
TextCommand0D:: ; 1c9a (0:1c9a)
|
||
push bc
|
||
call ManualTextScroll ; wait for A or B to be pressed
|
||
pop bc
|
||
pop hl
|
||
jp NextTextCommand
|
||
|
||
; process text commands in another ROM bank
|
||
; 17AAAABB
|
||
; AAAA = address of text commands
|
||
; BB = bank
|
||
TextCommand17:: ; 1ca3 (0:1ca3)
|
||
pop hl
|
||
ld a,[H_LOADEDROMBANK]
|
||
push af
|
||
ld a,[hli]
|
||
ld e,a
|
||
ld a,[hli]
|
||
ld d,a
|
||
ld a,[hli]
|
||
ld [H_LOADEDROMBANK],a
|
||
ld [$2000],a
|
||
push hl
|
||
ld l,e
|
||
ld h,d
|
||
call TextCommandProcessor
|
||
pop hl
|
||
pop af
|
||
ld [H_LOADEDROMBANK],a
|
||
ld [$2000],a
|
||
jp NextTextCommand
|
||
|
||
TextCommandJumpTable:: ; 1cc1 (0:1cc1)
|
||
dw TextCommand00
|
||
dw TextCommand01
|
||
dw TextCommand02
|
||
dw TextCommand03
|
||
dw TextCommand04
|
||
dw TextCommand05
|
||
dw TextCommand06
|
||
dw TextCommand07
|
||
dw TextCommand08
|
||
dw TextCommand09
|
||
dw TextCommand0A
|
||
dw TextCommand0B
|
||
dw TextCommand0C
|
||
dw TextCommand0D
|
||
|
||
; 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
|
||
|
||
; unrolled loop and using pop for speed
|
||
TransferBgRows:: ; 1d9e (0:1d9e)
|
||
pop de
|
||
ld [hl],e
|
||
inc l
|
||
ld [hl],d
|
||
inc l
|
||
pop de
|
||
ld [hl],e
|
||
inc l
|
||
ld [hl],d
|
||
inc l
|
||
pop de
|
||
ld [hl],e
|
||
inc l
|
||
ld [hl],d
|
||
inc l
|
||
pop de
|
||
ld [hl],e
|
||
inc l
|
||
ld [hl],d
|
||
inc l
|
||
pop de
|
||
ld [hl],e
|
||
inc l
|
||
ld [hl],d
|
||
inc l
|
||
pop de
|
||
ld [hl],e
|
||
inc l
|
||
ld [hl],d
|
||
inc l
|
||
pop de
|
||
ld [hl],e
|
||
inc l
|
||
ld [hl],d
|
||
inc l
|
||
pop de
|
||
ld [hl],e
|
||
inc l
|
||
ld [hl],d
|
||
inc l
|
||
pop de
|
||
ld [hl],e
|
||
inc l
|
||
ld [hl],d
|
||
inc l
|
||
pop de
|
||
ld [hl],e
|
||
inc l
|
||
ld [hl],d
|
||
ld a,13
|
||
add l
|
||
ld l,a
|
||
jr nc,.noCarry
|
||
inc h
|
||
.noCarry
|
||
dec b
|
||
jr nz,TransferBgRows
|
||
ld a,[H_SPTEMP]
|
||
ld h,a
|
||
ld a,[H_SPTEMP + 1]
|
||
ld l,a
|
||
ld sp,hl ; restore stack pointer
|
||
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 20
|
||
ret c
|
||
cp 21
|
||
jr z, .flower
|
||
|
||
ld hl, vTileset + $14 * $10
|
||
ld c, $10
|
||
|
||
ld a, [wd085]
|
||
inc a
|
||
and 7
|
||
ld [wd085], a
|
||
|
||
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]
|
||
and 3
|
||
cp 2
|
||
ld hl, FlowerTile1
|
||
jr c, .copy
|
||
ld hl, FlowerTile2
|
||
jr z, .copy
|
||
ld hl, FlowerTile3
|
||
.copy
|
||
ld de, vTileset + $3 * $10
|
||
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, wc000 ; start of WRAM
|
||
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
|
||
|
||
ld h, vBGMap0 / $100
|
||
call ClearBgMap
|
||
ld h, vBGMap1 / $100
|
||
call ClearBgMap
|
||
|
||
ld a, rLCDC_DEFAULT
|
||
ld [rLCDC], a
|
||
ld a, 16
|
||
ld [hSoftReset], a
|
||
call StopAllSounds
|
||
|
||
ei
|
||
|
||
ld a, $40 ; PREDEF_SGB_BORDER
|
||
call Predef
|
||
|
||
ld a, $1f
|
||
ld [wc0ef], a
|
||
ld [wc0f0], a
|
||
ld a, $9c
|
||
ld [$ffbd], a
|
||
xor a
|
||
ld [$ffbc], a
|
||
dec a
|
||
ld [wcfcb], a
|
||
|
||
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
|
||
xor a
|
||
ld [wMusicHeaderPointer], a
|
||
ld [wc0ee], a
|
||
ld [wcfca], a
|
||
dec a
|
||
jp PlaySound
|
||
|
||
|
||
VBlank::
|
||
|
||
push af
|
||
push bc
|
||
push de
|
||
push hl
|
||
|
||
ld a, [H_LOADEDROMBANK]
|
||
ld [wd122], a
|
||
|
||
ld a, [$ffae]
|
||
ld [rSCX], a
|
||
ld a, [$ffaf]
|
||
ld [rSCY], a
|
||
|
||
ld a, [wd0a0]
|
||
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
|
||
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]
|
||
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
|
||
; XXX this is a hack--rgbasm adds
|
||
; a nop after halts by default.
|
||
db $76 ; halt
|
||
|
||
ld a, [H_VBLANKOCCURRED]
|
||
and a
|
||
jr nz, .halt
|
||
ret
|
||
|
||
|
||
; These routines manage gradual fading
|
||
; (e.g., entering a doorway)
|
||
LoadGBPal:: ; 20ba (0:20ba)
|
||
ld a,[wd35d] ;tells if cur.map is dark (requires HM5_FLASH?)
|
||
ld b,a
|
||
ld hl,GBPalTable_00 ;16
|
||
ld a,l
|
||
sub b
|
||
ld l,a
|
||
jr nc,.jr0
|
||
dec h
|
||
.jr0
|
||
ld a,[hli]
|
||
ld [rBGP],a
|
||
ld a,[hli]
|
||
ld [rOBP0],a
|
||
ld a,[hli]
|
||
ld [rOBP1],a
|
||
ret
|
||
|
||
GBFadeOut1:: ; 20d1 (0:20d1)
|
||
ld hl,IncGradGBPalTable_01 ;0d
|
||
ld b,$04
|
||
jr GBFadeOutCommon
|
||
|
||
GBFadeOut2:: ; 20d8 (0:20d8)
|
||
ld hl,IncGradGBPalTable_02 ;1c
|
||
ld b,$03
|
||
|
||
GBFadeOutCommon:: ; 20dd (0:20dd)
|
||
ld a,[hli]
|
||
ld [rBGP],a
|
||
ld a,[hli]
|
||
ld [rOBP0],a
|
||
ld a,[hli]
|
||
ld [rOBP1],a
|
||
ld c,8
|
||
call DelayFrames
|
||
dec b
|
||
jr nz,GBFadeOutCommon
|
||
ret
|
||
|
||
GBFadeIn1:: ; 20ef (0:20ef)
|
||
ld hl,DecGradGBPalTable_01 ;18
|
||
ld b,$04
|
||
jr GBFadeInCommon
|
||
|
||
GBFadeIn2:: ; 20f6 (0:20f6)
|
||
ld hl,DecGradGBPalTable_02 ;21
|
||
ld b,$03
|
||
|
||
GBFadeInCommon:: ; 20fb (0:20fb)
|
||
ld a,[hld]
|
||
ld [rOBP1],a
|
||
ld a,[hld]
|
||
ld [rOBP0],a
|
||
ld a,[hld]
|
||
ld [rBGP],a
|
||
ld c,8
|
||
call DelayFrames
|
||
dec b
|
||
jr nz,GBFadeInCommon
|
||
ret
|
||
|
||
IncGradGBPalTable_01:: ; 210d (0:210d)
|
||
db %11111111 ;BG Pal
|
||
db %11111111 ;OBJ Pal 1
|
||
db %11111111 ;OBJ Pal 2
|
||
;and so on...
|
||
db %11111110
|
||
db %11111110
|
||
db %11111000
|
||
|
||
db %11111001
|
||
db %11100100
|
||
db %11100100
|
||
GBPalTable_00:: ; 2116 (0:2116)
|
||
db %11100100
|
||
db %11010000
|
||
DecGradGBPalTable_01:: ; 2118 (0:2118)
|
||
db %11100000
|
||
;19
|
||
db %11100100
|
||
db %11010000
|
||
db %11100000
|
||
IncGradGBPalTable_02:: ; 211c (0:211c)
|
||
db %10010000
|
||
db %10000000
|
||
db %10010000
|
||
|
||
db %01000000
|
||
db %01000000
|
||
DecGradGBPalTable_02:: ; 2121 (0:2121)
|
||
db %01000000
|
||
|
||
db %00000000
|
||
db %00000000
|
||
db %00000000
|
||
|
||
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
|
||
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
|
||
dec a
|
||
ld [W_NUMHITS], a ; wd074
|
||
jr nz, .asm_21a7
|
||
ld a, [wd075]
|
||
dec a
|
||
ld [wd075], a
|
||
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
|
||
ld a, $50
|
||
ld [wd075], a
|
||
.asm_2204
|
||
ld a, [$ffad]
|
||
cp $fe
|
||
ret nz
|
||
call Func_2237
|
||
jr z, .asm_221f
|
||
push hl
|
||
ld hl, wcc48
|
||
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
|
||
ld a, [hli]
|
||
or [hl]
|
||
pop hl
|
||
ret
|
||
|
||
Func_223f:: ; 223f (0:223f)
|
||
dec a
|
||
ld [wcc47], a
|
||
ld [wcc48], a
|
||
ret
|
||
|
||
Func_2247:: ; 2247 (0:2247)
|
||
ld hl, wcc42
|
||
ld de, wcc3d
|
||
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
|
||
.asm_2284
|
||
call Func_22c3
|
||
call DelayFrame
|
||
call Func_2237
|
||
jr z, .asm_22a0
|
||
push hl
|
||
ld hl, wcc48
|
||
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]
|
||
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
|
||
ret
|
||
|
||
Func_22c3:: ; 22c3 (0:22c3)
|
||
call asm_22d7
|
||
ld a, [wcc42]
|
||
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
|
||
and $f0
|
||
cp $60
|
||
ret nz
|
||
xor a
|
||
ld [$ffad], a
|
||
ld a, [wcc3d]
|
||
and $f
|
||
ld [wcc3e], a
|
||
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
|
||
jr asm_2324
|
||
|
||
Func_2312:: ; 2312 (0:2312)
|
||
ld c, $a
|
||
ld d, $0
|
||
ld a, [wd72e]
|
||
bit 5, a
|
||
jr z, asm_2324
|
||
xor a
|
||
ld [wcfca], a
|
||
ld c, $8
|
||
ld d, c
|
||
asm_2324:: ; 2324 (0:2324)
|
||
ld a, [wd700]
|
||
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
|
||
.asm_233e
|
||
ld [wc0f0], a
|
||
jr .asm_234c
|
||
.asm_2343
|
||
ld a, [wd35b]
|
||
ld b, a
|
||
call Func_2385
|
||
jr c, .asm_2351
|
||
.asm_234c
|
||
ld a, [wcfca]
|
||
cp b
|
||
ret z
|
||
.asm_2351
|
||
ld a, c
|
||
ld [wMusicHeaderPointer], a
|
||
ld a, b
|
||
ld [wcfca], a
|
||
ld [wc0ee], a
|
||
jp PlaySound
|
||
|
||
Func_235f:: ; 235f (0:235f)
|
||
ld a, [wc0ef]
|
||
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]
|
||
ld e, a
|
||
ld a, [wc0ef]
|
||
cp e
|
||
jr nz, .asm_2394
|
||
ld [wc0f0], a
|
||
and a
|
||
ret
|
||
.asm_2394
|
||
ld a, c
|
||
and a
|
||
ld a, e
|
||
jr nz, .asm_239c
|
||
ld [wc0ef], a
|
||
.asm_239c
|
||
ld [wc0f0], a
|
||
scf
|
||
ret
|
||
|
||
PlayMusic:: ; 23a1 (0:23a1)
|
||
ld b, a
|
||
ld [wc0ee], a
|
||
xor a
|
||
ld [wMusicHeaderPointer], a
|
||
ld a, c
|
||
ld [wc0ef], a
|
||
ld [wc0f0], a
|
||
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]
|
||
and a
|
||
jr z, .asm_23c8
|
||
xor a
|
||
ld [wc02a], a
|
||
ld [wc02b], a
|
||
ld [wc02c], a
|
||
ld [wc02d], a
|
||
.asm_23c8
|
||
ld a, [wMusicHeaderPointer]
|
||
and a
|
||
jr z, .asm_23e3
|
||
ld a, [wc0ee]
|
||
and a
|
||
jr z, .asm_2425
|
||
xor a
|
||
ld [wc0ee], a
|
||
ld a, [wcfca]
|
||
cp $ff
|
||
jr nz, .asm_2414
|
||
xor a
|
||
ld [wMusicHeaderPointer], a
|
||
.asm_23e3
|
||
xor a
|
||
ld [wc0ee], a
|
||
ld a, [H_LOADEDROMBANK]
|
||
ld [$ffb9], a
|
||
ld a, [wc0ef]
|
||
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
|
||
ld a, [wMusicHeaderPointer]
|
||
ld [wcfc8], a
|
||
ld [wcfc9], a
|
||
ld a, b
|
||
ld [wMusicHeaderPointer], a
|
||
.asm_2425
|
||
pop bc
|
||
pop de
|
||
pop hl
|
||
ret
|
||
|
||
UpdateSprites:: ; 2429 (0:2429)
|
||
ld a, [wcfcb]
|
||
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
|
||
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
|
||
; 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
|
||
bit 0, a
|
||
jr z, .useSpriteBuffer1 ; check which buffer to use
|
||
ld hl, S_SPRITEBUFFER2
|
||
.useSpriteBuffer1
|
||
call StoreSpriteOutputPointer
|
||
ld a, [W_SPRITELOADFLAGS] ; wd0a8
|
||
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
|
||
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
|
||
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
|
||
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
|
||
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]
|
||
bit 1, a
|
||
ret nz
|
||
ld a, $77
|
||
ld [$ff24], a
|
||
ret
|
||
.asm_28dc
|
||
ld a, [wcfc9]
|
||
and a
|
||
jr z, .asm_28e7
|
||
dec a
|
||
ld [wcfc9], a
|
||
ret
|
||
.asm_28e7
|
||
ld a, [wcfc8]
|
||
ld [wcfc9], a
|
||
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
|
||
call PlaySound
|
||
ld a, [wc0f0]
|
||
ld [wc0ef], a
|
||
ld a, b
|
||
ld [wc0ee], a
|
||
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
|
||
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
|
||
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
|
||
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]
|
||
and a
|
||
jr nz,HoldTextDisplayOpen
|
||
|
||
AfterDisplayingTextID:: ; 29d6 (0:29d6)
|
||
ld a,[wcc47]
|
||
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)
|
||
call Joypad
|
||
ld a,[hJoyHeld]
|
||
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
|
||
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
|
||
res 0,[hl]
|
||
ld a,[wd732]
|
||
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
|
||
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
|
||
ld a,h
|
||
ld [wd128],a
|
||
ld a,l
|
||
ld [wd129],a
|
||
ld de,wStringBuffer2 + 11
|
||
.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]
|
||
res 5,a
|
||
ld [wd732],a
|
||
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
|
||
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
|
||
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
|
||
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
|
||
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
|
||
; 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)
|
||
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
|
||
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]
|
||
ld l,a
|
||
ld a,[wcf8c]
|
||
ld h,a ; hl = address of the list
|
||
ld a,[hl]
|
||
ld [wd12a],a ; [wd12a] = number of list entries
|
||
ld a,$0d ; list menu text box ID
|
||
ld [wd125],a
|
||
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]
|
||
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
|
||
xor a
|
||
ld [wcc37],a
|
||
ld a,[wCurrentMenuItem]
|
||
ld c,a
|
||
ld a,[wListScrollOffset]
|
||
add c
|
||
ld c,a
|
||
ld a,[wd12a] ; number of list entries
|
||
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]
|
||
ld l,a
|
||
ld a,[wcf8c]
|
||
ld h,a
|
||
inc hl ; hl = beginning of list entries
|
||
ld b,0
|
||
add hl,bc
|
||
ld a,[hl]
|
||
ld [wcf91],a
|
||
ld a,[wListMenuID]
|
||
and a ; 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
|
||
.skipGettingQuantity
|
||
ld a,[wcf91]
|
||
ld [wd0b5],a
|
||
ld a,$01
|
||
ld [wPredefBank],a
|
||
call GetName
|
||
jr .storeChosenEntry
|
||
.pokemonList
|
||
ld hl,W_NUMINPARTY
|
||
ld a,[wcf8b]
|
||
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
|
||
ld a,$01
|
||
ld [wd12e],a
|
||
ld a,[wCurrentMenuItem]
|
||
ld [wd12d],a
|
||
xor a
|
||
ld [$ffb7],a ; joypad state update flag
|
||
ld hl,wd730
|
||
res 6,[hl] ; turn on letter printing delay
|
||
jp BankswitchBack
|
||
.checkOtherKeys ; check B, SELECT, Up, and Down keys
|
||
bit 1,a ; was the B button pressed?
|
||
jp nz,ExitListMenu ; if so, exit the menu
|
||
bit 2,a ; was the select button pressed?
|
||
jp nz,HandleItemListSwapping ; if so, allow the player to swap menu entries
|
||
ld b,a
|
||
bit 7,b ; was Down pressed?
|
||
ld hl,wListScrollOffset
|
||
jr z,.upPressed
|
||
.downPressed
|
||
ld a,[hl]
|
||
add a,3
|
||
ld b,a
|
||
ld a,[wd12a] ; number of list entries
|
||
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
|
||
jp .incrementQuantity
|
||
.waitForKeyPressLoop
|
||
call JoypadLowSensitivity
|
||
ld a,[hJoyPressed] ; newly pressed buttons
|
||
bit 0,a ; was the A button pressed?
|
||
jp nz,.buttonAPressed
|
||
bit 1,a ; was the B button pressed?
|
||
jp nz,.buttonBPressed
|
||
bit 6,a ; was Up pressed?
|
||
jr nz,.incrementQuantity
|
||
bit 7,a ; was Down pressed?
|
||
jr nz,.decrementQuantity
|
||
jr .waitForKeyPressLoop
|
||
.incrementQuantity
|
||
ld a,[wcf97] ; max quantity
|
||
inc a
|
||
ld b,a
|
||
ld hl,wcf96 ; current quantity
|
||
inc [hl]
|
||
ld a,[hl]
|
||
cp b
|
||
jr nz,.handleNewQuantity
|
||
; wrap to 1 if the player goes above the max quantity
|
||
ld a,1
|
||
ld [hl],a
|
||
jr .handleNewQuantity
|
||
.decrementQuantity
|
||
ld hl,wcf96 ; current quantity
|
||
dec [hl]
|
||
jr nz,.handleNewQuantity
|
||
; wrap to the max quantity if the player goes below 1
|
||
ld a,[wcf97] ; max quantity
|
||
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]
|
||
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
|
||
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
|
||
ret
|
||
.buttonBPressed ; the player chose to cancel the transaction
|
||
xor a
|
||
ld [wcc35],a ; 0 means no item is currently being swapped
|
||
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
|
||
ld a,$02
|
||
ld [wd12e],a
|
||
ld [wcc37],a
|
||
xor a
|
||
ld [$ffb7],a
|
||
ld hl,wd730
|
||
res 6,[hl]
|
||
call BankswitchBack
|
||
xor a
|
||
ld [wcc35],a ; 0 means no item is currently being swapped
|
||
scf
|
||
ret
|
||
|
||
PrintListMenuEntries:: ; 2e5a (0:2e5a)
|
||
FuncCoord 5, 3
|
||
ld hl,Coord
|
||
ld b,$09
|
||
ld c,$0e
|
||
call ClearScreenArea
|
||
ld a,[wcf8b]
|
||
ld e,a
|
||
ld a,[wcf8c]
|
||
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
|
||
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]
|
||
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]
|
||
and a ; should prices be printed?
|
||
jr z,.skipPrintingItemPrice
|
||
.printItemPrice
|
||
push hl
|
||
ld a,[de]
|
||
ld de,ItemPrices
|
||
ld [wcf91],a
|
||
call GetItemPrice ; get price
|
||
pop hl
|
||
ld bc,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]
|
||
push af
|
||
push hl
|
||
ld hl,W_NUMINPARTY
|
||
ld a,[wcf8b]
|
||
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
|
||
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]
|
||
and a ; is it a list of party pokemon or box pokemon?
|
||
jr z,.skipCopyingLevel
|
||
.copyLevel
|
||
ld a,[wcf9b]
|
||
ld [wcfb9],a
|
||
.skipCopyingLevel
|
||
pop hl
|
||
ld bc,$001c
|
||
add hl,bc
|
||
call PrintLevel ; print level
|
||
pop af
|
||
ld [wd11e],a
|
||
.skipPrintingPokemonLevel
|
||
pop hl
|
||
pop de
|
||
inc de
|
||
ld a,[wListMenuID]
|
||
cp a,ITEMLISTMENU
|
||
jr nz,.nextListEntry
|
||
.printItemQuantity
|
||
ld a,[wd11e]
|
||
ld [wcf91],a
|
||
call IsKeyItem ; check if item is unsellable
|
||
ld a,[wd124]
|
||
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]
|
||
push af
|
||
ld a,[de]
|
||
ld [wcf97],a
|
||
push de
|
||
ld de,wd11e
|
||
ld [de],a
|
||
ld bc,$0102
|
||
call PrintNumber
|
||
pop de
|
||
pop af
|
||
ld [wd11e],a
|
||
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)
|
||
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]
|
||
dec a
|
||
ld hl,MonsterNames ; 421E
|
||
ld c,10
|
||
ld b,0
|
||
call AddNTimes
|
||
ld de,wcd6d
|
||
push de
|
||
ld bc,10
|
||
call CopyData
|
||
ld hl,wcd77
|
||
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
|
||
push hl
|
||
push bc
|
||
ld a,[wd11e]
|
||
cp HM_01 ; is this a TM/HM?
|
||
jr nc,.Machine
|
||
|
||
ld [wd0b5],a
|
||
ld a,ITEM_NAME
|
||
ld [W_LISTTYPE],a
|
||
ld a,BANK(ItemNames)
|
||
ld [wPredefBank],a
|
||
call GetName
|
||
jr .Finish
|
||
|
||
.Machine
|
||
call GetMachineName
|
||
.Finish
|
||
ld de,wcd6d ; pointer to where item name is stored in RAM
|
||
pop bc
|
||
pop hl
|
||
ret
|
||
|
||
GetMachineName:: ; 2ff3 (0:2ff3)
|
||
; copies the name of the TM/HM in [wd11e] to wcd6d
|
||
push hl
|
||
push de
|
||
push bc
|
||
ld a,[wd11e]
|
||
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
|
||
ld hl,HiddenPrefix ; points to "HM"
|
||
ld bc,2
|
||
jr .WriteMachinePrefix
|
||
.WriteTM
|
||
ld hl,TechnicalPrefix ; points to "TM"
|
||
ld bc,2
|
||
.WriteMachinePrefix
|
||
ld de,wcd6d
|
||
call CopyData
|
||
|
||
; now get the machine number and convert it to text
|
||
ld a,[wd11e]
|
||
sub 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
|
||
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
|
||
ld a,BANK(MoveNames)
|
||
ld [wPredefBank],a
|
||
call GetName
|
||
ld de,wcd6d ; pointer to where move name is stored in RAM
|
||
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
|
||
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
|
||
ret
|
||
|
||
; uses an item
|
||
; UseItem is used with dummy items to perform certain other functions as well
|
||
; INPUT:
|
||
; [wcf91] = item ID
|
||
; OUTPUT:
|
||
; [wcd6a] = success
|
||
; 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
|
||
; 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
|
||
; OUTPUT:
|
||
; [wd124] = result
|
||
; 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
|
||
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]
|
||
and a
|
||
ret nz
|
||
ld a, [wd736]
|
||
bit 1, a
|
||
ret nz
|
||
ld a, [wd730]
|
||
and $80
|
||
ret
|
||
|
||
Func_310e:: ; 310e (0:310e)
|
||
ld hl, wd736
|
||
bit 0, [hl]
|
||
res 0, [hl]
|
||
jr nz, .asm_3146
|
||
ld a, [wcc57]
|
||
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]
|
||
ld [H_LOADEDROMBANK], a
|
||
ld [$2000], a
|
||
ld a, [wcf10]
|
||
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)
|
||
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]
|
||
cp $ff
|
||
jr nz, .trainerEngaging
|
||
xor a
|
||
ld [wcf13], a
|
||
ld [wTrainerHeaderFlagBit], a
|
||
ret
|
||
.trainerEngaging
|
||
ld hl, W_FLAGS_D733
|
||
set 3, [hl]
|
||
ld [wcd4f], a
|
||
xor a
|
||
ld [wcd50], a
|
||
ld a, $4c
|
||
call Predef
|
||
ld a, D_RIGHT | D_LEFT | D_UP | D_DOWN
|
||
ld [wJoyIgnore], a
|
||
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]
|
||
and $1
|
||
ret nz
|
||
ld [wJoyIgnore], a
|
||
ld a, [wcf13]
|
||
ld [H_DOWNARROWBLINKCNT2], a ; $ff8c
|
||
call DisplayTextID
|
||
|
||
Func_325d:: ; 325d (0:325d)
|
||
xor a
|
||
ld [wJoyIgnore], a
|
||
call InitBattleEnemyParameters
|
||
ld hl, wd72d
|
||
set 6, [hl]
|
||
set 7, [hl]
|
||
ld hl, wd72e
|
||
set 1, [hl]
|
||
ld hl, W_CURMAPSCRIPT
|
||
inc [hl] ; progress to battle phase 2 (battling)
|
||
ret
|
||
|
||
EndTrainerBattle:: ; 3275 (0:3275)
|
||
ld hl, wd126
|
||
set 5, [hl]
|
||
set 6, [hl]
|
||
ld hl, wd72d
|
||
res 7, [hl]
|
||
ld hl, wFlags_0xcd60
|
||
res 0, [hl] ; player is no longer engaged by any trainer
|
||
ld a, [W_ISINBATTLE] ; W_ISINBATTLE
|
||
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]
|
||
call IsInArray ; search for sprite ID
|
||
inc hl
|
||
ld a, [hl]
|
||
ld [wcc4d], a ; load corresponding missable object index and remove it
|
||
ld a, $11
|
||
call Predef ; indirect jump to RemoveMissableObject (f1d7 (3:71d7))
|
||
.skipRemoveSprite
|
||
ld hl, wd730
|
||
bit 4, [hl]
|
||
res 4, [hl]
|
||
ret nz
|
||
|
||
ResetButtonPressedAndMapScript:: ; 32c1 (0:32c1)
|
||
xor a
|
||
ld [wJoyIgnore], a
|
||
ld [hJoyHeld], a
|
||
ld [hJoyPressed], a
|
||
ld [hJoyReleased], a
|
||
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
|
||
ld [W_ENEMYMONORTRAINERCLASS], a
|
||
cp $c8
|
||
ld a, [wEngagedTrainerSet] ; wcd2e
|
||
jr c, .noTrainer
|
||
ld [W_TRAINERNO], a ; wd05d
|
||
ret
|
||
.noTrainer
|
||
ld [W_CURENEMYLVL], a ; W_CURENEMYLVL
|
||
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
|
||
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]
|
||
swap a
|
||
ld [wTrainerSpriteOffset], a ; wWhichTrade
|
||
ld a, $39
|
||
call Predef ; indirect jump to CheckEngagePlayer (5690f (15:690f))
|
||
pop de
|
||
pop hl
|
||
ld a, [wTrainerSpriteOffset] ; wWhichTrade
|
||
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
|
||
EngageMapTrainer:: ; 336a (0:336a)
|
||
ld hl, W_MAPSPRITEEXTRADATA
|
||
ld d, $0
|
||
ld a, [wcf13]
|
||
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
|
||
jp PlayTrainerMusic
|
||
|
||
Func_3381:: ; 3381 (0:3381)
|
||
push hl
|
||
ld hl, wd72d
|
||
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]
|
||
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
|
||
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
|
||
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
|
||
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
|
||
call DecodeRLEList
|
||
dec a
|
||
ld [wcd38], a
|
||
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
|
||
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
|
||
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
|
||
; 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
|
||
.loop
|
||
ld a,[hli]
|
||
cp a,$ff ; reached terminator?
|
||
jr z,.notInArray
|
||
push hl
|
||
ld hl,wWhichTrade
|
||
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
|
||
; sets carry if the coordinates are in the array, clears carry if not
|
||
CheckBoulderCoords:: ; 34e4 (0:34e4)
|
||
push hl
|
||
ld hl, wSpriteStateData2 + $04
|
||
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
|
||
and a
|
||
jr nz, .linkBattle
|
||
ld a, Bank(TrainerPicAndMoneyPointers)
|
||
call BankswitchHome
|
||
ld a, [W_TRAINERCLASS] ; wd031
|
||
dec a
|
||
ld hl, TrainerPicAndMoneyPointers
|
||
ld bc, $5
|
||
call AddNTimes
|
||
ld de, wd033
|
||
ld a, [hli]
|
||
ld [de], a
|
||
inc de
|
||
ld a, [hli]
|
||
ld [de], a
|
||
ld de, wd046
|
||
ld a, [hli]
|
||
ld [de], a
|
||
inc de
|
||
ld a, [hli]
|
||
ld [de], a
|
||
jp BankswitchBack
|
||
.linkBattle
|
||
ld hl, wd033
|
||
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
|
||
|
||
|
||
HasEnoughMoney::
|
||
; Check if the player has at least as much
|
||
; money as the 3-byte BCD value at $ff9f.
|
||
ld de, wPlayerMoney
|
||
ld hl, $ff9f
|
||
ld c, 3
|
||
jp StringCmp
|
||
|
||
HasEnoughCoins::
|
||
; Check if the player has at least as many
|
||
; coins as the 2-byte BCD value at $ffa0.
|
||
ld de, wPlayerCoins
|
||
ld hl, $ffa0
|
||
ld c, 2
|
||
jp StringCmp
|
||
|
||
|
||
BankswitchHome:: ; 35bc (0:35bc)
|
||
; switches to bank # in a
|
||
; Only use this when in the home bank!
|
||
ld [wcf09],a
|
||
ld a,[H_LOADEDROMBANK]
|
||
ld [wcf08],a
|
||
ld a,[wcf09]
|
||
ld [H_LOADEDROMBANK],a
|
||
ld [$2000],a
|
||
ret
|
||
|
||
BankswitchBack:: ; 35cd (0:35cd)
|
||
; returns from BankswitchHome
|
||
ld a,[wcf08]
|
||
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
|
||
call InitYesNoTextBoxParameters
|
||
jp DisplayTextBoxID
|
||
|
||
InitYesNoTextBoxParameters:: ; 35ff (0:35ff)
|
||
xor a
|
||
ld [wd12c], a
|
||
FuncCoord 14, 7
|
||
ld hl, Coord
|
||
ld bc, $80f
|
||
ret
|
||
|
||
YesNoChoicePokeCenter:: ; 360a (0:360a)
|
||
call SaveScreenTilesToBuffer1
|
||
ld a, $6
|
||
ld [wd12c], a
|
||
FuncCoord 11, 6
|
||
ld hl, Coord
|
||
ld bc, $80c
|
||
jr DisplayYesNoChoice
|
||
|
||
Func_361a:: ; 361a (0:361a)
|
||
call SaveScreenTilesToBuffer1
|
||
ld a, $3
|
||
ld [wd12c], a
|
||
FuncCoord 12, 7
|
||
ld hl, Coord
|
||
ld bc, $080d
|
||
DisplayYesNoChoice:: ; 3628 (0:3628)
|
||
ld a, $14
|
||
ld [wd125], a
|
||
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
|
||
call SetSpriteMovementBytesToFF
|
||
MoveSprite_:: ; 363d (0:363d)
|
||
push hl
|
||
push bc
|
||
call GetSpriteMovementByte1Pointer
|
||
xor a
|
||
ld [hl],a
|
||
ld hl,wcc5b
|
||
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
|
||
|
||
pop bc
|
||
ld hl,wd730
|
||
set 0,[hl]
|
||
pop hl
|
||
xor a
|
||
ld [wcd3b],a
|
||
ld [wccd3],a
|
||
dec a
|
||
ld [wJoyIgnore],a
|
||
ld [wcd3a],a
|
||
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
|
||
ld de,vFont
|
||
ld bc,$400
|
||
ld a,BANK(FontGraphics)
|
||
jp FarCopyDataDouble ; if LCD is off, transfer all at once
|
||
.lcdEnabled
|
||
ld de,FontGraphics
|
||
ld hl,vFont
|
||
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
|
||
ld de,vChars2 + $600
|
||
ld bc,$200
|
||
ld a,BANK(TextBoxGraphics)
|
||
jp FarCopyData2 ; if LCD is off, transfer all at once
|
||
.lcdEnabled
|
||
ld de,TextBoxGraphics
|
||
ld hl,vChars2 + $600
|
||
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
|
||
ld de,vChars2 + $620
|
||
ld bc,$1e0
|
||
ld a,BANK(HpBarAndStatusGraphics)
|
||
jp FarCopyData2 ; if LCD is off, transfer all at once
|
||
.lcdEnabled
|
||
ld de,HpBarAndStatusGraphics
|
||
ld hl,vChars2 + $620
|
||
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]
|
||
and $80
|
||
ret nz
|
||
push hl
|
||
.asm_374f
|
||
ld hl, wc02a
|
||
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
|
||
;
|
||
; returns pointer to name in de
|
||
ld a,[wd0b5]
|
||
ld [wd11e],a
|
||
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]
|
||
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]
|
||
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
|
||
ld bc,$0014
|
||
call CopyData
|
||
.gotPtr ; $37cd
|
||
ld a,e
|
||
ld [wcf8d],a
|
||
ld a,d
|
||
ld [wcf8e],a
|
||
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
|
||
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
|
||
ld a, [hli]
|
||
ld h, [hl]
|
||
ld l, a
|
||
ld a, [wcf91]
|
||
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]
|
||
CopyStringToCF4B:: ; 3826 (0:3826)
|
||
ld hl, wcf4b
|
||
; 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)
|
||
; Just copies [hJoyPressed] to [$ffb5].
|
||
; 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)
|
||
JoypadLowSensitivity:: ; 3831 (0:3831)
|
||
call Joypad
|
||
ld a,[$ffb7] ; flag
|
||
and a ; get all currently pressed buttons or only newly pressed buttons?
|
||
ld a,[hJoyPressed] ; newly pressed buttons
|
||
jr z,.storeButtonState
|
||
ld a,[hJoyHeld] ; all currently pressed buttons
|
||
.storeButtonState
|
||
ld [$ffb5],a
|
||
ld a,[hJoyPressed] ; newly pressed buttons
|
||
and a ; have any buttons been newly pressed since last check?
|
||
jr z,.noNewlyPressedButtons
|
||
.newlyPressedButtons
|
||
ld a,30 ; half a second delay
|
||
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
|
||
ld a,[hJoyHeld]
|
||
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]
|
||
and a
|
||
jr z, .asm_387c
|
||
call Func_716c6
|
||
.asm_387c
|
||
FuncCoord 18, 16
|
||
ld hl, Coord
|
||
call HandleDownArrowBlinkTiming
|
||
pop hl
|
||
call JoypadLowSensitivity
|
||
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
|
||
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.
|
||
PrintLetterDelay:: ; 38d3 (0:38d3)
|
||
ld a,[wd730]
|
||
bit 6,a
|
||
ret nz
|
||
ld a,[wd358]
|
||
bit 1,a
|
||
ret z
|
||
push hl
|
||
push de
|
||
push bc
|
||
ld a,[wd358]
|
||
bit 0,a
|
||
jr z,.waitOneFrame
|
||
ld a,[W_OPTIONS]
|
||
and a,$0f
|
||
ld [H_FRAMECOUNTER],a
|
||
jr .checkButtons
|
||
.waitOneFrame
|
||
ld a,1
|
||
ld [H_FRAMECOUNTER],a
|
||
.checkButtons
|
||
call Joypad
|
||
ld a,[hJoyHeld]
|
||
.checkAButton
|
||
bit 0,a ; is the A button pressed?
|
||
jr z,.checkBButton
|
||
jr .endWait
|
||
.checkBButton
|
||
bit 1,a ; is the B button pressed?
|
||
jr z,.buttonsNotPressed
|
||
.endWait
|
||
call DelayFrame
|
||
jr .done
|
||
.buttonsNotPressed ; if neither A nor B is pressed
|
||
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.
|
||
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
|
||
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
|
||
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)
|
||
ld h,wOAMBuffer / $100
|
||
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
|
||
|
||
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
|
||
call PlaceMenuCursor
|
||
call Delay3
|
||
.loop2
|
||
push hl
|
||
ld a,[wd09b]
|
||
and a ; is it a pokemon selection menu?
|
||
jr z,.getJoypadState
|
||
callba AnimatePartyMon ; shake mini sprite of selected pokemon
|
||
.getJoypadState
|
||
pop hl
|
||
call JoypadLowSensitivity
|
||
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
|
||
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]
|
||
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).
|
||
|
||
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
|
||
xor a
|
||
ld [wcc3c],a ; make DisplayTextID wait for button press
|
||
ret
|
||
|
||
PrintText:: ; 3c49 (0:3c49)
|
||
; given a pointer in hl, print the text there
|
||
push hl
|
||
ld a,1
|
||
ld [wd125],a
|
||
call DisplayTextBoxID
|
||
call UpdateSprites
|
||
call Delay3
|
||
pop hl
|
||
Func_3c59:: ; 3c59 (0:3c59)
|
||
FuncCoord 1,14
|
||
ld bc,Coord
|
||
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
|
||
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]
|
||
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
|
||
ld a, [hl]
|
||
push af
|
||
res 0, [hl]
|
||
push hl
|
||
xor a
|
||
ld [W_SPRITESETID], a ; W_SPRITESETID
|
||
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.
|
||
; Return carry on success.
|
||
ld a, b
|
||
ld [wd11e], a
|
||
ld [wcf91], a
|
||
ld a, c
|
||
ld [wcf96], a
|
||
ld hl,wNumBagItems
|
||
call AddItemToInventory
|
||
ret nc
|
||
call GetItemName
|
||
call CopyStringToCF4B
|
||
scf
|
||
ret
|
||
|
||
GivePokemon::
|
||
; Give the player monster b at level c.
|
||
ld a, b
|
||
ld [wcf91], a
|
||
ld a, c
|
||
ld [W_CURENEMYLVL], a
|
||
xor a
|
||
ld [wcc49], a
|
||
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
|
||
ld a, [hJoyHeld]
|
||
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]
|
||
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
|
||
set 0, [hl]
|
||
call DisplayTextID
|
||
|
||
Func_3f05:: ; 3f05 (0:3f05)
|
||
ld hl, W_MAPTEXTPTR ; wd36c
|
||
ld a, [$ffec]
|
||
ld [hli], a
|
||
ld a, [$ffed]
|
||
ld [hl], a
|
||
ret
|
||
|
||
Func_3f0f:: ; 3f0f (0:3f0f)
|
||
ld a, [W_MAPTEXTPTR] ; wd36c
|
||
ld [$ffec], a
|
||
ld a, [W_MAPTEXTPTR + 1]
|
||
ld [$ffed], a
|
||
ld a, l
|
||
ld [W_MAPTEXTPTR], a ; wd36c
|
||
ld a, h
|
||
ld [W_MAPTEXTPTR + 1], a
|
||
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
|