Move more code from home.asm to home/

This commit is contained in:
Rangi 2020-07-03 22:57:43 -04:00
parent 6ef36800b0
commit 053afc4634
19 changed files with 2836 additions and 2854 deletions

View file

@ -1,7 +1,10 @@
HMMoveArray:
; This file is INCLUDEd twice:
; - for HMMoves in home/names.asm
; - for HMMoveArray in engine/pokemon/bills_pc.asm
db CUT
db FLY
db SURF
db STRENGTH
db FLASH
db -1
db -1 ; end

View file

@ -1,3 +1,9 @@
add_predef: MACRO
\1Predef::
db BANK(\1)
dw \1
ENDM
PredefPointers::
; these are pointers to ASM routines.
; they appear to be used in overworld map scripts.

View file

@ -0,0 +1,71 @@
add_tx_pre: MACRO
\1_id:: dw \1
ENDM
TextPredefs::
add_tx_pre CardKeySuccessText ; 01
add_tx_pre CardKeyFailText ; 02
add_tx_pre RedBedroomPCText ; 03
add_tx_pre RedBedroomSNESText ; 04
add_tx_pre PushStartText ; 05
add_tx_pre SaveOptionText ; 06
add_tx_pre StrengthsAndWeaknessesText ; 07
add_tx_pre OakLabEmailText ; 08
add_tx_pre AerodactylFossilText ; 09
add_tx_pre Route15UpstairsBinocularsText ; 0A
add_tx_pre KabutopsFossilText ; 0B
add_tx_pre GymStatueText1 ; 0C
add_tx_pre GymStatueText2 ; 0D
add_tx_pre BookcaseText ; 0E
add_tx_pre ViridianCityPokecenterBenchGuyText ; 0F
add_tx_pre PewterCityPokecenterBenchGuyText ; 10
add_tx_pre CeruleanCityPokecenterBenchGuyText ; 11
add_tx_pre LavenderCityPokecenterBenchGuyText ; 12
add_tx_pre VermilionCityPokecenterBenchGuyText ; 13
add_tx_pre CeladonCityPokecenterBenchGuyText ; 14
add_tx_pre CeladonCityHotelText ; 15
add_tx_pre FuchsiaCityPokecenterBenchGuyText ; 16
add_tx_pre CinnabarIslandPokecenterBenchGuyText ; 17
add_tx_pre SaffronCityPokecenterBenchGuyText ; 18
add_tx_pre MtMoonPokecenterBenchGuyText ; 19
add_tx_pre RockTunnelPokecenterBenchGuyText ; 1A
add_tx_pre UnusedBenchGuyText1 ; 1B XXX unused
add_tx_pre UnusedBenchGuyText2 ; 1C XXX unused
add_tx_pre UnusedBenchGuyText3 ; 1D XXX unused
add_tx_pre UnusedPredefText ; 1E XXX unused
add_tx_pre PokemonCenterPCText ; 1F
add_tx_pre ViridianSchoolNotebook ; 20
add_tx_pre ViridianSchoolBlackboard ; 21
add_tx_pre JustAMomentText ; 22
add_tx_pre OpenBillsPCText ; 23
add_tx_pre FoundHiddenItemText ; 24
add_tx_pre HiddenItemBagFullText ; 25 XXX unused
add_tx_pre VermilionGymTrashText ; 26
add_tx_pre IndigoPlateauHQText ; 27
add_tx_pre GameCornerOutOfOrderText ; 28
add_tx_pre GameCornerOutToLunchText ; 29
add_tx_pre GameCornerSomeonesKeysText ; 2A
add_tx_pre FoundHiddenCoinsText ; 2B
add_tx_pre DroppedHiddenCoinsText ; 2C
add_tx_pre BillsHouseMonitorText ; 2D
add_tx_pre BillsHouseInitiatedText ; 2E
add_tx_pre BillsHousePokemonList ; 2F
add_tx_pre MagazinesText ; 30
add_tx_pre CinnabarGymQuiz ; 31
add_tx_pre GameCornerNoCoinsText ; 32
add_tx_pre GameCornerCoinCaseText ; 33
add_tx_pre LinkCableHelp ; 34
add_tx_pre TMNotebook ; 35
add_tx_pre FightingDojoText ; 36
add_tx_pre EnemiesOnEverySideText ; 37
add_tx_pre WhatGoesAroundComesAroundText ; 38
add_tx_pre NewBicycleText ; 39
add_tx_pre IndigoPlateauStatues ; 3A
add_tx_pre VermilionGymTrashSuccessText1 ; 3B
add_tx_pre VermilionGymTrashSuccessText2 ; 3C XXX unused
add_tx_pre VermilionGymTrashSuccessText3 ; 3D
add_tx_pre VermilionGymTrashFailText ; 3E
add_tx_pre TownMapText ; 3F
add_tx_pre BookOrSculptureText ; 40
add_tx_pre ElevatorText ; 41
add_tx_pre PokemonStuffText ; 42

