mirror of
https://github.com/pret/pokered.git
synced 2024-10-22 22:55:31 +00:00
1808 lines
36 KiB
NASM
1808 lines
36 KiB
NASM
INCLUDE "constants.asm"
|
|
|
|
|
|
SECTION "NULL", ROM0
|
|
NULL::
|
|
|
|
INCLUDE "home/header.asm"
|
|
|
|
|
|
SECTION "High Home", ROM0
|
|
|
|
INCLUDE "home/lcd.asm"
|
|
INCLUDE "home/clear_sprites.asm"
|
|
INCLUDE "home/copy.asm"
|
|
|
|
|
|
SECTION "Home", ROM0
|
|
|
|
INCLUDE "home/start.asm"
|
|
INCLUDE "home/joypad.asm"
|
|
INCLUDE "data/maps/map_header_pointers.asm"
|
|
INCLUDE "home/overworld.asm"
|
|
|
|
CheckForUserInterruption::
|
|
; Return carry if Up+Select+B, Start or A are pressed in c frames.
|
|
; Used only in the intro and title screen.
|
|
call DelayFrame
|
|
|
|
push bc
|
|
call JoypadLowSensitivity
|
|
pop bc
|
|
|
|
ldh a, [hJoyHeld]
|
|
cp D_UP + SELECT + B_BUTTON
|
|
jr z, .input
|
|
|
|
ldh a, [hJoy5]
|
|
and START | A_BUTTON
|
|
jr nz, .input
|
|
|
|
dec c
|
|
jr nz, CheckForUserInterruption
|
|
|
|
and a
|
|
ret
|
|
|
|
.input
|
|
scf
|
|
ret
|
|
|
|
; function to load position data for destination warp when switching maps
|
|
; INPUT:
|
|
; a = ID of destination warp within destination map
|
|
LoadDestinationWarpPosition::
|
|
ld b, a
|
|
ldh a, [hLoadedROMBank]
|
|
push af
|
|
ld a, [wPredefParentBank]
|
|
ldh [hLoadedROMBank], a
|
|
ld [MBC1RomBank], a
|
|
ld a, b
|
|
add a
|
|
add a
|
|
ld c, a
|
|
ld b, 0
|
|
add hl, bc
|
|
ld bc, 4
|
|
ld de, wCurrentTileBlockMapViewPointer
|
|
call CopyData
|
|
pop af
|
|
ldh [hLoadedROMBank], a
|
|
ld [MBC1RomBank], a
|
|
ret
|
|
|
|
INCLUDE "home/pokemon.asm"
|
|
INCLUDE "home/print_bcd.asm"
|
|
INCLUDE "home/pics.asm"
|
|
INCLUDE "data/tilesets/collision_tile_ids.asm"
|
|
INCLUDE "home/copy2.asm"
|
|
INCLUDE "home/text.asm"
|
|
INCLUDE "home/vcopy.asm"
|
|
INCLUDE "home/init.asm"
|
|
INCLUDE "home/vblank.asm"
|
|
INCLUDE "home/fade.asm"
|
|
INCLUDE "home/serial.asm"
|
|
INCLUDE "home/timer.asm"
|
|
INCLUDE "home/audio.asm"
|
|
|
|
UpdateSprites::
|
|
ld a, [wUpdateSpritesEnabled]
|
|
dec a
|
|
ret nz
|
|
ldh a, [hLoadedROMBank]
|
|
push af
|
|
ld a, BANK(_UpdateSprites)
|
|
ldh [hLoadedROMBank], a
|
|
ld [MBC1RomBank], a
|
|
call _UpdateSprites
|
|
pop af
|
|
ldh [hLoadedROMBank], a
|
|
ld [MBC1RomBank], a
|
|
ret
|
|
|
|
INCLUDE "data/items/marts.asm"
|
|
INCLUDE "home/overworld_text.asm"
|
|
INCLUDE "home/uncompress.asm"
|
|
|
|
ResetPlayerSpriteData::
|
|
ld hl, wSpriteStateData1
|
|
call ResetPlayerSpriteData_ClearSpriteData
|
|
ld hl, wSpriteStateData2
|
|
call ResetPlayerSpriteData_ClearSpriteData
|
|
ld a, $1
|
|
ld [wSpritePlayerStateData1PictureID], a
|
|
ld [wSpritePlayerStateData2ImageBaseOffset], a
|
|
ld hl, wSpritePlayerStateData1YPixels
|
|
ld [hl], $3c ; set Y screen pos
|
|
inc hl
|
|
inc hl
|
|
ld [hl], $40 ; set X screen pos
|
|
ret
|
|
|
|
; overwrites sprite data with zeroes
|
|
ResetPlayerSpriteData_ClearSpriteData::
|
|
ld bc, $10
|
|
xor a
|
|
jp FillMemory
|
|
|
|
FadeOutAudio::
|
|
ld a, [wAudioFadeOutControl]
|
|
and a ; currently fading out audio?
|
|
jr nz, .fadingOut
|
|
ld a, [wd72c]
|
|
bit 1, a
|
|
ret nz
|
|
ld a, $77
|
|
ldh [rNR50], a
|
|
ret
|
|
.fadingOut
|
|
ld a, [wAudioFadeOutCounter]
|
|
and a
|
|
jr z, .counterReachedZero
|
|
dec a
|
|
ld [wAudioFadeOutCounter], a
|
|
ret
|
|
.counterReachedZero
|
|
ld a, [wAudioFadeOutCounterReloadValue]
|
|
ld [wAudioFadeOutCounter], a
|
|
ldh a, [rNR50]
|
|
and a ; has the volume reached 0?
|
|
jr z, .fadeOutComplete
|
|
ld b, a
|
|
and $f
|
|
dec a
|
|
ld c, a
|
|
ld a, b
|
|
and $f0
|
|
swap a
|
|
dec a
|
|
swap a
|
|
or c
|
|
ldh [rNR50], a
|
|
ret
|
|
.fadeOutComplete
|
|
ld a, [wAudioFadeOutControl]
|
|
ld b, a
|
|
xor a
|
|
ld [wAudioFadeOutControl], a
|
|
ld a, SFX_STOP_ALL_MUSIC
|
|
ld [wNewSoundID], a
|
|
call PlaySound
|
|
ld a, [wAudioSavedROMBank]
|
|
ld [wAudioROMBank], a
|
|
ld a, b
|
|
ld [wNewSoundID], a
|
|
jp PlaySound
|
|
|
|
INCLUDE "home/text_script.asm"
|
|
INCLUDE "home/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:
|
|
; [wNumSetBits] = number of set bits
|
|
CountSetBits::
|
|
ld c, 0
|
|
.loop
|
|
ld a, [hli]
|
|
ld e, a
|
|
ld d, 8
|
|
.innerLoop ; count how many bits are set in the current byte
|
|
srl e
|
|
ld a, 0
|
|
adc c
|
|
ld c, a
|
|
dec d
|
|
jr nz, .innerLoop
|
|
dec b
|
|
jr nz, .loop
|
|
ld a, c
|
|
ld [wNumSetBits], a
|
|
ret
|
|
|
|
; subtracts the amount the player paid from their money
|
|
; OUTPUT: carry = 0(success) or 1(fail because there is not enough money)
|
|
SubtractAmountPaidFromMoney::
|
|
farjp SubtractAmountPaidFromMoney_
|
|
|
|
; adds the amount the player sold to their money
|
|
AddAmountSoldToMoney::
|
|
ld de, wPlayerMoney + 2
|
|
ld hl, hMoney + 2 ; total price of items
|
|
ld c, 3 ; length of money in bytes
|
|
predef AddBCDPredef ; add total price to money
|
|
ld a, MONEY_BOX
|
|
ld [wTextBoxID], a
|
|
call DisplayTextBoxID ; redraw money text box
|
|
ld a, SFX_PURCHASE
|
|
call PlaySoundWaitForCurrent
|
|
jp WaitForSoundToFinish
|
|
|
|
; function to remove an item (in varying quantities) from the player's bag or PC box
|
|
; INPUT:
|
|
; HL = address of inventory (either wNumBagItems or wNumBoxItems)
|
|
; [wWhichPokemon] = index (within the inventory) of the item to remove
|
|
; [wItemQuantity] = quantity to remove
|
|
RemoveItemFromInventory::
|
|
ldh a, [hLoadedROMBank]
|
|
push af
|
|
ld a, BANK(RemoveItemFromInventory_)
|
|
ldh [hLoadedROMBank], a
|
|
ld [MBC1RomBank], a
|
|
call RemoveItemFromInventory_
|
|
pop af
|
|
ldh [hLoadedROMBank], a
|
|
ld [MBC1RomBank], 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
|
|
; [wItemQuantity] = item quantity
|
|
; sets carry flag if successful, unsets carry flag if unsuccessful
|
|
AddItemToInventory::
|
|
push bc
|
|
ldh a, [hLoadedROMBank]
|
|
push af
|
|
ld a, BANK(AddItemToInventory_)
|
|
ldh [hLoadedROMBank], a
|
|
ld [MBC1RomBank], a
|
|
call AddItemToInventory_
|
|
pop bc
|
|
ld a, b
|
|
ldh [hLoadedROMBank], a
|
|
ld [MBC1RomBank], a
|
|
pop bc
|
|
ret
|
|
|
|
INCLUDE "home/list_menu.asm"
|
|
INCLUDE "home/names.asm"
|
|
|
|
; reloads text box tile patterns, current map view, and tileset tile patterns
|
|
ReloadMapData::
|
|
ldh a, [hLoadedROMBank]
|
|
push af
|
|
ld a, [wCurMap]
|
|
call SwitchToMapRomBank
|
|
call DisableLCD
|
|
call LoadTextBoxTilePatterns
|
|
call LoadCurrentMapView
|
|
call LoadTilesetTilePatternData
|
|
call EnableLCD
|
|
pop af
|
|
ldh [hLoadedROMBank], a
|
|
ld [MBC1RomBank], a
|
|
ret
|
|
|
|
; reloads tileset tile patterns
|
|
ReloadTilesetTilePatterns::
|
|
ldh a, [hLoadedROMBank]
|
|
push af
|
|
ld a, [wCurMap]
|
|
call SwitchToMapRomBank
|
|
call DisableLCD
|
|
call LoadTilesetTilePatternData
|
|
call EnableLCD
|
|
pop af
|
|
ldh [hLoadedROMBank], a
|
|
ld [MBC1RomBank], a
|
|
ret
|
|
|
|
; shows the town map and lets the player choose a destination to fly to
|
|
ChooseFlyDestination::
|
|
ld hl, wd72e
|
|
res 4, [hl]
|
|
farjp LoadTownMap_Fly
|
|
|
|
; causes the text box to close without waiting for a button press after displaying text
|
|
DisableWaitingAfterTextDisplay::
|
|
ld a, $01
|
|
ld [wDoNotWaitForButtonPressAfterDisplayingText], a
|
|
ret
|
|
|
|
; uses an item
|
|
; UseItem is used with dummy items to perform certain other functions as well
|
|
; INPUT:
|
|
; [wcf91] = item ID
|
|
; OUTPUT:
|
|
; [wActionResultOrTookBattleTurn] = success
|
|
; 00: unsuccessful
|
|
; 01: successful
|
|
; 02: not able to be used right now, no extra menu displayed (only certain items use this)
|
|
UseItem::
|
|
farjp UseItem_
|
|
|
|
; confirms the item toss and then tosses the item
|
|
; INPUT:
|
|
; hl = address of inventory (either wNumBagItems or wNumBoxItems)
|
|
; [wcf91] = item ID
|
|
; [wWhichPokemon] = index of item within inventory
|
|
; [wItemQuantity] = quantity to toss
|
|
; OUTPUT:
|
|
; clears carry flag if the item is tossed, sets carry flag if not
|
|
TossItem::
|
|
ldh a, [hLoadedROMBank]
|
|
push af
|
|
ld a, BANK(TossItem_)
|
|
ldh [hLoadedROMBank], a
|
|
ld [MBC1RomBank], a
|
|
call TossItem_
|
|
pop de
|
|
ld a, d
|
|
ldh [hLoadedROMBank], a
|
|
ld [MBC1RomBank], a
|
|
ret
|
|
|
|
; checks if an item is a key item
|
|
; INPUT:
|
|
; [wcf91] = item ID
|
|
; OUTPUT:
|
|
; [wIsKeyItem] = result
|
|
; 00: item is not key item
|
|
; 01: item is key item
|
|
IsKeyItem::
|
|
push hl
|
|
push de
|
|
push bc
|
|
farcall IsKeyItem_
|
|
pop bc
|
|
pop de
|
|
pop hl
|
|
ret
|
|
|
|
; function to draw various text boxes
|
|
; INPUT:
|
|
; [wTextBoxID] = text box ID
|
|
; b, c = y, x cursor position (TWO_OPTION_MENU only)
|
|
DisplayTextBoxID::
|
|
ldh a, [hLoadedROMBank]
|
|
push af
|
|
ld a, BANK(DisplayTextBoxID_)
|
|
ldh [hLoadedROMBank], a
|
|
ld [MBC1RomBank], a
|
|
call DisplayTextBoxID_
|
|
pop bc
|
|
ld a, b
|
|
ldh [hLoadedROMBank], a
|
|
ld [MBC1RomBank], a
|
|
ret
|
|
|
|
; not zero if an NPC movement script is running, the player character is
|
|
; automatically stepping down from a door, or joypad states are being simulated
|
|
IsPlayerCharacterBeingControlledByGame::
|
|
ld a, [wNPCMovementScriptPointerTableNum]
|
|
and a
|
|
ret nz
|
|
ld a, [wd736]
|
|
bit 1, a ; currently stepping down from door bit
|
|
ret nz
|
|
ld a, [wd730]
|
|
and $80
|
|
ret
|
|
|
|
RunNPCMovementScript::
|
|
ld hl, wd736
|
|
bit 0, [hl]
|
|
res 0, [hl]
|
|
jr nz, .playerStepOutFromDoor
|
|
ld a, [wNPCMovementScriptPointerTableNum]
|
|
and a
|
|
ret z
|
|
dec a
|
|
add a
|
|
ld d, 0
|
|
ld e, a
|
|
ld hl, .NPCMovementScriptPointerTables
|
|
add hl, de
|
|
ld a, [hli]
|
|
ld h, [hl]
|
|
ld l, a
|
|
ldh a, [hLoadedROMBank]
|
|
push af
|
|
ld a, [wNPCMovementScriptBank]
|
|
ldh [hLoadedROMBank], a
|
|
ld [MBC1RomBank], a
|
|
ld a, [wNPCMovementScriptFunctionNum]
|
|
call CallFunctionInTable
|
|
pop af
|
|
ldh [hLoadedROMBank], a
|
|
ld [MBC1RomBank], a
|
|
ret
|
|
|
|
.NPCMovementScriptPointerTables
|
|
dw PalletMovementScriptPointerTable
|
|
dw PewterMuseumGuyMovementScriptPointerTable
|
|
dw PewterGymGuyMovementScriptPointerTable
|
|
.playerStepOutFromDoor
|
|
farjp PlayerStepOutFromDoor
|
|
|
|
EndNPCMovementScript::
|
|
farjp _EndNPCMovementScript
|
|
|
|
EmptyFunc2::
|
|
ret
|
|
|
|
INCLUDE "home/trainers.asm"
|
|
|
|
; checks if the player's coordinates match an arrow movement tile's coordinates
|
|
; and if so, decodes the RLE movement data
|
|
; b = player Y
|
|
; c = player X
|
|
DecodeArrowMovementRLE::
|
|
ld a, [hli]
|
|
cp $ff
|
|
ret z ; no match in the list
|
|
cp b
|
|
jr nz, .nextArrowMovementTileEntry1
|
|
ld a, [hli]
|
|
cp c
|
|
jr nz, .nextArrowMovementTileEntry2
|
|
ld a, [hli]
|
|
ld d, [hl]
|
|
ld e, a
|
|
ld hl, wSimulatedJoypadStatesEnd
|
|
call DecodeRLEList
|
|
dec a
|
|
ld [wSimulatedJoypadStatesIndex], a
|
|
ret
|
|
.nextArrowMovementTileEntry1
|
|
inc hl
|
|
.nextArrowMovementTileEntry2
|
|
inc hl
|
|
inc hl
|
|
jr DecodeArrowMovementRLE
|
|
|
|
TextScript_ItemStoragePC::
|
|
call SaveScreenTilesToBuffer2
|
|
ld b, BANK(PlayerPC)
|
|
ld hl, PlayerPC
|
|
jr bankswitchAndContinue
|
|
|
|
TextScript_BillsPC::
|
|
call SaveScreenTilesToBuffer2
|
|
ld b, BANK(BillsPC_)
|
|
ld hl, BillsPC_
|
|
jr bankswitchAndContinue
|
|
|
|
TextScript_GameCornerPrizeMenu::
|
|
; XXX find a better name for this function
|
|
; special_F7
|
|
ld b, BANK(CeladonPrizeMenu)
|
|
ld hl, CeladonPrizeMenu
|
|
bankswitchAndContinue::
|
|
call Bankswitch
|
|
jp HoldTextDisplayOpen ; continue to main text-engine function
|
|
|
|
TextScript_PokemonCenterPC::
|
|
ld b, BANK(ActivatePC)
|
|
ld hl, ActivatePC
|
|
jr bankswitchAndContinue
|
|
|
|
StartSimulatingJoypadStates::
|
|
xor a
|
|
ld [wOverrideSimulatedJoypadStatesMask], a
|
|
ld [wSpritePlayerStateData2MovementByte1], a
|
|
ld hl, wd730
|
|
set 7, [hl]
|
|
ret
|
|
|
|
IsItemInBag::
|
|
; given an item_id in b
|
|
; set zero flag if item isn't in player's bag
|
|
; else reset zero flag
|
|
; related to Pokémon Tower and ghosts
|
|
predef GetQuantityOfItemInBag
|
|
ld a, b
|
|
and a
|
|
ret
|
|
|
|
DisplayPokedex::
|
|
ld [wd11e], a
|
|
farjp _DisplayPokedex
|
|
|
|
SetSpriteFacingDirectionAndDelay::
|
|
call SetSpriteFacingDirection
|
|
ld c, 6
|
|
jp DelayFrames
|
|
|
|
SetSpriteFacingDirection::
|
|
ld a, $9
|
|
ldh [hSpriteDataOffset], a
|
|
call GetPointerWithinSpriteStateData1
|
|
ldh a, [hSpriteFacingDirection]
|
|
ld [hl], a
|
|
ret
|
|
|
|
SetSpriteImageIndexAfterSettingFacingDirection::
|
|
ld de, -7
|
|
add hl, de
|
|
ld [hl], a
|
|
ret
|
|
|
|
; tests if the player's coordinates are in a specified array
|
|
; INPUT:
|
|
; hl = address of array
|
|
; OUTPUT:
|
|
; [wCoordIndex] = if there is match, the matching array index
|
|
; sets carry if the coordinates are in the array, clears carry if not
|
|
ArePlayerCoordsInArray::
|
|
ld a, [wYCoord]
|
|
ld b, a
|
|
ld a, [wXCoord]
|
|
ld c, a
|
|
; fallthrough
|
|
|
|
CheckCoords::
|
|
xor a
|
|
ld [wCoordIndex], a
|
|
.loop
|
|
ld a, [hli]
|
|
cp $ff ; reached terminator?
|
|
jr z, .notInArray
|
|
push hl
|
|
ld hl, wCoordIndex
|
|
inc [hl]
|
|
pop hl
|
|
.compareYCoord
|
|
cp b
|
|
jr z, .compareXCoord
|
|
inc hl
|
|
jr .loop
|
|
.compareXCoord
|
|
ld a, [hli]
|
|
cp c
|
|
jr nz, .loop
|
|
.inArray
|
|
scf
|
|
ret
|
|
.notInArray
|
|
and a
|
|
ret
|
|
|
|
; tests if a boulder's coordinates are in a specified array
|
|
; INPUT:
|
|
; hl = address of array
|
|
; [hSpriteIndex] = index of boulder sprite
|
|
; OUTPUT:
|
|
; [wCoordIndex] = if there is match, the matching array index
|
|
; sets carry if the coordinates are in the array, clears carry if not
|
|
CheckBoulderCoords::
|
|
push hl
|
|
ld hl, wSpritePlayerStateData2MapY
|
|
ldh a, [hSpriteIndex]
|
|
swap a
|
|
ld d, $0
|
|
ld e, a
|
|
add hl, de
|
|
ld a, [hli]
|
|
sub $4 ; because sprite coordinates are offset by 4
|
|
ld b, a
|
|
ld a, [hl]
|
|
sub $4 ; because sprite coordinates are offset by 4
|
|
ld c, a
|
|
pop hl
|
|
jp CheckCoords
|
|
|
|
GetPointerWithinSpriteStateData1::
|
|
ld h, $c1
|
|
jr _GetPointerWithinSpriteStateData
|
|
|
|
GetPointerWithinSpriteStateData2::
|
|
ld h, $c2
|
|
|
|
_GetPointerWithinSpriteStateData:
|
|
ldh a, [hSpriteDataOffset]
|
|
ld b, a
|
|
ldh a, [hSpriteIndex]
|
|
swap a
|
|
add b
|
|
ld l, a
|
|
ret
|
|
|
|
; decodes a $ff-terminated RLEncoded list
|
|
; each entry is a pair of bytes <byte value> <repetitions>
|
|
; the final $ff will be replicated in the output list and a contains the number of bytes written
|
|
; de: input list
|
|
; hl: output list
|
|
DecodeRLEList::
|
|
xor a
|
|
ld [wRLEByteCount], a ; count written bytes here
|
|
.listLoop
|
|
ld a, [de]
|
|
cp $ff
|
|
jr z, .endOfList
|
|
ldh [hRLEByteValue], a ; store byte value to be written
|
|
inc de
|
|
ld a, [de]
|
|
ld b, $0
|
|
ld c, a ; number of bytes to be written
|
|
ld a, [wRLEByteCount]
|
|
add c
|
|
ld [wRLEByteCount], a ; update total number of written bytes
|
|
ldh a, [hRLEByteValue]
|
|
call FillMemory ; write a c-times to output
|
|
inc de
|
|
jr .listLoop
|
|
.endOfList
|
|
ld a, $ff
|
|
ld [hl], a ; write final $ff
|
|
ld a, [wRLEByteCount]
|
|
inc a ; include sentinel in counting
|
|
ret
|
|
|
|
; sets movement byte 1 for sprite [hSpriteIndex] to $FE and byte 2 to [hSpriteMovementByte2]
|
|
SetSpriteMovementBytesToFE::
|
|
push hl
|
|
call GetSpriteMovementByte1Pointer
|
|
ld [hl], $fe
|
|
call GetSpriteMovementByte2Pointer
|
|
ldh a, [hSpriteMovementByte2]
|
|
ld [hl], a
|
|
pop hl
|
|
ret
|
|
|
|
; sets both movement bytes for sprite [hSpriteIndex] to $FF
|
|
SetSpriteMovementBytesToFF::
|
|
push hl
|
|
call GetSpriteMovementByte1Pointer
|
|
ld [hl], $FF
|
|
call GetSpriteMovementByte2Pointer
|
|
ld [hl], $FF ; prevent person from walking?
|
|
pop hl
|
|
ret
|
|
|
|
; returns the sprite movement byte 1 pointer for sprite [hSpriteIndex] in hl
|
|
GetSpriteMovementByte1Pointer::
|
|
ld h, $C2
|
|
ldh a, [hSpriteIndex]
|
|
swap a
|
|
add 6
|
|
ld l, a
|
|
ret
|
|
|
|
; returns the sprite movement byte 2 pointer for sprite [hSpriteIndex] in hl
|
|
GetSpriteMovementByte2Pointer::
|
|
push de
|
|
ld hl, wMapSpriteData
|
|
ldh a, [hSpriteIndex]
|
|
dec a
|
|
add a
|
|
ld d, 0
|
|
ld e, a
|
|
add hl, de
|
|
pop de
|
|
ret
|
|
|
|
GetTrainerInformation::
|
|
call GetTrainerName
|
|
ld a, [wLinkState]
|
|
and a
|
|
jr nz, .linkBattle
|
|
ld a, BANK(TrainerPicAndMoneyPointers)
|
|
call BankswitchHome
|
|
ld a, [wTrainerClass]
|
|
dec a
|
|
ld hl, TrainerPicAndMoneyPointers
|
|
ld bc, $5
|
|
call AddNTimes
|
|
ld de, wTrainerPicPointer
|
|
ld a, [hli]
|
|
ld [de], a
|
|
inc de
|
|
ld a, [hli]
|
|
ld [de], a
|
|
ld de, wTrainerBaseMoney
|
|
ld a, [hli]
|
|
ld [de], a
|
|
inc de
|
|
ld a, [hli]
|
|
ld [de], a
|
|
jp BankswitchBack
|
|
.linkBattle
|
|
ld hl, wTrainerPicPointer
|
|
ld de, RedPicFront
|
|
ld [hl], e
|
|
inc hl
|
|
ld [hl], d
|
|
ret
|
|
|
|
GetTrainerName::
|
|
farjp GetTrainerName_
|
|
|
|
HasEnoughMoney::
|
|
; Check if the player has at least as much
|
|
; money as the 3-byte BCD value at hMoney.
|
|
ld de, wPlayerMoney
|
|
ld hl, hMoney
|
|
ld c, 3
|
|
jp StringCmp
|
|
|
|
HasEnoughCoins::
|
|
; Check if the player has at least as many
|
|
; coins as the 2-byte BCD value at hCoins.
|
|
ld de, wPlayerCoins
|
|
ld hl, hCoins
|
|
ld c, 2
|
|
jp StringCmp
|
|
|
|
INCLUDE "home/bankswitch.asm"
|
|
INCLUDE "home/yes_no.asm"
|
|
|
|
; calculates the difference |a-b|, setting carry flag if a<b
|
|
CalcDifference::
|
|
sub b
|
|
ret nc
|
|
cpl
|
|
add $1
|
|
scf
|
|
ret
|
|
|
|
MoveSprite::
|
|
; move the sprite [hSpriteIndex] with the movement pointed to by de
|
|
; actually only copies the movement data to wNPCMovementDirections for later
|
|
call SetSpriteMovementBytesToFF
|
|
MoveSprite_::
|
|
push hl
|
|
push bc
|
|
call GetSpriteMovementByte1Pointer
|
|
xor a
|
|
ld [hl], a
|
|
ld hl, wNPCMovementDirections
|
|
ld c, 0
|
|
|
|
.loop
|
|
ld a, [de]
|
|
ld [hli], a
|
|
inc de
|
|
inc c
|
|
cp $FF ; have we reached the end of the movement data?
|
|
jr nz, .loop
|
|
|
|
ld a, c
|
|
ld [wNPCNumScriptedSteps], a ; number of steps taken
|
|
|
|
pop bc
|
|
ld hl, wd730
|
|
set 0, [hl]
|
|
pop hl
|
|
xor a
|
|
ld [wOverrideSimulatedJoypadStatesMask], a
|
|
ld [wSimulatedJoypadStatesEnd], a
|
|
dec a
|
|
ld [wJoyIgnore], a
|
|
ld [wWastedByteCD3A], a
|
|
ret
|
|
|
|
; divides [hDividend2] by [hDivisor2] and stores the quotient in [hQuotient2]
|
|
DivideBytes::
|
|
push hl
|
|
ld hl, hQuotient2
|
|
xor a
|
|
ld [hld], a
|
|
ld a, [hld]
|
|
and a
|
|
jr z, .done
|
|
ld a, [hli]
|
|
.loop
|
|
sub [hl]
|
|
jr c, .done
|
|
inc hl
|
|
inc [hl]
|
|
dec hl
|
|
jr .loop
|
|
.done
|
|
pop hl
|
|
ret
|
|
|
|
LoadFontTilePatterns::
|
|
ldh a, [rLCDC]
|
|
bit 7, a ; is the LCD enabled?
|
|
jr nz, .on
|
|
.off
|
|
ld hl, FontGraphics
|
|
ld de, vFont
|
|
ld bc, FontGraphicsEnd - FontGraphics
|
|
ld a, BANK(FontGraphics)
|
|
jp FarCopyDataDouble ; if LCD is off, transfer all at once
|
|
.on
|
|
ld de, FontGraphics
|
|
ld hl, vFont
|
|
lb bc, BANK(FontGraphics), (FontGraphicsEnd - FontGraphics) / $8
|
|
jp CopyVideoDataDouble ; if LCD is on, transfer during V-blank
|
|
|
|
LoadTextBoxTilePatterns::
|
|
ldh a, [rLCDC]
|
|
bit 7, a ; is the LCD enabled?
|
|
jr nz, .on
|
|
.off
|
|
ld hl, TextBoxGraphics
|
|
ld de, vChars2 + $600
|
|
ld bc, TextBoxGraphicsEnd - TextBoxGraphics
|
|
ld a, BANK(TextBoxGraphics)
|
|
jp FarCopyData2 ; if LCD is off, transfer all at once
|
|
.on
|
|
ld de, TextBoxGraphics
|
|
ld hl, vChars2 + $600
|
|
lb bc, BANK(TextBoxGraphics), (TextBoxGraphicsEnd - TextBoxGraphics) / $10
|
|
jp CopyVideoData ; if LCD is on, transfer during V-blank
|
|
|
|
LoadHpBarAndStatusTilePatterns::
|
|
ldh a, [rLCDC]
|
|
bit 7, a ; is the LCD enabled?
|
|
jr nz, .on
|
|
.off
|
|
ld hl, HpBarAndStatusGraphics
|
|
ld de, vChars2 + $620
|
|
ld bc, HpBarAndStatusGraphicsEnd - HpBarAndStatusGraphics
|
|
ld a, BANK(HpBarAndStatusGraphics)
|
|
jp FarCopyData2 ; if LCD is off, transfer all at once
|
|
.on
|
|
ld de, HpBarAndStatusGraphics
|
|
ld hl, vChars2 + $620
|
|
lb bc, BANK(HpBarAndStatusGraphics), (HpBarAndStatusGraphicsEnd - HpBarAndStatusGraphics) / $10
|
|
jp CopyVideoData ; if LCD is on, transfer during V-blank
|
|
|
|
FillMemory::
|
|
; Fill bc bytes at hl with a.
|
|
push de
|
|
ld d, a
|
|
.loop
|
|
ld a, d
|
|
ld [hli], a
|
|
dec bc
|
|
ld a, b
|
|
or c
|
|
jr nz, .loop
|
|
pop de
|
|
ret
|
|
|
|
UncompressSpriteFromDE::
|
|
; Decompress pic at a:de.
|
|
ld hl, wSpriteInputPtr
|
|
ld [hl], e
|
|
inc hl
|
|
ld [hl], d
|
|
jp UncompressSpriteData
|
|
|
|
SaveScreenTilesToBuffer2::
|
|
coord hl, 0, 0
|
|
ld de, wTileMapBackup2
|
|
ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
|
|
call CopyData
|
|
ret
|
|
|
|
LoadScreenTilesFromBuffer2::
|
|
call LoadScreenTilesFromBuffer2DisableBGTransfer
|
|
ld a, 1
|
|
ldh [hAutoBGTransferEnabled], a
|
|
ret
|
|
|
|
; loads screen tiles stored in wTileMapBackup2 but leaves hAutoBGTransferEnabled disabled
|
|
LoadScreenTilesFromBuffer2DisableBGTransfer::
|
|
xor a
|
|
ldh [hAutoBGTransferEnabled], a
|
|
ld hl, wTileMapBackup2
|
|
coord de, 0, 0
|
|
ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
|
|
call CopyData
|
|
ret
|
|
|
|
SaveScreenTilesToBuffer1::
|
|
coord hl, 0, 0
|
|
ld de, wTileMapBackup
|
|
ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
|
|
jp CopyData
|
|
|
|
LoadScreenTilesFromBuffer1::
|
|
xor a
|
|
ldh [hAutoBGTransferEnabled], a
|
|
ld hl, wTileMapBackup
|
|
coord de, 0, 0
|
|
ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
|
|
call CopyData
|
|
ld a, 1
|
|
ldh [hAutoBGTransferEnabled], a
|
|
ret
|
|
|
|
DelayFrames::
|
|
; wait c frames
|
|
call DelayFrame
|
|
dec c
|
|
jr nz, DelayFrames
|
|
ret
|
|
|
|
PlaySoundWaitForCurrent::
|
|
push af
|
|
call WaitForSoundToFinish
|
|
pop af
|
|
jp PlaySound
|
|
|
|
; Wait for sound to finish playing
|
|
WaitForSoundToFinish::
|
|
ld a, [wLowHealthAlarm]
|
|
and $80
|
|
ret nz
|
|
push hl
|
|
.waitLoop
|
|
ld hl, wChannelSoundIDs + Ch5
|
|
xor a
|
|
or [hl]
|
|
inc hl
|
|
or [hl]
|
|
inc hl
|
|
inc hl
|
|
or [hl]
|
|
jr nz, .waitLoop
|
|
pop hl
|
|
ret
|
|
|
|
INCLUDE "home/names2.asm"
|
|
|
|
GetItemPrice::
|
|
; Stores item's price as BCD at hItemPrice (3 bytes)
|
|
; Input: [wcf91] = item id
|
|
ldh a, [hLoadedROMBank]
|
|
push af
|
|
ld a, [wListMenuID]
|
|
cp MOVESLISTMENU
|
|
ld a, BANK(ItemPrices)
|
|
jr nz, .ok
|
|
ld a, $f ; hardcoded Bank
|
|
.ok
|
|
ldh [hLoadedROMBank], a
|
|
ld [MBC1RomBank], a
|
|
ld hl, wItemPrices
|
|
ld a, [hli]
|
|
ld h, [hl]
|
|
ld l, a
|
|
ld a, [wcf91] ; a contains item id
|
|
cp HM01
|
|
jr nc, .getTMPrice
|
|
ld bc, $3
|
|
.loop
|
|
add hl, bc
|
|
dec a
|
|
jr nz, .loop
|
|
dec hl
|
|
ld a, [hld]
|
|
ldh [hItemPrice + 2], a
|
|
ld a, [hld]
|
|
ldh [hItemPrice + 1], a
|
|
ld a, [hl]
|
|
ldh [hItemPrice], a
|
|
jr .done
|
|
.getTMPrice
|
|
ld a, BANK(GetMachinePrice)
|
|
ldh [hLoadedROMBank], a
|
|
ld [MBC1RomBank], a
|
|
call GetMachinePrice
|
|
.done
|
|
ld de, hItemPrice
|
|
pop af
|
|
ldh [hLoadedROMBank], a
|
|
ld [MBC1RomBank], a
|
|
ret
|
|
|
|
; copies a string from [de] to [wcf4b]
|
|
CopyStringToCF4B::
|
|
ld hl, wcf4b
|
|
; fall through
|
|
|
|
; copies a string from [de] to [hl]
|
|
CopyString::
|
|
ld a, [de]
|
|
inc de
|
|
ld [hli], a
|
|
cp "@"
|
|
jr nz, CopyString
|
|
ret
|
|
|
|
; this function is used when lower button sensitivity is wanted (e.g. menus)
|
|
; OUTPUT: [hJoy5] = pressed buttons in usual format
|
|
; there are two flags that control its functionality, [hJoy6] and [hJoy7]
|
|
; there are essentially three modes of operation
|
|
; 1. Get newly pressed buttons only
|
|
; ([hJoy7] == 0, [hJoy6] == any)
|
|
; Just copies [hJoyPressed] to [hJoy5].
|
|
; 2. Get currently pressed buttons at low sample rate with delay
|
|
; ([hJoy7] == 1, [hJoy6] != 0)
|
|
; If the user holds down buttons for more than half a second,
|
|
; report buttons as being pressed up to 12 times per second thereafter.
|
|
; If the user holds down buttons for less than half a second,
|
|
; report only one button press.
|
|
; 3. Same as 2, but report no buttons as pressed if A or B is held down.
|
|
; ([hJoy7] == 1, [hJoy6] == 0)
|
|
JoypadLowSensitivity::
|
|
call Joypad
|
|
ldh a, [hJoy7] ; flag
|
|
and a ; get all currently pressed buttons or only newly pressed buttons?
|
|
ldh a, [hJoyPressed] ; newly pressed buttons
|
|
jr z, .storeButtonState
|
|
ldh a, [hJoyHeld] ; all currently pressed buttons
|
|
.storeButtonState
|
|
ldh [hJoy5], a
|
|
ldh a, [hJoyPressed] ; newly pressed buttons
|
|
and a ; have any buttons been newly pressed since last check?
|
|
jr z, .noNewlyPressedButtons
|
|
.newlyPressedButtons
|
|
ld a, 30 ; half a second delay
|
|
ldh [hFrameCounter], a
|
|
ret
|
|
.noNewlyPressedButtons
|
|
ldh a, [hFrameCounter]
|
|
and a ; is the delay over?
|
|
jr z, .delayOver
|
|
.delayNotOver
|
|
xor a
|
|
ldh [hJoy5], a ; report no buttons as pressed
|
|
ret
|
|
.delayOver
|
|
; if [hJoy6] = 0 and A or B is pressed, report no buttons as pressed
|
|
ldh a, [hJoyHeld]
|
|
and A_BUTTON | B_BUTTON
|
|
jr z, .setShortDelay
|
|
ldh a, [hJoy6] ; flag
|
|
and a
|
|
jr nz, .setShortDelay
|
|
xor a
|
|
ldh [hJoy5], a
|
|
.setShortDelay
|
|
ld a, 5 ; 1/12 of a second delay
|
|
ldh [hFrameCounter], a
|
|
ret
|
|
|
|
WaitForTextScrollButtonPress::
|
|
ldh a, [hDownArrowBlinkCount1]
|
|
push af
|
|
ldh a, [hDownArrowBlinkCount2]
|
|
push af
|
|
xor a
|
|
ldh [hDownArrowBlinkCount1], a
|
|
ld a, $6
|
|
ldh [hDownArrowBlinkCount2], a
|
|
.loop
|
|
push hl
|
|
ld a, [wTownMapSpriteBlinkingEnabled]
|
|
and a
|
|
jr z, .skipAnimation
|
|
call TownMapSpriteBlinkingAnimation
|
|
.skipAnimation
|
|
coord hl, 18, 16
|
|
call HandleDownArrowBlinkTiming
|
|
pop hl
|
|
call JoypadLowSensitivity
|
|
predef CableClub_Run
|
|
ldh a, [hJoy5]
|
|
and A_BUTTON | B_BUTTON
|
|
jr z, .loop
|
|
pop af
|
|
ldh [hDownArrowBlinkCount2], a
|
|
pop af
|
|
ldh [hDownArrowBlinkCount1], a
|
|
ret
|
|
|
|
; (unless in link battle) waits for A or B being pressed and outputs the scrolling sound effect
|
|
ManualTextScroll::
|
|
ld a, [wLinkState]
|
|
cp LINK_STATE_BATTLING
|
|
jr z, .inLinkBattle
|
|
call WaitForTextScrollButtonPress
|
|
ld a, SFX_PRESS_AB
|
|
jp PlaySound
|
|
.inLinkBattle
|
|
ld c, 65
|
|
jp DelayFrames
|
|
|
|
; function to do multiplication
|
|
; all values are big endian
|
|
; INPUT
|
|
; FF96-FF98 = multiplicand
|
|
; FF99 = multiplier
|
|
; OUTPUT
|
|
; FF95-FF98 = product
|
|
Multiply::
|
|
push hl
|
|
push bc
|
|
callfar _Multiply
|
|
pop bc
|
|
pop hl
|
|
ret
|
|
|
|
; function to do division
|
|
; all values are big endian
|
|
; INPUT
|
|
; FF95-FF98 = dividend
|
|
; FF99 = divisor
|
|
; b = number of bytes in the dividend (starting from FF95)
|
|
; OUTPUT
|
|
; FF95-FF98 = quotient
|
|
; FF99 = remainder
|
|
Divide::
|
|
push hl
|
|
push de
|
|
push bc
|
|
ldh a, [hLoadedROMBank]
|
|
push af
|
|
ld a, BANK(_Divide)
|
|
ldh [hLoadedROMBank], a
|
|
ld [MBC1RomBank], a
|
|
call _Divide
|
|
pop af
|
|
ldh [hLoadedROMBank], a
|
|
ld [MBC1RomBank], 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 [wLetterPrintingDelayFlags] flags.
|
|
PrintLetterDelay::
|
|
ld a, [wd730]
|
|
bit 6, a
|
|
ret nz
|
|
ld a, [wLetterPrintingDelayFlags]
|
|
bit 1, a
|
|
ret z
|
|
push hl
|
|
push de
|
|
push bc
|
|
ld a, [wLetterPrintingDelayFlags]
|
|
bit 0, a
|
|
jr z, .waitOneFrame
|
|
ld a, [wOptions]
|
|
and $f
|
|
ldh [hFrameCounter], a
|
|
jr .checkButtons
|
|
.waitOneFrame
|
|
ld a, 1
|
|
ldh [hFrameCounter], a
|
|
.checkButtons
|
|
call Joypad
|
|
ldh a, [hJoyHeld]
|
|
.checkAButton
|
|
bit 0, a ; is the A button pressed?
|
|
jr z, .checkBButton
|
|
jr .endWait
|
|
.checkBButton
|
|
bit 1, a ; is the B button pressed?
|
|
jr z, .buttonsNotPressed
|
|
.endWait
|
|
call DelayFrame
|
|
jr .done
|
|
.buttonsNotPressed ; if neither A nor B is pressed
|
|
ldh a, [hFrameCounter]
|
|
and a
|
|
jr nz, .checkButtons
|
|
.done
|
|
pop bc
|
|
pop de
|
|
pop hl
|
|
ret
|
|
|
|
; Copies [hl, bc) to [de, de + bc - hl).
|
|
; In other words, the source data is from hl up to but not including bc,
|
|
; and the destination is de.
|
|
CopyDataUntil::
|
|
ld a, [hli]
|
|
ld [de], a
|
|
inc de
|
|
ld a, h
|
|
cp b
|
|
jr nz, CopyDataUntil
|
|
ld a, l
|
|
cp c
|
|
jr nz, CopyDataUntil
|
|
ret
|
|
|
|
INCLUDE "home/move_mon.asm"
|
|
|
|
; skips a text entries, each of size NAME_LENGTH (like trainer name, OT name, rival name, ...)
|
|
; hl: base pointer, will be incremented by NAME_LENGTH * a
|
|
SkipFixedLengthTextEntries::
|
|
and a
|
|
ret z
|
|
ld bc, NAME_LENGTH
|
|
.skipLoop
|
|
add hl, bc
|
|
dec a
|
|
jr nz, .skipLoop
|
|
ret
|
|
|
|
AddNTimes::
|
|
; add bc to hl a times
|
|
and a
|
|
ret z
|
|
.loop
|
|
add hl, bc
|
|
dec a
|
|
jr nz, .loop
|
|
ret
|
|
|
|
; Compare strings, c bytes in length, at de and hl.
|
|
; Often used to compare big endian numbers in battle calculations.
|
|
StringCmp::
|
|
ld a, [de]
|
|
cp [hl]
|
|
ret nz
|
|
inc de
|
|
inc hl
|
|
dec c
|
|
jr nz, StringCmp
|
|
ret
|
|
|
|
; INPUT:
|
|
; a = oam block index (each block is 4 oam entries)
|
|
; b = Y coordinate of upper left corner of sprite
|
|
; c = X coordinate of upper left corner of sprite
|
|
; de = base address of 4 tile number and attribute pairs
|
|
WriteOAMBlock::
|
|
ld h, HIGH(wOAMBuffer)
|
|
swap a ; multiply by 16
|
|
ld l, a
|
|
call .writeOneEntry ; upper left
|
|
push bc
|
|
ld a, 8
|
|
add c
|
|
ld c, a
|
|
call .writeOneEntry ; upper right
|
|
pop bc
|
|
ld a, 8
|
|
add b
|
|
ld b, a
|
|
call .writeOneEntry ; lower left
|
|
ld a, 8
|
|
add c
|
|
ld c, a
|
|
; lower right
|
|
.writeOneEntry
|
|
ld [hl], b ; Y coordinate
|
|
inc hl
|
|
ld [hl], c ; X coordinate
|
|
inc hl
|
|
ld a, [de] ; tile number
|
|
inc de
|
|
ld [hli], a
|
|
ld a, [de] ; attribute
|
|
inc de
|
|
ld [hli], a
|
|
ret
|
|
|
|
HandleMenuInput::
|
|
xor a
|
|
ld [wPartyMenuAnimMonEnabled], a
|
|
|
|
HandleMenuInput_::
|
|
ldh a, [hDownArrowBlinkCount1]
|
|
push af
|
|
ldh a, [hDownArrowBlinkCount2]
|
|
push af ; save existing values on stack
|
|
xor a
|
|
ldh [hDownArrowBlinkCount1], a ; blinking down arrow timing value 1
|
|
ld a, 6
|
|
ldh [hDownArrowBlinkCount2], a ; blinking down arrow timing value 2
|
|
.loop1
|
|
xor a
|
|
ld [wAnimCounter], a ; counter for pokemon shaking animation
|
|
call PlaceMenuCursor
|
|
call Delay3
|
|
.loop2
|
|
push hl
|
|
ld a, [wPartyMenuAnimMonEnabled]
|
|
and a ; is it a pokemon selection menu?
|
|
jr z, .getJoypadState
|
|
farcall AnimatePartyMon ; shake mini sprite of selected pokemon
|
|
.getJoypadState
|
|
pop hl
|
|
call JoypadLowSensitivity
|
|
ldh a, [hJoy5]
|
|
and a ; was a key pressed?
|
|
jr nz, .keyPressed
|
|
push hl
|
|
coord hl, 18, 11 ; coordinates of blinking down arrow in some menus
|
|
call HandleDownArrowBlinkTiming ; blink down arrow (if any)
|
|
pop hl
|
|
ld a, [wMenuJoypadPollCount]
|
|
dec a
|
|
jr z, .giveUpWaiting
|
|
jr .loop2
|
|
.giveUpWaiting
|
|
; if a key wasn't pressed within the specified number of checks
|
|
pop af
|
|
ldh [hDownArrowBlinkCount2], a
|
|
pop af
|
|
ldh [hDownArrowBlinkCount1], a ; restore previous values
|
|
xor a
|
|
ld [wMenuWrappingEnabled], a ; disable menu wrapping
|
|
ret
|
|
.keyPressed
|
|
xor a
|
|
ld [wCheckFor180DegreeTurn], a
|
|
ldh a, [hJoy5]
|
|
ld b, a
|
|
bit 6, a ; pressed Up key?
|
|
jr z, .checkIfDownPressed
|
|
.upPressed
|
|
ld a, [wCurrentMenuItem] ; selected menu item
|
|
and a ; already at the top of the menu?
|
|
jr z, .alreadyAtTop
|
|
.notAtTop
|
|
dec a
|
|
ld [wCurrentMenuItem], a ; move selected menu item up one space
|
|
jr .checkOtherKeys
|
|
.alreadyAtTop
|
|
ld a, [wMenuWrappingEnabled]
|
|
and a ; is wrapping around enabled?
|
|
jr z, .noWrappingAround
|
|
ld a, [wMaxMenuItem]
|
|
ld [wCurrentMenuItem], a ; wrap to the bottom of the menu
|
|
jr .checkOtherKeys
|
|
.checkIfDownPressed
|
|
bit 7, a
|
|
jr z, .checkOtherKeys
|
|
.downPressed
|
|
ld a, [wCurrentMenuItem]
|
|
inc a
|
|
ld c, a
|
|
ld a, [wMaxMenuItem]
|
|
cp c
|
|
jr nc, .notAtBottom
|
|
.alreadyAtBottom
|
|
ld a, [wMenuWrappingEnabled]
|
|
and a ; is wrapping around enabled?
|
|
jr z, .noWrappingAround
|
|
ld c, $00 ; wrap from bottom to top
|
|
.notAtBottom
|
|
ld a, c
|
|
ld [wCurrentMenuItem], a
|
|
.checkOtherKeys
|
|
ld a, [wMenuWatchedKeys]
|
|
and b ; does the menu care about any of the pressed keys?
|
|
jp z, .loop1
|
|
.checkIfAButtonOrBButtonPressed
|
|
ldh a, [hJoy5]
|
|
and A_BUTTON | B_BUTTON
|
|
jr z, .skipPlayingSound
|
|
.AButtonOrBButtonPressed
|
|
push hl
|
|
ld hl, wFlags_0xcd60
|
|
bit 5, [hl]
|
|
pop hl
|
|
jr nz, .skipPlayingSound
|
|
ld a, SFX_PRESS_AB
|
|
call PlaySound
|
|
.skipPlayingSound
|
|
pop af
|
|
ldh [hDownArrowBlinkCount2], a
|
|
pop af
|
|
ldh [hDownArrowBlinkCount1], a ; restore previous values
|
|
xor a
|
|
ld [wMenuWrappingEnabled], a ; disable menu wrapping
|
|
ldh a, [hJoy5]
|
|
ret
|
|
.noWrappingAround
|
|
ld a, [wMenuWatchMovingOutOfBounds]
|
|
and a ; should we return if the user tried to go past the top or bottom?
|
|
jr z, .checkOtherKeys
|
|
jr .checkIfAButtonOrBButtonPressed
|
|
|
|
PlaceMenuCursor::
|
|
ld a, [wTopMenuItemY]
|
|
and a ; is the y coordinate 0?
|
|
jr z, .adjustForXCoord
|
|
coord hl, 0, 0
|
|
ld bc, SCREEN_WIDTH
|
|
.topMenuItemLoop
|
|
add hl, bc
|
|
dec a
|
|
jr nz, .topMenuItemLoop
|
|
.adjustForXCoord
|
|
ld a, [wTopMenuItemX]
|
|
ld b, 0
|
|
ld c, a
|
|
add hl, bc
|
|
push hl
|
|
ld a, [wLastMenuItem]
|
|
and a ; was the previous menu id 0?
|
|
jr z, .checkForArrow1
|
|
push af
|
|
ldh a, [hFlagsFFF6]
|
|
bit 1, a ; is the menu double spaced?
|
|
jr z, .doubleSpaced1
|
|
ld bc, 20
|
|
jr .getOldMenuItemScreenPosition
|
|
.doubleSpaced1
|
|
ld bc, 40
|
|
.getOldMenuItemScreenPosition
|
|
pop af
|
|
.oldMenuItemLoop
|
|
add hl, bc
|
|
dec a
|
|
jr nz, .oldMenuItemLoop
|
|
.checkForArrow1
|
|
ld a, [hl]
|
|
cp "▶" ; was an arrow next to the previously selected menu item?
|
|
jr nz, .skipClearingArrow
|
|
.clearArrow
|
|
ld a, [wTileBehindCursor]
|
|
ld [hl], a
|
|
.skipClearingArrow
|
|
pop hl
|
|
ld a, [wCurrentMenuItem]
|
|
and a
|
|
jr z, .checkForArrow2
|
|
push af
|
|
ldh a, [hFlagsFFF6]
|
|
bit 1, a ; is the menu double spaced?
|
|
jr z, .doubleSpaced2
|
|
ld bc, 20
|
|
jr .getCurrentMenuItemScreenPosition
|
|
.doubleSpaced2
|
|
ld bc, 40
|
|
.getCurrentMenuItemScreenPosition
|
|
pop af
|
|
.currentMenuItemLoop
|
|
add hl, bc
|
|
dec a
|
|
jr nz, .currentMenuItemLoop
|
|
.checkForArrow2
|
|
ld a, [hl]
|
|
cp "▶" ; has the right arrow already been placed?
|
|
jr z, .skipSavingTile ; if so, don't lose the saved tile
|
|
ld [wTileBehindCursor], a ; save tile before overwriting with right arrow
|
|
.skipSavingTile
|
|
ld a, "▶" ; place right arrow
|
|
ld [hl], a
|
|
ld a, l
|
|
ld [wMenuCursorLocation], a
|
|
ld a, h
|
|
ld [wMenuCursorLocation + 1], a
|
|
ld a, [wCurrentMenuItem]
|
|
ld [wLastMenuItem], a
|
|
ret
|
|
|
|
; This is used to mark a menu cursor other than the one currently being
|
|
; manipulated. In the case of submenus, this is used to show the location of
|
|
; the menu cursor in the parent menu. In the case of swapping items in list,
|
|
; this is used to mark the item that was first chosen to be swapped.
|
|
PlaceUnfilledArrowMenuCursor::
|
|
ld b, a
|
|
ld a, [wMenuCursorLocation]
|
|
ld l, a
|
|
ld a, [wMenuCursorLocation + 1]
|
|
ld h, a
|
|
ld [hl], $ec ; outline of right arrow
|
|
ld a, b
|
|
ret
|
|
|
|
; Replaces the menu cursor with a blank space.
|
|
EraseMenuCursor::
|
|
ld a, [wMenuCursorLocation]
|
|
ld l, a
|
|
ld a, [wMenuCursorLocation + 1]
|
|
ld h, a
|
|
ld [hl], " "
|
|
ret
|
|
|
|
; This toggles a blinking down arrow at hl on and off after a delay has passed.
|
|
; This is often called even when no blinking is occurring.
|
|
; The reason is that most functions that call this initialize hDownArrowBlinkCount1 to 0.
|
|
; The effect is that if the tile at hl is initialized with a down arrow,
|
|
; this function will toggle that down arrow on and off, but if the tile isn't
|
|
; initialized with a down arrow, this function does nothing.
|
|
; That allows this to be called without worrying about if a down arrow should
|
|
; be blinking.
|
|
HandleDownArrowBlinkTiming::
|
|
ld a, [hl]
|
|
ld b, a
|
|
ld a, "▼"
|
|
cp b
|
|
jr nz, .downArrowOff
|
|
.downArrowOn
|
|
ldh a, [hDownArrowBlinkCount1]
|
|
dec a
|
|
ldh [hDownArrowBlinkCount1], a
|
|
ret nz
|
|
ldh a, [hDownArrowBlinkCount2]
|
|
dec a
|
|
ldh [hDownArrowBlinkCount2], a
|
|
ret nz
|
|
ld a, " "
|
|
ld [hl], a
|
|
ld a, $ff
|
|
ldh [hDownArrowBlinkCount1], a
|
|
ld a, $06
|
|
ldh [hDownArrowBlinkCount2], a
|
|
ret
|
|
.downArrowOff
|
|
ldh a, [hDownArrowBlinkCount1]
|
|
and a
|
|
ret z
|
|
dec a
|
|
ldh [hDownArrowBlinkCount1], a
|
|
ret nz
|
|
dec a
|
|
ldh [hDownArrowBlinkCount1], a
|
|
ldh a, [hDownArrowBlinkCount2]
|
|
dec a
|
|
ldh [hDownArrowBlinkCount2], a
|
|
ret nz
|
|
ld a, $06
|
|
ldh [hDownArrowBlinkCount2], a
|
|
ld a, "▼"
|
|
ld [hl], a
|
|
ret
|
|
|
|
; The following code either enables or disables the automatic drawing of
|
|
; text boxes by DisplayTextID. Both functions cause DisplayTextID to wait
|
|
; for a button press after displaying text (unless [wEnteringCableClub] is set).
|
|
|
|
EnableAutoTextBoxDrawing::
|
|
xor a
|
|
jr AutoTextBoxDrawingCommon
|
|
|
|
DisableAutoTextBoxDrawing::
|
|
ld a, $01
|
|
|
|
AutoTextBoxDrawingCommon::
|
|
ld [wAutoTextBoxDrawingControl], a
|
|
xor a
|
|
ld [wDoNotWaitForButtonPressAfterDisplayingText], a ; make DisplayTextID wait for button press
|
|
ret
|
|
|
|
PrintText::
|
|
; Print text hl at (1, 14).
|
|
push hl
|
|
ld a, MESSAGE_BOX
|
|
ld [wTextBoxID], a
|
|
call DisplayTextBoxID
|
|
call UpdateSprites
|
|
call Delay3
|
|
pop hl
|
|
PrintText_NoCreatingTextBox::
|
|
coord bc, 1, 14
|
|
jp TextCommandProcessor
|
|
|
|
INCLUDE "home/print_num.asm"
|
|
|
|
CallFunctionInTable::
|
|
; Call function a in jumptable hl.
|
|
; de is not preserved.
|
|
push hl
|
|
push de
|
|
push bc
|
|
add a
|
|
ld d, 0
|
|
ld e, a
|
|
add hl, de
|
|
ld a, [hli]
|
|
ld h, [hl]
|
|
ld l, a
|
|
ld de, .returnAddress
|
|
push de
|
|
jp hl
|
|
.returnAddress
|
|
pop bc
|
|
pop de
|
|
pop hl
|
|
ret
|
|
|
|
IsInArray::
|
|
; Search an array at hl for the value in a.
|
|
; Entry size is de bytes.
|
|
; Return count b and carry if found.
|
|
ld b, 0
|
|
|
|
IsInRestOfArray::
|
|
ld c, a
|
|
.loop
|
|
ld a, [hl]
|
|
cp -1
|
|
jr z, .notfound
|
|
cp c
|
|
jr z, .found
|
|
inc b
|
|
add hl, de
|
|
jr .loop
|
|
|
|
.notfound
|
|
and a
|
|
ret
|
|
|
|
.found
|
|
scf
|
|
ret
|
|
|
|
RestoreScreenTilesAndReloadTilePatterns::
|
|
call ClearSprites
|
|
ld a, $1
|
|
ld [wUpdateSpritesEnabled], a
|
|
call ReloadMapSpriteTilePatterns
|
|
call LoadScreenTilesFromBuffer2
|
|
call LoadTextBoxTilePatterns
|
|
call RunDefaultPaletteCommand
|
|
jr Delay3
|
|
|
|
GBPalWhiteOutWithDelay3::
|
|
call GBPalWhiteOut
|
|
|
|
Delay3::
|
|
; The bg map is updated each frame in thirds.
|
|
; Wait three frames to let the bg map fully update.
|
|
ld c, 3
|
|
jp DelayFrames
|
|
|
|
GBPalNormal::
|
|
; Reset BGP and OBP0.
|
|
ld a, %11100100 ; 3210
|
|
ldh [rBGP], a
|
|
ld a, %11010000 ; 3100
|
|
ldh [rOBP0], a
|
|
ret
|
|
|
|
GBPalWhiteOut::
|
|
; White out all palettes.
|
|
xor a
|
|
ldh [rBGP], a
|
|
ldh [rOBP0], a
|
|
ldh [rOBP1], a
|
|
ret
|
|
|
|
RunDefaultPaletteCommand::
|
|
ld b, SET_PAL_DEFAULT
|
|
RunPaletteCommand::
|
|
ld a, [wOnSGB]
|
|
and a
|
|
ret z
|
|
predef_jump _RunPaletteCommand
|
|
|
|
GetHealthBarColor::
|
|
; Return at hl the palette of
|
|
; an HP bar e pixels long.
|
|
ld a, e
|
|
cp 27
|
|
ld d, 0 ; green
|
|
jr nc, .gotColor
|
|
cp 10
|
|
inc d ; yellow
|
|
jr nc, .gotColor
|
|
inc d ; red
|
|
.gotColor
|
|
ld [hl], d
|
|
ret
|
|
|
|
; Copy the current map's sprites' tile patterns to VRAM again after they have
|
|
; been overwritten by other tile patterns.
|
|
ReloadMapSpriteTilePatterns::
|
|
ld hl, wFontLoaded
|
|
ld a, [hl]
|
|
push af
|
|
res 0, [hl]
|
|
push hl
|
|
xor a
|
|
ld [wSpriteSetID], a
|
|
call DisableLCD
|
|
farcall InitMapSprites
|
|
call EnableLCD
|
|
pop hl
|
|
pop af
|
|
ld [hl], a
|
|
call LoadPlayerSpriteGraphics
|
|
call LoadFontTilePatterns
|
|
jp UpdateSprites
|
|
|
|
GiveItem::
|
|
; Give player quantity c of item b,
|
|
; and copy the item's name to wcf4b.
|
|
; Return carry on success.
|
|
ld a, b
|
|
ld [wd11e], a
|
|
ld [wcf91], a
|
|
ld a, c
|
|
ld [wItemQuantity], a
|
|
ld hl, wNumBagItems
|
|
call AddItemToInventory
|
|
ret nc
|
|
call GetItemName
|
|
call CopyStringToCF4B
|
|
scf
|
|
ret
|
|
|
|
GivePokemon::
|
|
; Give the player monster b at level c.
|
|
ld a, b
|
|
ld [wcf91], a
|
|
ld a, c
|
|
ld [wCurEnemyLVL], a
|
|
xor a ; PLAYER_PARTY_DATA
|
|
ld [wMonDataLocation], a
|
|
farjp _GivePokemon
|
|
|
|
Random::
|
|
; Return a random number in a.
|
|
; For battles, use BattleRandom.
|
|
push hl
|
|
push de
|
|
push bc
|
|
farcall Random_
|
|
ldh a, [hRandomAdd]
|
|
pop bc
|
|
pop de
|
|
pop hl
|
|
ret
|
|
|
|
INCLUDE "home/predef.asm"
|
|
|
|
UpdateCinnabarGymGateTileBlocks::
|
|
farjp UpdateCinnabarGymGateTileBlocks_
|
|
|
|
CheckForHiddenObjectOrBookshelfOrCardKeyDoor::
|
|
ldh a, [hLoadedROMBank]
|
|
push af
|
|
ldh a, [hJoyHeld]
|
|
bit 0, a ; A button
|
|
jr z, .nothingFound
|
|
; A button is pressed
|
|
ld a, BANK(CheckForHiddenObject)
|
|
ld [MBC1RomBank], a
|
|
ldh [hLoadedROMBank], a
|
|
call CheckForHiddenObject
|
|
ldh a, [hDidntFindAnyHiddenObject]
|
|
and a
|
|
jr nz, .hiddenObjectNotFound
|
|
ld a, [wHiddenObjectFunctionRomBank]
|
|
ld [MBC1RomBank], a
|
|
ldh [hLoadedROMBank], a
|
|
ld de, .returnAddress
|
|
push de
|
|
jp hl
|
|
.returnAddress
|
|
xor a
|
|
jr .done
|
|
.hiddenObjectNotFound
|
|
farcall PrintBookshelfText
|
|
ldh a, [hFFDB]
|
|
and a
|
|
jr z, .done
|
|
.nothingFound
|
|
ld a, $ff
|
|
.done
|
|
ldh [hItemAlreadyFound], a
|
|
pop af
|
|
ld [MBC1RomBank], a
|
|
ldh [hLoadedROMBank], a
|
|
ret
|
|
|
|
PrintPredefTextID::
|
|
ldh [hSpriteIndexOrTextID], a
|
|
ld hl, TextPredefs
|
|
call SetMapTextPointer
|
|
ld hl, wTextPredefFlag
|
|
set 0, [hl]
|
|
call DisplayTextID
|
|
|
|
RestoreMapTextPointer::
|
|
ld hl, wMapTextPtr
|
|
ldh a, [hSavedMapTextPtr]
|
|
ld [hli], a
|
|
ldh a, [hSavedMapTextPtr + 1]
|
|
ld [hl], a
|
|
ret
|
|
|
|
SetMapTextPointer::
|
|
ld a, [wMapTextPtr]
|
|
ldh [hSavedMapTextPtr], a
|
|
ld a, [wMapTextPtr + 1]
|
|
ldh [hSavedMapTextPtr + 1], a
|
|
ld a, l
|
|
ld [wMapTextPtr], a
|
|
ld a, h
|
|
ld [wMapTextPtr + 1], a
|
|
ret
|
|
|
|
INCLUDE "data/text_predef_pointers.asm"
|