View file

@ -376,6 +376,7 @@ KnowsHMMove::
and a
ret
HMMoveArray:
INCLUDE "data/moves/hm_moves.asm"
DisplayDepositWithdrawMenu:

2845
home.asm

File diff suppressed because it is too large Load diff

35
home/bankswitch.asm Normal file
View file

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

526
home/list_menu.asm Normal file
View file

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

242
home/move_mon.asm Normal file
View file

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

141
home/names.asm Normal file
View file

@ -0,0 +1,141 @@
GetMonName::
push hl
ld a, [hLoadedROMBank]
push af
ld a, BANK(MonsterNames)
ld [hLoadedROMBank], a
ld [MBC1RomBank], a
ld a, [wd11e]
dec a
ld hl, MonsterNames
ld c, 10
ld b, 0
call AddNTimes
ld de, wcd6d
push de
ld bc, 10
call CopyData
ld hl, wcd6d + 10
ld [hl], "@"
pop de
pop af
ld [hLoadedROMBank], a
ld [MBC1RomBank], a
pop hl
ret
GetItemName::
; given an item ID at [wd11e], store the name of the item into a string
; starting at wcd6d
push hl
push bc
ld a, [wd11e]
cp HM_01 ; is this a TM/HM?
jr nc, .Machine
ld [wd0b5], a
ld a, ITEM_NAME
ld [wNameListType], a
ld a, BANK(ItemNames)
ld [wPredefBank], a
call GetName
jr .Finish
.Machine
call GetMachineName
.Finish
ld de, wcd6d ; pointer to where item name is stored in RAM
pop bc
pop hl
ret
GetMachineName::
; copies the name of the TM/HM in [wd11e] to wcd6d
push hl
push de
push bc
ld a, [wd11e]
push af
cp 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, "0"
.FirstDigit
sub 10
jr c, .SecondDigit
inc b
jr .FirstDigit
.SecondDigit
add 10
push af
ld a, b
ld [de], a
inc de
pop af
ld b, "0"
add b
ld [de], a
inc de
ld a, "@"
ld [de], a
pop af
ld [wd11e], a
pop bc
pop de
pop hl
ret
TechnicalPrefix::
db "TM"
HiddenPrefix::
db "HM"
; sets carry if item is HM, clears carry if item is not HM
; Input: a = item ID
IsItemHM::
cp HM_01
jr c, .notHM
cp 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::
ld hl, HMMoves
ld de, 1
jp IsInArray
HMMoves::
INCLUDE "data/moves/hm_moves.asm"
GetMoveName::
push hl
ld a, MOVE_NAME
ld [wNameListType], a
ld a, [wd11e]
ld [wd0b5], a
ld a, BANK(MoveNames)
ld [wPredefBank], a
call GetName
ld de, wcd6d ; pointer to where move name is stored in RAM
pop hl
ret

93
home/names2.asm Normal file
View file

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

31
home/overworld_text.asm Normal file
View file

@ -0,0 +1,31 @@
TextScriptEndingChar::
db "@"
TextScriptEnd::
ld hl, TextScriptEndingChar
ret
ExclamationText::
TX_FAR _ExclamationText
db "@"
GroundRoseText::
TX_FAR _GroundRoseText
db "@"
BoulderText::
TX_FAR _BoulderText
db "@"
MartSignText::
TX_FAR _MartSignText
db "@"
PokeCenterSignText::
TX_FAR _PokeCenterSignText
db "@"
PickUpItemText::
TX_ASM
predef PickUpItem
jp TextScriptEnd

464
home/pokemon.asm Normal file
View file

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

237
home/predef_text.asm Normal file
View file

@ -0,0 +1,237 @@
; this function is used to display sign messages, sprite dialog, etc.
; INPUT: [hSpriteIndexOrTextID] = sprite ID or text ID
DisplayTextID::
ld a, [hLoadedROMBank]
push af
callba DisplayTextIDInit ; initialization
ld hl, wTextPredefFlag
bit 0, [hl]
res 0, [hl]
jr nz, .skipSwitchToMapBank
ld a, [wCurMap]
call SwitchToMapRomBank
.skipSwitchToMapBank
ld a, 30 ; half a second
ld [hFrameCounter], a ; used as joypad poll timer
ld hl, wMapTextPtr
ld a, [hli]
ld h, [hl]
ld l, a ; hl = map text pointer
ld d, $00
ld a, [hSpriteIndexOrTextID] ; text ID
ld [wSpriteIndex], a
and a
jp z, DisplayStartMenu
cp TEXT_SAFARI_GAME_OVER
jp z, DisplaySafariGameOverText
cp TEXT_MON_FAINTED
jp z, DisplayPokemonFaintedText
cp TEXT_BLACKED_OUT
jp z, DisplayPlayerBlackedOutText
cp TEXT_REPEL_WORE_OFF
jp z, DisplayRepelWoreOffText
ld a, [wNumSprites]
ld e, a
ld a, [hSpriteIndexOrTextID] ; sprite ID
cp e
jr z, .spriteHandling
jr nc, .skipSpriteHandling
.spriteHandling
; get the text ID of the sprite
push hl
push de
push bc
callba UpdateSpriteFacingOffsetAndDelayMovement ; update the graphics of the sprite the player is talking to (to face the right direction)
pop bc
pop de
ld hl, wMapSpriteData ; NPC text entries
ld a, [hSpriteIndexOrTextID]
dec a
add a
add l
ld l, a
jr nc, .noCarry
inc h
.noCarry
inc hl
ld a, [hl] ; a = text ID of the sprite
pop hl
.skipSpriteHandling
; look up the address of the text in the map's text entries
dec a
ld e, a
sla e
add hl, de
ld a, [hli]
ld h, [hl]
ld l, a ; hl = address of the text
ld a, [hl] ; a = first byte of text
; check first byte of text for special cases
cp $fe ; Pokemart NPC
jp z, DisplayPokemartDialogue
cp $ff ; Pokemon Center NPC
jp z, DisplayPokemonCenterDialogue
cp $fc ; Item Storage PC
jp z, FuncTX_ItemStoragePC
cp $fd ; Bill's PC
jp z, FuncTX_BillsPC
cp $f9 ; Pokemon Center PC
jp z, FuncTX_PokemonCenterPC
cp $f5 ; Vending Machine
jr nz, .notVendingMachine
callba VendingMachineMenu ; jump banks to vending machine routine
jr AfterDisplayingTextID
.notVendingMachine
cp $f7 ; prize menu
jp z, FuncTX_GameCornerPrizeMenu
cp $f6 ; cable connection NPC in Pokemon Center
jr nz, .notSpecialCase
callab CableClubNPC
jr AfterDisplayingTextID
.notSpecialCase
call PrintText_NoCreatingTextBox ; display the text
ld a, [wDoNotWaitForButtonPressAfterDisplayingText]
and a
jr nz, HoldTextDisplayOpen
AfterDisplayingTextID::
ld a, [wEnteringCableClub]
and a
jr nz, HoldTextDisplayOpen
call WaitForTextScrollButtonPress ; wait for a button press after displaying all the text
; loop to hold the dialogue box open as long as the player keeps holding down the A button
HoldTextDisplayOpen::
call Joypad
ld a, [hJoyHeld]
bit 0, a ; is the A button being pressed?
jr nz, HoldTextDisplayOpen
CloseTextDisplay::
ld a, [wCurMap]
call SwitchToMapRomBank
ld a, $90
ld [hWY], a ; move the window off the screen
call DelayFrame
call LoadGBPal
xor a
ld [hAutoBGTransferEnabled], a ; disable continuous WRAM to VRAM transfer each V-blank
; loop to make sprites face the directions they originally faced before the dialogue
ld hl, 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 [hLoadedROMBank], a
ld [MBC1RomBank], a
call InitMapSprites ; reload sprite tile pattern data (since it was partially overwritten by text tile patterns)
ld hl, wFontLoaded
res 0, [hl]
ld a, [wd732]
bit 3, a ; used fly warp
call z, LoadPlayerSpriteGraphics
call LoadCurrentMapView
pop af
ld [hLoadedROMBank], a
ld [MBC1RomBank], a
jp UpdateSprites
DisplayPokemartDialogue::
push hl
ld hl, PokemartGreetingText
call PrintText
pop hl
inc hl
call LoadItemList
ld a, PRICEDITEMLISTMENU
ld [wListMenuID], a
ld a, [hLoadedROMBank]
push af
ld a, BANK(DisplayPokemartDialogue_)
ld [hLoadedROMBank], a
ld [MBC1RomBank], a
call DisplayPokemartDialogue_
pop af
ld [hLoadedROMBank], a
ld [MBC1RomBank], a
jp AfterDisplayingTextID
PokemartGreetingText::
TX_FAR _PokemartGreetingText
db "@"
LoadItemList::
ld a, 1
ld [wUpdateSpritesEnabled], a
ld a, h
ld [wItemListPointer], a
ld a, l
ld [wItemListPointer + 1], a
ld de, wItemList
.loop
ld a, [hli]
ld [de], a
inc de
cp $ff
jr nz, .loop
ret
DisplayPokemonCenterDialogue::
; zeroing these doesn't appear to serve any purpose
xor a
ld [hItemPrice], a
ld [hItemPrice + 1], a
ld [hItemPrice + 2], a
inc hl
ld a, [hLoadedROMBank]
push af
ld a, BANK(DisplayPokemonCenterDialogue_)
ld [hLoadedROMBank], a
ld [MBC1RomBank], a
call DisplayPokemonCenterDialogue_
pop af
ld [hLoadedROMBank], a
ld [MBC1RomBank], a
jp AfterDisplayingTextID
DisplaySafariGameOverText::
callab PrintSafariGameOverText
jp AfterDisplayingTextID
DisplayPokemonFaintedText::
ld hl, PokemonFaintedText
call PrintText
jp AfterDisplayingTextID
PokemonFaintedText::
TX_FAR _PokemonFaintedText
db "@"
DisplayPlayerBlackedOutText::
ld hl, PlayerBlackedOutText
call PrintText
ld a, [wd732]
res 5, a ; reset forced to use bike bit
ld [wd732], a
jp HoldTextDisplayOpen
PlayerBlackedOutText::
TX_FAR _PlayerBlackedOutText
db "@"
DisplayRepelWoreOffText::
ld hl, RepelWoreOffText
call PrintText
jp AfterDisplayingTextID
RepelWoreOffText::
TX_FAR _RepelWoreOffText
db "@"

77
home/print_bcd.asm Normal file
View file

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

217
home/print_num.asm Normal file
View file

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

436
home/trainers.asm Normal file
View file

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

196
home/uncompress.asm Normal file
View file

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

40
home/yes_no.asm Normal file
View file

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

View file

@ -1,13 +1,3 @@
predef_const: MACRO
const \1PredefID
ENDM
add_predef: MACRO
\1Predef::
db BANK(\1)
dw \1
ENDM
predef_id: MACRO
ld a, (\1Predef - PredefPointers) / 3
ENDM
@ -22,17 +12,6 @@ predef_jump: MACRO
jp Predef
ENDM
tx_pre_const: MACRO
const \1_id
ENDM
add_tx_pre: MACRO
\1_id:: dw \1
ENDM
db_tx_pre: MACRO
db (\1_id - TextPredefs) / 2 + 1
ENDM
tx_pre_id: MACRO
ld a, (\1_id - TextPredefs) / 2 + 1
@ -47,3 +26,7 @@ tx_pre_jump: MACRO
tx_pre_id \1
jp PrintPredefTextID
ENDM
db_tx_pre: MACRO
db (\1_id - TextPredefs) / 2 + 1
ENDM