ref: c85050497c1bd062e9cd40bf5b32fa3beca366cc
parent: 5559d51c863b6fb529ea0494d857950a36fe85b7
parent: 87ef75c173b5d5f227912860487600b6f53d1d1f
author: Rangi <35663410+Rangi42@users.noreply.github.com>
date: Fri Jul 3 05:38:52 EDT 2020
Merge pull request #256 from Rangi42/master Add subdirectories to engine/ similar to pokecrystal
--- a/audio.asm
+++ b/audio.asm
@@ -352,248 +352,30 @@
INCLUDE "audio/sfx/cry22_3.asm"
-
SECTION "Audio Engine 1", ROMX
-PlayBattleMusic::
- xor a
- ld [wAudioFadeOutControl], a
- ld [wLowHealthAlarm], a
- dec a
- ld [wNewSoundID], a
- call PlaySound ; stop music
- call DelayFrame
- ld c, BANK(Music_GymLeaderBattle)
- ld a, [wGymLeaderNo]
- and a
- jr z, .notGymLeaderBattle
- ld a, MUSIC_GYM_LEADER_BATTLE
- jr .playSong
-.notGymLeaderBattle
- ld a, [wCurOpponent]
- cp OPP_ID_OFFSET
- jr c, .wildBattle
- cp OPP_SONY3
- jr z, .finalBattle
- cp OPP_LANCE
- jr nz, .normalTrainerBattle
- ld a, MUSIC_GYM_LEADER_BATTLE ; lance also plays gym leader theme
- jr .playSong
-.normalTrainerBattle
- ld a, MUSIC_TRAINER_BATTLE
- jr .playSong
-.finalBattle
- ld a, MUSIC_FINAL_BATTLE
- jr .playSong
-.wildBattle
- ld a, MUSIC_WILD_BATTLE
-.playSong
- jp PlayMusic
-
-
+INCLUDE "audio/play_battle_music.asm"
INCLUDE "audio/engine_1.asm"
+INCLUDE "audio/alternate_tempo.asm"
-; an alternate start for MeetRival which has a different first measure
-Music_RivalAlternateStart::
- ld c, BANK(Music_MeetRival)
- ld a, MUSIC_MEET_RIVAL
- call PlayMusic
- ld hl, wChannelCommandPointers
- ld de, Music_MeetRival_branch_b1a2
- call Audio1_OverwriteChannelPointer
- ld de, Music_MeetRival_branch_b21d
- call Audio1_OverwriteChannelPointer
- ld de, Music_MeetRival_branch_b2b5
+SECTION "Low Health Alarm (Audio Engine 2)", ROMX
-Audio1_OverwriteChannelPointer:
- ld a, e
- ld [hli], a
- ld a, d
- ld [hli], a
- ret
+INCLUDE "audio/low_health_alarm.asm"
-; an alternate tempo for MeetRival which is slightly slower
-Music_RivalAlternateTempo::
- ld c, BANK(Music_MeetRival)
- ld a, MUSIC_MEET_RIVAL
- call PlayMusic
- ld hl, wChannelCommandPointers
- ld de, Music_MeetRival_branch_b119
- jp Audio1_OverwriteChannelPointer
-; applies both the alternate start and alternate tempo
-Music_RivalAlternateStartAndTempo::
- call Music_RivalAlternateStart
- ld hl, wChannelCommandPointers
- ld de, Music_MeetRival_branch_b19b
- jp Audio1_OverwriteChannelPointer
-
-; an alternate tempo for Cities1 which is used for the Hall of Fame room
-Music_Cities1AlternateTempo::
- ld a, 10
- ld [wAudioFadeOutCounterReloadValue], a
- ld [wAudioFadeOutCounter], a
- ld a, $ff ; stop playing music after the fade-out is finished
- ld [wAudioFadeOutControl], a
- ld c, 100
- call DelayFrames ; wait for the fade-out to finish
- ld c, BANK(Music_Cities1)
- ld a, MUSIC_CITIES1
- call PlayMusic
- ld hl, wChannelCommandPointers
- ld de, Music_Cities1_branch_aa6f
- jp Audio1_OverwriteChannelPointer
-
-
SECTION "Audio Engine 2", ROMX
-Music_DoLowHealthAlarm::
- ld a, [wLowHealthAlarm]
- cp $ff
- jr z, .disableAlarm
-
- bit 7, a ;alarm enabled?
- ret z ;nope
-
- and $7f ;low 7 bits are the timer.
- jr nz, .asm_21383 ;if timer > 0, play low tone.
-
- call .playToneHi
- ld a, 30 ;keep this tone for 30 frames.
- jr .asm_21395 ;reset the timer.
-
-.asm_21383
- cp 20
- jr nz, .asm_2138a ;if timer == 20,
- call .playToneLo ;actually set the sound registers.
-
-.asm_2138a
- ld a, $86
- ld [wChannelSoundIDs + Ch5], a ;disable sound channel?
- ld a, [wLowHealthAlarm]
- and $7f ;decrement alarm timer.
- dec a
-
-.asm_21395
- ; reset the timer and enable flag.
- set 7, a
- ld [wLowHealthAlarm], a
- ret
-
-.disableAlarm
- xor a
- ld [wLowHealthAlarm], a ;disable alarm
- ld [wChannelSoundIDs + Ch5], a ;re-enable sound channel?
- ld de, .toneDataSilence
- jr .playTone
-
-;update the sound registers to change the frequency.
-;the tone set here stays until we change it.
-.playToneHi
- ld de, .toneDataHi
- jr .playTone
-
-.playToneLo
- ld de, .toneDataLo
-
-;update sound channel 1 to play the alarm, overriding all other sounds.
-.playTone
- ld hl, rNR10 ;channel 1 sound register
- ld c, $5
- xor a
-
-.copyLoop
- ld [hli], a
- ld a, [de]
- inc de
- dec c
- jr nz, .copyLoop
- ret
-
-;bytes to write to sound channel 1 registers for health alarm.
-;starting at FF11 (FF10 is always zeroed), so these bytes are:
-;length, envelope, freq lo, freq hi
-.toneDataHi
- db $A0,$E2,$50,$87
-
-.toneDataLo
- db $B0,$E2,$EE,$86
-
-;written to stop the alarm
-.toneDataSilence
- db $00,$00,$00,$80
-
-
-INCLUDE "engine/menu/bills_pc.asm"
-
INCLUDE "audio/engine_2.asm"
+INCLUDE "audio/poke_flute.asm"
-Music_PokeFluteInBattle::
- ; begin playing the "caught mon" sound effect
- ld a, SFX_CAUGHT_MON
- call PlaySoundWaitForCurrent
- ; then immediately overwrite the channel pointers
- ld hl, wChannelCommandPointers + Ch5 * 2
- ld de, SFX_Pokeflute_Ch5
- call Audio2_OverwriteChannelPointer
- ld de, SFX_Pokeflute_Ch6
- call Audio2_OverwriteChannelPointer
- ld de, SFX_Pokeflute_Ch7
-
-Audio2_OverwriteChannelPointer:
- ld a, e
- ld [hli], a
- ld a, d
- ld [hli], a
- ret
-
-
SECTION "Audio Engine 3", ROMX
-PlayPokedexRatingSfx::
- ld a, [$ffdc]
- ld c, $0
- ld hl, OwnedMonValues
-.getSfxPointer
- cp [hl]
- jr c, .gotSfxPointer
- inc c
- inc hl
- jr .getSfxPointer
-.gotSfxPointer
- push bc
- ld a, $ff
- ld [wNewSoundID], a
- call PlaySoundWaitForCurrent
- pop bc
- ld b, $0
- ld hl, PokedexRatingSfxPointers
- add hl, bc
- add hl, bc
- ld a, [hli]
- ld c, [hl]
- call PlayMusic
- jp PlayDefaultMusic
-
-PokedexRatingSfxPointers:
- db SFX_DENIED, BANK(SFX_Denied_3)
- db SFX_POKEDEX_RATING, BANK(SFX_Pokedex_Rating_1)
- db SFX_GET_ITEM_1, BANK(SFX_Get_Item1_1)
- db SFX_CAUGHT_MON, BANK(SFX_Caught_Mon)
- db SFX_LEVEL_UP, BANK(SFX_Level_Up)
- db SFX_GET_KEY_ITEM, BANK(SFX_Get_Key_Item_1)
- db SFX_GET_ITEM_2, BANK(SFX_Get_Item2_1)
-
-OwnedMonValues:
- db 10, 40, 60, 90, 120, 150, $ff
-
-
+INCLUDE "audio/pokedex_rating_sfx.asm"
INCLUDE "audio/engine_3.asm"
-
SECTION "Music 1", ROMX
INCLUDE "audio/music/pkmnhealed.asm"
@@ -663,4 +445,3 @@
INCLUDE "audio/music/jigglypuffsong.asm"
INCLUDE "audio/music/halloffame.asm"
INCLUDE "audio/music/credits.asm"
-
--- /dev/null
+++ b/audio/alternate_tempo.asm
@@ -1,0 +1,50 @@
+; an alternate start for MeetRival which has a different first measure
+Music_RivalAlternateStart::
+ ld c, BANK(Music_MeetRival)
+ ld a, MUSIC_MEET_RIVAL
+ call PlayMusic
+ ld hl, wChannelCommandPointers
+ ld de, Music_MeetRival_branch_b1a2
+ call Audio1_OverwriteChannelPointer
+ ld de, Music_MeetRival_branch_b21d
+ call Audio1_OverwriteChannelPointer
+ ld de, Music_MeetRival_branch_b2b5
+
+Audio1_OverwriteChannelPointer:
+ ld a, e
+ ld [hli], a
+ ld a, d
+ ld [hli], a
+ ret
+
+; an alternate tempo for MeetRival which is slightly slower
+Music_RivalAlternateTempo::
+ ld c, BANK(Music_MeetRival)
+ ld a, MUSIC_MEET_RIVAL
+ call PlayMusic
+ ld hl, wChannelCommandPointers
+ ld de, Music_MeetRival_branch_b119
+ jp Audio1_OverwriteChannelPointer
+
+; applies both the alternate start and alternate tempo
+Music_RivalAlternateStartAndTempo::
+ call Music_RivalAlternateStart
+ ld hl, wChannelCommandPointers
+ ld de, Music_MeetRival_branch_b19b
+ jp Audio1_OverwriteChannelPointer
+
+; an alternate tempo for Cities1 which is used for the Hall of Fame room
+Music_Cities1AlternateTempo::
+ ld a, 10
+ ld [wAudioFadeOutCounterReloadValue], a
+ ld [wAudioFadeOutCounter], a
+ ld a, $ff ; stop playing music after the fade-out is finished
+ ld [wAudioFadeOutControl], a
+ ld c, 100
+ call DelayFrames ; wait for the fade-out to finish
+ ld c, BANK(Music_Cities1)
+ ld a, MUSIC_CITIES1
+ call PlayMusic
+ ld hl, wChannelCommandPointers
+ ld de, Music_Cities1_branch_aa6f
+ jp Audio1_OverwriteChannelPointer
--- /dev/null
+++ b/audio/low_health_alarm.asm
@@ -1,0 +1,75 @@
+Music_DoLowHealthAlarm::
+ ld a, [wLowHealthAlarm]
+ cp $ff
+ jr z, .disableAlarm
+
+ bit 7, a ;alarm enabled?
+ ret z ;nope
+
+ and $7f ;low 7 bits are the timer.
+ jr nz, .asm_21383 ;if timer > 0, play low tone.
+
+ call .playToneHi
+ ld a, 30 ;keep this tone for 30 frames.
+ jr .asm_21395 ;reset the timer.
+
+.asm_21383
+ cp 20
+ jr nz, .asm_2138a ;if timer == 20,
+ call .playToneLo ;actually set the sound registers.
+
+.asm_2138a
+ ld a, $86
+ ld [wChannelSoundIDs + Ch5], a ;disable sound channel?
+ ld a, [wLowHealthAlarm]
+ and $7f ;decrement alarm timer.
+ dec a
+
+.asm_21395
+ ; reset the timer and enable flag.
+ set 7, a
+ ld [wLowHealthAlarm], a
+ ret
+
+.disableAlarm
+ xor a
+ ld [wLowHealthAlarm], a ;disable alarm
+ ld [wChannelSoundIDs + Ch5], a ;re-enable sound channel?
+ ld de, .toneDataSilence
+ jr .playTone
+
+;update the sound registers to change the frequency.
+;the tone set here stays until we change it.
+.playToneHi
+ ld de, .toneDataHi
+ jr .playTone
+
+.playToneLo
+ ld de, .toneDataLo
+
+;update sound channel 1 to play the alarm, overriding all other sounds.
+.playTone
+ ld hl, rNR10 ;channel 1 sound register
+ ld c, $5
+ xor a
+
+.copyLoop
+ ld [hli], a
+ ld a, [de]
+ inc de
+ dec c
+ jr nz, .copyLoop
+ ret
+
+;bytes to write to sound channel 1 registers for health alarm.
+;starting at FF11 (FF10 is always zeroed), so these bytes are:
+;length, envelope, freq lo, freq hi
+.toneDataHi
+ db $A0,$E2,$50,$87
+
+.toneDataLo
+ db $B0,$E2,$EE,$86
+
+;written to stop the alarm
+.toneDataSilence
+ db $00,$00,$00,$80
--- a/audio/notes.asm
+++ b/audio/notes.asm
@@ -1,3 +1,5 @@
+; This file is INCLUDEd three times, once in each audio engine.
+
dw $F82C ; C_
dw $F89D ; C#
dw $F907 ; D_
--- /dev/null
+++ b/audio/play_battle_music.asm
@@ -1,0 +1,34 @@
+PlayBattleMusic::
+ xor a
+ ld [wAudioFadeOutControl], a
+ ld [wLowHealthAlarm], a
+ dec a
+ ld [wNewSoundID], a
+ call PlaySound ; stop music
+ call DelayFrame
+ ld c, BANK(Music_GymLeaderBattle)
+ ld a, [wGymLeaderNo]
+ and a
+ jr z, .notGymLeaderBattle
+ ld a, MUSIC_GYM_LEADER_BATTLE
+ jr .playSong
+.notGymLeaderBattle
+ ld a, [wCurOpponent]
+ cp OPP_ID_OFFSET
+ jr c, .wildBattle
+ cp OPP_SONY3
+ jr z, .finalBattle
+ cp OPP_LANCE
+ jr nz, .normalTrainerBattle
+ ld a, MUSIC_GYM_LEADER_BATTLE ; lance also plays gym leader theme
+ jr .playSong
+.normalTrainerBattle
+ ld a, MUSIC_TRAINER_BATTLE
+ jr .playSong
+.finalBattle
+ ld a, MUSIC_FINAL_BATTLE
+ jr .playSong
+.wildBattle
+ ld a, MUSIC_WILD_BATTLE
+.playSong
+ jp PlayMusic
--- /dev/null
+++ b/audio/poke_flute.asm
@@ -1,0 +1,18 @@
+Music_PokeFluteInBattle::
+ ; begin playing the "caught mon" sound effect
+ ld a, SFX_CAUGHT_MON
+ call PlaySoundWaitForCurrent
+ ; then immediately overwrite the channel pointers
+ ld hl, wChannelCommandPointers + Ch5 * 2
+ ld de, SFX_Pokeflute_Ch5
+ call Audio2_OverwriteChannelPointer
+ ld de, SFX_Pokeflute_Ch6
+ call Audio2_OverwriteChannelPointer
+ ld de, SFX_Pokeflute_Ch7
+
+Audio2_OverwriteChannelPointer:
+ ld a, e
+ ld [hli], a
+ ld a, d
+ ld [hli], a
+ ret
--- /dev/null
+++ b/audio/pokedex_rating_sfx.asm
@@ -1,0 +1,36 @@
+PlayPokedexRatingSfx::
+ ld a, [$ffdc]
+ ld c, $0
+ ld hl, OwnedMonValues
+.getSfxPointer
+ cp [hl]
+ jr c, .gotSfxPointer
+ inc c
+ inc hl
+ jr .getSfxPointer
+.gotSfxPointer
+ push bc
+ ld a, $ff
+ ld [wNewSoundID], a
+ call PlaySoundWaitForCurrent
+ pop bc
+ ld b, $0
+ ld hl, PokedexRatingSfxPointers
+ add hl, bc
+ add hl, bc
+ ld a, [hli]
+ ld c, [hl]
+ call PlayMusic
+ jp PlayDefaultMusic
+
+PokedexRatingSfxPointers:
+ db SFX_DENIED, BANK(SFX_Denied_3)
+ db SFX_POKEDEX_RATING, BANK(SFX_Pokedex_Rating_1)
+ db SFX_GET_ITEM_1, BANK(SFX_Get_Item1_1)
+ db SFX_CAUGHT_MON, BANK(SFX_Caught_Mon)
+ db SFX_LEVEL_UP, BANK(SFX_Level_Up)
+ db SFX_GET_KEY_ITEM, BANK(SFX_Get_Key_Item_1)
+ db SFX_GET_ITEM_2, BANK(SFX_Get_Item2_1)
+
+OwnedMonValues:
+ db 10, 40, 60, 90, 120, 150, $ff
--- a/audio/wave_instruments.asm
+++ b/audio/wave_instruments.asm
@@ -1,3 +1,5 @@
+; This file is INCLUDEd three times, once for each audio engine.
+
dw .wave0
dw .wave1
dw .wave2
--- /dev/null
+++ b/data/hm_moves.asm
@@ -1,0 +1,7 @@
+HMMoveArray:
+ db CUT
+ db FLY
+ db SURF
+ db STRENGTH
+ db FLASH
+ db -1
--- a/engine/HoF_room_pc.asm
+++ /dev/null
@@ -1,270 +1,0 @@
-HallOfFamePC:
- callba AnimateHallOfFame
- call ClearScreen
- ld c, 100
- call DelayFrames
- call DisableLCD
- ld hl, vFont
- ld bc, $800 / 2
- call ZeroMemory
- ld hl, vChars2 + $600
- ld bc, $200 / 2
- call ZeroMemory
- ld hl, vChars2 + $7e0
- ld bc, $10
- ld a, $ff
- call FillMemory
- coord hl, 0, 0
- call FillFourRowsWithBlack
- coord hl, 0, 14
- call FillFourRowsWithBlack
- ld a, %11000000
- ld [rBGP], a
- call EnableLCD
- ld a, $ff
- call PlaySoundWaitForCurrent
- ld c, BANK(Music_Credits)
- ld a, MUSIC_CREDITS
- call PlayMusic
- ld c, 128
- call DelayFrames
- xor a
- ld [wUnusedCD3D], a ; not read
- ld [wNumCreditsMonsDisplayed], a
- jp Credits
-
-FadeInCreditsText:
- ld hl, HoFGBPalettes
- ld b, 4
-.loop
- ld a, [hli]
- ld [rBGP], a
- ld c, 5
- call DelayFrames
- dec b
- jr nz, .loop
- ret
-
-DisplayCreditsMon:
- xor a
- ld [H_AUTOBGTRANSFERENABLED], a
- call SaveScreenTilesToBuffer1
- call FillMiddleOfScreenWithWhite
-
- ; display the next monster from CreditsMons
- ld hl, wNumCreditsMonsDisplayed
- ld c, [hl] ; how many monsters have we displayed so far?
- inc [hl]
- ld b, 0
- ld hl, CreditsMons
- add hl, bc ; go that far in the list of monsters and get the next one
- ld a, [hl]
- ld [wcf91], a
- ld [wd0b5], a
- coord hl, 8, 6
- call GetMonHeader
- call LoadFrontSpriteByMonIndex
- ld hl, vBGMap0 + $c
- call CreditsCopyTileMapToVRAM
- xor a
- ld [H_AUTOBGTRANSFERENABLED], a
- call LoadScreenTilesFromBuffer1
- ld hl, vBGMap0
- call CreditsCopyTileMapToVRAM
- ld a, $A7
- ld [rWX], a
- ld hl, vBGMap1
- call CreditsCopyTileMapToVRAM
- call FillMiddleOfScreenWithWhite
- ld a, %11111100 ; make the mon a black silhouette
- ld [rBGP], a
-
-; scroll the mon left by one tile 7 times
- ld bc, 7
-.scrollLoop1
- call ScrollCreditsMonLeft
- dec c
- jr nz, .scrollLoop1
-
-; scroll the mon left by one tile 20 times
-; This time, we have to move the window left too in order to hide the text that
-; is wrapping around to the right side of the screen.
- ld c, 20
-.scrollLoop2
- call ScrollCreditsMonLeft
- ld a, [rWX]
- sub 8
- ld [rWX], a
- dec c
- jr nz, .scrollLoop2
-
- xor a
- ld [hWY], a
- ld a, %11000000
- ld [rBGP], a
- ret
-
-INCLUDE "data/credit_mons.asm"
-
-ScrollCreditsMonLeft:
- ld h, b
- ld l, $20
- call ScrollCreditsMonLeft_SetSCX
- ld h, $0
- ld l, $70
- call ScrollCreditsMonLeft_SetSCX
- ld a, b
- add $8
- ld b, a
- ret
-
-ScrollCreditsMonLeft_SetSCX:
- ld a, [rLY]
- cp l
- jr nz, ScrollCreditsMonLeft_SetSCX
- ld a, h
- ld [rSCX], a
-.loop
- ld a, [rLY]
- cp h
- jr z, .loop
- ret
-
-HoFGBPalettes:
- db %11000000
- db %11010000
- db %11100000
- db %11110000
-
-CreditsCopyTileMapToVRAM:
- ld a, l
- ld [H_AUTOBGTRANSFERDEST], a
- ld a, h
- ld [H_AUTOBGTRANSFERDEST + 1], a
- ld a, 1
- ld [H_AUTOBGTRANSFERENABLED], a
- jp Delay3
-
-ZeroMemory:
-; zero bc bytes at hl
- ld [hl], 0
- inc hl
- inc hl
- dec bc
- ld a, b
- or c
- jr nz, ZeroMemory
- ret
-
-FillFourRowsWithBlack:
- ld bc, SCREEN_WIDTH * 4
- ld a, $7e
- jp FillMemory
-
-FillMiddleOfScreenWithWhite:
- coord hl, 0, 4
- ld bc, SCREEN_WIDTH * 10
- ld a, " "
- jp FillMemory
-
-Credits:
- ld de, CreditsOrder
- push de
-.nextCreditsScreen
- pop de
- coord hl, 9, 6
- push hl
- call FillMiddleOfScreenWithWhite
- pop hl
-.nextCreditsCommand
- ld a, [de]
- inc de
- push de
- cp $ff
- jr z, .fadeInTextAndShowMon
- cp $fe
- jr z, .showTextAndShowMon
- cp $fd
- jr z, .fadeInText
- cp $fc
- jr z, .showText
- cp $fb
- jr z, .showCopyrightText
- cp $fa
- jr z, .showTheEnd
- push hl
- push hl
- ld hl, CreditsTextPointers
- add a
- ld c, a
- ld b, 0
- add hl, bc
- ld e, [hl]
- inc hl
- ld d, [hl]
- ld a, [de]
- inc de
- ld c, a
- ld b, $ff
- pop hl
- add hl, bc
- call PlaceString
- pop hl
- ld bc, SCREEN_WIDTH * 2
- add hl, bc
- pop de
- jr .nextCreditsCommand
-.fadeInTextAndShowMon
- call FadeInCreditsText
- ld c, 90
- jr .next1
-.showTextAndShowMon
- ld c, 110
-.next1
- call DelayFrames
- call DisplayCreditsMon
- jr .nextCreditsScreen
-.fadeInText
- call FadeInCreditsText
- ld c, 120
- jr .next2
-.showText
- ld c, 140
-.next2
- call DelayFrames
- jr .nextCreditsScreen
-.showCopyrightText
- push de
- callba LoadCopyrightTiles
- pop de
- pop de
- jr .nextCreditsCommand
-.showTheEnd
- ld c, 16
- call DelayFrames
- call FillMiddleOfScreenWithWhite
- pop de
- ld de, TheEndGfx
- ld hl, vChars2 + $600
- lb bc, BANK(TheEndGfx), (TheEndGfxEnd - TheEndGfx) / $10
- call CopyVideoData
- coord hl, 4, 8
- ld de, TheEndTextString
- call PlaceString
- coord hl, 4, 9
- inc de
- call PlaceString
- jp FadeInCreditsText
-
-TheEndTextString:
-; "T H E E N D"
- db $60," ",$62," ",$64," ",$64," ",$66," ",$68,"@"
- db $61," ",$63," ",$65," ",$65," ",$67," ",$69,"@"
-
-INCLUDE "data/credits_order.asm"
-
-INCLUDE "text/credits_text.asm"
-
-TheEndGfx:
- INCBIN "gfx/intro_credits/the_end.2bpp"
-TheEndGfxEnd:
--- a/engine/add_mon.asm
+++ /dev/null
@@ -1,516 +1,0 @@
-_AddPartyMon::
-; Adds a new mon to the player's or enemy's party.
-; [wMonDataLocation] is used in an unusual way in this function.
-; If the lower nybble is 0, the mon is added to the player's party, else the enemy's.
-; If the entire value is 0, then the player is allowed to name the mon.
- ld de, wPartyCount
- ld a, [wMonDataLocation]
- and $f
- jr z, .next
- ld de, wEnemyPartyCount
-.next
- ld a, [de]
- inc a
- cp PARTY_LENGTH + 1
- ret nc ; return if the party is already full
- ld [de], a
- ld a, [de]
- ld [hNewPartyLength], a
- add e
- ld e, a
- jr nc, .noCarry
- inc d
-.noCarry
- ld a, [wcf91]
- ld [de], a ; write species of new mon in party list
- inc de
- ld a, $ff ; terminator
- ld [de], a
- ld hl, wPartyMonOT
- ld a, [wMonDataLocation]
- and $f
- jr z, .next2
- ld hl, wEnemyMonOT
-.next2
- ld a, [hNewPartyLength]
- dec a
- call SkipFixedLengthTextEntries
- ld d, h
- ld e, l
- ld hl, wPlayerName
- ld bc, NAME_LENGTH
- call CopyData
- ld a, [wMonDataLocation]
- and a
- jr nz, .skipNaming
- ld hl, wPartyMonNicks
- ld a, [hNewPartyLength]
- dec a
- call SkipFixedLengthTextEntries
- ld a, NAME_MON_SCREEN
- ld [wNamingScreenType], a
- predef AskName
-.skipNaming
- ld hl, wPartyMons
- ld a, [wMonDataLocation]
- and $f
- jr z, .next3
- ld hl, wEnemyMons
-.next3
- ld a, [hNewPartyLength]
- dec a
- ld bc, wPartyMon2 - wPartyMon1
- call AddNTimes
- ld e, l
- ld d, h
- push hl
- ld a, [wcf91]
- ld [wd0b5], a
- call GetMonHeader
- ld hl, wMonHeader
- ld a, [hli]
- ld [de], a ; species
- inc de
- pop hl
- push hl
- ld a, [wMonDataLocation]
- and $f
- ld a, $98 ; set enemy trainer mon IVs to fixed average values
- ld b, $88
- jr nz, .next4
-
-; If the mon is being added to the player's party, update the pokedex.
- ld a, [wcf91]
- ld [wd11e], a
- push de
- predef IndexToPokedex
- pop de
- ld a, [wd11e]
- dec a
- ld c, a
- ld b, FLAG_TEST
- ld hl, wPokedexOwned
- call FlagAction
- ld a, c ; whether the mon was already flagged as owned
- ld [wUnusedD153], a ; not read
- ld a, [wd11e]
- dec a
- ld c, a
- ld b, FLAG_SET
- push bc
- call FlagAction
- pop bc
- ld hl, wPokedexSeen
- call FlagAction
-
- pop hl
- push hl
-
- ld a, [wIsInBattle]
- and a ; is this a wild mon caught in battle?
- jr nz, .copyEnemyMonData
-
-; Not wild.
- call Random ; generate random IVs
- ld b, a
- call Random
-
-.next4
- push bc
- ld bc, wPartyMon1DVs - wPartyMon1
- add hl, bc
- pop bc
- ld [hli], a
- ld [hl], b ; write IVs
- ld bc, (wPartyMon1HPExp - 1) - (wPartyMon1DVs + 1)
- add hl, bc
- ld a, 1
- ld c, a
- xor a
- ld b, a
- call CalcStat ; calc HP stat (set cur Hp to max HP)
- ld a, [H_MULTIPLICAND+1]
- ld [de], a
- inc de
- ld a, [H_MULTIPLICAND+2]
- ld [de], a
- inc de
- xor a
- ld [de], a ; box level
- inc de
- ld [de], a ; status ailments
- inc de
- jr .copyMonTypesAndMoves
-.copyEnemyMonData
- ld bc, wEnemyMon1DVs - wEnemyMon1
- add hl, bc
- ld a, [wEnemyMonDVs] ; copy IVs from cur enemy mon
- ld [hli], a
- ld a, [wEnemyMonDVs + 1]
- ld [hl], a
- ld a, [wEnemyMonHP] ; copy HP from cur enemy mon
- ld [de], a
- inc de
- ld a, [wEnemyMonHP+1]
- ld [de], a
- inc de
- xor a
- ld [de], a ; box level
- inc de
- ld a, [wEnemyMonStatus] ; copy status ailments from cur enemy mon
- ld [de], a
- inc de
-.copyMonTypesAndMoves
- ld hl, wMonHTypes
- ld a, [hli] ; type 1
- ld [de], a
- inc de
- ld a, [hli] ; type 2
- ld [de], a
- inc de
- ld a, [hli] ; catch rate (held item in gen 2)
- ld [de], a
- ld hl, wMonHMoves
- ld a, [hli]
- inc de
- push de
- ld [de], a
- ld a, [hli]
- inc de
- ld [de], a
- ld a, [hli]
- inc de
- ld [de], a
- ld a, [hli]
- inc de
- ld [de], a
- push de
- dec de
- dec de
- dec de
- xor a
- ld [wLearningMovesFromDayCare], a
- predef WriteMonMoves
- pop de
- ld a, [wPlayerID] ; set trainer ID to player ID
- inc de
- ld [de], a
- ld a, [wPlayerID + 1]
- inc de
- ld [de], a
- push de
- ld a, [wCurEnemyLVL]
- ld d, a
- callab CalcExperience
- pop de
- inc de
- ld a, [hExperience] ; write experience
- ld [de], a
- inc de
- ld a, [hExperience + 1]
- ld [de], a
- inc de
- ld a, [hExperience + 2]
- ld [de], a
- xor a
- ld b, NUM_STATS * 2
-.writeEVsLoop ; set all EVs to 0
- inc de
- ld [de], a
- dec b
- jr nz, .writeEVsLoop
- inc de
- inc de
- pop hl
- call AddPartyMon_WriteMovePP
- inc de
- ld a, [wCurEnemyLVL]
- ld [de], a
- inc de
- ld a, [wIsInBattle]
- dec a
- jr nz, .calcFreshStats
- ld hl, wEnemyMonMaxHP
- ld bc, $a
- call CopyData ; copy stats of cur enemy mon
- pop hl
- jr .done
-.calcFreshStats
- pop hl
- ld bc, wPartyMon1HPExp - 1 - wPartyMon1
- add hl, bc
- ld b, $0
- call CalcStats ; calculate fresh set of stats
-.done
- scf
- ret
-
-LoadMovePPs:
- call GetPredefRegisters
- ; fallthrough
-AddPartyMon_WriteMovePP:
- ld b, NUM_MOVES
-.pploop
- ld a, [hli] ; read move ID
- and a
- jr z, .empty
- dec a
- push hl
- push de
- push bc
- ld hl, Moves
- ld bc, MoveEnd - Moves
- call AddNTimes
- ld de, wcd6d
- ld a, BANK(Moves)
- call FarCopyData
- pop bc
- pop de
- pop hl
- ld a, [wcd6d + 5] ; PP is byte 5 of move data
-.empty
- inc de
- ld [de], a
- dec b
- jr nz, .pploop ; there are still moves to read
- ret
-
-; adds enemy mon [wcf91] (at position [wWhichPokemon] in enemy list) to own party
-; used in the cable club trade center
-_AddEnemyMonToPlayerParty::
- ld hl, wPartyCount
- ld a, [hl]
- cp PARTY_LENGTH
- scf
- ret z ; party full, return failure
- inc a
- ld [hl], a ; add 1 to party members
- ld c, a
- ld b, $0
- add hl, bc
- ld a, [wcf91]
- ld [hli], a ; add mon as last list entry
- ld [hl], $ff ; write new sentinel
- ld hl, wPartyMons
- ld a, [wPartyCount]
- dec a
- ld bc, wPartyMon2 - wPartyMon1
- call AddNTimes
- ld e, l
- ld d, h
- ld hl, wLoadedMon
- call CopyData ; write new mon's data (from wLoadedMon)
- ld hl, wPartyMonOT
- ld a, [wPartyCount]
- dec a
- call SkipFixedLengthTextEntries
- ld d, h
- ld e, l
- ld hl, wEnemyMonOT
- ld a, [wWhichPokemon]
- call SkipFixedLengthTextEntries
- ld bc, NAME_LENGTH
- call CopyData ; write new mon's OT name (from an enemy mon)
- ld hl, wPartyMonNicks
- ld a, [wPartyCount]
- dec a
- call SkipFixedLengthTextEntries
- ld d, h
- ld e, l
- ld hl, wEnemyMonNicks
- ld a, [wWhichPokemon]
- call SkipFixedLengthTextEntries
- ld bc, NAME_LENGTH
- call CopyData ; write new mon's nickname (from an enemy mon)
- ld a, [wcf91]
- ld [wd11e], a
- predef IndexToPokedex
- ld a, [wd11e]
- dec a
- ld c, a
- ld b, FLAG_SET
- ld hl, wPokedexOwned
- push bc
- call FlagAction ; add to owned pokemon
- pop bc
- ld hl, wPokedexSeen
- call FlagAction ; add to seen pokemon
- and a
- ret ; return success
-
-_MoveMon::
- ld a, [wMoveMonType]
- and a ; BOX_TO_PARTY
- jr z, .checkPartyMonSlots
- cp DAYCARE_TO_PARTY
- jr z, .checkPartyMonSlots
- cp PARTY_TO_DAYCARE
- ld hl, wDayCareMon
- jr z, .findMonDataSrc
- ; else it's PARTY_TO_BOX
- ld hl, wNumInBox
- ld a, [hl]
- cp MONS_PER_BOX
- jr nz, .partyOrBoxNotFull
- jr .boxFull
-.checkPartyMonSlots
- ld hl, wPartyCount
- ld a, [hl]
- cp PARTY_LENGTH
- jr nz, .partyOrBoxNotFull
-.boxFull
- scf
- ret
-.partyOrBoxNotFull
- inc a
- ld [hl], a ; increment number of mons in party/box
- ld c, a
- ld b, 0
- add hl, bc
- ld a, [wMoveMonType]
- cp DAYCARE_TO_PARTY
- ld a, [wDayCareMon]
- jr z, .copySpecies
- ld a, [wcf91]
-.copySpecies
- ld [hli], a ; write new mon ID
- ld [hl], $ff ; write new sentinel
-.findMonDataDest
- ld a, [wMoveMonType]
- dec a
- ld hl, wPartyMons
- ld bc, wPartyMon2 - wPartyMon1 ; $2c
- ld a, [wPartyCount]
- jr nz, .addMonOffset
- ; if it's PARTY_TO_BOX
- ld hl, wBoxMons
- ld bc, wBoxMon2 - wBoxMon1 ; $21
- ld a, [wNumInBox]
-.addMonOffset
- dec a
- call AddNTimes
-.findMonDataSrc
- push hl
- ld e, l
- ld d, h
- ld a, [wMoveMonType]
- and a
- ld hl, wBoxMons
- ld bc, wBoxMon2 - wBoxMon1 ; $21
- jr z, .addMonOffset2
- cp DAYCARE_TO_PARTY
- ld hl, wDayCareMon
- jr z, .copyMonData
- ld hl, wPartyMons
- ld bc, wPartyMon2 - wPartyMon1 ; $2c
-.addMonOffset2
- ld a, [wWhichPokemon]
- call AddNTimes
-.copyMonData
- push hl
- push de
- ld bc, wBoxMon2 - wBoxMon1
- call CopyData
- pop de
- pop hl
- ld a, [wMoveMonType]
- and a ; BOX_TO_PARTY
- jr z, .findOTdest
- cp DAYCARE_TO_PARTY
- jr z, .findOTdest
- ld bc, wBoxMon2 - wBoxMon1
- add hl, bc
- ld a, [hl] ; hl = Level
- inc de
- inc de
- inc de
- ld [de], a ; de = BoxLevel
-.findOTdest
- ld a, [wMoveMonType]
- cp PARTY_TO_DAYCARE
- ld de, wDayCareMonOT
- jr z, .findOTsrc
- dec a
- ld hl, wPartyMonOT
- ld a, [wPartyCount]
- jr nz, .addOToffset
- ld hl, wBoxMonOT
- ld a, [wNumInBox]
-.addOToffset
- dec a
- call SkipFixedLengthTextEntries
- ld d, h
- ld e, l
-.findOTsrc
- ld hl, wBoxMonOT
- ld a, [wMoveMonType]
- and a
- jr z, .addOToffset2
- ld hl, wDayCareMonOT
- cp DAYCARE_TO_PARTY
- jr z, .copyOT
- ld hl, wPartyMonOT
-.addOToffset2
- ld a, [wWhichPokemon]
- call SkipFixedLengthTextEntries
-.copyOT
- ld bc, NAME_LENGTH
- call CopyData
- ld a, [wMoveMonType]
-.findNickDest
- cp PARTY_TO_DAYCARE
- ld de, wDayCareMonName
- jr z, .findNickSrc
- dec a
- ld hl, wPartyMonNicks
- ld a, [wPartyCount]
- jr nz, .addNickOffset
- ld hl, wBoxMonNicks
- ld a, [wNumInBox]
-.addNickOffset
- dec a
- call SkipFixedLengthTextEntries
- ld d, h
- ld e, l
-.findNickSrc
- ld hl, wBoxMonNicks
- ld a, [wMoveMonType]
- and a
- jr z, .addNickOffset2
- ld hl, wDayCareMonName
- cp DAYCARE_TO_PARTY
- jr z, .copyNick
- ld hl, wPartyMonNicks
-.addNickOffset2
- ld a, [wWhichPokemon]
- call SkipFixedLengthTextEntries
-.copyNick
- ld bc, NAME_LENGTH
- call CopyData
- pop hl
- ld a, [wMoveMonType]
- cp PARTY_TO_BOX
- jr z, .done
- cp PARTY_TO_DAYCARE
- jr z, .done
- push hl
- srl a
- add $2
- ld [wMonDataLocation], a
- call LoadMonData
- callba CalcLevelFromExperience
- ld a, d
- ld [wCurEnemyLVL], a
- pop hl
- ld bc, wBoxMon2 - wBoxMon1
- add hl, bc
- ld [hli], a
- ld d, h
- ld e, l
- ld bc, -18
- add hl, bc
- ld b, $1
- call CalcStats
-.done
- and a
- ret
--- a/engine/battle/bank_e_misc.asm
+++ /dev/null
@@ -1,122 +1,0 @@
-; formats a string at wMovesString that lists the moves at wMoves
-FormatMovesString:
- ld hl, wMoves
- ld de, wMovesString
- ld b, $0
-.printMoveNameLoop
- ld a, [hli]
- and a ; end of move list?
- jr z, .printDashLoop ; print dashes when no moves are left
- push hl
- ld [wd0b5], a
- ld a, BANK(MoveNames)
- ld [wPredefBank], a
- ld a, MOVE_NAME
- ld [wNameListType], a
- call GetName
- ld hl, wcd6d
-.copyNameLoop
- ld a, [hli]
- cp $50
- jr z, .doneCopyingName
- ld [de], a
- inc de
- jr .copyNameLoop
-.doneCopyingName
- ld a, b
- ld [wNumMovesMinusOne], a
- inc b
- ld a, $4e ; line break
- ld [de], a
- inc de
- pop hl
- ld a, b
- cp NUM_MOVES
- jr z, .done
- jr .printMoveNameLoop
-.printDashLoop
- ld a, "-"
- ld [de], a
- inc de
- inc b
- ld a, b
- cp NUM_MOVES
- jr z, .done
- ld a, $4e ; line break
- ld [de], a
- inc de
- jr .printDashLoop
-.done
- ld a, "@"
- ld [de], a
- ret
-
-; XXX this is called in a few places, but it doesn't appear to do anything useful
-InitList:
- ld a, [wInitListType]
- cp INIT_ENEMYOT_LIST
- jr nz, .notEnemy
- ld hl, wEnemyPartyCount
- ld de, wEnemyMonOT
- ld a, ENEMYOT_NAME
- jr .done
-.notEnemy
- cp INIT_PLAYEROT_LIST
- jr nz, .notPlayer
- ld hl, wPartyCount
- ld de, wPartyMonOT
- ld a, PLAYEROT_NAME
- jr .done
-.notPlayer
- cp INIT_MON_LIST
- jr nz, .notMonster
- ld hl, wItemList
- ld de, MonsterNames
- ld a, MONSTER_NAME
- jr .done
-.notMonster
- cp INIT_BAG_ITEM_LIST
- jr nz, .notBag
- ld hl, wNumBagItems
- ld de, ItemNames
- ld a, ITEM_NAME
- jr .done
-.notBag
- ld hl, wItemList
- ld de, ItemNames
- ld a, ITEM_NAME
-.done
- ld [wNameListType], a
- ld a, l
- ld [wListPointer], a
- ld a, h
- ld [wListPointer + 1], a
- ld a, e
- ld [wUnusedCF8D], a
- ld a, d
- ld [wUnusedCF8D + 1], a
- ld bc, ItemPrices
- ld a, c
- ld [wItemPrices], a
- ld a, b
- ld [wItemPrices + 1], a
- ret
-
-; get species of mon e in list [wMonDataLocation] for LoadMonData
-GetMonSpecies:
- ld hl, wPartySpecies
- ld a, [wMonDataLocation]
- and a
- jr z, .getSpecies
- dec a
- jr z, .enemyParty
- ld hl, wBoxSpecies
- jr .getSpecies
-.enemyParty
- ld hl, wEnemyPartyMons
-.getSpecies
- ld d, 0
- add hl, de
- ld a, [hl]
- ld [wcf91], a
- ret
--- /dev/null
+++ b/engine/battle/misc.asm
@@ -1,0 +1,122 @@
+; formats a string at wMovesString that lists the moves at wMoves
+FormatMovesString:
+ ld hl, wMoves
+ ld de, wMovesString
+ ld b, $0
+.printMoveNameLoop
+ ld a, [hli]
+ and a ; end of move list?
+ jr z, .printDashLoop ; print dashes when no moves are left
+ push hl
+ ld [wd0b5], a
+ ld a, BANK(MoveNames)
+ ld [wPredefBank], a
+ ld a, MOVE_NAME
+ ld [wNameListType], a
+ call GetName
+ ld hl, wcd6d
+.copyNameLoop
+ ld a, [hli]
+ cp $50
+ jr z, .doneCopyingName
+ ld [de], a
+ inc de
+ jr .copyNameLoop
+.doneCopyingName
+ ld a, b
+ ld [wNumMovesMinusOne], a
+ inc b
+ ld a, $4e ; line break
+ ld [de], a
+ inc de
+ pop hl
+ ld a, b
+ cp NUM_MOVES
+ jr z, .done
+ jr .printMoveNameLoop
+.printDashLoop
+ ld a, "-"
+ ld [de], a
+ inc de
+ inc b
+ ld a, b
+ cp NUM_MOVES
+ jr z, .done
+ ld a, $4e ; line break
+ ld [de], a
+ inc de
+ jr .printDashLoop
+.done
+ ld a, "@"
+ ld [de], a
+ ret
+
+; XXX this is called in a few places, but it doesn't appear to do anything useful
+InitList:
+ ld a, [wInitListType]
+ cp INIT_ENEMYOT_LIST
+ jr nz, .notEnemy
+ ld hl, wEnemyPartyCount
+ ld de, wEnemyMonOT
+ ld a, ENEMYOT_NAME
+ jr .done
+.notEnemy
+ cp INIT_PLAYEROT_LIST
+ jr nz, .notPlayer
+ ld hl, wPartyCount
+ ld de, wPartyMonOT
+ ld a, PLAYEROT_NAME
+ jr .done
+.notPlayer
+ cp INIT_MON_LIST
+ jr nz, .notMonster
+ ld hl, wItemList
+ ld de, MonsterNames
+ ld a, MONSTER_NAME
+ jr .done
+.notMonster
+ cp INIT_BAG_ITEM_LIST
+ jr nz, .notBag
+ ld hl, wNumBagItems
+ ld de, ItemNames
+ ld a, ITEM_NAME
+ jr .done
+.notBag
+ ld hl, wItemList
+ ld de, ItemNames
+ ld a, ITEM_NAME
+.done
+ ld [wNameListType], a
+ ld a, l
+ ld [wListPointer], a
+ ld a, h
+ ld [wListPointer + 1], a
+ ld a, e
+ ld [wUnusedCF8D], a
+ ld a, d
+ ld [wUnusedCF8D + 1], a
+ ld bc, ItemPrices
+ ld a, c
+ ld [wItemPrices], a
+ ld a, b
+ ld [wItemPrices + 1], a
+ ret
+
+; get species of mon e in list [wMonDataLocation] for LoadMonData
+GetMonSpecies:
+ ld hl, wPartySpecies
+ ld a, [wMonDataLocation]
+ and a
+ jr z, .getSpecies
+ dec a
+ jr z, .enemyParty
+ ld hl, wBoxSpecies
+ jr .getSpecies
+.enemyParty
+ ld hl, wEnemyPartyMons
+.getSpecies
+ ld d, 0
+ add hl, de
+ ld a, [hl]
+ ld [wcf91], a
+ ret
--- a/engine/battle/moveEffects/conversion_effect.asm
+++ /dev/null
@@ -1,35 +1,0 @@
-ConversionEffect_:
- ld hl, wEnemyMonType1
- ld de, wBattleMonType1
- ld a, [H_WHOSETURN]
- and a
- ld a, [wEnemyBattleStatus1]
- jr z, .conversionEffect
- push hl
- ld h, d
- ld l, e
- pop de
- ld a, [wPlayerBattleStatus1]
-.conversionEffect
- bit INVULNERABLE, a ; is mon immune to typical attacks (dig/fly)
- jr nz, PrintButItFailedText
-; copy target's types to user
- ld a, [hli]
- ld [de], a
- inc de
- ld a, [hl]
- ld [de], a
- ld hl, PlayCurrentMoveAnimation
- call CallBankF
- ld hl, ConvertedTypeText
- jp PrintText
-
-ConvertedTypeText:
- TX_FAR _ConvertedTypeText
- db "@"
-
-PrintButItFailedText:
- ld hl, PrintButItFailedText_
-CallBankF:
- ld b, BANK(PrintButItFailedText_)
- jp Bankswitch
--- a/engine/battle/moveEffects/drain_hp_effect.asm
+++ /dev/null
@@ -1,104 +1,0 @@
-DrainHPEffect_:
- ld hl, wDamage
- ld a, [hl]
- srl a ; divide damage by 2
- ld [hli], a
- ld a, [hl]
- rr a
- ld [hld], a
- or [hl] ; is damage 0?
- jr nz, .getAttackerHP
-; if damage is 0, increase to 1 so that the attacker gains at least 1 HP
- inc hl
- inc [hl]
-.getAttackerHP
- ld hl, wBattleMonHP
- ld de, wBattleMonMaxHP
- ld a, [H_WHOSETURN]
- and a
- jp z, .addDamageToAttackerHP
- ld hl, wEnemyMonHP
- ld de, wEnemyMonMaxHP
-.addDamageToAttackerHP
- ld bc, wHPBarOldHP+1
-; copy current HP to wHPBarOldHP
- ld a, [hli]
- ld [bc], a
- ld a, [hl]
- dec bc
- ld [bc], a
-; copy max HP to wHPBarMaxHP
- ld a, [de]
- dec bc
- ld [bc], a
- inc de
- ld a, [de]
- dec bc
- ld [bc], a
-; add damage to attacker's HP and copy new HP to wHPBarNewHP
- ld a, [wDamage + 1]
- ld b, [hl]
- add b
- ld [hld], a
- ld [wHPBarNewHP], a
- ld a, [wDamage]
- ld b, [hl]
- adc b
- ld [hli], a
- ld [wHPBarNewHP+1], a
- jr c, .capToMaxHP ; if HP > 65,535, cap to max HP
-; compare HP with max HP
- ld a, [hld]
- ld b, a
- ld a, [de]
- dec de
- sub b
- ld a, [hli]
- ld b, a
- ld a, [de]
- inc de
- sbc b
- jr nc, .next
-.capToMaxHP
- ld a, [de]
- ld [hld], a
- ld [wHPBarNewHP], a
- dec de
- ld a, [de]
- ld [hli], a
- ld [wHPBarNewHP+1], a
- inc de
-.next
- ld a, [H_WHOSETURN]
- and a
- coord hl, 10, 9
- ld a, $1
- jr z, .next2
- coord hl, 2, 2
- xor a
-.next2
- ld [wHPBarType], a
- predef UpdateHPBar2
- predef DrawPlayerHUDAndHPBar
- predef DrawEnemyHUDAndHPBar
- callab ReadPlayerMonCurHPAndStatus
- ld hl, SuckedHealthText
- ld a, [H_WHOSETURN]
- and a
- ld a, [wPlayerMoveEffect]
- jr z, .next3
- ld a, [wEnemyMoveEffect]
-.next3
- cp DREAM_EATER_EFFECT
- jr nz, .printText
- ld hl, DreamWasEatenText
-.printText
- jp PrintText
-
-SuckedHealthText:
- TX_FAR _SuckedHealthText
- db "@"
-
-DreamWasEatenText:
- TX_FAR _DreamWasEatenText
- db "@"
--- a/engine/battle/moveEffects/focus_energy_effect.asm
+++ /dev/null
@@ -1,22 +1,0 @@
-FocusEnergyEffect_:
- ld hl, wPlayerBattleStatus2
- ld a, [H_WHOSETURN]
- and a
- jr z, .notEnemy
- ld hl, wEnemyBattleStatus2
-.notEnemy
- bit GETTING_PUMPED, [hl] ; is mon already using focus energy?
- jr nz, .alreadyUsing
- set GETTING_PUMPED, [hl] ; mon is now using focus energy
- callab PlayCurrentMoveAnimation
- ld hl, GettingPumpedText
- jp PrintText
-.alreadyUsing
- ld c, 50
- call DelayFrames
- jpab PrintButItFailedText_
-
-GettingPumpedText:
- TX_DELAY
- TX_FAR _GettingPumpedText
- db "@"
--- a/engine/battle/moveEffects/haze_effect.asm
+++ /dev/null
@@ -1,81 +1,0 @@
-HazeEffect_:
- ld a, $7
-; store 7 on every stat mod
- ld hl, wPlayerMonAttackMod
- call ResetStatMods
- ld hl, wEnemyMonAttackMod
- call ResetStatMods
-; copy unmodified stats to battle stats
- ld hl, wPlayerMonUnmodifiedAttack
- ld de, wBattleMonAttack
- call ResetStats
- ld hl, wEnemyMonUnmodifiedAttack
- ld de, wEnemyMonAttack
- call ResetStats
-; cure non-volatile status, but only for the target
- ld hl, wEnemyMonStatus
- ld de, wEnemySelectedMove
- ld a, [H_WHOSETURN]
- and a
- jr z, .cureStatuses
- ld hl, wBattleMonStatus
- dec de ; wPlayerSelectedMove
-
-.cureStatuses
- ld a, [hl]
- ld [hl], $0
- and SLP | (1 << FRZ)
- jr z, .cureVolatileStatuses
-; prevent the Pokemon from executing a move if it was asleep or frozen
- ld a, $ff
- ld [de], a
-
-.cureVolatileStatuses
- xor a
- ld [wPlayerDisabledMove], a
- ld [wEnemyDisabledMove], a
- ld hl, wPlayerDisabledMoveNumber
- ld [hli], a
- ld [hl], a
- ld hl, wPlayerBattleStatus1
- call CureVolatileStatuses
- ld hl, wEnemyBattleStatus1
- call CureVolatileStatuses
- ld hl, PlayCurrentMoveAnimation
- call CallBankF
- ld hl, StatusChangesEliminatedText
- jp PrintText
-
-CureVolatileStatuses:
- res CONFUSED, [hl]
- inc hl ; BATTSTATUS2
- ld a, [hl]
- ; clear USING_X_ACCURACY, PROTECTED_BY_MIST, GETTING_PUMPED, and SEEDED statuses
- and $ff ^((1 << USING_X_ACCURACY) | (1 << PROTECTED_BY_MIST) | (1 << GETTING_PUMPED) | (1 << SEEDED))
- ld [hli], a ; BATTSTATUS3
- ld a, [hl]
- and %11110000 | (1 << TRANSFORMED) ; clear Bad Poison, Reflect and Light Screen statuses
- ld [hl], a
- ret
-
-ResetStatMods:
- ld b, $8
-.loop
- ld [hli], a
- dec b
- jr nz, .loop
- ret
-
-ResetStats:
- ld b, $8
-.loop
- ld a, [hli]
- ld [de], a
- inc de
- dec b
- jr nz, .loop
- ret
-
-StatusChangesEliminatedText:
- TX_FAR _StatusChangesEliminatedText
- db "@"
--- a/engine/battle/moveEffects/heal_effect.asm
+++ /dev/null
@@ -1,120 +1,0 @@
-HealEffect_:
- ld a, [H_WHOSETURN]
- and a
- ld de, wBattleMonHP
- ld hl, wBattleMonMaxHP
- ld a, [wPlayerMoveNum]
- jr z, .healEffect
- ld de, wEnemyMonHP
- ld hl, wEnemyMonMaxHP
- ld a, [wEnemyMoveNum]
-.healEffect
- ld b, a
- ld a, [de]
- cp [hl] ; most significant bytes comparison is ignored
- ; causes the move to miss if max HP is 255 or 511 points higher than the current HP
- inc de
- inc hl
- ld a, [de]
- sbc [hl]
- jp z, .failed ; no effect if user's HP is already at its maximum
- ld a, b
- cp REST
- jr nz, .healHP
- push hl
- push de
- push af
- ld c, 50
- call DelayFrames
- ld hl, wBattleMonStatus
- ld a, [H_WHOSETURN]
- and a
- jr z, .restEffect
- ld hl, wEnemyMonStatus
-.restEffect
- ld a, [hl]
- and a
- ld [hl], 2 ; clear status and set number of turns asleep to 2
- ld hl, StartedSleepingEffect ; if mon didn't have an status
- jr z, .printRestText
- ld hl, FellAsleepBecameHealthyText ; if mon had an status
-.printRestText
- call PrintText
- pop af
- pop de
- pop hl
-.healHP
- ld a, [hld]
- ld [wHPBarMaxHP], a
- ld c, a
- ld a, [hl]
- ld [wHPBarMaxHP+1], a
- ld b, a
- jr z, .gotHPAmountToHeal
-; Recover and Softboiled only heal for half the mon's max HP
- srl b
- rr c
-.gotHPAmountToHeal
-; update HP
- ld a, [de]
- ld [wHPBarOldHP], a
- add c
- ld [de], a
- ld [wHPBarNewHP], a
- dec de
- ld a, [de]
- ld [wHPBarOldHP+1], a
- adc b
- ld [de], a
- ld [wHPBarNewHP+1], a
- inc hl
- inc de
- ld a, [de]
- dec de
- sub [hl]
- dec hl
- ld a, [de]
- sbc [hl]
- jr c, .playAnim
-; copy max HP to current HP if an overflow occurred
- ld a, [hli]
- ld [de], a
- ld [wHPBarNewHP+1], a
- inc de
- ld a, [hl]
- ld [de], a
- ld [wHPBarNewHP], a
-.playAnim
- ld hl, PlayCurrentMoveAnimation
- call BankswitchEtoF
- ld a, [H_WHOSETURN]
- and a
- coord hl, 10, 9
- ld a, $1
- jr z, .updateHPBar
- coord hl, 2, 2
- xor a
-.updateHPBar
- ld [wHPBarType], a
- predef UpdateHPBar2
- ld hl, DrawHUDsAndHPBars
- call BankswitchEtoF
- ld hl, RegainedHealthText
- jp PrintText
-.failed
- ld c, 50
- call DelayFrames
- ld hl, PrintButItFailedText_
- jp BankswitchEtoF
-
-StartedSleepingEffect:
- TX_FAR _StartedSleepingEffect
- db "@"
-
-FellAsleepBecameHealthyText:
- TX_FAR _FellAsleepBecameHealthyText
- db "@"
-
-RegainedHealthText:
- TX_FAR _RegainedHealthText
- db "@"
--- a/engine/battle/moveEffects/leech_seed_effect.asm
+++ /dev/null
@@ -1,40 +1,0 @@
-LeechSeedEffect_:
- callab MoveHitTest
- ld a, [wMoveMissed]
- and a
- jr nz, .moveMissed
- ld hl, wEnemyBattleStatus2
- ld de, wEnemyMonType1
- ld a, [H_WHOSETURN]
- and a
- jr z, .leechSeedEffect
- ld hl, wPlayerBattleStatus2
- ld de, wBattleMonType1
-.leechSeedEffect
-; miss if the target is grass-type or already seeded
- ld a, [de]
- cp GRASS
- jr z, .moveMissed
- inc de
- ld a, [de]
- cp GRASS
- jr z, .moveMissed
- bit SEEDED, [hl]
- jr nz, .moveMissed
- set SEEDED, [hl]
- callab PlayCurrentMoveAnimation
- ld hl, WasSeededText
- jp PrintText
-.moveMissed
- ld c, 50
- call DelayFrames
- ld hl, EvadedAttackText
- jp PrintText
-
-WasSeededText:
- TX_FAR _WasSeededText
- db "@"
-
-EvadedAttackText:
- TX_FAR _EvadedAttackText
- db "@"
--- a/engine/battle/moveEffects/mist_effect.asm
+++ /dev/null
@@ -1,19 +1,0 @@
-MistEffect_:
- ld hl, wPlayerBattleStatus2
- ld a, [H_WHOSETURN]
- and a
- jr z, .mistEffect
- ld hl, wEnemyBattleStatus2
-.mistEffect
- bit PROTECTED_BY_MIST, [hl] ; is mon protected by mist?
- jr nz, .mistAlreadyInUse
- set PROTECTED_BY_MIST, [hl] ; mon is now protected by mist
- callab PlayCurrentMoveAnimation
- ld hl, ShroudedInMistText
- jp PrintText
-.mistAlreadyInUse
- jpab PrintButItFailedText_
-
-ShroudedInMistText:
- TX_FAR _ShroudedInMistText
- db "@"
--- a/engine/battle/moveEffects/one_hit_ko_effect.asm
+++ /dev/null
@@ -1,38 +1,0 @@
-OneHitKOEffect_:
- ld hl, wDamage
- xor a
- ld [hli], a
- ld [hl], a ; set the damage output to zero
- dec a
- ld [wCriticalHitOrOHKO], a
- ld hl, wBattleMonSpeed + 1
- ld de, wEnemyMonSpeed + 1
- ld a, [H_WHOSETURN]
- and a
- jr z, .compareSpeed
- ld hl, wEnemyMonSpeed + 1
- ld de, wBattleMonSpeed + 1
-.compareSpeed
-; set damage to 65535 and OHKO flag is the user's current speed is higher than the target's
- ld a, [de]
- dec de
- ld b, a
- ld a, [hld]
- sub b
- ld a, [de]
- ld b, a
- ld a, [hl]
- sbc b
- jr c, .userIsSlower
- ld hl, wDamage
- ld a, $ff
- ld [hli], a
- ld [hl], a
- ld a, $2
- ld [wCriticalHitOrOHKO], a
- ret
-.userIsSlower
-; keep damage at 0 and set move missed flag if target's current speed is higher instead
- ld a, $1
- ld [wMoveMissed], a
- ret
--- a/engine/battle/moveEffects/paralyze_effect.asm
+++ /dev/null
@@ -1,47 +1,0 @@
-ParalyzeEffect_:
- ld hl, wEnemyMonStatus
- ld de, wPlayerMoveType
- ld a, [H_WHOSETURN]
- and a
- jp z, .next
- ld hl, wBattleMonStatus
- ld de, wEnemyMoveType
-.next
- ld a, [hl]
- and a ; does the target already have a status ailment?
- jr nz, .didntAffect
-; check if the target is immune due to types
- ld a, [de]
- cp ELECTRIC
- jr nz, .hitTest
- ld b, h
- ld c, l
- inc bc
- ld a, [bc]
- cp GROUND
- jr z, .doesntAffect
- inc bc
- ld a, [bc]
- cp GROUND
- jr z, .doesntAffect
-.hitTest
- push hl
- callab MoveHitTest
- pop hl
- ld a, [wMoveMissed]
- and a
- jr nz, .didntAffect
- set PAR, [hl]
- callab QuarterSpeedDueToParalysis
- ld c, 30
- call DelayFrames
- callab PlayCurrentMoveAnimation
- jpab PrintMayNotAttackText
-.didntAffect
- ld c, 50
- call DelayFrames
- jpab PrintDidntAffectText
-.doesntAffect
- ld c, 50
- call DelayFrames
- jpab PrintDoesntAffectText
--- a/engine/battle/moveEffects/pay_day_effect.asm
+++ /dev/null
@@ -1,45 +1,0 @@
-PayDayEffect_:
- xor a
- ld hl, wcd6d
- ld [hli], a
- ld a, [H_WHOSETURN]
- and a
- ld a, [wBattleMonLevel]
- jr z, .payDayEffect
- ld a, [wEnemyMonLevel]
-.payDayEffect
-; level * 2
- add a
- ld [H_DIVIDEND + 3], a
- xor a
- ld [H_DIVIDEND], a
- ld [H_DIVIDEND + 1], a
- ld [H_DIVIDEND + 2], a
-; convert to BCD
- ld a, 100
- ld [H_DIVISOR], a
- ld b, $4
- call Divide
- ld a, [H_QUOTIENT + 3]
- ld [hli], a
- ld a, [H_REMAINDER]
- ld [H_DIVIDEND + 3], a
- ld a, 10
- ld [H_DIVISOR], a
- ld b, $4
- call Divide
- ld a, [H_QUOTIENT + 3]
- swap a
- ld b, a
- ld a, [H_REMAINDER]
- add b
- ld [hl], a
- ld de, wTotalPayDayMoney + 2
- ld c, $3
- predef AddBCDPredef
- ld hl, CoinsScatteredText
- jp PrintText
-
-CoinsScatteredText:
- TX_FAR _CoinsScatteredText
- db "@"
--- a/engine/battle/moveEffects/recoil_effect.asm
+++ /dev/null
@@ -1,70 +1,0 @@
-RecoilEffect_:
- ld a, [H_WHOSETURN]
- and a
- ld a, [wPlayerMoveNum]
- ld hl, wBattleMonMaxHP
- jr z, .recoilEffect
- ld a, [wEnemyMoveNum]
- ld hl, wEnemyMonMaxHP
-.recoilEffect
- ld d, a
- ld a, [wDamage]
- ld b, a
- ld a, [wDamage + 1]
- ld c, a
- srl b
- rr c
- ld a, d
- cp STRUGGLE ; struggle deals 50% recoil damage
- jr z, .gotRecoilDamage
- srl b
- rr c
-.gotRecoilDamage
- ld a, b
- or c
- jr nz, .updateHP
- inc c ; minimum recoil damage is 1
-.updateHP
-; subtract HP from user due to the recoil damage
- ld a, [hli]
- ld [wHPBarMaxHP+1], a
- ld a, [hl]
- ld [wHPBarMaxHP], a
- push bc
- ld bc, wBattleMonHP - wBattleMonMaxHP
- add hl, bc
- pop bc
- ld a, [hl]
- ld [wHPBarOldHP], a
- sub c
- ld [hld], a
- ld [wHPBarNewHP], a
- ld a, [hl]
- ld [wHPBarOldHP+1], a
- sbc b
- ld [hl], a
- ld [wHPBarNewHP+1], a
- jr nc, .getHPBarCoords
-; if recoil damage is higher than the Pokemon's HP, set its HP to 0
- xor a
- ld [hli], a
- ld [hl], a
- ld hl, wHPBarNewHP
- ld [hli], a
- ld [hl], a
-.getHPBarCoords
- coord hl, 10, 9
- ld a, [H_WHOSETURN]
- and a
- ld a, $1
- jr z, .updateHPBar
- coord hl, 2, 2
- xor a
-.updateHPBar
- ld [wHPBarType], a
- predef UpdateHPBar2
- ld hl, HitWithRecoilText
- jp PrintText
-HitWithRecoilText:
- TX_FAR _HitWithRecoilText
- db "@"
--- a/engine/battle/moveEffects/reflect_light_screen_effect.asm
+++ /dev/null
@@ -1,45 +1,0 @@
-ReflectLightScreenEffect_:
- ld hl, wPlayerBattleStatus3
- ld de, wPlayerMoveEffect
- ld a, [H_WHOSETURN]
- and a
- jr z, .reflectLightScreenEffect
- ld hl, wEnemyBattleStatus3
- ld de, wEnemyMoveEffect
-.reflectLightScreenEffect
- ld a, [de]
- cp LIGHT_SCREEN_EFFECT
- jr nz, .reflect
- bit HAS_LIGHT_SCREEN_UP, [hl] ; is mon already protected by light screen?
- jr nz, .moveFailed
- set HAS_LIGHT_SCREEN_UP, [hl] ; mon is now protected by light screen
- ld hl, LightScreenProtectedText
- jr .playAnim
-.reflect
- bit HAS_REFLECT_UP, [hl] ; is mon already protected by reflect?
- jr nz, .moveFailed
- set HAS_REFLECT_UP, [hl] ; mon is now protected by reflect
- ld hl, ReflectGainedArmorText
-.playAnim
- push hl
- ld hl, PlayCurrentMoveAnimation
- call BankswitchEtoF
- pop hl
- jp PrintText
-.moveFailed
- ld c, 50
- call DelayFrames
- ld hl, PrintButItFailedText_
- jp BankswitchEtoF
-
-LightScreenProtectedText:
- TX_FAR _LightScreenProtectedText
- db "@"
-
-ReflectGainedArmorText:
- TX_FAR _ReflectGainedArmorText
- db "@"
-
-BankswitchEtoF:
- ld b, BANK(BattleCore)
- jp Bankswitch
--- a/engine/battle/moveEffects/substitute_effect.asm
+++ /dev/null
@@ -1,77 +1,0 @@
-SubstituteEffect_:
- ld c, 50
- call DelayFrames
- ld hl, wBattleMonMaxHP
- ld de, wPlayerSubstituteHP
- ld bc, wPlayerBattleStatus2
- ld a, [H_WHOSETURN]
- and a
- jr z, .notEnemy
- ld hl, wEnemyMonMaxHP
- ld de, wEnemySubstituteHP
- ld bc, wEnemyBattleStatus2
-.notEnemy
- ld a, [bc]
- bit HAS_SUBSTITUTE_UP, a ; user already has substitute?
- jr nz, .alreadyHasSubstitute
-; quarter health to remove from user
-; assumes max HP is 1023 or lower
- push bc
- ld a, [hli]
- ld b, [hl]
- srl a
- rr b
- srl a
- rr b ; max hp / 4
- push de
- ld de, wBattleMonHP - wBattleMonMaxHP
- add hl, de ; point hl to current HP low byte
- pop de
- ld a, b
- ld [de], a ; save copy of HP to subtract in wPlayerSubstituteHP/wEnemySubstituteHP
- ld a, [hld]
-; subtract [max hp / 4] to current HP
- sub b
- ld d, a
- ld a, [hl]
- sbc 0
- pop bc
- jr c, .notEnoughHP ; underflow means user would be left with negative health
- ; bug: since it only branches on carry, it will possibly leave user with 0 HP
-.userHasZeroOrMoreHP
- ldi [hl], a ; save resulting HP after subtraction into current HP
- ld [hl], d
- ld h, b
- ld l, c
- set HAS_SUBSTITUTE_UP, [hl]
- ld a, [wOptions]
- bit 7, a ; battle animation is enabled?
- ld hl, PlayCurrentMoveAnimation
- ld b, BANK(PlayCurrentMoveAnimation)
- jr z, .animationEnabled
- ld hl, AnimationSubstitute
- ld b, BANK(AnimationSubstitute)
-.animationEnabled
- call Bankswitch ; jump to routine depending on animation setting
- ld hl, SubstituteText
- call PrintText
- jpab DrawHUDsAndHPBars
-.alreadyHasSubstitute
- ld hl, HasSubstituteText
- jr .printText
-.notEnoughHP
- ld hl, TooWeakSubstituteText
-.printText
- jp PrintText
-
-SubstituteText:
- TX_FAR _SubstituteText
- db "@"
-
-HasSubstituteText:
- TX_FAR _HasSubstituteText
- db "@"
-
-TooWeakSubstituteText:
- TX_FAR _TooWeakSubstituteText
- db "@"
--- a/engine/battle/moveEffects/transform_effect.asm
+++ /dev/null
@@ -1,148 +1,0 @@
-TransformEffect_:
- ld hl, wBattleMonSpecies
- ld de, wEnemyMonSpecies
- ld bc, wEnemyBattleStatus3
- ld a, [wEnemyBattleStatus1]
- ld a, [H_WHOSETURN]
- and a
- jr nz, .hitTest
- ld hl, wEnemyMonSpecies
- ld de, wBattleMonSpecies
- ld bc, wPlayerBattleStatus3
- ld [wPlayerMoveListIndex], a
- ld a, [wPlayerBattleStatus1]
-.hitTest
- bit INVULNERABLE, a ; is mon invulnerable to typical attacks? (fly/dig)
- jp nz, .failed
- push hl
- push de
- push bc
- ld hl, wPlayerBattleStatus2
- ld a, [H_WHOSETURN]
- and a
- jr z, .transformEffect
- ld hl, wEnemyBattleStatus2
-.transformEffect
-; animation(s) played are different if target has Substitute up
- bit HAS_SUBSTITUTE_UP, [hl]
- push af
- ld hl, HideSubstituteShowMonAnim
- ld b, BANK(HideSubstituteShowMonAnim)
- call nz, Bankswitch
- ld a, [wOptions]
- add a
- ld hl, PlayCurrentMoveAnimation
- ld b, BANK(PlayCurrentMoveAnimation)
- jr nc, .gotAnimToPlay
- ld hl, AnimationTransformMon
- ld b, BANK(AnimationTransformMon)
-.gotAnimToPlay
- call Bankswitch
- ld hl, ReshowSubstituteAnim
- ld b, BANK(ReshowSubstituteAnim)
- pop af
- call nz, Bankswitch
- pop bc
- ld a, [bc]
- set TRANSFORMED, a ; mon is now transformed
- ld [bc], a
- pop de
- pop hl
- push hl
-; transform user into opposing Pokemon
-; species
- ld a, [hl]
- ld [de], a
-; type 1, type 2, catch rate, and moves
- ld bc, $5
- add hl, bc
- inc de
- inc de
- inc de
- inc de
- inc de
- inc bc
- inc bc
- call CopyData
- ld a, [H_WHOSETURN]
- and a
- jr z, .next
-; save enemy mon DVs at wTransformedEnemyMonOriginalDVs
- ld a, [de]
- ld [wTransformedEnemyMonOriginalDVs], a
- inc de
- ld a, [de]
- ld [wTransformedEnemyMonOriginalDVs + 1], a
- dec de
-.next
-; DVs
- ld a, [hli]
- ld [de], a
- inc de
- ld a, [hli]
- ld [de], a
- inc de
-; Attack, Defense, Speed, and Special stats
- inc hl
- inc hl
- inc hl
- inc de
- inc de
- inc de
- ld bc, $8
- call CopyData
- ld bc, wBattleMonMoves - wBattleMonPP
- add hl, bc ; ld hl, wBattleMonMoves
- ld b, NUM_MOVES
-.copyPPLoop
-; 5 PP for all moves
- ld a, [hli]
- and a
- jr z, .lessThanFourMoves
- ld a, $5
- ld [de], a
- inc de
- dec b
- jr nz, .copyPPLoop
- jr .copyStats
-.lessThanFourMoves
-; 0 PP for blank moves
- xor a
- ld [de], a
- inc de
- dec b
- jr nz, .lessThanFourMoves
-.copyStats
-; original (unmodified) stats and stat mods
- pop hl
- ld a, [hl]
- ld [wd11e], a
- call GetMonName
- ld hl, wEnemyMonUnmodifiedAttack
- ld de, wPlayerMonUnmodifiedAttack
- call .copyBasedOnTurn ; original (unmodified) stats
- ld hl, wEnemyMonStatMods
- ld de, wPlayerMonStatMods
- call .copyBasedOnTurn ; stat mods
- ld hl, TransformedText
- jp PrintText
-
-.copyBasedOnTurn
- ld a, [H_WHOSETURN]
- and a
- jr z, .gotStatsOrModsToCopy
- push hl
- ld h, d
- ld l, e
- pop de
-.gotStatsOrModsToCopy
- ld bc, $8
- jp CopyData
-
-.failed
- ld hl, PrintButItFailedText_
- jp BankswitchEtoF
-
-TransformedText:
- TX_FAR _TransformedText
- db "@"
--- /dev/null
+++ b/engine/battle/move_effects/conversion.asm
@@ -1,0 +1,35 @@
+ConversionEffect_:
+ ld hl, wEnemyMonType1
+ ld de, wBattleMonType1
+ ld a, [H_WHOSETURN]
+ and a
+ ld a, [wEnemyBattleStatus1]
+ jr z, .conversionEffect
+ push hl
+ ld h, d
+ ld l, e
+ pop de
+ ld a, [wPlayerBattleStatus1]
+.conversionEffect
+ bit INVULNERABLE, a ; is mon immune to typical attacks (dig/fly)
+ jr nz, PrintButItFailedText
+; copy target's types to user
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hl]
+ ld [de], a
+ ld hl, PlayCurrentMoveAnimation
+ call CallBankF
+ ld hl, ConvertedTypeText
+ jp PrintText
+
+ConvertedTypeText:
+ TX_FAR _ConvertedTypeText
+ db "@"
+
+PrintButItFailedText:
+ ld hl, PrintButItFailedText_
+CallBankF:
+ ld b, BANK(PrintButItFailedText_)
+ jp Bankswitch
--- /dev/null
+++ b/engine/battle/move_effects/drain_hp.asm
@@ -1,0 +1,104 @@
+DrainHPEffect_:
+ ld hl, wDamage
+ ld a, [hl]
+ srl a ; divide damage by 2
+ ld [hli], a
+ ld a, [hl]
+ rr a
+ ld [hld], a
+ or [hl] ; is damage 0?
+ jr nz, .getAttackerHP
+; if damage is 0, increase to 1 so that the attacker gains at least 1 HP
+ inc hl
+ inc [hl]
+.getAttackerHP
+ ld hl, wBattleMonHP
+ ld de, wBattleMonMaxHP
+ ld a, [H_WHOSETURN]
+ and a
+ jp z, .addDamageToAttackerHP
+ ld hl, wEnemyMonHP
+ ld de, wEnemyMonMaxHP
+.addDamageToAttackerHP
+ ld bc, wHPBarOldHP+1
+; copy current HP to wHPBarOldHP
+ ld a, [hli]
+ ld [bc], a
+ ld a, [hl]
+ dec bc
+ ld [bc], a
+; copy max HP to wHPBarMaxHP
+ ld a, [de]
+ dec bc
+ ld [bc], a
+ inc de
+ ld a, [de]
+ dec bc
+ ld [bc], a
+; add damage to attacker's HP and copy new HP to wHPBarNewHP
+ ld a, [wDamage + 1]
+ ld b, [hl]
+ add b
+ ld [hld], a
+ ld [wHPBarNewHP], a
+ ld a, [wDamage]
+ ld b, [hl]
+ adc b
+ ld [hli], a
+ ld [wHPBarNewHP+1], a
+ jr c, .capToMaxHP ; if HP > 65,535, cap to max HP
+; compare HP with max HP
+ ld a, [hld]
+ ld b, a
+ ld a, [de]
+ dec de
+ sub b
+ ld a, [hli]
+ ld b, a
+ ld a, [de]
+ inc de
+ sbc b
+ jr nc, .next
+.capToMaxHP
+ ld a, [de]
+ ld [hld], a
+ ld [wHPBarNewHP], a
+ dec de
+ ld a, [de]
+ ld [hli], a
+ ld [wHPBarNewHP+1], a
+ inc de
+.next
+ ld a, [H_WHOSETURN]
+ and a
+ coord hl, 10, 9
+ ld a, $1
+ jr z, .next2
+ coord hl, 2, 2
+ xor a
+.next2
+ ld [wHPBarType], a
+ predef UpdateHPBar2
+ predef DrawPlayerHUDAndHPBar
+ predef DrawEnemyHUDAndHPBar
+ callab ReadPlayerMonCurHPAndStatus
+ ld hl, SuckedHealthText
+ ld a, [H_WHOSETURN]
+ and a
+ ld a, [wPlayerMoveEffect]
+ jr z, .next3
+ ld a, [wEnemyMoveEffect]
+.next3
+ cp DREAM_EATER_EFFECT
+ jr nz, .printText
+ ld hl, DreamWasEatenText
+.printText
+ jp PrintText
+
+SuckedHealthText:
+ TX_FAR _SuckedHealthText
+ db "@"
+
+DreamWasEatenText:
+ TX_FAR _DreamWasEatenText
+ db "@"
--- /dev/null
+++ b/engine/battle/move_effects/focus_energy.asm
@@ -1,0 +1,22 @@
+FocusEnergyEffect_:
+ ld hl, wPlayerBattleStatus2
+ ld a, [H_WHOSETURN]
+ and a
+ jr z, .notEnemy
+ ld hl, wEnemyBattleStatus2
+.notEnemy
+ bit GETTING_PUMPED, [hl] ; is mon already using focus energy?
+ jr nz, .alreadyUsing
+ set GETTING_PUMPED, [hl] ; mon is now using focus energy
+ callab PlayCurrentMoveAnimation
+ ld hl, GettingPumpedText
+ jp PrintText
+.alreadyUsing
+ ld c, 50
+ call DelayFrames
+ jpab PrintButItFailedText_
+
+GettingPumpedText:
+ TX_DELAY
+ TX_FAR _GettingPumpedText
+ db "@"
--- /dev/null
+++ b/engine/battle/move_effects/haze.asm
@@ -1,0 +1,81 @@
+HazeEffect_:
+ ld a, $7
+; store 7 on every stat mod
+ ld hl, wPlayerMonAttackMod
+ call ResetStatMods
+ ld hl, wEnemyMonAttackMod
+ call ResetStatMods
+; copy unmodified stats to battle stats
+ ld hl, wPlayerMonUnmodifiedAttack
+ ld de, wBattleMonAttack
+ call ResetStats
+ ld hl, wEnemyMonUnmodifiedAttack
+ ld de, wEnemyMonAttack
+ call ResetStats
+; cure non-volatile status, but only for the target
+ ld hl, wEnemyMonStatus
+ ld de, wEnemySelectedMove
+ ld a, [H_WHOSETURN]
+ and a
+ jr z, .cureStatuses
+ ld hl, wBattleMonStatus
+ dec de ; wPlayerSelectedMove
+
+.cureStatuses
+ ld a, [hl]
+ ld [hl], $0
+ and SLP | (1 << FRZ)
+ jr z, .cureVolatileStatuses
+; prevent the Pokemon from executing a move if it was asleep or frozen
+ ld a, $ff
+ ld [de], a
+
+.cureVolatileStatuses
+ xor a
+ ld [wPlayerDisabledMove], a
+ ld [wEnemyDisabledMove], a
+ ld hl, wPlayerDisabledMoveNumber
+ ld [hli], a
+ ld [hl], a
+ ld hl, wPlayerBattleStatus1
+ call CureVolatileStatuses
+ ld hl, wEnemyBattleStatus1
+ call CureVolatileStatuses
+ ld hl, PlayCurrentMoveAnimation
+ call CallBankF
+ ld hl, StatusChangesEliminatedText
+ jp PrintText
+
+CureVolatileStatuses:
+ res CONFUSED, [hl]
+ inc hl ; BATTSTATUS2
+ ld a, [hl]
+ ; clear USING_X_ACCURACY, PROTECTED_BY_MIST, GETTING_PUMPED, and SEEDED statuses
+ and $ff ^((1 << USING_X_ACCURACY) | (1 << PROTECTED_BY_MIST) | (1 << GETTING_PUMPED) | (1 << SEEDED))
+ ld [hli], a ; BATTSTATUS3
+ ld a, [hl]
+ and %11110000 | (1 << TRANSFORMED) ; clear Bad Poison, Reflect and Light Screen statuses
+ ld [hl], a
+ ret
+
+ResetStatMods:
+ ld b, $8
+.loop
+ ld [hli], a
+ dec b
+ jr nz, .loop
+ ret
+
+ResetStats:
+ ld b, $8
+.loop
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec b
+ jr nz, .loop
+ ret
+
+StatusChangesEliminatedText:
+ TX_FAR _StatusChangesEliminatedText
+ db "@"
--- /dev/null
+++ b/engine/battle/move_effects/heal.asm
@@ -1,0 +1,120 @@
+HealEffect_:
+ ld a, [H_WHOSETURN]
+ and a
+ ld de, wBattleMonHP
+ ld hl, wBattleMonMaxHP
+ ld a, [wPlayerMoveNum]
+ jr z, .healEffect
+ ld de, wEnemyMonHP
+ ld hl, wEnemyMonMaxHP
+ ld a, [wEnemyMoveNum]
+.healEffect
+ ld b, a
+ ld a, [de]
+ cp [hl] ; most significant bytes comparison is ignored
+ ; causes the move to miss if max HP is 255 or 511 points higher than the current HP
+ inc de
+ inc hl
+ ld a, [de]
+ sbc [hl]
+ jp z, .failed ; no effect if user's HP is already at its maximum
+ ld a, b
+ cp REST
+ jr nz, .healHP
+ push hl
+ push de
+ push af
+ ld c, 50
+ call DelayFrames
+ ld hl, wBattleMonStatus
+ ld a, [H_WHOSETURN]
+ and a
+ jr z, .restEffect
+ ld hl, wEnemyMonStatus
+.restEffect
+ ld a, [hl]
+ and a
+ ld [hl], 2 ; clear status and set number of turns asleep to 2
+ ld hl, StartedSleepingEffect ; if mon didn't have an status
+ jr z, .printRestText
+ ld hl, FellAsleepBecameHealthyText ; if mon had an status
+.printRestText
+ call PrintText
+ pop af
+ pop de
+ pop hl
+.healHP
+ ld a, [hld]
+ ld [wHPBarMaxHP], a
+ ld c, a
+ ld a, [hl]
+ ld [wHPBarMaxHP+1], a
+ ld b, a
+ jr z, .gotHPAmountToHeal
+; Recover and Softboiled only heal for half the mon's max HP
+ srl b
+ rr c
+.gotHPAmountToHeal
+; update HP
+ ld a, [de]
+ ld [wHPBarOldHP], a
+ add c
+ ld [de], a
+ ld [wHPBarNewHP], a
+ dec de
+ ld a, [de]
+ ld [wHPBarOldHP+1], a
+ adc b
+ ld [de], a
+ ld [wHPBarNewHP+1], a
+ inc hl
+ inc de
+ ld a, [de]
+ dec de
+ sub [hl]
+ dec hl
+ ld a, [de]
+ sbc [hl]
+ jr c, .playAnim
+; copy max HP to current HP if an overflow occurred
+ ld a, [hli]
+ ld [de], a
+ ld [wHPBarNewHP+1], a
+ inc de
+ ld a, [hl]
+ ld [de], a
+ ld [wHPBarNewHP], a
+.playAnim
+ ld hl, PlayCurrentMoveAnimation
+ call BankswitchEtoF
+ ld a, [H_WHOSETURN]
+ and a
+ coord hl, 10, 9
+ ld a, $1
+ jr z, .updateHPBar
+ coord hl, 2, 2
+ xor a
+.updateHPBar
+ ld [wHPBarType], a
+ predef UpdateHPBar2
+ ld hl, DrawHUDsAndHPBars
+ call BankswitchEtoF
+ ld hl, RegainedHealthText
+ jp PrintText
+.failed
+ ld c, 50
+ call DelayFrames
+ ld hl, PrintButItFailedText_
+ jp BankswitchEtoF
+
+StartedSleepingEffect:
+ TX_FAR _StartedSleepingEffect
+ db "@"
+
+FellAsleepBecameHealthyText:
+ TX_FAR _FellAsleepBecameHealthyText
+ db "@"
+
+RegainedHealthText:
+ TX_FAR _RegainedHealthText
+ db "@"
--- /dev/null
+++ b/engine/battle/move_effects/leech_seed.asm
@@ -1,0 +1,40 @@
+LeechSeedEffect_:
+ callab MoveHitTest
+ ld a, [wMoveMissed]
+ and a
+ jr nz, .moveMissed
+ ld hl, wEnemyBattleStatus2
+ ld de, wEnemyMonType1
+ ld a, [H_WHOSETURN]
+ and a
+ jr z, .leechSeedEffect
+ ld hl, wPlayerBattleStatus2
+ ld de, wBattleMonType1
+.leechSeedEffect
+; miss if the target is grass-type or already seeded
+ ld a, [de]
+ cp GRASS
+ jr z, .moveMissed
+ inc de
+ ld a, [de]
+ cp GRASS
+ jr z, .moveMissed
+ bit SEEDED, [hl]
+ jr nz, .moveMissed
+ set SEEDED, [hl]
+ callab PlayCurrentMoveAnimation
+ ld hl, WasSeededText
+ jp PrintText
+.moveMissed
+ ld c, 50
+ call DelayFrames
+ ld hl, EvadedAttackText
+ jp PrintText
+
+WasSeededText:
+ TX_FAR _WasSeededText
+ db "@"
+
+EvadedAttackText:
+ TX_FAR _EvadedAttackText
+ db "@"
--- /dev/null
+++ b/engine/battle/move_effects/mist.asm
@@ -1,0 +1,19 @@
+MistEffect_:
+ ld hl, wPlayerBattleStatus2
+ ld a, [H_WHOSETURN]
+ and a
+ jr z, .mistEffect
+ ld hl, wEnemyBattleStatus2
+.mistEffect
+ bit PROTECTED_BY_MIST, [hl] ; is mon protected by mist?
+ jr nz, .mistAlreadyInUse
+ set PROTECTED_BY_MIST, [hl] ; mon is now protected by mist
+ callab PlayCurrentMoveAnimation
+ ld hl, ShroudedInMistText
+ jp PrintText
+.mistAlreadyInUse
+ jpab PrintButItFailedText_
+
+ShroudedInMistText:
+ TX_FAR _ShroudedInMistText
+ db "@"
--- /dev/null
+++ b/engine/battle/move_effects/one_hit_ko.asm
@@ -1,0 +1,38 @@
+OneHitKOEffect_:
+ ld hl, wDamage
+ xor a
+ ld [hli], a
+ ld [hl], a ; set the damage output to zero
+ dec a
+ ld [wCriticalHitOrOHKO], a
+ ld hl, wBattleMonSpeed + 1
+ ld de, wEnemyMonSpeed + 1
+ ld a, [H_WHOSETURN]
+ and a
+ jr z, .compareSpeed
+ ld hl, wEnemyMonSpeed + 1
+ ld de, wBattleMonSpeed + 1
+.compareSpeed
+; set damage to 65535 and OHKO flag is the user's current speed is higher than the target's
+ ld a, [de]
+ dec de
+ ld b, a
+ ld a, [hld]
+ sub b
+ ld a, [de]
+ ld b, a
+ ld a, [hl]
+ sbc b
+ jr c, .userIsSlower
+ ld hl, wDamage
+ ld a, $ff
+ ld [hli], a
+ ld [hl], a
+ ld a, $2
+ ld [wCriticalHitOrOHKO], a
+ ret
+.userIsSlower
+; keep damage at 0 and set move missed flag if target's current speed is higher instead
+ ld a, $1
+ ld [wMoveMissed], a
+ ret
--- /dev/null
+++ b/engine/battle/move_effects/paralyze.asm
@@ -1,0 +1,47 @@
+ParalyzeEffect_:
+ ld hl, wEnemyMonStatus
+ ld de, wPlayerMoveType
+ ld a, [H_WHOSETURN]
+ and a
+ jp z, .next
+ ld hl, wBattleMonStatus
+ ld de, wEnemyMoveType
+.next
+ ld a, [hl]
+ and a ; does the target already have a status ailment?
+ jr nz, .didntAffect
+; check if the target is immune due to types
+ ld a, [de]
+ cp ELECTRIC
+ jr nz, .hitTest
+ ld b, h
+ ld c, l
+ inc bc
+ ld a, [bc]
+ cp GROUND
+ jr z, .doesntAffect
+ inc bc
+ ld a, [bc]
+ cp GROUND
+ jr z, .doesntAffect
+.hitTest
+ push hl
+ callab MoveHitTest
+ pop hl
+ ld a, [wMoveMissed]
+ and a
+ jr nz, .didntAffect
+ set PAR, [hl]
+ callab QuarterSpeedDueToParalysis
+ ld c, 30
+ call DelayFrames
+ callab PlayCurrentMoveAnimation
+ jpab PrintMayNotAttackText
+.didntAffect
+ ld c, 50
+ call DelayFrames
+ jpab PrintDidntAffectText
+.doesntAffect
+ ld c, 50
+ call DelayFrames
+ jpab PrintDoesntAffectText
--- /dev/null
+++ b/engine/battle/move_effects/pay_day.asm
@@ -1,0 +1,45 @@
+PayDayEffect_:
+ xor a
+ ld hl, wcd6d
+ ld [hli], a
+ ld a, [H_WHOSETURN]
+ and a
+ ld a, [wBattleMonLevel]
+ jr z, .payDayEffect
+ ld a, [wEnemyMonLevel]
+.payDayEffect
+; level * 2
+ add a
+ ld [H_DIVIDEND + 3], a
+ xor a
+ ld [H_DIVIDEND], a
+ ld [H_DIVIDEND + 1], a
+ ld [H_DIVIDEND + 2], a
+; convert to BCD
+ ld a, 100
+ ld [H_DIVISOR], a
+ ld b, $4
+ call Divide
+ ld a, [H_QUOTIENT + 3]
+ ld [hli], a
+ ld a, [H_REMAINDER]
+ ld [H_DIVIDEND + 3], a
+ ld a, 10
+ ld [H_DIVISOR], a
+ ld b, $4
+ call Divide
+ ld a, [H_QUOTIENT + 3]
+ swap a
+ ld b, a
+ ld a, [H_REMAINDER]
+ add b
+ ld [hl], a
+ ld de, wTotalPayDayMoney + 2
+ ld c, $3
+ predef AddBCDPredef
+ ld hl, CoinsScatteredText
+ jp PrintText
+
+CoinsScatteredText:
+ TX_FAR _CoinsScatteredText
+ db "@"
--- /dev/null
+++ b/engine/battle/move_effects/recoil.asm
@@ -1,0 +1,70 @@
+RecoilEffect_:
+ ld a, [H_WHOSETURN]
+ and a
+ ld a, [wPlayerMoveNum]
+ ld hl, wBattleMonMaxHP
+ jr z, .recoilEffect
+ ld a, [wEnemyMoveNum]
+ ld hl, wEnemyMonMaxHP
+.recoilEffect
+ ld d, a
+ ld a, [wDamage]
+ ld b, a
+ ld a, [wDamage + 1]
+ ld c, a
+ srl b
+ rr c
+ ld a, d
+ cp STRUGGLE ; struggle deals 50% recoil damage
+ jr z, .gotRecoilDamage
+ srl b
+ rr c
+.gotRecoilDamage
+ ld a, b
+ or c
+ jr nz, .updateHP
+ inc c ; minimum recoil damage is 1
+.updateHP
+; subtract HP from user due to the recoil damage
+ ld a, [hli]
+ ld [wHPBarMaxHP+1], a
+ ld a, [hl]
+ ld [wHPBarMaxHP], a
+ push bc
+ ld bc, wBattleMonHP - wBattleMonMaxHP
+ add hl, bc
+ pop bc
+ ld a, [hl]
+ ld [wHPBarOldHP], a
+ sub c
+ ld [hld], a
+ ld [wHPBarNewHP], a
+ ld a, [hl]
+ ld [wHPBarOldHP+1], a
+ sbc b
+ ld [hl], a
+ ld [wHPBarNewHP+1], a
+ jr nc, .getHPBarCoords
+; if recoil damage is higher than the Pokemon's HP, set its HP to 0
+ xor a
+ ld [hli], a
+ ld [hl], a
+ ld hl, wHPBarNewHP
+ ld [hli], a
+ ld [hl], a
+.getHPBarCoords
+ coord hl, 10, 9
+ ld a, [H_WHOSETURN]
+ and a
+ ld a, $1
+ jr z, .updateHPBar
+ coord hl, 2, 2
+ xor a
+.updateHPBar
+ ld [wHPBarType], a
+ predef UpdateHPBar2
+ ld hl, HitWithRecoilText
+ jp PrintText
+HitWithRecoilText:
+ TX_FAR _HitWithRecoilText
+ db "@"
--- /dev/null
+++ b/engine/battle/move_effects/reflect_light_screen.asm
@@ -1,0 +1,45 @@
+ReflectLightScreenEffect_:
+ ld hl, wPlayerBattleStatus3
+ ld de, wPlayerMoveEffect
+ ld a, [H_WHOSETURN]
+ and a
+ jr z, .reflectLightScreenEffect
+ ld hl, wEnemyBattleStatus3
+ ld de, wEnemyMoveEffect
+.reflectLightScreenEffect
+ ld a, [de]
+ cp LIGHT_SCREEN_EFFECT
+ jr nz, .reflect
+ bit HAS_LIGHT_SCREEN_UP, [hl] ; is mon already protected by light screen?
+ jr nz, .moveFailed
+ set HAS_LIGHT_SCREEN_UP, [hl] ; mon is now protected by light screen
+ ld hl, LightScreenProtectedText
+ jr .playAnim
+.reflect
+ bit HAS_REFLECT_UP, [hl] ; is mon already protected by reflect?
+ jr nz, .moveFailed
+ set HAS_REFLECT_UP, [hl] ; mon is now protected by reflect
+ ld hl, ReflectGainedArmorText
+.playAnim
+ push hl
+ ld hl, PlayCurrentMoveAnimation
+ call BankswitchEtoF
+ pop hl
+ jp PrintText
+.moveFailed
+ ld c, 50
+ call DelayFrames
+ ld hl, PrintButItFailedText_
+ jp BankswitchEtoF
+
+LightScreenProtectedText:
+ TX_FAR _LightScreenProtectedText
+ db "@"
+
+ReflectGainedArmorText:
+ TX_FAR _ReflectGainedArmorText
+ db "@"
+
+BankswitchEtoF:
+ ld b, BANK(BattleCore)
+ jp Bankswitch
--- /dev/null
+++ b/engine/battle/move_effects/substitute.asm
@@ -1,0 +1,77 @@
+SubstituteEffect_:
+ ld c, 50
+ call DelayFrames
+ ld hl, wBattleMonMaxHP
+ ld de, wPlayerSubstituteHP
+ ld bc, wPlayerBattleStatus2
+ ld a, [H_WHOSETURN]
+ and a
+ jr z, .notEnemy
+ ld hl, wEnemyMonMaxHP
+ ld de, wEnemySubstituteHP
+ ld bc, wEnemyBattleStatus2
+.notEnemy
+ ld a, [bc]
+ bit HAS_SUBSTITUTE_UP, a ; user already has substitute?
+ jr nz, .alreadyHasSubstitute
+; quarter health to remove from user
+; assumes max HP is 1023 or lower
+ push bc
+ ld a, [hli]
+ ld b, [hl]
+ srl a
+ rr b
+ srl a
+ rr b ; max hp / 4
+ push de
+ ld de, wBattleMonHP - wBattleMonMaxHP
+ add hl, de ; point hl to current HP low byte
+ pop de
+ ld a, b
+ ld [de], a ; save copy of HP to subtract in wPlayerSubstituteHP/wEnemySubstituteHP
+ ld a, [hld]
+; subtract [max hp / 4] to current HP
+ sub b
+ ld d, a
+ ld a, [hl]
+ sbc 0
+ pop bc
+ jr c, .notEnoughHP ; underflow means user would be left with negative health
+ ; bug: since it only branches on carry, it will possibly leave user with 0 HP
+.userHasZeroOrMoreHP
+ ldi [hl], a ; save resulting HP after subtraction into current HP
+ ld [hl], d
+ ld h, b
+ ld l, c
+ set HAS_SUBSTITUTE_UP, [hl]
+ ld a, [wOptions]
+ bit 7, a ; battle animation is enabled?
+ ld hl, PlayCurrentMoveAnimation
+ ld b, BANK(PlayCurrentMoveAnimation)
+ jr z, .animationEnabled
+ ld hl, AnimationSubstitute
+ ld b, BANK(AnimationSubstitute)
+.animationEnabled
+ call Bankswitch ; jump to routine depending on animation setting
+ ld hl, SubstituteText
+ call PrintText
+ jpab DrawHUDsAndHPBars
+.alreadyHasSubstitute
+ ld hl, HasSubstituteText
+ jr .printText
+.notEnoughHP
+ ld hl, TooWeakSubstituteText
+.printText
+ jp PrintText
+
+SubstituteText:
+ TX_FAR _SubstituteText
+ db "@"
+
+HasSubstituteText:
+ TX_FAR _HasSubstituteText
+ db "@"
+
+TooWeakSubstituteText:
+ TX_FAR _TooWeakSubstituteText
+ db "@"
--- /dev/null
+++ b/engine/battle/move_effects/transform.asm
@@ -1,0 +1,148 @@
+TransformEffect_:
+ ld hl, wBattleMonSpecies
+ ld de, wEnemyMonSpecies
+ ld bc, wEnemyBattleStatus3
+ ld a, [wEnemyBattleStatus1]
+ ld a, [H_WHOSETURN]
+ and a
+ jr nz, .hitTest
+ ld hl, wEnemyMonSpecies
+ ld de, wBattleMonSpecies
+ ld bc, wPlayerBattleStatus3
+ ld [wPlayerMoveListIndex], a
+ ld a, [wPlayerBattleStatus1]
+.hitTest
+ bit INVULNERABLE, a ; is mon invulnerable to typical attacks? (fly/dig)
+ jp nz, .failed
+ push hl
+ push de
+ push bc
+ ld hl, wPlayerBattleStatus2
+ ld a, [H_WHOSETURN]
+ and a
+ jr z, .transformEffect
+ ld hl, wEnemyBattleStatus2
+.transformEffect
+; animation(s) played are different if target has Substitute up
+ bit HAS_SUBSTITUTE_UP, [hl]
+ push af
+ ld hl, HideSubstituteShowMonAnim
+ ld b, BANK(HideSubstituteShowMonAnim)
+ call nz, Bankswitch
+ ld a, [wOptions]
+ add a
+ ld hl, PlayCurrentMoveAnimation
+ ld b, BANK(PlayCurrentMoveAnimation)
+ jr nc, .gotAnimToPlay
+ ld hl, AnimationTransformMon
+ ld b, BANK(AnimationTransformMon)
+.gotAnimToPlay
+ call Bankswitch
+ ld hl, ReshowSubstituteAnim
+ ld b, BANK(ReshowSubstituteAnim)
+ pop af
+ call nz, Bankswitch
+ pop bc
+ ld a, [bc]
+ set TRANSFORMED, a ; mon is now transformed
+ ld [bc], a
+ pop de
+ pop hl
+ push hl
+; transform user into opposing Pokemon
+; species
+ ld a, [hl]
+ ld [de], a
+; type 1, type 2, catch rate, and moves
+ ld bc, $5
+ add hl, bc
+ inc de
+ inc de
+ inc de
+ inc de
+ inc de
+ inc bc
+ inc bc
+ call CopyData
+ ld a, [H_WHOSETURN]
+ and a
+ jr z, .next
+; save enemy mon DVs at wTransformedEnemyMonOriginalDVs
+ ld a, [de]
+ ld [wTransformedEnemyMonOriginalDVs], a
+ inc de
+ ld a, [de]
+ ld [wTransformedEnemyMonOriginalDVs + 1], a
+ dec de
+.next
+; DVs
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hli]
+ ld [de], a
+ inc de
+; Attack, Defense, Speed, and Special stats
+ inc hl
+ inc hl
+ inc hl
+ inc de
+ inc de
+ inc de
+ ld bc, $8
+ call CopyData
+ ld bc, wBattleMonMoves - wBattleMonPP
+ add hl, bc ; ld hl, wBattleMonMoves
+ ld b, NUM_MOVES
+.copyPPLoop
+; 5 PP for all moves
+ ld a, [hli]
+ and a
+ jr z, .lessThanFourMoves
+ ld a, $5
+ ld [de], a
+ inc de
+ dec b
+ jr nz, .copyPPLoop
+ jr .copyStats
+.lessThanFourMoves
+; 0 PP for blank moves
+ xor a
+ ld [de], a
+ inc de
+ dec b
+ jr nz, .lessThanFourMoves
+.copyStats
+; original (unmodified) stats and stat mods
+ pop hl
+ ld a, [hl]
+ ld [wd11e], a
+ call GetMonName
+ ld hl, wEnemyMonUnmodifiedAttack
+ ld de, wPlayerMonUnmodifiedAttack
+ call .copyBasedOnTurn ; original (unmodified) stats
+ ld hl, wEnemyMonStatMods
+ ld de, wPlayerMonStatMods
+ call .copyBasedOnTurn ; stat mods
+ ld hl, TransformedText
+ jp PrintText
+
+.copyBasedOnTurn
+ ld a, [H_WHOSETURN]
+ and a
+ jr z, .gotStatsOrModsToCopy
+ push hl
+ ld h, d
+ ld l, e
+ pop de
+.gotStatsOrModsToCopy
+ ld bc, $8
+ jp CopyData
+
+.failed
+ ld hl, PrintButItFailedText_
+ jp BankswitchEtoF
+
+TransformedText:
+ TX_FAR _TransformedText
+ db "@"
--- a/engine/battle/trainer_ai.asm
+++ b/engine/battle/trainer_ai.asm
@@ -279,7 +279,7 @@
INCLUDE "text/trainer_names.asm"
-INCLUDE "engine/battle/bank_e_misc.asm"
+INCLUDE "engine/battle/misc.asm"
INCLUDE "engine/battle/read_trainer_party.asm"
--- a/engine/bcd.asm
+++ /dev/null
@@ -1,214 +1,0 @@
-DivideBCDPredef::
-DivideBCDPredef2::
-DivideBCDPredef3::
-DivideBCDPredef4::
- call GetPredefRegisters
-
-DivideBCD::
- xor a
- ld [hDivideBCDBuffer], a
- ld [hDivideBCDBuffer+1], a
- ld [hDivideBCDBuffer+2], a
- ld d, $1
-.mulBy10Loop
-; multiply the divisor by 10 until the leading digit is nonzero
-; to set up the standard long division algorithm
- ld a, [hDivideBCDDivisor]
- and $f0
- jr nz, .next
- inc d
- ld a, [hDivideBCDDivisor]
- swap a
- and $f0
- ld b, a
- ld a, [hDivideBCDDivisor+1]
- swap a
- ld [hDivideBCDDivisor+1], a
- and $f
- or b
- ld [hDivideBCDDivisor], a
- ld a, [hDivideBCDDivisor+1]
- and $f0
- ld b, a
- ld a, [hDivideBCDDivisor+2]
- swap a
- ld [hDivideBCDDivisor+2], a
- and $f
- or b
- ld [hDivideBCDDivisor+1], a
- ld a, [hDivideBCDDivisor+2]
- and $f0
- ld [hDivideBCDDivisor+2], a
- jr .mulBy10Loop
-.next
- push de
- push de
- call DivideBCD_getNextDigit
- pop de
- ld a, b
- swap a
- and $f0
- ld [hDivideBCDBuffer], a
- dec d
- jr z, .next2
- push de
- call DivideBCD_divDivisorBy10
- call DivideBCD_getNextDigit
- pop de
- ld a, [hDivideBCDBuffer]
- or b
- ld [hDivideBCDBuffer], a
- dec d
- jr z, .next2
- push de
- call DivideBCD_divDivisorBy10
- call DivideBCD_getNextDigit
- pop de
- ld a, b
- swap a
- and $f0
- ld [hDivideBCDBuffer+1], a
- dec d
- jr z, .next2
- push de
- call DivideBCD_divDivisorBy10
- call DivideBCD_getNextDigit
- pop de
- ld a, [hDivideBCDBuffer+1]
- or b
- ld [hDivideBCDBuffer+1], a
- dec d
- jr z, .next2
- push de
- call DivideBCD_divDivisorBy10
- call DivideBCD_getNextDigit
- pop de
- ld a, b
- swap a
- and $f0
- ld [hDivideBCDBuffer+2], a
- dec d
- jr z, .next2
- push de
- call DivideBCD_divDivisorBy10
- call DivideBCD_getNextDigit
- pop de
- ld a, [hDivideBCDBuffer+2]
- or b
- ld [hDivideBCDBuffer+2], a
-.next2
- ld a, [hDivideBCDBuffer]
- ld [hDivideBCDQuotient], a ; the same memory location as hDivideBCDDivisor
- ld a, [hDivideBCDBuffer+1]
- ld [hDivideBCDQuotient+1], a
- ld a, [hDivideBCDBuffer+2]
- ld [hDivideBCDQuotient+2], a
- pop de
- ld a, $6
- sub d
- and a
- ret z
-.divResultBy10loop
- push af
- call DivideBCD_divDivisorBy10
- pop af
- dec a
- jr nz, .divResultBy10loop
- ret
-
-DivideBCD_divDivisorBy10:
- ld a, [hDivideBCDDivisor+2]
- swap a
- and $f
- ld b, a
- ld a, [hDivideBCDDivisor+1]
- swap a
- ld [hDivideBCDDivisor+1], a
- and $f0
- or b
- ld [hDivideBCDDivisor+2], a
- ld a, [hDivideBCDDivisor+1]
- and $f
- ld b, a
- ld a, [hDivideBCDDivisor]
- swap a
- ld [hDivideBCDDivisor], a
- and $f0
- or b
- ld [hDivideBCDDivisor+1], a
- ld a, [hDivideBCDDivisor]
- and $f
- ld [hDivideBCDDivisor], a
- ret
-
-DivideBCD_getNextDigit:
- ld bc, $3
-.loop
- ld de, hMoney ; the dividend
- ld hl, hDivideBCDDivisor
- push bc
- call StringCmp
- pop bc
- ret c
- inc b
- ld de, hMoney+2 ; since SubBCD works starting from the least significant digit
- ld hl, hDivideBCDDivisor+2
- push bc
- call SubBCD
- pop bc
- jr .loop
-
-
-AddBCDPredef::
- call GetPredefRegisters
-
-AddBCD::
- and a
- ld b, c
-.add
- ld a, [de]
- adc [hl]
- daa
- ld [de], a
- dec de
- dec hl
- dec c
- jr nz, .add
- jr nc, .done
- ld a, $99
- inc de
-.fill
- ld [de], a
- inc de
- dec b
- jr nz, .fill
-.done
- ret
-
-
-SubBCDPredef::
- call GetPredefRegisters
-
-SubBCD::
- and a
- ld b, c
-.sub
- ld a, [de]
- sbc [hl]
- daa
- ld [de], a
- dec de
- dec hl
- dec c
- jr nz, .sub
- jr nc, .done
- ld a, $00
- inc de
-.fill
- ld [de], a
- inc de
- dec b
- jr nz, .fill
- scf
-.done
- ret
--- a/engine/black_out.asm
+++ /dev/null
@@ -1,46 +1,0 @@
-ResetStatusAndHalveMoneyOnBlackout::
-; Reset player status on blackout.
- xor a
- ld [wBattleResult], a
- ld [wWalkBikeSurfState], a
- ld [wIsInBattle], a
- ld [wMapPalOffset], a
- ld [wNPCMovementScriptFunctionNum], a
- ld [hJoyHeld], a
- ld [wNPCMovementScriptPointerTableNum], a
- ld [wFlags_0xcd60], a
-
- ld [hMoney], a
- ld [hMoney + 1], a
- ld [hMoney + 2], a
- call HasEnoughMoney
- jr c, .lostmoney ; never happens
-
- ; Halve the player's money.
- ld a, [wPlayerMoney]
- ld [hMoney], a
- ld a, [wPlayerMoney + 1]
- ld [hMoney + 1], a
- ld a, [wPlayerMoney + 2]
- ld [hMoney + 2], a
- xor a
- ld [hDivideBCDDivisor], a
- ld [hDivideBCDDivisor + 1], a
- ld a, 2
- ld [hDivideBCDDivisor + 2], a
- predef DivideBCDPredef3
- ld a, [hDivideBCDQuotient]
- ld [wPlayerMoney], a
- ld a, [hDivideBCDQuotient + 1]
- ld [wPlayerMoney + 1], a
- ld a, [hDivideBCDQuotient + 2]
- ld [wPlayerMoney + 2], a
-
-.lostmoney
- ld hl, wd732
- set 2, [hl]
- res 3, [hl]
- set 6, [hl]
- ld a, %11111111
- ld [wJoyIgnore], a
- predef_jump HealParty
--- a/engine/cable_club.asm
+++ /dev/null
@@ -1,977 +1,0 @@
-; performs the appropriate action when the player uses the gameboy on the table in the Colosseum or Trade Center
-; In the Colosseum, it starts a battle. In the Trade Center, it displays the trade selection screen.
-; Before doing either action, it swaps random numbers, trainer names and party data with the other gameboy.
-CableClub_DoBattleOrTrade:
- ld c, 80
- call DelayFrames
- call ClearScreen
- call UpdateSprites
- call LoadFontTilePatterns
- call LoadHpBarAndStatusTilePatterns
- call LoadTrainerInfoTextBoxTiles
- coord hl, 3, 8
- ld b, 2
- ld c, 12
- call CableClub_TextBoxBorder
- coord hl, 4, 10
- ld de, PleaseWaitString
- call PlaceString
- ld hl, wPlayerNumHits
- xor a
- ld [hli], a
- ld [hl], $50
- ; fall through
-
-; This is called after completing a trade.
-CableClub_DoBattleOrTradeAgain:
- ld hl, wSerialPlayerDataBlock
- ld a, SERIAL_PREAMBLE_BYTE
- ld b, 6
-.writePlayerDataBlockPreambleLoop
- ld [hli], a
- dec b
- jr nz, .writePlayerDataBlockPreambleLoop
- ld hl, wSerialRandomNumberListBlock
- ld a, SERIAL_PREAMBLE_BYTE
- ld b, 7
-.writeRandomNumberListPreambleLoop
- ld [hli], a
- dec b
- jr nz, .writeRandomNumberListPreambleLoop
- ld b, 10
-.generateRandomNumberListLoop
- call Random
- cp SERIAL_PREAMBLE_BYTE ; all the random numbers have to be less than the preamble byte
- jr nc, .generateRandomNumberListLoop
- ld [hli], a
- dec b
- jr nz, .generateRandomNumberListLoop
- ld hl, wSerialPartyMonsPatchList
- ld a, SERIAL_PREAMBLE_BYTE
- ld [hli], a
- ld [hli], a
- ld [hli], a
- ld b, $c8
- xor a
-.zeroPlayerDataPatchListLoop
- ld [hli], a
- dec b
- jr nz, .zeroPlayerDataPatchListLoop
- ld hl, wGrassRate
- ld bc, wTrainerHeaderPtr - wGrassRate
-.zeroEnemyPartyLoop
- xor a
- ld [hli], a
- dec bc
- ld a, b
- or c
- jr nz, .zeroEnemyPartyLoop
- ld hl, wPartyMons - 1
- ld de, wSerialPartyMonsPatchList + 10
- ld bc, 0
-.patchPartyMonsLoop
- inc c
- ld a, c
- cp SERIAL_PREAMBLE_BYTE
- jr z, .startPatchListPart2
- ld a, b
- dec a ; are we in part 2 of the patch list?
- jr nz, .checkPlayerDataByte ; jump if in part 1
-; if we're in part 2
- ld a, c
- cp (wPartyMonOT - (wPartyMons - 1)) - (SERIAL_PREAMBLE_BYTE - 1)
- jr z, .finishedPatchingPlayerData
-.checkPlayerDataByte
- inc hl
- ld a, [hl]
- cp SERIAL_NO_DATA_BYTE
- jr nz, .patchPartyMonsLoop
-; if the player data byte matches SERIAL_NO_DATA_BYTE, patch it with $FF and record the offset in the patch list
- ld a, c
- ld [de], a
- inc de
- ld [hl], $ff
- jr .patchPartyMonsLoop
-.startPatchListPart2
- ld a, SERIAL_PATCH_LIST_PART_TERMINATOR
- ld [de], a ; end of part 1
- inc de
- lb bc, 1, 0
- jr .patchPartyMonsLoop
-.finishedPatchingPlayerData
- ld a, SERIAL_PATCH_LIST_PART_TERMINATOR
- ld [de], a ; end of part 2
- call Serial_SyncAndExchangeNybble
- ld a, [hSerialConnectionStatus]
- cp USING_INTERNAL_CLOCK
- jr nz, .skipSendingTwoZeroBytes
-; if using internal clock
-; send two zero bytes for syncing purposes?
- call Delay3
- xor a
- ld [hSerialSendData], a
- ld a, START_TRANSFER_INTERNAL_CLOCK
- ld [rSC], a
- call DelayFrame
- xor a
- ld [hSerialSendData], a
- ld a, START_TRANSFER_INTERNAL_CLOCK
- ld [rSC], a
-.skipSendingTwoZeroBytes
- call Delay3
- ld a, (1 << SERIAL)
- ld [rIE], a
- ld hl, wSerialRandomNumberListBlock
- ld de, wSerialOtherGameboyRandomNumberListBlock
- ld bc, $11
- call Serial_ExchangeBytes
- ld a, SERIAL_NO_DATA_BYTE
- ld [de], a
- ld hl, wSerialPlayerDataBlock
- ld de, wSerialEnemyDataBlock
- ld bc, $1a8
- call Serial_ExchangeBytes
- ld a, SERIAL_NO_DATA_BYTE
- ld [de], a
- ld hl, wSerialPartyMonsPatchList
- ld de, wSerialEnemyMonsPatchList
- ld bc, $c8
- call Serial_ExchangeBytes
- ld a, (1 << SERIAL) | (1 << TIMER) | (1 << VBLANK)
- ld [rIE], a
- ld a, $ff
- call PlaySound
- ld a, [hSerialConnectionStatus]
- cp USING_INTERNAL_CLOCK
- jr z, .skipCopyingRandomNumberList ; the list generated by the gameboy clocking the connection is used by both gameboys
- ld hl, wSerialOtherGameboyRandomNumberListBlock
-.findStartOfRandomNumberListLoop
- ld a, [hli]
- and a
- jr z, .findStartOfRandomNumberListLoop
- cp SERIAL_PREAMBLE_BYTE
- jr z, .findStartOfRandomNumberListLoop
- cp SERIAL_NO_DATA_BYTE
- jr z, .findStartOfRandomNumberListLoop
- dec hl
- ld de, wLinkBattleRandomNumberList
- ld c, 10
-.copyRandomNumberListLoop
- ld a, [hli]
- cp SERIAL_NO_DATA_BYTE
- jr z, .copyRandomNumberListLoop
- ld [de], a
- inc de
- dec c
- jr nz, .copyRandomNumberListLoop
-.skipCopyingRandomNumberList
- ld hl, wSerialEnemyDataBlock + 3
-.findStartOfEnemyNameLoop
- ld a, [hli]
- and a
- jr z, .findStartOfEnemyNameLoop
- cp SERIAL_PREAMBLE_BYTE
- jr z, .findStartOfEnemyNameLoop
- cp SERIAL_NO_DATA_BYTE
- jr z, .findStartOfEnemyNameLoop
- dec hl
- ld de, wLinkEnemyTrainerName
- ld c, NAME_LENGTH
-.copyEnemyNameLoop
- ld a, [hli]
- cp SERIAL_NO_DATA_BYTE
- jr z, .copyEnemyNameLoop
- ld [de], a
- inc de
- dec c
- jr nz, .copyEnemyNameLoop
- ld de, wEnemyPartyCount
- ld bc, wTrainerHeaderPtr - wEnemyPartyCount
-.copyEnemyPartyLoop
- ld a, [hli]
- cp SERIAL_NO_DATA_BYTE
- jr z, .copyEnemyPartyLoop
- ld [de], a
- inc de
- dec bc
- ld a, b
- or c
- jr nz, .copyEnemyPartyLoop
- ld de, wSerialPartyMonsPatchList
- ld hl, wPartyMons
- ld c, 2 ; patch list has 2 parts
-.unpatchPartyMonsLoop
- ld a, [de]
- inc de
- and a
- jr z, .unpatchPartyMonsLoop
- cp SERIAL_PREAMBLE_BYTE
- jr z, .unpatchPartyMonsLoop
- cp SERIAL_NO_DATA_BYTE
- jr z, .unpatchPartyMonsLoop
- cp SERIAL_PATCH_LIST_PART_TERMINATOR
- jr z, .finishedPartyMonsPatchListPart
- push hl
- push bc
- ld b, 0
- dec a
- ld c, a
- add hl, bc
- ld a, SERIAL_NO_DATA_BYTE
- ld [hl], a
- pop bc
- pop hl
- jr .unpatchPartyMonsLoop
-.finishedPartyMonsPatchListPart
- ld hl, wPartyMons + (SERIAL_PREAMBLE_BYTE - 1)
- dec c ; is there another part?
- jr nz, .unpatchPartyMonsLoop
- ld de, wSerialEnemyMonsPatchList
- ld hl, wEnemyMons
- ld c, 2 ; patch list has 2 parts
-.unpatchEnemyMonsLoop
- ld a, [de]
- inc de
- and a
- jr z, .unpatchEnemyMonsLoop
- cp SERIAL_PREAMBLE_BYTE
- jr z, .unpatchEnemyMonsLoop
- cp SERIAL_NO_DATA_BYTE
- jr z, .unpatchEnemyMonsLoop
- cp SERIAL_PATCH_LIST_PART_TERMINATOR
- jr z, .finishedEnemyMonsPatchListPart
- push hl
- push bc
- ld b, 0
- dec a
- ld c, a
- add hl, bc
- ld a, SERIAL_NO_DATA_BYTE
- ld [hl], a
- pop bc
- pop hl
- jr .unpatchEnemyMonsLoop
-.finishedEnemyMonsPatchListPart
- ld hl, wEnemyMons + (SERIAL_PREAMBLE_BYTE - 1)
- dec c
- jr nz, .unpatchEnemyMonsLoop
- ld a, wEnemyMonOT % $100
- ld [wUnusedCF8D], a
- ld a, wEnemyMonOT / $100
- ld [wUnusedCF8D + 1], a
- xor a
- ld [wTradeCenterPointerTableIndex], a
- ld a, $ff
- call PlaySound
- ld a, [hSerialConnectionStatus]
- cp USING_INTERNAL_CLOCK
- ld c, 66
- call z, DelayFrames ; delay if using internal clock
- ld a, [wLinkState]
- cp LINK_STATE_START_BATTLE
- ld a, LINK_STATE_TRADING
- ld [wLinkState], a
- jr nz, .trading
- ld a, LINK_STATE_BATTLING
- ld [wLinkState], a
- ld a, OPP_SONY1
- ld [wCurOpponent], a
- call ClearScreen
- call Delay3
- ld hl, wOptions
- res 7, [hl]
- predef InitOpponent
- predef HealParty
- jp ReturnToCableClubRoom
-.trading
- ld c, BANK(Music_GameCorner)
- ld a, MUSIC_GAME_CORNER
- call PlayMusic
- jr CallCurrentTradeCenterFunction
-
-PleaseWaitString:
- db "PLEASE WAIT!@"
-
-CallCurrentTradeCenterFunction:
- ld hl, TradeCenterPointerTable
- ld b, 0
- ld a, [wTradeCenterPointerTableIndex]
- cp $ff
- jp z, DisplayTitleScreen
- add a
- ld c, a
- add hl, bc
- ld a, [hli]
- ld h, [hl]
- ld l, a
- jp hl
-
-TradeCenter_SelectMon:
- call ClearScreen
- call LoadTrainerInfoTextBoxTiles
- call TradeCenter_DrawPartyLists
- call TradeCenter_DrawCancelBox
- xor a
- ld hl, wSerialSyncAndExchangeNybbleReceiveData
- ld [hli], a
- ld [hli], a
- ld [hli], a
- ld [hl], a
- ld [wMenuWatchMovingOutOfBounds], a
- ld [wCurrentMenuItem], a
- ld [wLastMenuItem], a
- ld [wMenuJoypadPollCount], a
- inc a
- ld [wSerialExchangeNybbleSendData], a
- jp .playerMonMenu
-.enemyMonMenu
- xor a
- ld [wMenuWatchMovingOutOfBounds], a
- inc a
- ld [wWhichTradeMonSelectionMenu], a
- ld a, D_DOWN | D_LEFT | A_BUTTON
- ld [wMenuWatchedKeys], a
- ld a, [wEnemyPartyCount]
- ld [wMaxMenuItem], a
- ld a, 9
- ld [wTopMenuItemY], a
- ld a, 1
- ld [wTopMenuItemX], a
-.enemyMonMenu_HandleInput
- ld hl, hFlags_0xFFF6
- set 1, [hl]
- call HandleMenuInput
- ld hl, hFlags_0xFFF6
- res 1, [hl]
- and a
- jp z, .getNewInput
- bit 0, a ; A button pressed?
- jr z, .enemyMonMenu_ANotPressed
-; if A button pressed
- ld a, [wMaxMenuItem]
- ld c, a
- ld a, [wCurrentMenuItem]
- cp c
- jr c, .displayEnemyMonStats
- ld a, [wMaxMenuItem]
- dec a
- ld [wCurrentMenuItem], a
-.displayEnemyMonStats
- ld a, INIT_ENEMYOT_LIST
- ld [wInitListType], a
- callab InitList ; the list isn't used
- ld hl, wEnemyMons
- call TradeCenter_DisplayStats
- jp .getNewInput
-.enemyMonMenu_ANotPressed
- bit 5, a ; Left pressed?
- jr z, .enemyMonMenu_LeftNotPressed
-; if Left pressed, switch back to the player mon menu
- xor a ; player mon menu
- ld [wWhichTradeMonSelectionMenu], a
- ld a, [wMenuCursorLocation]
- ld l, a
- ld a, [wMenuCursorLocation + 1]
- ld h, a
- ld a, [wTileBehindCursor]
- ld [hl], a
- ld a, [wCurrentMenuItem]
- ld b, a
- ld a, [wPartyCount]
- dec a
- cp b
- jr nc, .playerMonMenu
- ld [wCurrentMenuItem], a
- jr .playerMonMenu
-.enemyMonMenu_LeftNotPressed
- bit 7, a ; Down pressed?
- jp z, .getNewInput
- jp .selectedCancelMenuItem ; jump if Down pressed
-.playerMonMenu
- xor a ; player mon menu
- ld [wWhichTradeMonSelectionMenu], a
- ld [wMenuWatchMovingOutOfBounds], a
- ld a, D_DOWN | D_RIGHT | A_BUTTON
- ld [wMenuWatchedKeys], a
- ld a, [wPartyCount]
- ld [wMaxMenuItem], a
- ld a, 1
- ld [wTopMenuItemY], a
- ld a, 1
- ld [wTopMenuItemX], a
- coord hl, 1, 1
- lb bc, 6, 1
- call ClearScreenArea
-.playerMonMenu_HandleInput
- ld hl, hFlags_0xFFF6
- set 1, [hl]
- call HandleMenuInput
- ld hl, hFlags_0xFFF6
- res 1, [hl]
- and a ; was anything pressed?
- jr nz, .playerMonMenu_SomethingPressed
- jp .getNewInput
-.playerMonMenu_SomethingPressed
- bit 0, a ; A button pressed?
- jr z, .playerMonMenu_ANotPressed
- jp .chosePlayerMon ; jump if A button pressed
-; unreachable code
- ld a, INIT_PLAYEROT_LIST
- ld [wInitListType], a
- callab InitList ; the list isn't used
- call TradeCenter_DisplayStats
- jp .getNewInput
-.playerMonMenu_ANotPressed
- bit 4, a ; Right pressed?
- jr z, .playerMonMenu_RightNotPressed
-; if Right pressed, switch to the enemy mon menu
- ld a, $1 ; enemy mon menu
- ld [wWhichTradeMonSelectionMenu], a
- ld a, [wMenuCursorLocation]
- ld l, a
- ld a, [wMenuCursorLocation + 1]
- ld h, a
- ld a, [wTileBehindCursor]
- ld [hl], a
- ld a, [wCurrentMenuItem]
- ld b, a
- ld a, [wEnemyPartyCount]
- dec a
- cp b
- jr nc, .notPastLastEnemyMon
-; when switching to the enemy mon menu, if the menu selection would be past the last enemy mon, select the last enemy mon
- ld [wCurrentMenuItem], a
-.notPastLastEnemyMon
- jp .enemyMonMenu
-.playerMonMenu_RightNotPressed
- bit 7, a ; Down pressed?
- jr z, .getNewInput
- jp .selectedCancelMenuItem ; jump if Down pressed
-.getNewInput
- ld a, [wWhichTradeMonSelectionMenu]
- and a
- jp z, .playerMonMenu_HandleInput
- jp .enemyMonMenu_HandleInput
-.chosePlayerMon
- call SaveScreenTilesToBuffer1
- call PlaceUnfilledArrowMenuCursor
- ld a, [wMaxMenuItem]
- ld c, a
- ld a, [wCurrentMenuItem]
- cp c
- jr c, .displayStatsTradeMenu
- ld a, [wMaxMenuItem]
- dec a
-.displayStatsTradeMenu
- push af
- coord hl, 0, 14
- ld b, 2
- ld c, 18
- call CableClub_TextBoxBorder
- coord hl, 2, 16
- ld de, .statsTrade
- call PlaceString
- xor a
- ld [wCurrentMenuItem], a
- ld [wLastMenuItem], a
- ld [wMenuJoypadPollCount], a
- ld [wMaxMenuItem], a
- ld a, 16
- ld [wTopMenuItemY], a
-.selectStatsMenuItem
- ld a, " "
- Coorda 11, 16
- ld a, D_RIGHT | B_BUTTON | A_BUTTON
- ld [wMenuWatchedKeys], a
- ld a, 1
- ld [wTopMenuItemX], a
- call HandleMenuInput
- bit 4, a ; Right pressed?
- jr nz, .selectTradeMenuItem
- bit 1, a ; B button pressed?
- jr z, .displayPlayerMonStats
-.cancelPlayerMonChoice
- pop af
- ld [wCurrentMenuItem], a
- call LoadScreenTilesFromBuffer1
- jp .playerMonMenu
-.selectTradeMenuItem
- ld a, " "
- Coorda 1, 16
- ld a, D_LEFT | B_BUTTON | A_BUTTON
- ld [wMenuWatchedKeys], a
- ld a, 11
- ld [wTopMenuItemX], a
- call HandleMenuInput
- bit 5, a ; Left pressed?
- jr nz, .selectStatsMenuItem
- bit 1, a ; B button pressed?
- jr nz, .cancelPlayerMonChoice
- jr .choseTrade
-.displayPlayerMonStats
- pop af
- ld [wCurrentMenuItem], a
- ld a, INIT_PLAYEROT_LIST
- ld [wInitListType], a
- callab InitList ; the list isn't used
- call TradeCenter_DisplayStats
- call LoadScreenTilesFromBuffer1
- jp .playerMonMenu
-.choseTrade
- call PlaceUnfilledArrowMenuCursor
- pop af
- ld [wCurrentMenuItem], a
- ld [wTradingWhichPlayerMon], a
- ld [wSerialExchangeNybbleSendData], a
- call Serial_PrintWaitingTextAndSyncAndExchangeNybble
- ld a, [wSerialSyncAndExchangeNybbleReceiveData]
- cp $f
- jp z, CallCurrentTradeCenterFunction ; go back to the beginning of the trade selection menu if the other person cancelled
- ld [wTradingWhichEnemyMon], a
- call TradeCenter_PlaceSelectedEnemyMonMenuCursor
- ld a, $1 ; TradeCenter_Trade
- ld [wTradeCenterPointerTableIndex], a
- jp CallCurrentTradeCenterFunction
-.statsTrade
- db "STATS TRADE@"
-.selectedCancelMenuItem
- ld a, [wCurrentMenuItem]
- ld b, a
- ld a, [wMaxMenuItem]
- cp b
- jp nz, .getNewInput
- ld a, [wMenuCursorLocation]
- ld l, a
- ld a, [wMenuCursorLocation + 1]
- ld h, a
- ld a, " "
- ld [hl], a
-.cancelMenuItem_Loop
- ld a, "▶" ; filled arrow cursor
- Coorda 1, 16
-.cancelMenuItem_JoypadLoop
- call JoypadLowSensitivity
- ld a, [hJoy5]
- and a ; pressed anything?
- jr z, .cancelMenuItem_JoypadLoop
- bit 0, a ; A button pressed?
- jr nz, .cancelMenuItem_APressed
- bit 6, a ; Up pressed?
- jr z, .cancelMenuItem_JoypadLoop
-; if Up pressed
- ld a, " "
- Coorda 1, 16
- ld a, [wPartyCount]
- dec a
- ld [wCurrentMenuItem], a
- jp .playerMonMenu
-.cancelMenuItem_APressed
- ld a, "▷" ; unfilled arrow cursor
- Coorda 1, 16
- ld a, $f
- ld [wSerialExchangeNybbleSendData], a
- call Serial_PrintWaitingTextAndSyncAndExchangeNybble
- ld a, [wSerialSyncAndExchangeNybbleReceiveData]
- cp $f ; did the other person choose Cancel too?
- jr nz, .cancelMenuItem_Loop
- ; fall through
-
-ReturnToCableClubRoom:
- call GBPalWhiteOutWithDelay3
- ld hl, wFontLoaded
- ld a, [hl]
- push af
- push hl
- res 0, [hl]
- xor a
- ld [wd72d], a
- dec a
- ld [wDestinationWarpID], a
- call LoadMapData
- callba ClearVariablesOnEnterMap
- pop hl
- pop af
- ld [hl], a
- call GBFadeInFromWhite
- ret
-
-TradeCenter_DrawCancelBox:
- coord hl, 11, 15
- ld a, $7e
- ld bc, 2 * SCREEN_WIDTH + 9
- call FillMemory
- coord hl, 0, 15
- ld b, 1
- ld c, 9
- call CableClub_TextBoxBorder
- coord hl, 2, 16
- ld de, CancelTextString
- jp PlaceString
-
-CancelTextString:
- db "CANCEL@"
-
-TradeCenter_PlaceSelectedEnemyMonMenuCursor:
- ld a, [wSerialSyncAndExchangeNybbleReceiveData]
- coord hl, 1, 9
- ld bc, SCREEN_WIDTH
- call AddNTimes
- ld [hl], "▷" ; cursor
- ret
-
-TradeCenter_DisplayStats:
- ld a, [wCurrentMenuItem]
- ld [wWhichPokemon], a
- predef StatusScreen
- predef StatusScreen2
- call GBPalNormal
- call LoadTrainerInfoTextBoxTiles
- call TradeCenter_DrawPartyLists
- jp TradeCenter_DrawCancelBox
-
-TradeCenter_DrawPartyLists:
- coord hl, 0, 0
- ld b, 6
- ld c, 18
- call CableClub_TextBoxBorder
- coord hl, 0, 8
- ld b, 6
- ld c, 18
- call CableClub_TextBoxBorder
- coord hl, 5, 0
- ld de, wPlayerName
- call PlaceString
- coord hl, 5, 8
- ld de, wLinkEnemyTrainerName
- call PlaceString
- coord hl, 2, 1
- ld de, wPartySpecies
- call TradeCenter_PrintPartyListNames
- coord hl, 2, 9
- ld de, wEnemyPartyMons
- ; fall through
-
-TradeCenter_PrintPartyListNames:
- ld c, $0
-.loop
- ld a, [de]
- cp $ff
- ret z
- ld [wd11e], a
- push bc
- push hl
- push de
- push hl
- ld a, c
- ld [$ff95], a
- call GetMonName
- pop hl
- call PlaceString
- pop de
- inc de
- pop hl
- ld bc, 20
- add hl, bc
- pop bc
- inc c
- jr .loop
-
-TradeCenter_Trade:
- ld c, 100
- call DelayFrames
- xor a
- ld [wSerialExchangeNybbleSendData + 1], a ; unnecessary
- ld [wSerialExchangeNybbleReceiveData], a
- ld [wMenuWatchMovingOutOfBounds], a
- ld [wMenuJoypadPollCount], a
- coord hl, 0, 12
- ld b, 4
- ld c, 18
- call CableClub_TextBoxBorder
- ld a, [wTradingWhichPlayerMon]
- ld hl, wPartySpecies
- ld c, a
- ld b, 0
- add hl, bc
- ld a, [hl]
- ld [wd11e], a
- call GetMonName
- ld hl, wcd6d
- ld de, wNameOfPlayerMonToBeTraded
- ld bc, NAME_LENGTH
- call CopyData
- ld a, [wTradingWhichEnemyMon]
- ld hl, wEnemyPartyMons
- ld c, a
- ld b, 0
- add hl, bc
- ld a, [hl]
- ld [wd11e], a
- call GetMonName
- ld hl, WillBeTradedText
- coord bc, 1, 14
- call TextCommandProcessor
- call SaveScreenTilesToBuffer1
- coord hl, 10, 7
- lb bc, 8, 11
- ld a, TRADE_CANCEL_MENU
- ld [wTwoOptionMenuID], a
- ld a, TWO_OPTION_MENU
- ld [wTextBoxID], a
- call DisplayTextBoxID
- call LoadScreenTilesFromBuffer1
- ld a, [wCurrentMenuItem]
- and a
- jr z, .tradeConfirmed
-; if trade cancelled
- ld a, $1
- ld [wSerialExchangeNybbleSendData], a
- coord hl, 0, 12
- ld b, 4
- ld c, 18
- call CableClub_TextBoxBorder
- coord hl, 1, 14
- ld de, TradeCanceled
- call PlaceString
- call Serial_PrintWaitingTextAndSyncAndExchangeNybble
- jp .tradeCancelled
-.tradeConfirmed
- ld a, $2
- ld [wSerialExchangeNybbleSendData], a
- call Serial_PrintWaitingTextAndSyncAndExchangeNybble
- ld a, [wSerialSyncAndExchangeNybbleReceiveData]
- dec a ; did the other person cancel?
- jr nz, .doTrade
-; if the other person cancelled
- coord hl, 0, 12
- ld b, 4
- ld c, 18
- call CableClub_TextBoxBorder
- coord hl, 1, 14
- ld de, TradeCanceled
- call PlaceString
- jp .tradeCancelled
-.doTrade
- ld a, [wTradingWhichPlayerMon]
- ld hl, wPartyMonOT
- call SkipFixedLengthTextEntries
- ld de, wTradedPlayerMonOT
- ld bc, NAME_LENGTH
- call CopyData
- ld hl, wPartyMon1Species
- ld a, [wTradingWhichPlayerMon]
- ld bc, wPartyMon2 - wPartyMon1
- call AddNTimes
- ld bc, wPartyMon1OTID - wPartyMon1
- add hl, bc
- ld a, [hli]
- ld [wTradedPlayerMonOTID], a
- ld a, [hl]
- ld [wTradedPlayerMonOTID + 1], a
- ld a, [wTradingWhichEnemyMon]
- ld hl, wEnemyMonOT
- call SkipFixedLengthTextEntries
- ld de, wTradedEnemyMonOT
- ld bc, NAME_LENGTH
- call CopyData
- ld hl, wEnemyMons
- ld a, [wTradingWhichEnemyMon]
- ld bc, wEnemyMon2 - wEnemyMon1
- call AddNTimes
- ld bc, wEnemyMon1OTID - wEnemyMon1
- add hl, bc
- ld a, [hli]
- ld [wTradedEnemyMonOTID], a
- ld a, [hl]
- ld [wTradedEnemyMonOTID + 1], a
- ld a, [wTradingWhichPlayerMon]
- ld [wWhichPokemon], a
- ld hl, wPartySpecies
- ld b, 0
- ld c, a
- add hl, bc
- ld a, [hl]
- ld [wTradedPlayerMonSpecies], a
- xor a
- ld [wRemoveMonFromBox], a
- call RemovePokemon
- ld a, [wTradingWhichEnemyMon]
- ld c, a
- ld [wWhichPokemon], a
- ld hl, wEnemyPartyMons
- ld d, 0
- ld e, a
- add hl, de
- ld a, [hl]
- ld [wcf91], a
- ld hl, wEnemyMons
- ld a, c
- ld bc, wEnemyMon2 - wEnemyMon1
- call AddNTimes
- ld de, wLoadedMon
- ld bc, wEnemyMon2 - wEnemyMon1
- call CopyData
- call AddEnemyMonToPlayerParty
- ld a, [wPartyCount]
- dec a
- ld [wWhichPokemon], a
- ld a, $1
- ld [wForceEvolution], a
- ld a, [wTradingWhichEnemyMon]
- ld hl, wEnemyPartyMons
- ld b, 0
- ld c, a
- add hl, bc
- ld a, [hl]
- ld [wTradedEnemyMonSpecies], a
- ld a, 10
- ld [wAudioFadeOutControl], a
- ld a, BANK(Music_SafariZone)
- ld [wAudioSavedROMBank], a
- ld a, MUSIC_SAFARI_ZONE
- ld [wNewSoundID], a
- call PlaySound
- ld c, 100
- call DelayFrames
- call ClearScreen
- call LoadHpBarAndStatusTilePatterns
- xor a
- ld [wUnusedCC5B], a
- ld a, [hSerialConnectionStatus]
- cp USING_EXTERNAL_CLOCK
- jr z, .usingExternalClock
- predef InternalClockTradeAnim
- jr .tradeCompleted
-.usingExternalClock
- predef ExternalClockTradeAnim
-.tradeCompleted
- callab TryEvolvingMon
- call ClearScreen
- call LoadTrainerInfoTextBoxTiles
- call Serial_PrintWaitingTextAndSyncAndExchangeNybble
- ld c, 40
- call DelayFrames
- coord hl, 0, 12
- ld b, 4
- ld c, 18
- call CableClub_TextBoxBorder
- coord hl, 1, 14
- ld de, TradeCompleted
- call PlaceString
- predef SaveSAVtoSRAM2
- ld c, 50
- call DelayFrames
- xor a
- ld [wTradeCenterPointerTableIndex], a
- jp CableClub_DoBattleOrTradeAgain
-.tradeCancelled
- ld c, 100
- call DelayFrames
- xor a ; TradeCenter_SelectMon
- ld [wTradeCenterPointerTableIndex], a
- jp CallCurrentTradeCenterFunction
-
-WillBeTradedText:
- TX_FAR _WillBeTradedText
- db "@"
-
-TradeCompleted:
- db "Trade completed!@"
-
-TradeCanceled:
- db "Too bad! The trade"
- next "was canceled!@"
-
-TradeCenterPointerTable:
- dw TradeCenter_SelectMon
- dw TradeCenter_Trade
-
-CableClub_Run:
- ld a, [wLinkState]
- cp LINK_STATE_START_TRADE
- jr z, .doBattleOrTrade
- cp LINK_STATE_START_BATTLE
- jr z, .doBattleOrTrade
- cp LINK_STATE_RESET ; this is never used
- ret nz
- predef EmptyFunc3
- jp Init
-.doBattleOrTrade
- call CableClub_DoBattleOrTrade
- ld hl, Club_GFX
- ld a, h
- ld [wTilesetGfxPtr + 1], a
- ld a, l
- ld [wTilesetGfxPtr], a
- ld a, Bank(Club_GFX)
- ld [wTilesetBank], a
- ld hl, Club_Coll
- ld a, h
- ld [wTilesetCollisionPtr + 1], a
- ld a, l
- ld [wTilesetCollisionPtr], a
- xor a
- ld [wGrassRate], a
- inc a ; LINK_STATE_IN_CABLE_CLUB
- ld [wLinkState], a
- ld [hJoy5], a
- ld a, 10
- ld [wAudioFadeOutControl], a
- ld a, BANK(Music_Celadon)
- ld [wAudioSavedROMBank], a
- ld a, MUSIC_CELADON
- ld [wNewSoundID], a
- jp PlaySound
-
-EmptyFunc3:
- ret
-
-Diploma_TextBoxBorder:
- call GetPredefRegisters
-
-; b = height
-; c = width
-CableClub_TextBoxBorder:
- push hl
- ld a, $78 ; border upper left corner tile
- ld [hli], a
- inc a ; border top horizontal line tile
- call CableClub_DrawHorizontalLine
- inc a ; border upper right corner tile
- ld [hl], a
- pop hl
- ld de, 20
- add hl, de
-.loop
- push hl
- ld a, $7b ; border left vertical line tile
- ld [hli], a
- ld a, " "
- call CableClub_DrawHorizontalLine
- ld [hl], $77 ; border right vertical line tile
- pop hl
- ld de, 20
- add hl, de
- dec b
- jr nz, .loop
- ld a, $7c ; border lower left corner tile
- ld [hli], a
- ld a, $76 ; border bottom horizontal line tile
- call CableClub_DrawHorizontalLine
- ld [hl], $7d ; border lower right corner tile
- ret
-
-; c = width
-CableClub_DrawHorizontalLine:
- ld d, c
-.loop
- ld [hli], a
- dec d
- jr nz, .loop
- ret
-
-LoadTrainerInfoTextBoxTiles:
- ld de, TrainerInfoTextBoxTileGraphics
- ld hl, vChars2 + $760
- lb bc, BANK(TrainerInfoTextBoxTileGraphics), (TrainerInfoTextBoxTileGraphicsEnd - TrainerInfoTextBoxTileGraphics) / $10
- jp CopyVideoData
--- a/engine/clear_save.asm
+++ /dev/null
@@ -1,23 +1,0 @@
-DoClearSaveDialogue:
- call ClearScreen
- call RunDefaultPaletteCommand
- call LoadFontTilePatterns
- call LoadTextBoxTilePatterns
- ld hl, ClearSaveDataText
- call PrintText
- coord hl, 14, 7
- lb bc, 8, 15
- ld a, NO_YES_MENU
- ld [wTwoOptionMenuID], a
- ld a, TWO_OPTION_MENU
- ld [wTextBoxID], a
- call DisplayTextBoxID
- ld a, [wCurrentMenuItem]
- and a
- jp z, Init
- callba ClearSAV
- jp Init
-
-ClearSaveDataText:
- TX_FAR _ClearSaveDataText
- db "@"
--- /dev/null
+++ b/engine/debug/debug_party.asm
@@ -1,0 +1,33 @@
+; This function appears to never be used.
+; It is likely a debugging feature to give the player Tsunekazu Ishihara's
+; favorite Pokemon. This is indicated by the overpowered Exeggutor, which
+; Ishihara (president of Creatures Inc.) said was his favorite Pokemon in an ABC
+; interview on February 8, 2000.
+; "Exeggutor is my favorite. That's because I was always using this character
+; while I was debugging the program."
+; http://www.ign.com/articles/2000/02/09/abc-news-pokamon-chat-transcript
+
+SetIshiharaTeam:
+ ld de, IshiharaTeam
+.loop
+ ld a, [de]
+ cp $ff
+ ret z
+ ld [wcf91], a
+ inc de
+ ld a, [de]
+ ld [wCurEnemyLVL], a
+ inc de
+ call AddPartyMon
+ jr .loop
+
+IshiharaTeam:
+ db EXEGGUTOR,90
+ db MEW,20
+ db JOLTEON,56
+ db DUGTRIO,56
+ db ARTICUNO,57
+ db $FF
+
+EmptyFunc:
+ ret
--- /dev/null
+++ b/engine/debug/test_battle.asm
@@ -1,0 +1,45 @@
+TestBattle:
+ ret
+
+.loop
+ call GBPalNormal
+
+ ; Don't mess around
+ ; with obedience.
+ ld a, %10000000 ; EARTHBADGE
+ ld [wObtainedBadges], a
+
+ ld hl, wFlags_D733
+ set BIT_TEST_BATTLE, [hl]
+
+ ; Reset the party.
+ ld hl, wPartyCount
+ xor a
+ ld [hli], a
+ dec a
+ ld [hl], a
+
+ ; Give the player a
+ ; level 20 Rhydon.
+ ld a, RHYDON
+ ld [wcf91], a
+ ld a, 20
+ ld [wCurEnemyLVL], a
+ xor a
+ ld [wMonDataLocation], a
+ ld [wCurMap], a
+ call AddPartyMon
+
+ ; Fight against a
+ ; level 20 Rhydon.
+ ld a, RHYDON
+ ld [wCurOpponent], a
+
+ predef InitOpponent
+
+ ; When the battle ends,
+ ; do it all again.
+ ld a, 1
+ ld [wUpdateSpritesEnabled], a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ jr .loop
--- a/engine/debug1.asm
+++ /dev/null
@@ -1,33 +1,0 @@
-; This function appears to never be used.
-; It is likely a debugging feature to give the player Tsunekazu Ishihara's
-; favorite Pokemon. This is indicated by the overpowered Exeggutor, which
-; Ishihara (president of Creatures Inc.) said was his favorite Pokemon in an ABC
-; interview on February 8, 2000.
-; "Exeggutor is my favorite. That's because I was always using this character
-; while I was debugging the program."
-; http://www.ign.com/articles/2000/02/09/abc-news-pokamon-chat-transcript
-
-SetIshiharaTeam:
- ld de, IshiharaTeam
-.loop
- ld a, [de]
- cp $ff
- ret z
- ld [wcf91], a
- inc de
- ld a, [de]
- ld [wCurEnemyLVL], a
- inc de
- call AddPartyMon
- jr .loop
-
-IshiharaTeam:
- db EXEGGUTOR,90
- db MEW,20
- db JOLTEON,56
- db DUGTRIO,56
- db ARTICUNO,57
- db $FF
-
-EmptyFunc:
- ret
--- a/engine/display_pokedex.asm
+++ /dev/null
@@ -1,19 +1,0 @@
-_DisplayPokedex::
- ld hl, wd730
- set 6, [hl]
- predef ShowPokedexData
- ld hl, wd730
- res 6, [hl]
- call ReloadMapData
- ld c, 10
- call DelayFrames
- predef IndexToPokedex
- ld a, [wd11e]
- dec a
- ld c, a
- ld b, FLAG_SET
- ld hl, wPokedexSeen
- predef FlagActionPredef
- ld a, $1
- ld [wDoNotWaitForButtonPressAfterDisplayingText], a
- ret
--- a/engine/display_text_id_init.asm
+++ /dev/null
@@ -1,78 +1,0 @@
-; function that performs initialization for DisplayTextID
-DisplayTextIDInit::
- xor a
- ld [wListMenuID], a
- ld a, [wAutoTextBoxDrawingControl]
- bit 0, a
- jr nz, .skipDrawingTextBoxBorder
- ld a, [hSpriteIndexOrTextID] ; text ID (or sprite ID)
- and a
- jr nz, .notStartMenu
-; if text ID is 0 (i.e. the start menu)
-; Note that the start menu text border is also drawn in the function directly
-; below this, so this seems unnecessary.
- CheckEvent EVENT_GOT_POKEDEX
-; start menu with pokedex
- coord hl, 10, 0
- ld b, $0e
- ld c, $08
- jr nz, .drawTextBoxBorder
-; start menu without pokedex
- coord hl, 10, 0
- ld b, $0c
- ld c, $08
- jr .drawTextBoxBorder
-; if text ID is not 0 (i.e. not the start menu) then do a standard dialogue text box
-.notStartMenu
- coord hl, 0, 12
- ld b, $04
- ld c, $12
-.drawTextBoxBorder
- call TextBoxBorder
-.skipDrawingTextBoxBorder
- ld hl, wFontLoaded
- set 0, [hl]
- ld hl, wFlags_0xcd60
- bit 4, [hl]
- res 4, [hl]
- jr nz, .skipMovingSprites
- call UpdateSprites
-.skipMovingSprites
-; loop to copy C1X9 (direction the sprite is facing) to C2X9 for each sprite
-; this is done because when you talk to an NPC, they turn to look your way
-; the original direction they were facing must be restored after the dialogue is over
- ld hl, wSpriteStateData1 + $19
- ld c, $0f
- ld de, $0010
-.spriteFacingDirectionCopyLoop
- ld a, [hl]
- inc h
- ld [hl], a
- dec h
- add hl, de
- dec c
- jr nz, .spriteFacingDirectionCopyLoop
-; loop to force all the sprites in the middle of animation to stand still
-; (so that they don't like they're frozen mid-step during the dialogue)
- ld hl, wSpriteStateData1 + 2
- ld de, $0010
- ld c, e
-.spriteStandStillLoop
- ld a, [hl]
- cp $ff ; is the sprite visible?
- jr z, .nextSprite
-; if it is visible
- and $fc
- ld [hl], a
-.nextSprite
- add hl, de
- dec c
- jr nz, .spriteStandStillLoop
- ld b, $9c ; window background address
- call CopyScreenTileBufferToVRAM ; transfer background in WRAM to VRAM
- xor a
- ld [hWY], a ; put the window on the screen
- call LoadFontTilePatterns
- ld a, $01
- ld [H_AUTOBGTRANSFERENABLED], a ; enable continuous WRAM to VRAM transfer each V-blank
- ret
--- /dev/null
+++ b/engine/events/black_out.asm
@@ -1,0 +1,46 @@
+ResetStatusAndHalveMoneyOnBlackout::
+; Reset player status on blackout.
+ xor a
+ ld [wBattleResult], a
+ ld [wWalkBikeSurfState], a
+ ld [wIsInBattle], a
+ ld [wMapPalOffset], a
+ ld [wNPCMovementScriptFunctionNum], a
+ ld [hJoyHeld], a
+ ld [wNPCMovementScriptPointerTableNum], a
+ ld [wFlags_0xcd60], a
+
+ ld [hMoney], a
+ ld [hMoney + 1], a
+ ld [hMoney + 2], a
+ call HasEnoughMoney
+ jr c, .lostmoney ; never happens
+
+ ; Halve the player's money.
+ ld a, [wPlayerMoney]
+ ld [hMoney], a
+ ld a, [wPlayerMoney + 1]
+ ld [hMoney + 1], a
+ ld a, [wPlayerMoney + 2]
+ ld [hMoney + 2], a
+ xor a
+ ld [hDivideBCDDivisor], a
+ ld [hDivideBCDDivisor + 1], a
+ ld a, 2
+ ld [hDivideBCDDivisor + 2], a
+ predef DivideBCDPredef3
+ ld a, [hDivideBCDQuotient]
+ ld [wPlayerMoney], a
+ ld a, [hDivideBCDQuotient + 1]
+ ld [wPlayerMoney + 1], a
+ ld a, [hDivideBCDQuotient + 2]
+ ld [wPlayerMoney + 2], a
+
+.lostmoney
+ ld hl, wd732
+ set 2, [hl]
+ res 3, [hl]
+ set 6, [hl]
+ ld a, %11111111
+ ld [wJoyIgnore], a
+ predef_jump HealParty
--- /dev/null
+++ b/engine/events/card_key.asm
@@ -1,0 +1,112 @@
+PrintCardKeyText:
+ ld hl, SilphCoMapList
+ ld a, [wCurMap]
+ ld b, a
+.silphCoMapListLoop
+ ld a, [hli]
+ cp $ff
+ ret z
+ cp b
+ jr nz, .silphCoMapListLoop
+ predef GetTileAndCoordsInFrontOfPlayer
+ ld a, [wTileInFrontOfPlayer]
+ cp $18
+ jr z, .cardKeyDoorInFrontOfPlayer
+ cp $24
+ jr z, .cardKeyDoorInFrontOfPlayer
+ ld b, a
+ ld a, [wCurMap]
+ cp SILPH_CO_11F
+ ret nz
+ ld a, b
+ cp $5e
+ ret nz
+.cardKeyDoorInFrontOfPlayer
+ ld b, CARD_KEY
+ call IsItemInBag
+ jr z, .noCardKey
+ call GetCoordsInFrontOfPlayer
+ push de
+ tx_pre_id CardKeySuccessText
+ ld [hSpriteIndexOrTextID], a
+ call PrintPredefTextID
+ pop de
+ srl d
+ ld a, d
+ ld b, a
+ ld [wCardKeyDoorY], a
+ srl e
+ ld a, e
+ ld c, a
+ ld [wCardKeyDoorX], a
+ ld a, [wCurMap]
+ cp SILPH_CO_11F
+ jr nz, .notSilphCo11F
+ ld a, $3
+ jr .replaceCardKeyDoorTileBlock
+.notSilphCo11F
+ ld a, $e
+.replaceCardKeyDoorTileBlock
+ ld [wNewTileBlockID], a
+ predef ReplaceTileBlock
+ ld hl, wCurrentMapScriptFlags
+ set 5, [hl]
+ ld a, SFX_GO_INSIDE
+ jp PlaySound
+.noCardKey
+ tx_pre_id CardKeyFailText
+ ld [hSpriteIndexOrTextID], a
+ jp PrintPredefTextID
+
+SilphCoMapList:
+ db SILPH_CO_2F
+ db SILPH_CO_3F
+ db SILPH_CO_4F
+ db SILPH_CO_5F
+ db SILPH_CO_6F
+ db SILPH_CO_7F
+ db SILPH_CO_8F
+ db SILPH_CO_9F
+ db SILPH_CO_10F
+ db SILPH_CO_11F
+ db $FF
+
+CardKeySuccessText::
+ TX_FAR _CardKeySuccessText1
+ TX_SFX_ITEM_1
+ TX_FAR _CardKeySuccessText2
+ db "@"
+
+CardKeyFailText::
+ TX_FAR _CardKeyFailText
+ db "@"
+
+; d = Y
+; e = X
+GetCoordsInFrontOfPlayer:
+ ld a, [wYCoord]
+ ld d, a
+ ld a, [wXCoord]
+ ld e, a
+ ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction
+ and a
+ jr nz, .notFacingDown
+; facing down
+ inc d
+ ret
+.notFacingDown
+ cp SPRITE_FACING_UP
+ jr nz, .notFacingUp
+; facing up
+ dec d
+ ret
+.notFacingUp
+ cp SPRITE_FACING_LEFT
+ jr nz, .notFacingLeft
+; facing left
+ dec e
+ ret
+.notFacingLeft
+; facing right
+ inc e
+ ret
--- /dev/null
+++ b/engine/events/cinnabar_lab.asm
@@ -1,0 +1,123 @@
+GiveFossilToCinnabarLab::
+ ld hl, wd730
+ set 6, [hl]
+ xor a
+ ld [wCurrentMenuItem], a
+ ld a, A_BUTTON | B_BUTTON
+ ld [wMenuWatchedKeys], a
+ ld a, [wFilteredBagItemsCount]
+ dec a
+ ld [wMaxMenuItem], a
+ ld a, 2
+ ld [wTopMenuItemY], a
+ ld a, 1
+ ld [wTopMenuItemX], a
+ ld a, [wFilteredBagItemsCount]
+ dec a
+ ld bc, 2
+ ld hl, 3
+ call AddNTimes
+ dec l
+ ld b, l
+ ld c, $d
+ coord hl, 0, 0
+ call TextBoxBorder
+ call UpdateSprites
+ call PrintFossilsInBag
+ ld hl, wd730
+ res 6, [hl]
+ call HandleMenuInput
+ bit 1, a ; pressed B?
+ jr nz, .cancelledGivingFossil
+ ld hl, wFilteredBagItems
+ ld a, [wCurrentMenuItem]
+ ld d, 0
+ ld e, a
+ add hl, de
+ ld a, [hl]
+ ld [$ffdb], a
+ cp DOME_FOSSIL
+ jr z, .choseDomeFossil
+ cp HELIX_FOSSIL
+ jr z, .choseHelixFossil
+ ld b, AERODACTYL
+ jr .fossilSelected
+.choseHelixFossil
+ ld b, OMANYTE
+ jr .fossilSelected
+.choseDomeFossil
+ ld b, KABUTO
+.fossilSelected
+ ld [wFossilItem], a
+ ld a, b
+ ld [wFossilMon], a
+ call LoadFossilItemAndMonName
+ ld hl, LabFossil_610ae
+ call PrintText
+ call YesNoChoice
+ ld a, [wCurrentMenuItem]
+ and a
+ jr nz, .cancelledGivingFossil
+ ld hl, LabFossil_610b3
+ call PrintText
+ ld a, [wFossilItem]
+ ld [hItemToRemoveID], a
+ callba RemoveItemByID
+ ld hl, LabFossil_610b8
+ call PrintText
+ SetEvents EVENT_GAVE_FOSSIL_TO_LAB, EVENT_LAB_STILL_REVIVING_FOSSIL
+ ret
+.cancelledGivingFossil
+ ld hl, LabFossil_610bd
+ call PrintText
+ ret
+
+LabFossil_610ae:
+ TX_FAR _Lab4Text_610ae
+ db "@"
+
+LabFossil_610b3:
+ TX_FAR _Lab4Text_610b3
+ db "@"
+
+LabFossil_610b8:
+ TX_FAR _Lab4Text_610b8
+ db "@"
+
+LabFossil_610bd:
+ TX_FAR _Lab4Text_610bd
+ db "@"
+
+PrintFossilsInBag:
+; Prints each fossil in the player's bag on a separate line in the menu.
+ ld hl, wFilteredBagItems
+ xor a
+ ld [hItemCounter], a
+.loop
+ ld a, [hli]
+ cp $ff
+ ret z
+ push hl
+ ld [wd11e], a
+ call GetItemName
+ coord hl, 2, 2
+ ld a, [hItemCounter]
+ ld bc, SCREEN_WIDTH * 2
+ call AddNTimes
+ ld de, wcd6d
+ call PlaceString
+ ld hl, hItemCounter
+ inc [hl]
+ pop hl
+ jr .loop
+
+; loads the names of the fossil item and the resulting mon
+LoadFossilItemAndMonName::
+ ld a, [wFossilMon]
+ ld [wd11e], a
+ call GetMonName
+ call CopyStringToCF4B
+ ld a, [wFossilItem]
+ ld [wd11e], a
+ call GetItemName
+ ret
--- /dev/null
+++ b/engine/events/diploma.asm
@@ -1,0 +1,113 @@
+DisplayDiploma::
+ call SaveScreenTilesToBuffer2
+ call GBPalWhiteOutWithDelay3
+ call ClearScreen
+ xor a
+ ld [wUpdateSpritesEnabled], a
+ ld hl, wd730
+ set 6, [hl]
+ call DisableLCD
+ ld hl, CircleTile
+ ld de, vChars2 + $700
+ ld bc, $0010
+ ld a, BANK(CircleTile)
+ call FarCopyData2
+ coord hl, 0, 0
+ lb bc, 16, 18
+ predef Diploma_TextBoxBorder
+ ld hl, DiplomaTextPointersAndCoords
+ ld c, $5
+.asm_56715
+ push bc
+ ld a, [hli]
+ ld e, a
+ ld a, [hli]
+ ld d, a
+ ld a, [hli]
+ push hl
+ ld h, [hl]
+ ld l, a
+ call PlaceString
+ pop hl
+ inc hl
+ pop bc
+ dec c
+ jr nz, .asm_56715
+ coord hl, 10, 4
+ ld de, wPlayerName
+ call PlaceString
+ callba DrawPlayerCharacter
+
+; Move the player 33 pixels right and set the priority bit so he appears
+; behind the background layer.
+ ld hl, wOAMBuffer + $01
+ lb bc, $80, $28
+.adjustPlayerGfxLoop
+ ld a, [hl] ; X
+ add 33
+ ld [hli], a
+ inc hl
+ ld a, b
+ ld [hli], a ; attributes
+ inc hl
+ dec c
+ jr nz, .adjustPlayerGfxLoop
+
+ call EnableLCD
+ callba LoadTrainerInfoTextBoxTiles
+ ld b, SET_PAL_GENERIC
+ call RunPaletteCommand
+ call Delay3
+ call GBPalNormal
+ ld a, $90
+ ld [rOBP0], a
+ call WaitForTextScrollButtonPress
+ ld hl, wd730
+ res 6, [hl]
+ call GBPalWhiteOutWithDelay3
+ call RestoreScreenTilesAndReloadTilePatterns
+ call Delay3
+ jp GBPalNormal
+
+UnusedPlayerNameLengthFunc:
+; Unused function that does a calculation involving the length of the player's
+; name.
+ ld hl, wPlayerName
+ ld bc, $ff00
+.loop
+ ld a, [hli]
+ cp "@"
+ ret z
+ dec c
+ jr .loop
+
+DiplomaTextPointersAndCoords:
+ dw DiplomaText
+ dwCoord 5, 2
+ dw DiplomaPlayer
+ dwCoord 3, 4
+ dw DiplomaEmptyText
+ dwCoord 15, 4
+ dw DiplomaCongrats
+ dwCoord 2, 6
+ dw DiplomaGameFreak
+ dwCoord 9, 16
+
+DiplomaText:
+ db $70,"Diploma",$70,"@"
+
+DiplomaPlayer:
+ db "Player@"
+
+DiplomaEmptyText:
+ db "@"
+
+DiplomaCongrats:
+ db "Congrats! This"
+ next "diploma certifies"
+ next "that you have"
+ next "completed your"
+ next "#DEX.@"
+
+DiplomaGameFreak:
+ db "GAME FREAK@"
--- /dev/null
+++ b/engine/events/display_pokedex.asm
@@ -1,0 +1,19 @@
+_DisplayPokedex::
+ ld hl, wd730
+ set 6, [hl]
+ predef ShowPokedexData
+ ld hl, wd730
+ res 6, [hl]
+ call ReloadMapData
+ ld c, 10
+ call DelayFrames
+ predef IndexToPokedex
+ ld a, [wd11e]
+ dec a
+ ld c, a
+ ld b, FLAG_SET
+ ld hl, wPokedexSeen
+ predef FlagActionPredef
+ ld a, $1
+ ld [wDoNotWaitForButtonPressAfterDisplayingText], a
+ ret
--- /dev/null
+++ b/engine/events/elevator.asm
@@ -1,0 +1,48 @@
+DisplayElevatorFloorMenu:
+ ld hl, WhichFloorText
+ call PrintText
+ ld hl, wItemList
+ ld a, l
+ ld [wListPointer], a
+ ld a, h
+ ld [wListPointer + 1], a
+ ld a, [wListScrollOffset]
+ push af
+ xor a
+ ld [wCurrentMenuItem], a
+ ld [wListScrollOffset], a
+ ld [wPrintItemPrices], a
+ ld a, SPECIALLISTMENU
+ ld [wListMenuID], a
+ call DisplayListMenuID
+ pop bc
+ ld a, b
+ ld [wListScrollOffset], a
+ ret c
+ ld hl, wCurrentMapScriptFlags
+ set 7, [hl]
+ ld hl, wElevatorWarpMaps
+ ld a, [wWhichPokemon]
+ add a
+ ld d, 0
+ ld e, a
+ add hl, de
+ ld a, [hli]
+ ld b, a
+ ld a, [hl]
+ ld c, a
+ ld hl, wWarpEntries
+ call .UpdateWarp
+
+.UpdateWarp
+ inc hl
+ inc hl
+ ld a, b
+ ld [hli], a ; destination warp ID
+ ld a, c
+ ld [hli], a ; destination map ID
+ ret
+
+WhichFloorText:
+ TX_FAR _WhichFloorText
+ db "@"
--- /dev/null
+++ b/engine/events/evolve_trade.asm
@@ -1,0 +1,44 @@
+EvolveTradeMon:
+; Verify the TradeMon's species name before
+; attempting to initiate a trade evolution.
+
+; The names of the trade evolutions in Blue (JP)
+; are checked. In that version, TradeMons that
+; can evolve are Graveler and Haunter.
+
+; In localization, this check was translated
+; before monster names were finalized.
+; Then, Haunter's name was "Spectre".
+; Since its name no longer starts with
+; "SP", it is prevented from evolving.
+
+; This may have been why Red/Green's trades
+; were used instead, where none can evolve.
+
+; This was fixed in Yellow.
+
+ ld a, [wInGameTradeReceiveMonName]
+
+ ; GRAVELER
+ cp "G"
+ jr z, .ok
+
+ ; "SPECTRE" (HAUNTER)
+ cp "S"
+ ret nz
+ ld a, [wInGameTradeReceiveMonName + 1]
+ cp "P"
+ ret nz
+
+.ok
+ ld a, [wPartyCount]
+ dec a
+ ld [wWhichPokemon], a
+ ld a, $1
+ ld [wForceEvolution], a
+ ld a, LINK_STATE_TRADING
+ ld [wLinkState], a
+ callab TryEvolvingMon
+ xor a ; LINK_STATE_NONE
+ ld [wLinkState], a
+ jp PlayDefaultMusic
--- /dev/null
+++ b/engine/events/give_pokemon.asm
@@ -1,0 +1,82 @@
+_GivePokemon::
+; returns success in carry
+; and whether the mon was added to the party in [wAddedToParty]
+ call EnableAutoTextBoxDrawing
+ xor a
+ ld [wAddedToParty], a
+ ld a, [wPartyCount]
+ cp PARTY_LENGTH
+ jr c, .addToParty
+ ld a, [wNumInBox]
+ cp MONS_PER_BOX
+ jr nc, .boxFull
+; add to box
+ xor a
+ ld [wEnemyBattleStatus3], a
+ ld a, [wcf91]
+ ld [wEnemyMonSpecies2], a
+ callab LoadEnemyMonData
+ call SetPokedexOwnedFlag
+ callab SendNewMonToBox
+ ld hl, wcf4b
+ ld a, [wCurrentBoxNum]
+ and $7f
+ cp 9
+ jr c, .singleDigitBoxNum
+ sub 9
+ ld [hl], "1"
+ inc hl
+ add "0"
+ jr .next
+.singleDigitBoxNum
+ add "1"
+.next
+ ld [hli], a
+ ld [hl], "@"
+ ld hl, SentToBoxText
+ call PrintText
+ scf
+ ret
+.boxFull
+ ld hl, BoxIsFullText
+ call PrintText
+ and a
+ ret
+.addToParty
+ call SetPokedexOwnedFlag
+ call AddPartyMon
+ ld a, 1
+ ld [wDoNotWaitForButtonPressAfterDisplayingText], a
+ ld [wAddedToParty], a
+ scf
+ ret
+
+SetPokedexOwnedFlag:
+ ld a, [wcf91]
+ push af
+ ld [wd11e], a
+ predef IndexToPokedex
+ ld a, [wd11e]
+ dec a
+ ld c, a
+ ld hl, wPokedexOwned
+ ld b, FLAG_SET
+ predef FlagActionPredef
+ pop af
+ ld [wd11e], a
+ call GetMonName
+ ld hl, GotMonText
+ jp PrintText
+
+GotMonText:
+ TX_FAR _GotMonText
+ TX_SFX_ITEM_1
+ db "@"
+
+SentToBoxText:
+ TX_FAR _SentToBoxText
+ db "@"
+
+BoxIsFullText:
+ TX_FAR _BoxIsFullText
+ db "@"
--- /dev/null
+++ b/engine/events/heal_party.asm
@@ -1,0 +1,99 @@
+HealParty:
+; Restore HP and PP.
+
+ ld hl, wPartySpecies
+ ld de, wPartyMon1HP
+.healmon
+ ld a, [hli]
+ cp $ff
+ jr z, .done
+
+ push hl
+ push de
+
+ ld hl, wPartyMon1Status - wPartyMon1HP
+ add hl, de
+ xor a
+ ld [hl], a
+
+ push de
+ ld b, NUM_MOVES ; A Pokémon has 4 moves
+.pp
+ ld hl, wPartyMon1Moves - wPartyMon1HP
+ add hl, de
+
+ ld a, [hl]
+ and a
+ jr z, .nextmove
+
+ dec a
+ ld hl, wPartyMon1PP - wPartyMon1HP
+ add hl, de
+
+ push hl
+ push de
+ push bc
+
+ ld hl, Moves
+ ld bc, MoveEnd - Moves
+ call AddNTimes
+ ld de, wcd6d
+ ld a, BANK(Moves)
+ call FarCopyData
+ ld a, [wcd6d + 5] ; PP is byte 5 of move data
+
+ pop bc
+ pop de
+ pop hl
+
+ inc de
+ push bc
+ ld b, a
+ ld a, [hl]
+ and $c0
+ add b
+ ld [hl], a
+ pop bc
+
+.nextmove
+ dec b
+ jr nz, .pp
+ pop de
+
+ ld hl, wPartyMon1MaxHP - wPartyMon1HP
+ add hl, de
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hl]
+ ld [de], a
+
+ pop de
+ pop hl
+
+ push hl
+ ld bc, wPartyMon2 - wPartyMon1
+ ld h, d
+ ld l, e
+ add hl, bc
+ ld d, h
+ ld e, l
+ pop hl
+ jr .healmon
+
+.done
+ xor a
+ ld [wWhichPokemon], a
+ ld [wd11e], a
+
+ ld a, [wPartyCount]
+ ld b, a
+.ppup
+ push bc
+ call RestoreBonusPP
+ pop bc
+ ld hl, wWhichPokemon
+ inc [hl]
+ dec b
+ jr nz, .ppup
+ ret
--- /dev/null
+++ b/engine/events/hidden_items.asm
@@ -1,0 +1,161 @@
+HiddenItems:
+ ld hl, HiddenItemCoords
+ call FindHiddenItemOrCoinsIndex
+ ld [wHiddenItemOrCoinsIndex], a
+ ld hl, wObtainedHiddenItemsFlags
+ ld a, [wHiddenItemOrCoinsIndex]
+ ld c, a
+ ld b, FLAG_TEST
+ predef FlagActionPredef
+ ld a, c
+ and a
+ ret nz
+ call EnableAutoTextBoxDrawing
+ ld a, 1
+ ld [wDoNotWaitForButtonPressAfterDisplayingText], a
+ ld a, [wHiddenObjectFunctionArgument] ; item ID
+ ld [wd11e], a
+ call GetItemName
+ tx_pre_jump FoundHiddenItemText
+
+INCLUDE "data/hidden_item_coords.asm"
+
+FoundHiddenItemText::
+ TX_FAR _FoundHiddenItemText
+ TX_ASM
+ ld a, [wHiddenObjectFunctionArgument] ; item ID
+ ld b, a
+ ld c, 1
+ call GiveItem
+ jr nc, .bagFull
+ ld hl, wObtainedHiddenItemsFlags
+ ld a, [wHiddenItemOrCoinsIndex]
+ ld c, a
+ ld b, FLAG_SET
+ predef FlagActionPredef
+ ld a, SFX_GET_ITEM_2
+ call PlaySoundWaitForCurrent
+ call WaitForSoundToFinish
+ jp TextScriptEnd
+.bagFull
+ call WaitForTextScrollButtonPress ; wait for button press
+ xor a
+ ld [wDoNotWaitForButtonPressAfterDisplayingText], a
+ ld hl, HiddenItemBagFullText
+ call PrintText
+ jp TextScriptEnd
+
+HiddenItemBagFullText::
+ TX_FAR _HiddenItemBagFullText
+ db "@"
+
+HiddenCoins:
+ ld b, COIN_CASE
+ predef GetQuantityOfItemInBag
+ ld a, b
+ and a
+ ret z
+ ld hl, HiddenCoinCoords
+ call FindHiddenItemOrCoinsIndex
+ ld [wHiddenItemOrCoinsIndex], a
+ ld hl, wObtainedHiddenCoinsFlags
+ ld a, [wHiddenItemOrCoinsIndex]
+ ld c, a
+ ld b, FLAG_TEST
+ predef FlagActionPredef
+ ld a, c
+ and a
+ ret nz
+ xor a
+ ld [hUnusedCoinsByte], a
+ ld [hCoins], a
+ ld [hCoins + 1], a
+ ld a, [wHiddenObjectFunctionArgument]
+ sub COIN
+ cp 10
+ jr z, .bcd10
+ cp 20
+ jr z, .bcd20
+ cp 40
+ jr z, .bcd20 ; should be bcd40
+ jr .bcd100
+.bcd10
+ ld a, $10
+ ld [hCoins + 1], a
+ jr .bcdDone
+.bcd20
+ ld a, $20
+ ld [hCoins + 1], a
+ jr .bcdDone
+.bcd40 ; due to a typo, this is never used
+ ld a, $40
+ ld [hCoins + 1], a
+ jr .bcdDone
+.bcd100
+ ld a, $1
+ ld [hCoins], a
+.bcdDone
+ ld de, wPlayerCoins + 1
+ ld hl, hCoins + 1
+ ld c, $2
+ predef AddBCDPredef
+ ld hl, wObtainedHiddenCoinsFlags
+ ld a, [wHiddenItemOrCoinsIndex]
+ ld c, a
+ ld b, FLAG_SET
+ predef FlagActionPredef
+ call EnableAutoTextBoxDrawing
+ ld a, [wPlayerCoins]
+ cp $99
+ jr nz, .roomInCoinCase
+ ld a, [wPlayerCoins + 1]
+ cp $99
+ jr nz, .roomInCoinCase
+ tx_pre_id DroppedHiddenCoinsText
+ jr .done
+.roomInCoinCase
+ tx_pre_id FoundHiddenCoinsText
+.done
+ jp PrintPredefTextID
+
+INCLUDE "data/hidden_coins.asm"
+
+FoundHiddenCoinsText::
+ TX_FAR _FoundHiddenCoinsText
+ TX_SFX_ITEM_2
+ db "@"
+
+DroppedHiddenCoinsText::
+ TX_FAR _FoundHiddenCoins2Text
+ TX_SFX_ITEM_2
+ TX_FAR _DroppedHiddenCoinsText
+ db "@"
+
+FindHiddenItemOrCoinsIndex:
+ ld a, [wHiddenObjectY]
+ ld d, a
+ ld a, [wHiddenObjectX]
+ ld e, a
+ ld a, [wCurMap]
+ ld b, a
+ ld c, -1
+.loop
+ inc c
+ ld a, [hli]
+ cp $ff ; end of the list?
+ ret z ; if so, we're done here
+ cp b
+ jr nz, .next1
+ ld a, [hli]
+ cp d
+ jr nz, .next2
+ ld a, [hli]
+ cp e
+ jr nz, .loop
+ ld a, c
+ ret
+.next1
+ inc hl
+.next2
+ inc hl
+ jr .loop
--- /dev/null
+++ b/engine/events/hidden_object_functions14.asm
@@ -1,0 +1,100 @@
+PrintNotebookText:
+ call EnableAutoTextBoxDrawing
+ ld a, $1
+ ld [wDoNotWaitForButtonPressAfterDisplayingText], a
+ ld a, [wHiddenObjectFunctionArgument]
+ jp PrintPredefTextID
+
+TMNotebook::
+ TX_FAR TMNotebookText
+ TX_WAIT
+ db "@"
+
+ViridianSchoolNotebook::
+ TX_ASM
+ ld hl, ViridianSchoolNotebookText1
+ call PrintText
+ call TurnPageSchoolNotebook
+ jr nz, .doneReading
+ ld hl, ViridianSchoolNotebookText2
+ call PrintText
+ call TurnPageSchoolNotebook
+ jr nz, .doneReading
+ ld hl, ViridianSchoolNotebookText3
+ call PrintText
+ call TurnPageSchoolNotebook
+ jr nz, .doneReading
+ ld hl, ViridianSchoolNotebookText4
+ call PrintText
+ ld hl, ViridianSchoolNotebookText5
+ call PrintText
+.doneReading
+ jp TextScriptEnd
+
+TurnPageSchoolNotebook:
+ ld hl, TurnPageText
+ call PrintText
+ call YesNoChoice
+ ld a, [wCurrentMenuItem]
+ and a
+ ret
+
+TurnPageText:
+ TX_FAR _TurnPageText
+ db "@"
+
+ViridianSchoolNotebookText5:
+ TX_FAR _ViridianSchoolNotebookText5
+ TX_WAIT
+ db "@"
+
+ViridianSchoolNotebookText1:
+ TX_FAR _ViridianSchoolNotebookText1
+ db "@"
+
+ViridianSchoolNotebookText2:
+ TX_FAR _ViridianSchoolNotebookText2
+ db "@"
+
+ViridianSchoolNotebookText3:
+ TX_FAR _ViridianSchoolNotebookText3
+ db "@"
+
+ViridianSchoolNotebookText4:
+ TX_FAR _ViridianSchoolNotebookText4
+ db "@"
+
+PrintFightingDojoText2:
+ call EnableAutoTextBoxDrawing
+ tx_pre_jump EnemiesOnEverySideText
+
+EnemiesOnEverySideText::
+ TX_FAR _EnemiesOnEverySideText
+ db "@"
+
+PrintFightingDojoText3:
+ call EnableAutoTextBoxDrawing
+ tx_pre_jump WhatGoesAroundComesAroundText
+
+WhatGoesAroundComesAroundText::
+ TX_FAR _WhatGoesAroundComesAroundText
+ db "@"
+
+PrintFightingDojoText:
+ call EnableAutoTextBoxDrawing
+ tx_pre_jump FightingDojoText
+
+FightingDojoText::
+ TX_FAR _FightingDojoText
+ db "@"
+
+PrintIndigoPlateauHQText:
+ ld a, [wSpriteStateData1 + 9]
+ cp SPRITE_FACING_UP
+ ret nz
+ call EnableAutoTextBoxDrawing
+ tx_pre_jump IndigoPlateauHQText
+
+IndigoPlateauHQText::
+ TX_FAR _IndigoPlateauHQText
+ db "@"
--- /dev/null
+++ b/engine/events/hidden_object_functions17.asm
@@ -1,0 +1,475 @@
+PrintRedSNESText:
+ call EnableAutoTextBoxDrawing
+ tx_pre_jump RedBedroomSNESText
+
+RedBedroomSNESText::
+ TX_FAR _RedBedroomSNESText
+ db "@"
+
+OpenRedsPC:
+ call EnableAutoTextBoxDrawing
+ tx_pre_jump RedBedroomPCText
+
+RedBedroomPCText::
+ TX_PLAYERS_PC
+
+Route15GateLeftBinoculars:
+ ld a, [wSpriteStateData1 + 9]
+ cp SPRITE_FACING_UP
+ ret nz
+ call EnableAutoTextBoxDrawing
+ tx_pre Route15UpstairsBinocularsText
+ ld a, ARTICUNO
+ ld [wcf91], a
+ call PlayCry
+ jp DisplayMonFrontSpriteInBox
+
+Route15UpstairsBinocularsText::
+ TX_FAR _Route15UpstairsBinocularsText
+ db "@"
+
+AerodactylFossil:
+ ld a, FOSSIL_AERODACTYL
+ ld [wcf91], a
+ call DisplayMonFrontSpriteInBox
+ call EnableAutoTextBoxDrawing
+ tx_pre AerodactylFossilText
+ ret
+
+AerodactylFossilText::
+ TX_FAR _AerodactylFossilText
+ db "@"
+
+KabutopsFossil:
+ ld a, FOSSIL_KABUTOPS
+ ld [wcf91], a
+ call DisplayMonFrontSpriteInBox
+ call EnableAutoTextBoxDrawing
+ tx_pre KabutopsFossilText
+ ret
+
+KabutopsFossilText::
+ TX_FAR _KabutopsFossilText
+ db "@"
+
+DisplayMonFrontSpriteInBox:
+; Displays a pokemon's front sprite in a pop-up window.
+; [wcf91] = pokemon internal id number
+ ld a, 1
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call Delay3
+ xor a
+ ld [hWY], a
+ call SaveScreenTilesToBuffer1
+ ld a, MON_SPRITE_POPUP
+ ld [wTextBoxID], a
+ call DisplayTextBoxID
+ call UpdateSprites
+ ld a, [wcf91]
+ ld [wd0b5], a
+ call GetMonHeader
+ ld de, vChars1 + $310
+ call LoadMonFrontSprite
+ ld a, $80
+ ld [hStartTileID], a
+ coord hl, 10, 11
+ predef AnimateSendingOutMon
+ call WaitForTextScrollButtonPress
+ call LoadScreenTilesFromBuffer1
+ call Delay3
+ ld a, $90
+ ld [hWY], a
+ ret
+
+PrintBlackboardLinkCableText:
+ call EnableAutoTextBoxDrawing
+ ld a, $1
+ ld [wDoNotWaitForButtonPressAfterDisplayingText], a
+ ld a, [wHiddenObjectFunctionArgument]
+ call PrintPredefTextID
+ ret
+
+LinkCableHelp::
+ TX_ASM
+ call SaveScreenTilesToBuffer1
+ ld hl, LinkCableHelpText1
+ call PrintText
+ xor a
+ ld [wMenuItemOffset], a ; not used
+ ld [wCurrentMenuItem], a
+ ld [wLastMenuItem], a
+ ld a, A_BUTTON | B_BUTTON
+ ld [wMenuWatchedKeys], a
+ ld a, 3
+ ld [wMaxMenuItem], a
+ ld a, 2
+ ld [wTopMenuItemY], a
+ ld a, 1
+ ld [wTopMenuItemX], a
+.linkHelpLoop
+ ld hl, wd730
+ set 6, [hl]
+ coord hl, 0, 0
+ ld b, 8
+ ld c, 13
+ call TextBoxBorder
+ coord hl, 2, 2
+ ld de, HowToLinkText
+ call PlaceString
+ ld hl, LinkCableHelpText2
+ call PrintText
+ call HandleMenuInput
+ bit 1, a ; pressed b
+ jr nz, .exit
+ ld a, [wCurrentMenuItem]
+ cp 3 ; pressed a on "STOP READING"
+ jr z, .exit
+ ld hl, wd730
+ res 6, [hl]
+ ld hl, LinkCableInfoTexts
+ add a
+ ld d, 0
+ ld e, a
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call PrintText
+ jp .linkHelpLoop
+.exit
+ ld hl, wd730
+ res 6, [hl]
+ call LoadScreenTilesFromBuffer1
+ jp TextScriptEnd
+
+LinkCableHelpText1:
+ TX_FAR _LinkCableHelpText1
+ db "@"
+
+LinkCableHelpText2:
+ TX_FAR _LinkCableHelpText2
+ db "@"
+
+HowToLinkText:
+ db "HOW TO LINK"
+ next "COLOSSEUM"
+ next "TRADE CENTER"
+ next "STOP READING@"
+
+LinkCableInfoTexts:
+ dw LinkCableInfoText1
+ dw LinkCableInfoText2
+ dw LinkCableInfoText3
+
+LinkCableInfoText1:
+ TX_FAR _LinkCableInfoText1
+ db "@"
+
+LinkCableInfoText2:
+ TX_FAR _LinkCableInfoText2
+ db "@"
+
+LinkCableInfoText3:
+ TX_FAR _LinkCableInfoText3
+ db "@"
+
+ViridianSchoolBlackboard::
+ TX_ASM
+ call SaveScreenTilesToBuffer1
+ ld hl, ViridianSchoolBlackboardText1
+ call PrintText
+ xor a
+ ld [wMenuItemOffset], a
+ ld [wCurrentMenuItem], a
+ ld [wLastMenuItem], a
+ ld a, D_LEFT | D_RIGHT | A_BUTTON | B_BUTTON
+ ld [wMenuWatchedKeys], a
+ ld a, 2
+ ld [wMaxMenuItem], a
+ ld a, 2
+ ld [wTopMenuItemY], a
+ ld a, 1
+ ld [wTopMenuItemX], a
+.blackboardLoop
+ ld hl, wd730
+ set 6, [hl]
+ coord hl, 0, 0
+ lb bc, 6, 10
+ call TextBoxBorder
+ coord hl, 1, 2
+ ld de, StatusAilmentText1
+ call PlaceString
+ coord hl, 6, 2
+ ld de, StatusAilmentText2
+ call PlaceString
+ ld hl, ViridianSchoolBlackboardText2
+ call PrintText
+ call HandleMenuInput ; pressing up and down is handled in here
+ bit 1, a ; pressed b
+ jr nz, .exitBlackboard
+ bit 4, a ; pressed right
+ jr z, .didNotPressRight
+ ; move cursor to right column
+ ld a, 2
+ ld [wMaxMenuItem], a
+ ld a, 2
+ ld [wTopMenuItemY], a
+ ld a, 6
+ ld [wTopMenuItemX], a
+ ld a, 3 ; in the the right column, use an offset to prevent overlap
+ ld [wMenuItemOffset], a
+ jr .blackboardLoop
+.didNotPressRight
+ bit 5, a ; pressed left
+ jr z, .didNotPressLeftOrRight
+ ; move cursor to left column
+ ld a, 2
+ ld [wMaxMenuItem], a
+ ld a, 2
+ ld [wTopMenuItemY], a
+ ld a, 1
+ ld [wTopMenuItemX], a
+ xor a
+ ld [wMenuItemOffset], a
+ jr .blackboardLoop
+.didNotPressLeftOrRight
+ ld a, [wCurrentMenuItem]
+ ld b, a
+ ld a, [wMenuItemOffset]
+ add b
+ cp 5 ; cursor is pointing to "QUIT"
+ jr z, .exitBlackboard
+ ; we must have pressed a on a status condition
+ ; so print the text
+ ld hl, wd730
+ res 6, [hl]
+ ld hl, ViridianBlackboardStatusPointers
+ add a
+ ld d, 0
+ ld e, a
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call PrintText
+ jp .blackboardLoop
+.exitBlackboard
+ ld hl, wd730
+ res 6, [hl]
+ call LoadScreenTilesFromBuffer1
+ jp TextScriptEnd
+
+ViridianSchoolBlackboardText1:
+ TX_FAR _ViridianSchoolBlackboardText1
+ db "@"
+
+ViridianSchoolBlackboardText2:
+ TX_FAR _ViridianSchoolBlackboardText2
+ db "@"
+
+StatusAilmentText1:
+ db " SLP"
+ next " PSN"
+ next " PAR@"
+
+StatusAilmentText2:
+ db " BRN"
+ next " FRZ"
+ next " QUIT@@"
+
+ViridianBlackboardStatusPointers:
+ dw ViridianBlackboardSleepText
+ dw ViridianBlackboardPoisonText
+ dw ViridianBlackboardPrlzText
+ dw ViridianBlackboardBurnText
+ dw ViridianBlackboardFrozenText
+
+ViridianBlackboardSleepText:
+ TX_FAR _ViridianBlackboardSleepText
+ db "@"
+
+ViridianBlackboardPoisonText:
+ TX_FAR _ViridianBlackboardPoisonText
+ db "@"
+
+ViridianBlackboardPrlzText:
+ TX_FAR _ViridianBlackboardPrlzText
+ db "@"
+
+ViridianBlackboardBurnText:
+ TX_FAR _ViridianBlackboardBurnText
+ db "@"
+
+ViridianBlackboardFrozenText:
+ TX_FAR _ViridianBlackboardFrozenText
+ db "@"
+
+PrintTrashText:
+ call EnableAutoTextBoxDrawing
+ tx_pre_jump VermilionGymTrashText
+
+VermilionGymTrashText::
+ TX_FAR _VermilionGymTrashText
+ db "@"
+
+GymTrashScript:
+ call EnableAutoTextBoxDrawing
+ ld a, [wHiddenObjectFunctionArgument]
+ ld [wGymTrashCanIndex], a
+
+; Don't do the trash can puzzle if it's already been done.
+ CheckEvent EVENT_2ND_LOCK_OPENED
+ jr z, .ok
+
+ tx_pre_jump VermilionGymTrashText
+
+.ok
+ CheckEventReuseA EVENT_1ST_LOCK_OPENED
+ jr nz, .trySecondLock
+
+ ld a, [wFirstLockTrashCanIndex]
+ ld b, a
+ ld a, [wGymTrashCanIndex]
+ cp b
+ jr z, .openFirstLock
+
+ tx_pre_id VermilionGymTrashText
+ jr .done
+
+.openFirstLock
+; Next can is trying for the second switch.
+ SetEvent EVENT_1ST_LOCK_OPENED
+
+ ld hl, GymTrashCans
+ ld a, [wGymTrashCanIndex]
+ ; * 5
+ ld b, a
+ add a
+ add a
+ add b
+
+ ld d, 0
+ ld e, a
+ add hl, de
+ ld a, [hli]
+
+; There is a bug in this code. It should calculate a value in the range [0, 3]
+; but if the mask and random number don't have any 1 bits in common, then
+; the result of the AND will be 0. When 1 is subtracted from that, the value
+; will become $ff. This will result in 255 being added to hl, which will cause
+; hl to point to one of the zero bytes that pad the end of the ROM bank.
+; Trash can 0 was intended to be able to have the second lock only when the
+; first lock was in trash can 1 or 3. However, due to this bug, trash can 0 can
+; have the second lock regardless of which trash can had the first lock.
+
+ ld [hGymTrashCanRandNumMask], a
+ push hl
+ call Random
+ swap a
+ ld b, a
+ ld a, [hGymTrashCanRandNumMask]
+ and b
+ dec a
+ pop hl
+
+ ld d, 0
+ ld e, a
+ add hl, de
+ ld a, [hl]
+ and $f
+ ld [wSecondLockTrashCanIndex], a
+
+ tx_pre_id VermilionGymTrashSuccessText1
+ jr .done
+
+.trySecondLock
+ ld a, [wSecondLockTrashCanIndex]
+ ld b, a
+ ld a, [wGymTrashCanIndex]
+ cp b
+ jr z, .openSecondLock
+
+; Reset the cans.
+ ResetEvent EVENT_1ST_LOCK_OPENED
+ call Random
+
+ and $e
+ ld [wFirstLockTrashCanIndex], a
+
+ tx_pre_id VermilionGymTrashFailText
+ jr .done
+
+.openSecondLock
+; Completed the trash can puzzle.
+ SetEvent EVENT_2ND_LOCK_OPENED
+ ld hl, wCurrentMapScriptFlags
+ set 6, [hl]
+
+ tx_pre_id VermilionGymTrashSuccessText3
+
+.done
+ jp PrintPredefTextID
+
+GymTrashCans:
+; byte 0: mask for random number
+; bytes 1-4: indices of the trash cans that can have the second lock
+; (but see the comment above explaining a bug regarding this)
+; Note that the mask is simply the number of valid trash can indices that
+; follow. The remaining bytes are filled with 0 to pad the length of each entry
+; to 5 bytes.
+ db 2, 1, 3, 0, 0 ; 0
+ db 3, 0, 2, 4, 0 ; 1
+ db 2, 1, 5, 0, 0 ; 2
+ db 3, 0, 4, 6, 0 ; 3
+ db 4, 1, 3, 5, 7 ; 4
+ db 3, 2, 4, 8, 0 ; 5
+ db 3, 3, 7, 9, 0 ; 6
+ db 4, 4, 6, 8, 10 ; 7
+ db 3, 5, 7, 11, 0 ; 8
+ db 3, 6, 10, 12, 0 ; 9
+ db 4, 7, 9, 11, 13 ; 10
+ db 3, 8, 10, 14, 0 ; 11
+ db 2, 9, 13, 0, 0 ; 12
+ db 3, 10, 12, 14, 0 ; 13
+ db 2, 11, 13, 0, 0 ; 14
+
+VermilionGymTrashSuccessText1::
+ TX_FAR _VermilionGymTrashSuccessText1
+ TX_ASM
+ call WaitForSoundToFinish
+ ld a, SFX_SWITCH
+ call PlaySound
+ call WaitForSoundToFinish
+ jp TextScriptEnd
+
+; unused
+VermilionGymTrashSuccessText2::
+ TX_FAR _VermilionGymTrashSuccessText2
+ db "@"
+
+; unused
+VermilionGymTrashSuccesPlaySfx:
+ TX_ASM
+ call WaitForSoundToFinish
+ ld a, SFX_SWITCH
+ call PlaySound
+ call WaitForSoundToFinish
+ jp TextScriptEnd
+
+VermilionGymTrashSuccessText3::
+ TX_FAR _VermilionGymTrashSuccessText3
+ TX_ASM
+ call WaitForSoundToFinish
+ ld a, SFX_GO_INSIDE
+ call PlaySound
+ call WaitForSoundToFinish
+ jp TextScriptEnd
+
+VermilionGymTrashFailText::
+ TX_FAR _VermilionGymTrashFailText
+ TX_ASM
+ call WaitForSoundToFinish
+ ld a, SFX_DENIED
+ call PlaySound
+ call WaitForSoundToFinish
+ jp TextScriptEnd
--- /dev/null
+++ b/engine/events/hidden_object_functions18.asm
@@ -1,0 +1,198 @@
+GymStatues:
+; if in a gym and have the corresponding badge, a = GymStatueText2_id and jp PrintPredefTextID
+; if in a gym and don’t have the corresponding badge, a = GymStatueText1_id and jp PrintPredefTextID
+; else ret
+ call EnableAutoTextBoxDrawing
+ ld a, [wSpriteStateData1 + 9]
+ cp SPRITE_FACING_UP
+ ret nz
+ ld hl, .BadgeFlags
+ ld a, [wCurMap]
+ ld b, a
+.loop
+ ld a, [hli]
+ cp $ff
+ ret z
+ cp b
+ jr z, .match
+ inc hl
+ jr .loop
+.match
+ ld b, [hl]
+ ld a, [wBeatGymFlags]
+ and b
+ cp b
+ tx_pre_id GymStatueText2
+ jr z, .haveBadge
+ tx_pre_id GymStatueText1
+.haveBadge
+ jp PrintPredefTextID
+
+.BadgeFlags:
+ db PEWTER_GYM, %00000001
+ db CERULEAN_GYM, %00000010
+ db VERMILION_GYM,%00000100
+ db CELADON_GYM, %00001000
+ db FUCHSIA_GYM, %00010000
+ db SAFFRON_GYM, %00100000
+ db CINNABAR_GYM, %01000000
+ db VIRIDIAN_GYM, %10000000
+ db $ff
+
+GymStatueText1::
+ TX_FAR _GymStatueText1
+ db "@"
+
+GymStatueText2::
+ TX_FAR _GymStatueText2
+ db "@"
+
+PrintBenchGuyText:
+ call EnableAutoTextBoxDrawing
+ ld hl, BenchGuyTextPointers
+ ld a, [wCurMap]
+ ld b, a
+.loop
+ ld a, [hli]
+ cp $ff
+ ret z
+ cp b
+ jr z, .match
+ inc hl
+ inc hl
+ jr .loop
+.match
+ ld a, [hli]
+ ld b, a
+ ld a, [wSpriteStateData1 + 9]
+ cp b
+ jr nz, .loop ; player isn't facing left at the bench guy
+ ld a, [hl]
+ jp PrintPredefTextID
+
+; format: db map id, player sprite facing direction, text id of PredefTextIDPointerTable
+BenchGuyTextPointers:
+ db VIRIDIAN_POKECENTER, SPRITE_FACING_LEFT
+ db_tx_pre ViridianCityPokecenterBenchGuyText
+ db PEWTER_POKECENTER, SPRITE_FACING_LEFT
+ db_tx_pre PewterCityPokecenterBenchGuyText
+ db CERULEAN_POKECENTER, SPRITE_FACING_LEFT
+ db_tx_pre CeruleanCityPokecenterBenchGuyText
+ db LAVENDER_POKECENTER, SPRITE_FACING_LEFT
+ db_tx_pre LavenderCityPokecenterBenchGuyText
+ db VERMILION_POKECENTER, SPRITE_FACING_LEFT
+ db_tx_pre VermilionCityPokecenterBenchGuyText
+ db CELADON_POKECENTER, SPRITE_FACING_LEFT
+ db_tx_pre CeladonCityPokecenterBenchGuyText
+ db CELADON_HOTEL, SPRITE_FACING_LEFT
+ db_tx_pre CeladonCityHotelText
+ db FUCHSIA_POKECENTER, SPRITE_FACING_LEFT
+ db_tx_pre FuchsiaCityPokecenterBenchGuyText
+ db CINNABAR_POKECENTER, SPRITE_FACING_LEFT
+ db_tx_pre CinnabarIslandPokecenterBenchGuyText
+ db SAFFRON_POKECENTER, SPRITE_FACING_LEFT
+ db_tx_pre SaffronCityPokecenterBenchGuyText
+ db MT_MOON_POKECENTER, SPRITE_FACING_LEFT
+ db_tx_pre MtMoonPokecenterBenchGuyText
+ db ROCK_TUNNEL_POKECENTER,SPRITE_FACING_LEFT
+ db_tx_pre RockTunnelPokecenterBenchGuyText
+ db $FF
+
+ViridianCityPokecenterBenchGuyText::
+ TX_FAR _ViridianCityPokecenterGuyText
+ db "@"
+
+PewterCityPokecenterBenchGuyText::
+ TX_FAR _PewterCityPokecenterGuyText
+ db "@"
+
+CeruleanCityPokecenterBenchGuyText::
+ TX_FAR _CeruleanPokecenterGuyText
+ db "@"
+
+LavenderCityPokecenterBenchGuyText::
+ TX_FAR _LavenderPokecenterGuyText
+ db "@"
+
+MtMoonPokecenterBenchGuyText::
+ TX_FAR _MtMoonPokecenterBenchGuyText
+ db "@"
+
+RockTunnelPokecenterBenchGuyText::
+ TX_FAR _RockTunnelPokecenterGuyText
+ db "@"
+
+UnusedBenchGuyText1::
+ TX_FAR _UnusedBenchGuyText1
+ db "@"
+
+UnusedBenchGuyText2::
+ TX_FAR _UnusedBenchGuyText2
+ db "@"
+
+UnusedBenchGuyText3::
+ TX_FAR _UnusedBenchGuyText3
+ db "@"
+
+VermilionCityPokecenterBenchGuyText::
+ TX_FAR _VermilionPokecenterGuyText
+ db "@"
+
+CeladonCityPokecenterBenchGuyText::
+ TX_FAR _CeladonCityPokecenterGuyText
+ db "@"
+
+FuchsiaCityPokecenterBenchGuyText::
+ TX_FAR _FuchsiaCityPokecenterGuyText
+ db "@"
+
+CinnabarIslandPokecenterBenchGuyText::
+ TX_FAR _CinnabarPokecenterGuyText
+ db "@"
+
+SaffronCityPokecenterBenchGuyText::
+ TX_ASM
+ CheckEvent EVENT_BEAT_SILPH_CO_GIOVANNI
+ ld hl, SaffronCityPokecenterBenchGuyText2
+ jr nz, .asm_624f2
+ ld hl, SaffronCityPokecenterBenchGuyText1
+.asm_624f2
+ call PrintText
+ jp TextScriptEnd
+
+SaffronCityPokecenterBenchGuyText1:
+ TX_FAR _SaffronCityPokecenterGuyText1
+ db "@"
+
+SaffronCityPokecenterBenchGuyText2:
+ TX_FAR _SaffronCityPokecenterGuyText2
+ db "@"
+
+CeladonCityHotelText::
+ TX_FAR _CeladonCityHotelText
+ db "@"
+
+ ret
+
+UnusedPredefText::
+ db "@"
+
+PrintBookcaseText:
+ call EnableAutoTextBoxDrawing
+ tx_pre_jump BookcaseText
+
+BookcaseText::
+ TX_FAR _BookcaseText
+ db "@"
+
+OpenPokemonCenterPC:
+ ld a, [wSpriteStateData1 + 9]
+ cp SPRITE_FACING_UP ; check to see if player is facing up
+ ret nz
+ call EnableAutoTextBoxDrawing
+ ld a, $1
+ ld [wAutoTextBoxDrawingControl], a
+ tx_pre_jump PokemonCenterPCText
+
+PokemonCenterPCText::
+ TX_POKECENTER_PC
--- /dev/null
+++ b/engine/events/hidden_object_functions3.asm
@@ -1,0 +1,117 @@
+; prints text for bookshelves in buildings without sign events
+PrintBookshelfText::
+ ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction
+ cp SPRITE_FACING_UP
+ jr nz, .noMatch
+; facing up
+ ld a, [wCurMapTileset]
+ ld b, a
+ aCoord 8, 7
+ ld c, a
+ ld hl, BookshelfTileIDs
+.loop
+ ld a, [hli]
+ cp $ff
+ jr z, .noMatch
+ cp b
+ jr nz, .nextBookshelfEntry1
+ ld a, [hli]
+ cp c
+ jr nz, .nextBookshelfEntry2
+ ld a, [hl]
+ push af
+ call EnableAutoTextBoxDrawing
+ pop af
+ call PrintPredefTextID
+ xor a
+ ld [$ffdb], a
+ ret
+.nextBookshelfEntry1
+ inc hl
+.nextBookshelfEntry2
+ inc hl
+ jr .loop
+.noMatch
+ ld a, $ff
+ ld [$ffdb], a
+ jpba PrintCardKeyText
+
+INCLUDE "data/bookshelf_tile_ids.asm"
+
+IndigoPlateauStatues::
+ TX_ASM
+ ld hl, IndigoPlateauStatuesText1
+ call PrintText
+ ld a, [wXCoord]
+ bit 0, a
+ ld hl, IndigoPlateauStatuesText2
+ jr nz, .ok
+ ld hl, IndigoPlateauStatuesText3
+.ok
+ call PrintText
+ jp TextScriptEnd
+
+IndigoPlateauStatuesText1:
+ TX_FAR _IndigoPlateauStatuesText1
+ db "@"
+
+IndigoPlateauStatuesText2:
+ TX_FAR _IndigoPlateauStatuesText2
+ db "@"
+
+IndigoPlateauStatuesText3:
+ TX_FAR _IndigoPlateauStatuesText3
+ db "@"
+
+BookOrSculptureText::
+ TX_ASM
+ ld hl, PokemonBooksText
+ ld a, [wCurMapTileset]
+ cp MANSION ; Celadon Mansion tileset
+ jr nz, .ok
+ aCoord 8, 6
+ cp $38
+ jr nz, .ok
+ ld hl, DiglettSculptureText
+.ok
+ call PrintText
+ jp TextScriptEnd
+
+PokemonBooksText:
+ TX_FAR _PokemonBooksText
+ db "@"
+
+DiglettSculptureText:
+ TX_FAR _DiglettSculptureText
+ db "@"
+
+ElevatorText::
+ TX_FAR _ElevatorText
+ db "@"
+
+TownMapText::
+ TX_FAR _TownMapText
+ TX_BLINK
+ TX_ASM
+ ld a, $1
+ ld [wDoNotWaitForButtonPressAfterDisplayingText], a
+ ld hl, wd730
+ set 6, [hl]
+ call GBPalWhiteOutWithDelay3
+ xor a
+ ld [hWY], a
+ inc a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call LoadFontTilePatterns
+ callba DisplayTownMap
+ ld hl, wd730
+ res 6, [hl]
+ ld de, TextScriptEnd
+ push de
+ ld a, [H_LOADEDROMBANK]
+ push af
+ jp CloseTextDisplay
+
+PokemonStuffText::
+ TX_FAR _PokemonStuffText
+ db "@"
--- /dev/null
+++ b/engine/events/hidden_object_functions7.asm
@@ -1,0 +1,467 @@
+PrintNewBikeText:
+ call EnableAutoTextBoxDrawing
+ tx_pre_jump NewBicycleText
+
+NewBicycleText::
+ TX_FAR _NewBicycleText
+ db "@"
+
+DisplayOakLabLeftPoster:
+ call EnableAutoTextBoxDrawing
+ tx_pre_jump PushStartText
+
+PushStartText::
+ TX_FAR _PushStartText
+ db "@"
+
+DisplayOakLabRightPoster:
+ call EnableAutoTextBoxDrawing
+ ld hl, wPokedexOwned
+ ld b, wPokedexOwnedEnd - wPokedexOwned
+ call CountSetBits
+ ld a, [wNumSetBits]
+ cp 2
+ tx_pre_id SaveOptionText
+ jr c, .ownLessThanTwo
+ ; own two or more mon
+ tx_pre_id StrengthsAndWeaknessesText
+.ownLessThanTwo
+ jp PrintPredefTextID
+
+SaveOptionText::
+ TX_FAR _SaveOptionText
+ db "@"
+
+StrengthsAndWeaknessesText::
+ TX_FAR _StrengthsAndWeaknessesText
+ db "@"
+
+SafariZoneCheck::
+ CheckEventHL EVENT_IN_SAFARI_ZONE ; if we are not in the Safari Zone,
+ jr z, SafariZoneGameStillGoing ; don't bother printing game over text
+ ld a, [wNumSafariBalls]
+ and a
+ jr z, SafariZoneGameOver
+ jr SafariZoneGameStillGoing
+
+SafariZoneCheckSteps::
+ ld a, [wSafariSteps]
+ ld b, a
+ ld a, [wSafariSteps + 1]
+ ld c, a
+ or b
+ jr z, SafariZoneGameOver
+ dec bc
+ ld a, b
+ ld [wSafariSteps], a
+ ld a, c
+ ld [wSafariSteps + 1], a
+SafariZoneGameStillGoing:
+ xor a
+ ld [wSafariZoneGameOver], a
+ ret
+
+SafariZoneGameOver:
+ call EnableAutoTextBoxDrawing
+ xor a
+ ld [wAudioFadeOutControl], a
+ dec a
+ call PlaySound
+ ld c, BANK(SFX_Safari_Zone_PA)
+ ld a, SFX_SAFARI_ZONE_PA
+ call PlayMusic
+.waitForMusicToPlay
+ ld a, [wChannelSoundIDs + Ch5]
+ cp SFX_SAFARI_ZONE_PA
+ jr nz, .waitForMusicToPlay
+ ld a, TEXT_SAFARI_GAME_OVER
+ ld [hSpriteIndexOrTextID], a
+ call DisplayTextID
+ xor a
+ ld [wPlayerMovingDirection], a
+ ld a, SAFARI_ZONE_GATE
+ ld [hWarpDestinationMap], a
+ ld a, $3
+ ld [wDestinationWarpID], a
+ ld a, $5
+ ld [wSafariZoneGateCurScript], a
+ SetEvent EVENT_SAFARI_GAME_OVER
+ ld a, 1
+ ld [wSafariZoneGameOver], a
+ ret
+
+PrintSafariGameOverText::
+ xor a
+ ld [wJoyIgnore], a
+ ld hl, SafariGameOverText
+ jp PrintText
+
+SafariGameOverText:
+ TX_ASM
+ ld a, [wNumSafariBalls]
+ and a
+ jr z, .noMoreSafariBalls
+ ld hl, TimesUpText
+ call PrintText
+.noMoreSafariBalls
+ ld hl, GameOverText
+ call PrintText
+ jp TextScriptEnd
+
+TimesUpText:
+ TX_FAR _TimesUpText
+ db "@"
+
+GameOverText:
+ TX_FAR _GameOverText
+ db "@"
+
+PrintCinnabarQuiz:
+ ld a, [wSpriteStateData1 + 9]
+ cp SPRITE_FACING_UP
+ ret nz
+ call EnableAutoTextBoxDrawing
+ tx_pre_jump CinnabarGymQuiz
+
+CinnabarGymQuiz::
+ TX_ASM
+ xor a
+ ld [wOpponentAfterWrongAnswer], a
+ ld a, [wHiddenObjectFunctionArgument]
+ push af
+ and $f
+ ld [hGymGateIndex], a
+ pop af
+ and $f0
+ swap a
+ ld [$ffdc], a
+ ld hl, CinnabarGymQuizIntroText
+ call PrintText
+ ld a, [hGymGateIndex]
+ dec a
+ add a
+ ld d, 0
+ ld e, a
+ ld hl, CinnabarQuizQuestions
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call PrintText
+ ld a, 1
+ ld [wDoNotWaitForButtonPressAfterDisplayingText], a
+ call CinnabarGymQuiz_1ea92
+ jp TextScriptEnd
+
+CinnabarGymQuizIntroText:
+ TX_FAR _CinnabarGymQuizIntroText
+ db "@"
+
+CinnabarQuizQuestions:
+ dw CinnabarQuizQuestionsText1
+ dw CinnabarQuizQuestionsText2
+ dw CinnabarQuizQuestionsText3
+ dw CinnabarQuizQuestionsText4
+ dw CinnabarQuizQuestionsText5
+ dw CinnabarQuizQuestionsText6
+
+CinnabarQuizQuestionsText1:
+ TX_FAR _CinnabarQuizQuestionsText1
+ db "@"
+
+CinnabarQuizQuestionsText2:
+ TX_FAR _CinnabarQuizQuestionsText2
+ db "@"
+
+CinnabarQuizQuestionsText3:
+ TX_FAR _CinnabarQuizQuestionsText3
+ db "@"
+
+CinnabarQuizQuestionsText4:
+ TX_FAR _CinnabarQuizQuestionsText4
+ db "@"
+
+CinnabarQuizQuestionsText5:
+ TX_FAR _CinnabarQuizQuestionsText5
+ db "@"
+
+CinnabarQuizQuestionsText6:
+ TX_FAR _CinnabarQuizQuestionsText6
+ db "@"
+
+CinnabarGymGateFlagAction:
+ EventFlagAddress hl, EVENT_CINNABAR_GYM_GATE0_UNLOCKED
+ predef_jump FlagActionPredef
+
+CinnabarGymQuiz_1ea92:
+ call YesNoChoice
+ ld a, [$ffdc]
+ ld c, a
+ ld a, [wCurrentMenuItem]
+ cp c
+ jr nz, .wrongAnswer
+ ld hl, wCurrentMapScriptFlags
+ set 5, [hl]
+ ld a, [hGymGateIndex]
+ ld [$ffe0], a
+ ld hl, CinnabarGymQuizCorrectText
+ call PrintText
+ ld a, [$ffe0]
+ AdjustEventBit EVENT_CINNABAR_GYM_GATE0_UNLOCKED, 0
+ ld c, a
+ ld b, FLAG_SET
+ call CinnabarGymGateFlagAction
+ jp UpdateCinnabarGymGateTileBlocks_
+.wrongAnswer
+ call WaitForSoundToFinish
+ ld a, SFX_DENIED
+ call PlaySound
+ call WaitForSoundToFinish
+ ld hl, CinnabarGymQuizIncorrectText
+ call PrintText
+ ld a, [hGymGateIndex]
+ add $2
+ AdjustEventBit EVENT_BEAT_CINNABAR_GYM_TRAINER_0, 2
+ ld c, a
+ ld b, FLAG_TEST
+ EventFlagAddress hl, EVENT_BEAT_CINNABAR_GYM_TRAINER_0
+ predef FlagActionPredef
+ ld a, c
+ and a
+ ret nz
+ ld a, [hGymGateIndex]
+ add $2
+ ld [wOpponentAfterWrongAnswer], a
+ ret
+
+CinnabarGymQuizCorrectText:
+ TX_SFX_ITEM_1
+ TX_FAR _CinnabarGymQuizCorrectText
+ TX_BLINK
+ TX_ASM
+
+ ld a, [$ffe0]
+ AdjustEventBit EVENT_CINNABAR_GYM_GATE0_UNLOCKED, 0
+ ld c, a
+ ld b, FLAG_TEST
+ call CinnabarGymGateFlagAction
+ ld a, c
+ and a
+ jp nz, TextScriptEnd
+ call WaitForSoundToFinish
+ ld a, SFX_GO_INSIDE
+ call PlaySound
+ call WaitForSoundToFinish
+ jp TextScriptEnd
+
+CinnabarGymQuizIncorrectText:
+ TX_FAR _CinnabarGymQuizIncorrectText
+ db "@"
+
+UpdateCinnabarGymGateTileBlocks_::
+; Update the overworld map with open floor blocks or locked gate blocks
+; depending on event flags.
+ ld a, 6
+ ld [hGymGateIndex], a
+.loop
+ ld a, [hGymGateIndex]
+ dec a
+ add a
+ add a
+ ld d, 0
+ ld e, a
+ ld hl, CinnabarGymGateCoords
+ add hl, de
+ ld a, [hli]
+ ld b, [hl]
+ ld c, a
+ inc hl
+ ld a, [hl]
+ ld [wGymGateTileBlock], a
+ push bc
+ ld a, [hGymGateIndex]
+ ld [$ffe0], a
+ AdjustEventBit EVENT_CINNABAR_GYM_GATE0_UNLOCKED, 0
+ ld c, a
+ ld b, FLAG_TEST
+ call CinnabarGymGateFlagAction
+ ld a, c
+ and a
+ jr nz, .unlocked
+ ld a, [wGymGateTileBlock]
+ jr .next
+.unlocked
+ ld a, $e
+.next
+ pop bc
+ ld [wNewTileBlockID], a
+ predef ReplaceTileBlock
+ ld hl, hGymGateIndex
+ dec [hl]
+ jr nz, .loop
+ ret
+
+CinnabarGymGateCoords:
+ ; format: x-coord, y-coord, direction, padding
+ ; direction: $54 = horizontal gate, $5f = vertical gate
+ db $09,$03,$54,$00
+ db $06,$03,$54,$00
+ db $06,$06,$54,$00
+ db $03,$08,$5f,$00
+ db $02,$06,$54,$00
+ db $02,$03,$54,$00
+
+PrintMagazinesText:
+ call EnableAutoTextBoxDrawing
+ tx_pre MagazinesText
+ ret
+
+MagazinesText::
+ TX_FAR _MagazinesText
+ db "@"
+
+BillsHousePC:
+ call EnableAutoTextBoxDrawing
+ ld a, [wSpriteStateData1 + 9]
+ cp SPRITE_FACING_UP
+ ret nz
+ CheckEvent EVENT_LEFT_BILLS_HOUSE_AFTER_HELPING
+ jr nz, .displayBillsHousePokemonList
+ CheckEventReuseA EVENT_USED_CELL_SEPARATOR_ON_BILL
+ jr nz, .displayBillsHouseMonitorText
+ CheckEventReuseA EVENT_BILL_SAID_USE_CELL_SEPARATOR
+ jr nz, .doCellSeparator
+.displayBillsHouseMonitorText
+ tx_pre_jump BillsHouseMonitorText
+.doCellSeparator
+ ld a, $1
+ ld [wDoNotWaitForButtonPressAfterDisplayingText], a
+ tx_pre BillsHouseInitiatedText
+ ld c, 32
+ call DelayFrames
+ ld a, SFX_TINK
+ call PlaySound
+ call WaitForSoundToFinish
+ ld c, 80
+ call DelayFrames
+ ld a, SFX_SHRINK
+ call PlaySound
+ call WaitForSoundToFinish
+ ld c, 48
+ call DelayFrames
+ ld a, SFX_TINK
+ call PlaySound
+ call WaitForSoundToFinish
+ ld c, 32
+ call DelayFrames
+ ld a, SFX_GET_ITEM_1
+ call PlaySound
+ call WaitForSoundToFinish
+ call PlayDefaultMusic
+ SetEvent EVENT_USED_CELL_SEPARATOR_ON_BILL
+ ret
+.displayBillsHousePokemonList
+ ld a, $1
+ ld [wDoNotWaitForButtonPressAfterDisplayingText], a
+ tx_pre BillsHousePokemonList
+ ret
+
+BillsHouseMonitorText::
+ TX_FAR _BillsHouseMonitorText
+ db "@"
+
+BillsHouseInitiatedText::
+ TX_FAR _BillsHouseInitiatedText
+ TX_BLINK
+ TX_ASM
+ ld a, $ff
+ ld [wNewSoundID], a
+ call PlaySound
+ ld c, 16
+ call DelayFrames
+ ld a, SFX_SWITCH
+ call PlaySound
+ call WaitForSoundToFinish
+ ld c, 60
+ call DelayFrames
+ jp TextScriptEnd
+
+BillsHousePokemonList::
+ TX_ASM
+ call SaveScreenTilesToBuffer1
+ ld hl, BillsHousePokemonListText1
+ call PrintText
+ xor a
+ ld [wMenuItemOffset], a ; not used
+ ld [wCurrentMenuItem], a
+ ld [wLastMenuItem], a
+ ld a, A_BUTTON | B_BUTTON
+ ld [wMenuWatchedKeys], a
+ ld a, 4
+ ld [wMaxMenuItem], a
+ ld a, 2
+ ld [wTopMenuItemY], a
+ ld a, 1
+ ld [wTopMenuItemX], a
+.billsPokemonLoop
+ ld hl, wd730
+ set 6, [hl]
+ coord hl, 0, 0
+ ld b, 10
+ ld c, 9
+ call TextBoxBorder
+ coord hl, 2, 2
+ ld de, BillsMonListText
+ call PlaceString
+ ld hl, BillsHousePokemonListText2
+ call PrintText
+ call SaveScreenTilesToBuffer2
+ call HandleMenuInput
+ bit 1, a ; pressed b
+ jr nz, .cancel
+ ld a, [wCurrentMenuItem]
+ add EEVEE
+ cp EEVEE
+ jr z, .displayPokedex
+ cp FLAREON
+ jr z, .displayPokedex
+ cp JOLTEON
+ jr z, .displayPokedex
+ cp VAPOREON
+ jr z, .displayPokedex
+ jr .cancel
+.displayPokedex
+ call DisplayPokedex
+ call LoadScreenTilesFromBuffer2
+ jr .billsPokemonLoop
+.cancel
+ ld hl, wd730
+ res 6, [hl]
+ call LoadScreenTilesFromBuffer2
+ jp TextScriptEnd
+
+BillsHousePokemonListText1:
+ TX_FAR _BillsHousePokemonListText1
+ db "@"
+
+BillsMonListText:
+ db "EEVEE"
+ next "FLAREON"
+ next "JOLTEON"
+ next "VAPOREON"
+ next "CANCEL@"
+
+BillsHousePokemonListText2:
+ TX_FAR _BillsHousePokemonListText2
+ db "@"
+
+DisplayOakLabEmailText:
+ ld a, [wSpriteStateData1 + 9]
+ cp SPRITE_FACING_UP
+ ret nz
+ call EnableAutoTextBoxDrawing
+ tx_pre_jump OakLabEmailText
+
+OakLabEmailText::
+ TX_FAR _OakLabEmailText
+ db "@"
--- /dev/null
+++ b/engine/events/in_game_trades.asm
@@ -1,0 +1,330 @@
+DoInGameTradeDialogue:
+; trigger the trade offer/action specified by wWhichTrade
+ call SaveScreenTilesToBuffer2
+ ld hl, TradeMons
+ ld a, [wWhichTrade]
+ ld b, a
+ swap a
+ sub b
+ sub b
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hli]
+ ld [wInGameTradeGiveMonSpecies], a
+ ld a, [hli]
+ ld [wInGameTradeReceiveMonSpecies], a
+ ld a, [hli]
+ push af
+ ld de, wInGameTradeMonNick
+ ld bc, NAME_LENGTH
+ call CopyData
+ pop af
+ ld l, a
+ ld h, 0
+ ld de, InGameTradeTextPointers
+ add hl, hl
+ add hl, de
+ ld a, [hli]
+ ld [wInGameTradeTextPointerTablePointer], a
+ ld a, [hl]
+ ld [wInGameTradeTextPointerTablePointer + 1], a
+ ld a, [wInGameTradeGiveMonSpecies]
+ ld de, wInGameTradeGiveMonName
+ call InGameTrade_GetMonName
+ ld a, [wInGameTradeReceiveMonSpecies]
+ ld de, wInGameTradeReceiveMonName
+ call InGameTrade_GetMonName
+ ld hl, wCompletedInGameTradeFlags
+ ld a, [wWhichTrade]
+ ld c, a
+ ld b, FLAG_TEST
+ predef FlagActionPredef
+ ld a, c
+ and a
+ ld a, $4
+ ld [wInGameTradeTextPointerTableIndex], a
+ jr nz, .printText
+; if the trade hasn't been done yet
+ xor a
+ ld [wInGameTradeTextPointerTableIndex], a
+ call .printText
+ ld a, $1
+ ld [wInGameTradeTextPointerTableIndex], a
+ call YesNoChoice
+ ld a, [wCurrentMenuItem]
+ and a
+ jr nz, .printText
+ call InGameTrade_DoTrade
+ jr c, .printText
+ ld hl, TradedForText
+ call PrintText
+.printText
+ ld hl, wInGameTradeTextPointerTableIndex
+ ld a, [hld] ; wInGameTradeTextPointerTableIndex
+ ld e, a
+ ld d, 0
+ ld a, [hld] ; wInGameTradeTextPointerTablePointer + 1
+ ld l, [hl] ; wInGameTradeTextPointerTablePointer
+ ld h, a
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp PrintText
+
+; copies name of species a to hl
+InGameTrade_GetMonName:
+ push de
+ ld [wd11e], a
+ call GetMonName
+ ld hl, wcd6d
+ pop de
+ ld bc, NAME_LENGTH
+ jp CopyData
+
+INCLUDE "data/trades.asm"
+
+InGameTrade_DoTrade:
+ xor a ; NORMAL_PARTY_MENU
+ ld [wPartyMenuTypeOrMessageID], a
+ dec a
+ ld [wUpdateSpritesEnabled], a
+ call DisplayPartyMenu
+ push af
+ call InGameTrade_RestoreScreen
+ pop af
+ ld a, $1
+ jp c, .tradeFailed ; jump if the player didn't select a pokemon
+ ld a, [wInGameTradeGiveMonSpecies]
+ ld b, a
+ ld a, [wcf91]
+ cp b
+ ld a, $2
+ jr nz, .tradeFailed ; jump if the selected mon's species is not the required one
+ ld a, [wWhichPokemon]
+ ld hl, wPartyMon1Level
+ ld bc, wPartyMon2 - wPartyMon1
+ call AddNTimes
+ ld a, [hl]
+ ld [wCurEnemyLVL], a
+ ld hl, wCompletedInGameTradeFlags
+ ld a, [wWhichTrade]
+ ld c, a
+ ld b, FLAG_SET
+ predef FlagActionPredef
+ ld hl, ConnectCableText
+ call PrintText
+ ld a, [wWhichPokemon]
+ push af
+ ld a, [wCurEnemyLVL]
+ push af
+ call LoadHpBarAndStatusTilePatterns
+ call InGameTrade_PrepareTradeData
+ predef InternalClockTradeAnim
+ pop af
+ ld [wCurEnemyLVL], a
+ pop af
+ ld [wWhichPokemon], a
+ ld a, [wInGameTradeReceiveMonSpecies]
+ ld [wcf91], a
+ xor a
+ ld [wMonDataLocation], a ; not used
+ ld [wRemoveMonFromBox], a
+ call RemovePokemon
+ ld a, $80 ; prevent the player from naming the mon
+ ld [wMonDataLocation], a
+ call AddPartyMon
+ call InGameTrade_CopyDataToReceivedMon
+ callab EvolveTradeMon
+ call ClearScreen
+ call InGameTrade_RestoreScreen
+ callba RedrawMapView
+ and a
+ ld a, $3
+ jr .tradeSucceeded
+.tradeFailed
+ scf
+.tradeSucceeded
+ ld [wInGameTradeTextPointerTableIndex], a
+ ret
+
+InGameTrade_RestoreScreen:
+ call GBPalWhiteOutWithDelay3
+ call RestoreScreenTilesAndReloadTilePatterns
+ call ReloadTilesetTilePatterns
+ call LoadScreenTilesFromBuffer2
+ call Delay3
+ call LoadGBPal
+ ld c, 10
+ call DelayFrames
+ jpba LoadWildData
+
+InGameTrade_PrepareTradeData:
+ ld hl, wTradedPlayerMonSpecies
+ ld a, [wInGameTradeGiveMonSpecies]
+ ld [hli], a ; wTradedPlayerMonSpecies
+ ld a, [wInGameTradeReceiveMonSpecies]
+ ld [hl], a ; wTradedEnemyMonSpecies
+ ld hl, wPartyMonOT
+ ld bc, NAME_LENGTH
+ ld a, [wWhichPokemon]
+ call AddNTimes
+ ld de, wTradedPlayerMonOT
+ ld bc, NAME_LENGTH
+ call InGameTrade_CopyData
+ ld hl, InGameTrade_TrainerString
+ ld de, wTradedEnemyMonOT
+ call InGameTrade_CopyData
+ ld de, wLinkEnemyTrainerName
+ call InGameTrade_CopyData
+ ld hl, wPartyMon1OTID
+ ld bc, wPartyMon2 - wPartyMon1
+ ld a, [wWhichPokemon]
+ call AddNTimes
+ ld de, wTradedPlayerMonOTID
+ ld bc, $2
+ call InGameTrade_CopyData
+ call Random
+ ld hl, hRandomAdd
+ ld de, wTradedEnemyMonOTID
+ jp CopyData
+
+InGameTrade_CopyData:
+ push hl
+ push bc
+ call CopyData
+ pop bc
+ pop hl
+ ret
+
+InGameTrade_CopyDataToReceivedMon:
+ ld hl, wPartyMonNicks
+ ld bc, NAME_LENGTH
+ call InGameTrade_GetReceivedMonPointer
+ ld hl, wInGameTradeMonNick
+ ld bc, NAME_LENGTH
+ call CopyData
+ ld hl, wPartyMonOT
+ ld bc, NAME_LENGTH
+ call InGameTrade_GetReceivedMonPointer
+ ld hl, InGameTrade_TrainerString
+ ld bc, NAME_LENGTH
+ call CopyData
+ ld hl, wPartyMon1OTID
+ ld bc, wPartyMon2 - wPartyMon1
+ call InGameTrade_GetReceivedMonPointer
+ ld hl, wTradedEnemyMonOTID
+ ld bc, $2
+ jp CopyData
+
+; the received mon's index is (partyCount - 1),
+; so this adds bc to hl (partyCount - 1) times and moves the result to de
+InGameTrade_GetReceivedMonPointer:
+ ld a, [wPartyCount]
+ dec a
+ call AddNTimes
+ ld e, l
+ ld d, h
+ ret
+
+InGameTrade_TrainerString:
+ ; "TRAINER@@@@@@@@@@"
+ db $5d, "@@@@@@@@@@"
+
+InGameTradeTextPointers:
+ dw TradeTextPointers1
+ dw TradeTextPointers2
+ dw TradeTextPointers3
+
+TradeTextPointers1:
+ dw WannaTrade1Text
+ dw NoTrade1Text
+ dw WrongMon1Text
+ dw Thanks1Text
+ dw AfterTrade1Text
+
+TradeTextPointers2:
+ dw WannaTrade2Text
+ dw NoTrade2Text
+ dw WrongMon2Text
+ dw Thanks2Text
+ dw AfterTrade2Text
+
+TradeTextPointers3:
+ dw WannaTrade3Text
+ dw NoTrade3Text
+ dw WrongMon3Text
+ dw Thanks3Text
+ dw AfterTrade3Text
+
+ConnectCableText:
+ TX_FAR _ConnectCableText
+ db "@"
+
+TradedForText:
+ TX_FAR _TradedForText
+ TX_SFX_KEY_ITEM
+ TX_DELAY
+ db "@"
+
+WannaTrade1Text:
+ TX_FAR _WannaTrade1Text
+ db "@"
+
+NoTrade1Text:
+ TX_FAR _NoTrade1Text
+ db "@"
+
+WrongMon1Text:
+ TX_FAR _WrongMon1Text
+ db "@"
+
+Thanks1Text:
+ TX_FAR _Thanks1Text
+ db "@"
+
+AfterTrade1Text:
+ TX_FAR _AfterTrade1Text
+ db "@"
+
+WannaTrade2Text:
+ TX_FAR _WannaTrade2Text
+ db "@"
+
+NoTrade2Text:
+ TX_FAR _NoTrade2Text
+ db "@"
+
+WrongMon2Text:
+ TX_FAR _WrongMon2Text
+ db "@"
+
+Thanks2Text:
+ TX_FAR _Thanks2Text
+ db "@"
+
+AfterTrade2Text:
+ TX_FAR _AfterTrade2Text
+ db "@"
+
+WannaTrade3Text:
+ TX_FAR _WannaTrade3Text
+ db "@"
+
+NoTrade3Text:
+ TX_FAR _NoTrade3Text
+ db "@"
+
+WrongMon3Text:
+ TX_FAR _WrongMon3Text
+ db "@"
+
+Thanks3Text:
+ TX_FAR _Thanks3Text
+ db "@"
+
+AfterTrade3Text:
+ TX_FAR _AfterTrade3Text
+ db "@"
--- /dev/null
+++ b/engine/events/oaks_aide.asm
@@ -1,0 +1,71 @@
+OaksAideScript:
+ ld hl, OaksAideHiText
+ call PrintText
+ call YesNoChoice
+ ld a, [wCurrentMenuItem]
+ and a
+ jr nz, .choseNo
+ ld hl, wPokedexOwned
+ ld b, wPokedexOwnedEnd - wPokedexOwned
+ call CountSetBits
+ ld a, [wNumSetBits]
+ ld [hOaksAideNumMonsOwned], a
+ ld b, a
+ ld a, [hOaksAideRequirement]
+ cp b
+ jr z, .giveItem
+ jr nc, .notEnoughOwnedMons
+.giveItem
+ ld hl, OaksAideHereYouGoText
+ call PrintText
+ ld a, [hOaksAideRewardItem]
+ ld b, a
+ ld c, 1
+ call GiveItem
+ jr nc, .bagFull
+ ld hl, OaksAideGotItemText
+ call PrintText
+ ld a, $1
+ jr .done
+.bagFull
+ ld hl, OaksAideNoRoomText
+ call PrintText
+ xor a
+ jr .done
+.notEnoughOwnedMons
+ ld hl, OaksAideUhOhText
+ call PrintText
+ ld a, $80
+ jr .done
+.choseNo
+ ld hl, OaksAideComeBackText
+ call PrintText
+ ld a, $ff
+.done
+ ld [hOaksAideResult], a
+ ret
+
+OaksAideHiText:
+ TX_FAR _OaksAideHiText
+ db "@"
+
+OaksAideUhOhText:
+ TX_FAR _OaksAideUhOhText
+ db "@"
+
+OaksAideComeBackText:
+ TX_FAR _OaksAideComeBackText
+ db "@"
+
+OaksAideHereYouGoText:
+ TX_FAR _OaksAideHereYouGoText
+ db "@"
+
+OaksAideGotItemText:
+ TX_FAR _OaksAideGotItemText
+ TX_SFX_ITEM_1
+ db "@"
+
+OaksAideNoRoomText:
+ TX_FAR _OaksAideNoRoomText
+ db "@"
--- /dev/null
+++ b/engine/events/pewter_guys.asm
@@ -1,0 +1,102 @@
+PewterGuys:
+ ld hl, wSimulatedJoypadStatesEnd
+ ld a, [wSimulatedJoypadStatesIndex]
+ dec a ; this decrement causes it to overwrite the last byte before $FF in the list
+ ld [wSimulatedJoypadStatesIndex], a
+ ld d, 0
+ ld e, a
+ add hl, de
+ ld d, h
+ ld e, l
+ ld hl, PointerTable_37ce6
+ ld a, [wWhichPewterGuy]
+ add a
+ ld b, 0
+ ld c, a
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [wYCoord]
+ ld b, a
+ ld a, [wXCoord]
+ ld c, a
+.findMatchingCoordsLoop
+ ld a, [hli]
+ cp b
+ jr nz, .nextEntry1
+ ld a, [hli]
+ cp c
+ jr nz, .nextEntry2
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+.copyMovementDataLoop
+ ld a, [hli]
+ cp $ff
+ ret z
+ ld [de], a
+ inc de
+ ld a, [wSimulatedJoypadStatesIndex]
+ inc a
+ ld [wSimulatedJoypadStatesIndex], a
+ jr .copyMovementDataLoop
+.nextEntry1
+ inc hl
+.nextEntry2
+ inc hl
+ inc hl
+ jr .findMatchingCoordsLoop
+
+PointerTable_37ce6:
+ dw PewterMuseumGuyCoords
+ dw PewterGymGuyCoords
+
+; these are the four coordinates of the spaces below, above, to the left and
+; to the right of the museum guy, and pointers to different movements for
+; the player to make to get positioned before the main movement.
+PewterMuseumGuyCoords:
+ db 18, 27
+ dw .down
+ db 16, 27
+ dw .up
+ db 17, 26
+ dw .left
+ db 17, 28
+ dw .right
+
+.down
+ db D_UP, D_UP, $ff
+.up
+ db D_RIGHT, D_LEFT, $ff
+.left
+ db D_UP, D_RIGHT, $ff
+.right
+ db D_UP, D_LEFT, $ff
+
+; these are the five coordinates which trigger the gym guy and pointers to
+; different movements for the player to make to get positioned before the
+; main movement
+; $00 is a pause
+PewterGymGuyCoords:
+ db 16, 34
+ dw .one
+ db 17, 35
+ dw .two
+ db 18, 37
+ dw .three
+ db 19, 37
+ dw .four
+ db 17, 36
+ dw .five
+
+.one
+ db D_LEFT, D_DOWN, D_DOWN, D_RIGHT, $ff
+.two
+ db D_LEFT, D_DOWN, D_RIGHT, D_LEFT, $ff
+.three
+ db D_LEFT, D_LEFT, D_LEFT, $00, $00, $00, $00, $00, $00, $00, $00, $ff
+.four
+ db D_LEFT, D_LEFT, D_UP, D_LEFT, $ff
+.five
+ db D_LEFT, D_DOWN, D_LEFT, $00, $00, $00, $00, $00, $00, $00, $00, $ff
--- /dev/null
+++ b/engine/events/pick_up_item.asm
@@ -1,0 +1,54 @@
+PickUpItem:
+ call EnableAutoTextBoxDrawing
+
+ ld a, [hSpriteIndexOrTextID]
+ ld b, a
+ ld hl, wMissableObjectList
+.missableObjectsListLoop
+ ld a, [hli]
+ cp $ff
+ ret z
+ cp b
+ jr z, .isMissable
+ inc hl
+ jr .missableObjectsListLoop
+
+.isMissable
+ ld a, [hl]
+ ld [$ffdb], a
+
+ ld hl, wMapSpriteExtraData
+ ld a, [hSpriteIndexOrTextID]
+ dec a
+ add a
+ ld d, 0
+ ld e, a
+ add hl, de
+ ld a, [hl]
+ ld b, a ; item
+ ld c, 1 ; quantity
+ call GiveItem
+ jr nc, .BagFull
+
+ ld a, [$ffdb]
+ ld [wMissableObjectIndex], a
+ predef HideObject
+ ld a, 1
+ ld [wDoNotWaitForButtonPressAfterDisplayingText], a
+ ld hl, FoundItemText
+ jr .print
+
+.BagFull
+ ld hl, NoMoreRoomForItemText
+ call PrintText
+ ret
+
+FoundItemText:
+ TX_FAR _FoundItemText
+ TX_SFX_ITEM_1
+ db "@"
+
+NoMoreRoomForItemText:
+ TX_FAR _NoMoreRoomForItemText
+ db "@"
--- /dev/null
+++ b/engine/events/poison.asm
@@ -1,0 +1,112 @@
+ApplyOutOfBattlePoisonDamage:
+ ld a, [wd730]
+ add a
+ jp c, .noBlackOut ; no black out if joypad states are being simulated
+ ld a, [wPartyCount]
+ and a
+ jp z, .noBlackOut
+ call IncrementDayCareMonExp
+ ld a, [wStepCounter]
+ and $3 ; is the counter a multiple of 4?
+ jp nz, .noBlackOut ; only apply poison damage every fourth step
+ ld [wWhichPokemon], a
+ ld hl, wPartyMon1Status
+ ld de, wPartySpecies
+.applyDamageLoop
+ ld a, [hl]
+ and (1 << PSN)
+ jr z, .nextMon2 ; not poisoned
+ dec hl
+ dec hl
+ ld a, [hld]
+ ld b, a
+ ld a, [hli]
+ or b
+ jr z, .nextMon ; already fainted
+; subtract 1 from HP
+ ld a, [hl]
+ dec a
+ ld [hld], a
+ inc a
+ jr nz, .noBorrow
+; borrow 1 from upper byte of HP
+ dec [hl]
+ inc hl
+ jr .nextMon
+.noBorrow
+ ld a, [hli]
+ or [hl]
+ jr nz, .nextMon ; didn't faint from damage
+; the mon fainted from the damage
+ push hl
+ inc hl
+ inc hl
+ ld [hl], a
+ ld a, [de]
+ ld [wd11e], a
+ push de
+ ld a, [wWhichPokemon]
+ ld hl, wPartyMonNicks
+ call GetPartyMonName
+ xor a
+ ld [wJoyIgnore], a
+ call EnableAutoTextBoxDrawing
+ ld a, TEXT_MON_FAINTED
+ ld [hSpriteIndexOrTextID], a
+ call DisplayTextID
+ pop de
+ pop hl
+.nextMon
+ inc hl
+ inc hl
+.nextMon2
+ inc de
+ ld a, [de]
+ inc a
+ jr z, .applyDamageLoopDone
+ ld bc, wPartyMon2 - wPartyMon1
+ add hl, bc
+ push hl
+ ld hl, wWhichPokemon
+ inc [hl]
+ pop hl
+ jr .applyDamageLoop
+.applyDamageLoopDone
+ ld hl, wPartyMon1Status
+ ld a, [wPartyCount]
+ ld d, a
+ ld e, 0
+.countPoisonedLoop
+ ld a, [hl]
+ and (1 << PSN)
+ or e
+ ld e, a
+ ld bc, wPartyMon2 - wPartyMon1
+ add hl, bc
+ dec d
+ jr nz, .countPoisonedLoop
+ ld a, e
+ and a ; are any party members poisoned?
+ jr z, .skipPoisonEffectAndSound
+ ld b, $2
+ predef ChangeBGPalColor0_4Frames ; change BG white to dark grey for 4 frames
+ ld a, SFX_POISONED
+ call PlaySound
+.skipPoisonEffectAndSound
+ predef AnyPartyAlive
+ ld a, d
+ and a
+ jr nz, .noBlackOut
+ call EnableAutoTextBoxDrawing
+ ld a, TEXT_BLACKED_OUT
+ ld [hSpriteIndexOrTextID], a
+ call DisplayTextID
+ ld hl, wd72e
+ set 5, [hl]
+ ld a, $ff
+ jr .done
+.noBlackOut
+ xor a
+.done
+ ld [wOutOfBattleBlackout], a
+ ret
--- /dev/null
+++ b/engine/events/pokecenter.asm
@@ -1,0 +1,68 @@
+DisplayPokemonCenterDialogue_::
+ call SaveScreenTilesToBuffer1 ; save screen
+ ld hl, PokemonCenterWelcomeText
+ call PrintText
+ ld hl, wd72e
+ bit 2, [hl]
+ set 1, [hl]
+ set 2, [hl]
+ jr nz, .skipShallWeHealYourPokemon
+ ld hl, ShallWeHealYourPokemonText
+ call PrintText
+.skipShallWeHealYourPokemon
+ call YesNoChoicePokeCenter ; yes/no menu
+ ld a, [wCurrentMenuItem]
+ and a
+ jr nz, .declinedHealing ; if the player chose No
+ call SetLastBlackoutMap
+ call LoadScreenTilesFromBuffer1 ; restore screen
+ ld hl, NeedYourPokemonText
+ call PrintText
+ ld a, $18
+ ld [wSpriteStateData1 + $12], a ; make the nurse turn to face the machine
+ call Delay3
+ predef HealParty
+ callba AnimateHealingMachine ; do the healing machine animation
+ xor a
+ ld [wAudioFadeOutControl], a
+ ld a, [wAudioSavedROMBank]
+ ld [wAudioROMBank], a
+ ld a, [wMapMusicSoundID]
+ ld [wLastMusicSoundID], a
+ ld [wNewSoundID], a
+ call PlaySound
+ ld hl, PokemonFightingFitText
+ call PrintText
+ ld a, $14
+ ld [wSpriteStateData1 + $12], a ; make the nurse bow
+ ld c, a
+ call DelayFrames
+ jr .done
+.declinedHealing
+ call LoadScreenTilesFromBuffer1 ; restore screen
+.done
+ ld hl, PokemonCenterFarewellText
+ call PrintText
+ jp UpdateSprites
+
+PokemonCenterWelcomeText:
+ TX_FAR _PokemonCenterWelcomeText
+ db "@"
+
+ShallWeHealYourPokemonText:
+ TX_DELAY
+ TX_FAR _ShallWeHealYourPokemonText
+ db "@"
+
+NeedYourPokemonText:
+ TX_FAR _NeedYourPokemonText
+ db "@"
+
+PokemonFightingFitText:
+ TX_FAR _PokemonFightingFitText
+ db "@"
+
+PokemonCenterFarewellText:
+ TX_DELAY
+ TX_FAR _PokemonCenterFarewellText
+ db "@"
--- /dev/null
+++ b/engine/events/pokedex_rating.asm
@@ -1,0 +1,154 @@
+DisplayDexRating:
+ ld hl, wPokedexSeen
+ ld b, wPokedexSeenEnd - wPokedexSeen
+ call CountSetBits
+ ld a, [wNumSetBits]
+ ld [hDexRatingNumMonsSeen], a
+ ld hl, wPokedexOwned
+ ld b, wPokedexOwnedEnd - wPokedexOwned
+ call CountSetBits
+ ld a, [wNumSetBits]
+ ld [hDexRatingNumMonsOwned], a
+ ld hl, DexRatingsTable
+.findRating
+ ld a, [hli]
+ ld b, a
+ ld a, [hDexRatingNumMonsOwned]
+ cp b
+ jr c, .foundRating
+ inc hl
+ inc hl
+ jr .findRating
+.foundRating
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a ; load text pointer into hl
+ CheckAndResetEventA EVENT_HALL_OF_FAME_DEX_RATING
+ jr nz, .hallOfFame
+ push hl
+ ld hl, PokedexRatingText_441cc
+ call PrintText
+ pop hl
+ call PrintText
+ callba PlayPokedexRatingSfx
+ jp WaitForTextScrollButtonPress
+.hallOfFame
+ ld de, wDexRatingNumMonsSeen
+ ld a, [hDexRatingNumMonsSeen]
+ ld [de], a
+ inc de
+ ld a, [hDexRatingNumMonsOwned]
+ ld [de], a
+ inc de
+.copyRatingTextLoop
+ ld a, [hli]
+ cp "@"
+ jr z, .doneCopying
+ ld [de], a
+ inc de
+ jr .copyRatingTextLoop
+.doneCopying
+ ld [de], a
+ ret
+
+PokedexRatingText_441cc:
+ TX_FAR _OaksLabText_441cc
+ db "@"
+
+DexRatingsTable:
+ db 10
+ dw PokedexRatingText_44201
+ db 20
+ dw PokedexRatingText_44206
+ db 30
+ dw PokedexRatingText_4420b
+ db 40
+ dw PokedexRatingText_44210
+ db 50
+ dw PokedexRatingText_44215
+ db 60
+ dw PokedexRatingText_4421a
+ db 70
+ dw PokedexRatingText_4421f
+ db 80
+ dw PokedexRatingText_44224
+ db 90
+ dw PokedexRatingText_44229
+ db 100
+ dw PokedexRatingText_4422e
+ db 110
+ dw PokedexRatingText_44233
+ db 120
+ dw PokedexRatingText_44238
+ db 130
+ dw PokedexRatingText_4423d
+ db 140
+ dw PokedexRatingText_44242
+ db 150
+ dw PokedexRatingText_44247
+ db NUM_POKEMON + 1
+ dw PokedexRatingText_4424c
+
+PokedexRatingText_44201:
+ TX_FAR _OaksLabText_44201
+ db "@"
+
+PokedexRatingText_44206:
+ TX_FAR _OaksLabText_44206
+ db "@"
+
+PokedexRatingText_4420b:
+ TX_FAR _OaksLabText_4420b
+ db "@"
+
+PokedexRatingText_44210:
+ TX_FAR _OaksLabText_44210
+ db "@"
+
+PokedexRatingText_44215:
+ TX_FAR _OaksLabText_44215
+ db "@"
+
+PokedexRatingText_4421a:
+ TX_FAR _OaksLabText_4421a
+ db "@"
+
+PokedexRatingText_4421f:
+ TX_FAR _OaksLabText_4421f
+ db "@"
+
+PokedexRatingText_44224:
+ TX_FAR _OaksLabText_44224
+ db "@"
+
+PokedexRatingText_44229:
+ TX_FAR _OaksLabText_44229
+ db "@"
+
+PokedexRatingText_4422e:
+ TX_FAR _OaksLabText_4422e
+ db "@"
+
+PokedexRatingText_44233:
+ TX_FAR _OaksLabText_44233
+ db "@"
+
+PokedexRatingText_44238:
+ TX_FAR _OaksLabText_44238
+ db "@"
+
+PokedexRatingText_4423d:
+ TX_FAR _OaksLabText_4423d
+ db "@"
+
+PokedexRatingText_44242:
+ TX_FAR _OaksLabText_44242
+ db "@"
+
+PokedexRatingText_44247:
+ TX_FAR _OaksLabText_44247
+ db "@"
+
+PokedexRatingText_4424c:
+ TX_FAR _OaksLabText_4424c
+ db "@"
--- /dev/null
+++ b/engine/events/pokemart.asm
@@ -1,0 +1,272 @@
+DisplayPokemartDialogue_::
+ ld a, [wListScrollOffset]
+ ld [wSavedListScrollOffset], a
+ call UpdateSprites
+ xor a
+ ld [wBoughtOrSoldItemInMart], a
+.loop
+ xor a
+ ld [wListScrollOffset], a
+ ld [wCurrentMenuItem], a
+ ld [wPlayerMonNumber], a
+ inc a
+ ld [wPrintItemPrices], a
+ ld a, MONEY_BOX
+ ld [wTextBoxID], a
+ call DisplayTextBoxID
+ ld a, BUY_SELL_QUIT_MENU
+ ld [wTextBoxID], a
+ call DisplayTextBoxID
+
+; This code is useless. It copies the address of the pokemart's inventory to hl,
+; but the address is never used.
+ ld hl, wItemListPointer
+ ld a, [hli]
+ ld l, [hl]
+ ld h, a
+
+ ld a, [wMenuExitMethod]
+ cp CANCELLED_MENU
+ jp z, .done
+ ld a, [wChosenMenuItem]
+ and a ; buying?
+ jp z, .buyMenu
+ dec a ; selling?
+ jp z, .sellMenu
+ dec a ; quitting?
+ jp z, .done
+.sellMenu
+
+; the same variables are set again below, so this code has no effect
+ xor a
+ ld [wPrintItemPrices], a
+ ld a, INIT_BAG_ITEM_LIST
+ ld [wInitListType], a
+ callab InitList
+
+ ld a, [wNumBagItems]
+ and a
+ jp z, .bagEmpty
+ ld hl, PokemonSellingGreetingText
+ call PrintText
+ call SaveScreenTilesToBuffer1 ; save screen
+.sellMenuLoop
+ call LoadScreenTilesFromBuffer1 ; restore saved screen
+ ld a, MONEY_BOX
+ ld [wTextBoxID], a
+ call DisplayTextBoxID ; draw money text box
+ ld hl, wNumBagItems
+ ld a, l
+ ld [wListPointer], a
+ ld a, h
+ ld [wListPointer + 1], a
+ xor a
+ ld [wPrintItemPrices], a
+ ld [wCurrentMenuItem], a
+ ld a, ITEMLISTMENU
+ ld [wListMenuID], a
+ call DisplayListMenuID
+ jp c, .returnToMainPokemartMenu ; if the player closed the menu
+.confirmItemSale ; if the player is trying to sell a specific item
+ call IsKeyItem
+ ld a, [wIsKeyItem]
+ and a
+ jr nz, .unsellableItem
+ ld a, [wcf91]
+ call IsItemHM
+ jr c, .unsellableItem
+ ld a, PRICEDITEMLISTMENU
+ ld [wListMenuID], a
+ ld [hHalveItemPrices], a ; halve prices when selling
+ call DisplayChooseQuantityMenu
+ inc a
+ jr z, .sellMenuLoop ; if the player closed the choose quantity menu with the B button
+ ld hl, PokemartTellSellPriceText
+ lb bc, 14, 1 ; location that PrintText always prints to, this is useless
+ call PrintText
+ coord hl, 14, 7
+ lb bc, 8, 15
+ ld a, TWO_OPTION_MENU
+ ld [wTextBoxID], a
+ call DisplayTextBoxID ; yes/no menu
+ ld a, [wMenuExitMethod]
+ cp CHOSE_SECOND_ITEM
+ jr z, .sellMenuLoop ; if the player chose No or pressed the B button
+
+; The following code is supposed to check if the player chose No, but the above
+; check already catches it.
+ ld a, [wChosenMenuItem]
+ dec a
+ jr z, .sellMenuLoop
+
+.sellItem
+ ld a, [wBoughtOrSoldItemInMart]
+ and a
+ jr nz, .skipSettingFlag1
+ inc a
+ ld [wBoughtOrSoldItemInMart], a
+.skipSettingFlag1
+ call AddAmountSoldToMoney
+ ld hl, wNumBagItems
+ call RemoveItemFromInventory
+ jp .sellMenuLoop
+.unsellableItem
+ ld hl, PokemartUnsellableItemText
+ call PrintText
+ jp .returnToMainPokemartMenu
+.bagEmpty
+ ld hl, PokemartItemBagEmptyText
+ call PrintText
+ call SaveScreenTilesToBuffer1
+ jp .returnToMainPokemartMenu
+.buyMenu
+
+; the same variables are set again below, so this code has no effect
+ ld a, 1
+ ld [wPrintItemPrices], a
+ ld a, INIT_OTHER_ITEM_LIST
+ ld [wInitListType], a
+ callab InitList
+
+ ld hl, PokemartBuyingGreetingText
+ call PrintText
+ call SaveScreenTilesToBuffer1
+.buyMenuLoop
+ call LoadScreenTilesFromBuffer1
+ ld a, MONEY_BOX
+ ld [wTextBoxID], a
+ call DisplayTextBoxID
+ ld hl, wItemList
+ ld a, l
+ ld [wListPointer], a
+ ld a, h
+ ld [wListPointer + 1], a
+ xor a
+ ld [wCurrentMenuItem], a
+ inc a
+ ld [wPrintItemPrices], a
+ inc a ; a = 2 (PRICEDITEMLISTMENU)
+ ld [wListMenuID], a
+ call DisplayListMenuID
+ jr c, .returnToMainPokemartMenu ; if the player closed the menu
+ ld a, 99
+ ld [wMaxItemQuantity], a
+ xor a
+ ld [hHalveItemPrices], a ; don't halve item prices when buying
+ call DisplayChooseQuantityMenu
+ inc a
+ jr z, .buyMenuLoop ; if the player closed the choose quantity menu with the B button
+ ld a, [wcf91] ; item ID
+ ld [wd11e], a ; store item ID for GetItemName
+ call GetItemName
+ call CopyStringToCF4B ; copy name to wcf4b
+ ld hl, PokemartTellBuyPriceText
+ call PrintText
+ coord hl, 14, 7
+ lb bc, 8, 15
+ ld a, TWO_OPTION_MENU
+ ld [wTextBoxID], a
+ call DisplayTextBoxID ; yes/no menu
+ ld a, [wMenuExitMethod]
+ cp CHOSE_SECOND_ITEM
+ jp z, .buyMenuLoop ; if the player chose No or pressed the B button
+
+; The following code is supposed to check if the player chose No, but the above
+; check already catches it.
+ ld a, [wChosenMenuItem]
+ dec a
+ jr z, .buyMenuLoop
+
+.buyItem
+ call .isThereEnoughMoney
+ jr c, .notEnoughMoney
+ ld hl, wNumBagItems
+ call AddItemToInventory
+ jr nc, .bagFull
+ call SubtractAmountPaidFromMoney
+ ld a, [wBoughtOrSoldItemInMart]
+ and a
+ jr nz, .skipSettingFlag2
+ ld a, 1
+ ld [wBoughtOrSoldItemInMart], a
+.skipSettingFlag2
+ ld a, SFX_PURCHASE
+ call PlaySoundWaitForCurrent
+ call WaitForSoundToFinish
+ ld hl, PokemartBoughtItemText
+ call PrintText
+ jp .buyMenuLoop
+.returnToMainPokemartMenu
+ call LoadScreenTilesFromBuffer1
+ ld a, MONEY_BOX
+ ld [wTextBoxID], a
+ call DisplayTextBoxID
+ ld hl, PokemartAnythingElseText
+ call PrintText
+ jp .loop
+.isThereEnoughMoney
+ ld de, wPlayerMoney
+ ld hl, hMoney
+ ld c, 3 ; length of money in bytes
+ jp StringCmp
+.notEnoughMoney
+ ld hl, PokemartNotEnoughMoneyText
+ call PrintText
+ jr .returnToMainPokemartMenu
+.bagFull
+ ld hl, PokemartItemBagFullText
+ call PrintText
+ jr .returnToMainPokemartMenu
+.done
+ ld hl, PokemartThankYouText
+ call PrintText
+ ld a, 1
+ ld [wUpdateSpritesEnabled], a
+ call UpdateSprites
+ ld a, [wSavedListScrollOffset]
+ ld [wListScrollOffset], a
+ ret
+
+PokemartBuyingGreetingText:
+ TX_FAR _PokemartBuyingGreetingText
+ db "@"
+
+PokemartTellBuyPriceText:
+ TX_FAR _PokemartTellBuyPriceText
+ db "@"
+
+PokemartBoughtItemText:
+ TX_FAR _PokemartBoughtItemText
+ db "@"
+
+PokemartNotEnoughMoneyText:
+ TX_FAR _PokemartNotEnoughMoneyText
+ db "@"
+
+PokemartItemBagFullText:
+ TX_FAR _PokemartItemBagFullText
+ db "@"
+
+PokemonSellingGreetingText:
+ TX_FAR _PokemonSellingGreetingText
+ db "@"
+
+PokemartTellSellPriceText:
+ TX_FAR _PokemartTellSellPriceText
+ db "@"
+
+PokemartItemBagEmptyText:
+ TX_FAR _PokemartItemBagEmptyText
+ db "@"
+
+PokemartUnsellableItemText:
+ TX_FAR _PokemartUnsellableItemText
+ db "@"
+
+PokemartThankYouText:
+ TX_FAR _PokemartThankYouText
+ db "@"
+
+PokemartAnythingElseText:
+ TX_FAR _PokemartAnythingElseText
+ db "@"
--- /dev/null
+++ b/engine/events/prize_menu.asm
@@ -1,0 +1,306 @@
+CeladonPrizeMenu::
+ ld b, COIN_CASE
+ call IsItemInBag
+ jr nz, .havingCoinCase
+ ld hl, RequireCoinCaseTextPtr
+ jp PrintText
+.havingCoinCase
+ ld hl, wd730
+ set 6, [hl] ; disable letter-printing delay
+ ld hl, ExchangeCoinsForPrizesTextPtr
+ call PrintText
+; the following are the menu settings
+ xor a
+ ld [wCurrentMenuItem], a
+ ld [wLastMenuItem], a
+ ld a, A_BUTTON | B_BUTTON
+ ld [wMenuWatchedKeys], a
+ ld a, $03
+ ld [wMaxMenuItem], a
+ ld a, $04
+ ld [wTopMenuItemY], a
+ ld a, $01
+ ld [wTopMenuItemX], a
+ call PrintPrizePrice
+ coord hl, 0, 2
+ ld b, 8
+ ld c, 16
+ call TextBoxBorder
+ call GetPrizeMenuId
+ call UpdateSprites
+ ld hl, WhichPrizeTextPtr
+ call PrintText
+ call HandleMenuInput ; menu choice handler
+ bit 1, a ; keypress = B (Cancel)
+ jr nz, .noChoice
+ ld a, [wCurrentMenuItem]
+ cp 3 ; "NO,THANKS" choice
+ jr z, .noChoice
+ call HandlePrizeChoice
+.noChoice
+ ld hl, wd730
+ res 6, [hl]
+ ret
+
+RequireCoinCaseTextPtr:
+ TX_FAR _RequireCoinCaseText
+ TX_WAIT
+ db "@"
+
+ExchangeCoinsForPrizesTextPtr:
+ TX_FAR _ExchangeCoinsForPrizesText
+ db "@"
+
+WhichPrizeTextPtr:
+ TX_FAR _WhichPrizeText
+ db "@"
+
+GetPrizeMenuId:
+; determine which one among the three
+; prize-texts has been selected
+; using the text ID (stored in [hSpriteIndexOrTextID])
+; load the three prizes at wd13d-wd13f
+; load the three prices at wd141-wd146
+; display the three prizes' names
+; (distinguishing between Pokemon names
+; and Items (specifically TMs) names)
+ ld a, [hSpriteIndexOrTextID]
+ sub 3 ; prize-texts' id are 3, 4 and 5
+ ld [wWhichPrizeWindow], a ; prize-texts' id (relative, i.e. 0, 1 or 2)
+ add a
+ add a
+ ld d, 0
+ ld e, a
+ ld hl, PrizeDifferentMenuPtrs
+ add hl, de
+ ld a, [hli]
+ ld d, [hl]
+ ld e, a
+ inc hl
+ push hl
+ ld hl, wPrize1
+ call CopyString
+ pop hl
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, wPrize1Price
+ ld bc, 6
+ call CopyData
+ ld a, [wWhichPrizeWindow]
+ cp 2 ;is TM_menu?
+ jr nz, .putMonName
+ ld a, [wPrize1]
+ ld [wd11e], a
+ call GetItemName
+ coord hl, 2, 4
+ call PlaceString
+ ld a, [wPrize2]
+ ld [wd11e], a
+ call GetItemName
+ coord hl, 2, 6
+ call PlaceString
+ ld a, [wPrize3]
+ ld [wd11e], a
+ call GetItemName
+ coord hl, 2, 8
+ call PlaceString
+ jr .putNoThanksText
+.putMonName
+ ld a, [wPrize1]
+ ld [wd11e], a
+ call GetMonName
+ coord hl, 2, 4
+ call PlaceString
+ ld a, [wPrize2]
+ ld [wd11e], a
+ call GetMonName
+ coord hl, 2, 6
+ call PlaceString
+ ld a, [wPrize3]
+ ld [wd11e], a
+ call GetMonName
+ coord hl, 2, 8
+ call PlaceString
+.putNoThanksText
+ coord hl, 2, 10
+ ld de, NoThanksText
+ call PlaceString
+; put prices on the right side of the textbox
+ ld de, wPrize1Price
+ coord hl, 13, 5
+; reg. c:
+; [low nybble] number of bytes
+; [bit 765 = %100] space-padding (not zero-padding)
+ ld c, (1 << 7 | 2)
+; Function $15CD displays BCD value (same routine
+; used by text-command $02)
+ call PrintBCDNumber
+ ld de, wPrize2Price
+ coord hl, 13, 7
+ ld c, (1 << 7 | 2)
+ call PrintBCDNumber
+ ld de, wPrize3Price
+ coord hl, 13, 9
+ ld c, (1 << 7 | 2)
+ jp PrintBCDNumber
+
+INCLUDE "data/prizes.asm"
+
+PrintPrizePrice:
+ coord hl, 11, 0
+ ld b, 1
+ ld c, 7
+ call TextBoxBorder
+ call UpdateSprites
+ coord hl, 12, 0
+ ld de, .CoinString
+ call PlaceString
+ coord hl, 13, 1
+ ld de, .SixSpacesString
+ call PlaceString
+ coord hl, 13, 1
+ ld de, wPlayerCoins
+ ld c, %10000010
+ call PrintBCDNumber
+ ret
+
+.CoinString:
+ db "COIN@"
+
+.SixSpacesString:
+ db " @"
+
+LoadCoinsToSubtract:
+ ld a, [wWhichPrize]
+ add a
+ ld d, 0
+ ld e, a
+ ld hl, wPrize1Price
+ add hl, de ; get selected prize's price
+ xor a
+ ld [hUnusedCoinsByte], a
+ ld a, [hli]
+ ld [hCoins], a
+ ld a, [hl]
+ ld [hCoins + 1], a
+ ret
+
+HandlePrizeChoice:
+ ld a, [wCurrentMenuItem]
+ ld [wWhichPrize], a
+ ld d, 0
+ ld e, a
+ ld hl, wPrize1
+ add hl, de
+ ld a, [hl]
+ ld [wd11e], a
+ ld a, [wWhichPrizeWindow]
+ cp 2 ; is prize a TM?
+ jr nz, .getMonName
+ call GetItemName
+ jr .givePrize
+.getMonName
+ call GetMonName
+.givePrize
+ ld hl, SoYouWantPrizeTextPtr
+ call PrintText
+ call YesNoChoice
+ ld a, [wCurrentMenuItem] ; yes/no answer (Y=0, N=1)
+ and a
+ jr nz, .printOhFineThen
+ call LoadCoinsToSubtract
+ call HasEnoughCoins
+ jr c, .notEnoughCoins
+ ld a, [wWhichPrizeWindow]
+ cp $02
+ jr nz, .giveMon
+ ld a, [wd11e]
+ ld b, a
+ ld a, 1
+ ld c, a
+ call GiveItem
+ jr nc, .bagFull
+ jr .subtractCoins
+.giveMon
+ ld a, [wd11e]
+ ld [wcf91], a
+ push af
+ call GetPrizeMonLevel
+ ld c, a
+ pop af
+ ld b, a
+ call GivePokemon
+
+; If either the party or box was full, wait after displaying message.
+ push af
+ ld a, [wAddedToParty]
+ and a
+ call z, WaitForTextScrollButtonPress
+ pop af
+
+; If the mon couldn't be given to the player (because both the party and box
+; were full), return without subtracting coins.
+ ret nc
+
+.subtractCoins
+ call LoadCoinsToSubtract
+ ld hl, hCoins + 1
+ ld de, wPlayerCoins + 1
+ ld c, $02 ; how many bytes
+ predef SubBCDPredef
+ jp PrintPrizePrice
+.bagFull
+ ld hl, PrizeRoomBagIsFullTextPtr
+ jp PrintText
+.notEnoughCoins
+ ld hl, SorryNeedMoreCoinsText
+ jp PrintText
+.printOhFineThen
+ ld hl, OhFineThenTextPtr
+ jp PrintText
+
+UnknownPrizeData:
+; XXX what's this?
+ db $00,$01,$00,$01,$00,$01,$00,$00,$01
+
+HereYouGoTextPtr:
+ TX_FAR _HereYouGoText
+ TX_WAIT
+ db "@"
+
+SoYouWantPrizeTextPtr:
+ TX_FAR _SoYouWantPrizeText
+ db "@"
+
+SorryNeedMoreCoinsText:
+ TX_FAR _SorryNeedMoreCoinsText
+ TX_WAIT
+ db "@"
+
+PrizeRoomBagIsFullTextPtr:
+ TX_FAR _OopsYouDontHaveEnoughRoomText
+ TX_WAIT
+ db "@"
+
+OhFineThenTextPtr:
+ TX_FAR _OhFineThenText
+ TX_WAIT
+ db "@"
+
+GetPrizeMonLevel:
+ ld a, [wcf91]
+ ld b, a
+ ld hl, PrizeMonLevelDictionary
+.loop
+ ld a, [hli]
+ cp b
+ jr z, .matchFound
+ inc hl
+ jr .loop
+.matchFound
+ ld a, [hl]
+ ld [wCurEnemyLVL], a
+ ret
+
+INCLUDE "data/prize_mon_levels.asm"
--- /dev/null
+++ b/engine/events/saffron_guards.asm
@@ -1,0 +1,15 @@
+RemoveGuardDrink::
+ ld hl, GuardDrinksList
+.drinkLoop
+ ld a, [hli]
+ ld [$ffdb], a
+ and a
+ ret z
+ push hl
+ ld b, a
+ call IsItemInBag
+ pop hl
+ jr z, .drinkLoop
+ jpba RemoveItemByID
+
+INCLUDE "data/guard_drink_items.asm"
--- /dev/null
+++ b/engine/events/set_blackout_map.asm
@@ -1,0 +1,25 @@
+SetLastBlackoutMap:
+; Set the map to return to when
+; blacking out or using Teleport or Dig.
+; Safari rest houses don't count.
+
+ push hl
+ ld hl, SafariZoneRestHouses
+ ld a, [wCurMap]
+ ld b, a
+.loop
+ ld a, [hli]
+ cp -1
+ jr z, .notresthouse
+ cp b
+ jr nz, .loop
+ jr .done
+
+.notresthouse
+ ld a, [wLastMap]
+ ld [wLastBlackoutMap], a
+.done
+ pop hl
+ ret
+
+INCLUDE "data/rest_house_maps.asm"
--- /dev/null
+++ b/engine/events/starter_dex.asm
@@ -1,0 +1,9 @@
+; this function temporarily makes the starters (and Ivysaur) seen
+; so that the full Pokedex information gets displayed in Oak's lab
+StarterDex:
+ ld a, %01001011 ; set starter flags
+ ld [wPokedexOwned], a
+ predef ShowPokedexData
+ xor a ; unset starter flags
+ ld [wPokedexOwned], a
+ ret
--- /dev/null
+++ b/engine/events/vending_machine.asm
@@ -1,0 +1,133 @@
+VendingMachineMenu::
+ ld hl, VendingMachineText1
+ call PrintText
+ ld a, MONEY_BOX
+ ld [wTextBoxID], a
+ call DisplayTextBoxID
+ xor a
+ ld [wCurrentMenuItem], a
+ ld [wLastMenuItem], a
+ ld a, A_BUTTON | B_BUTTON
+ ld [wMenuWatchedKeys], a
+ ld a, 3
+ ld [wMaxMenuItem], a
+ ld a, 5
+ ld [wTopMenuItemY], a
+ ld a, 1
+ ld [wTopMenuItemX], a
+ ld hl, wd730
+ set 6, [hl]
+ coord hl, 0, 3
+ ld b, 8
+ ld c, 12
+ call TextBoxBorder
+ call UpdateSprites
+ coord hl, 2, 5
+ ld de, DrinkText
+ call PlaceString
+ coord hl, 9, 6
+ ld de, DrinkPriceText
+ call PlaceString
+ ld hl, wd730
+ res 6, [hl]
+ call HandleMenuInput
+ bit 1, a ; pressed B?
+ jr nz, .notThirsty
+ ld a, [wCurrentMenuItem]
+ cp 3 ; chose Cancel?
+ jr z, .notThirsty
+ xor a
+ ld [hMoney], a
+ ld [hMoney + 2], a
+ ld a, $2
+ ld [hMoney + 1], a
+ call HasEnoughMoney
+ jr nc, .enoughMoney
+ ld hl, VendingMachineText4
+ jp PrintText
+.enoughMoney
+ call LoadVendingMachineItem
+ ld a, [hVendingMachineItem]
+ ld b, a
+ ld c, 1
+ call GiveItem
+ jr nc, .BagFull
+
+ ld b, 60 ; number of times to play the "brrrrr" sound
+.playDeliverySound
+ ld c, 2
+ call DelayFrames
+ push bc
+ ld a, SFX_PUSH_BOULDER
+ call PlaySound
+ pop bc
+ dec b
+ jr nz, .playDeliverySound
+
+ ld hl, VendingMachineText5
+ call PrintText
+ ld hl, hVendingMachinePrice + 2
+ ld de, wPlayerMoney + 2
+ ld c, $3
+ predef SubBCDPredef
+ ld a, MONEY_BOX
+ ld [wTextBoxID], a
+ jp DisplayTextBoxID
+.BagFull
+ ld hl, VendingMachineText6
+ jp PrintText
+.notThirsty
+ ld hl, VendingMachineText7
+ jp PrintText
+
+VendingMachineText1:
+ TX_FAR _VendingMachineText1
+ db "@"
+
+DrinkText:
+ db "FRESH WATER"
+ next "SODA POP"
+ next "LEMONADE"
+ next "CANCEL@"
+
+DrinkPriceText:
+ db "¥200"
+ next "¥300"
+ next "¥350"
+ next "@"
+
+VendingMachineText4:
+ TX_FAR _VendingMachineText4
+ db "@"
+
+VendingMachineText5:
+ TX_FAR _VendingMachineText5
+ db "@"
+
+VendingMachineText6:
+ TX_FAR _VendingMachineText6
+ db "@"
+
+VendingMachineText7:
+ TX_FAR _VendingMachineText7
+ db "@"
+
+LoadVendingMachineItem:
+ ld hl, VendingPrices
+ ld a, [wCurrentMenuItem]
+ add a
+ add a
+ ld d, 0
+ ld e, a
+ add hl, de
+ ld a, [hli]
+ ld [hVendingMachineItem], a
+ ld a, [hli]
+ ld [hVendingMachinePrice], a
+ ld a, [hli]
+ ld [hVendingMachinePrice + 1], a
+ ld a, [hl]
+ ld [hVendingMachinePrice + 2], a
+ ret
+
+INCLUDE "data/vending_prices.asm"
--- a/engine/evolution.asm
+++ /dev/null
@@ -1,160 +1,0 @@
-EvolveMon:
- push hl
- push de
- push bc
- ld a, [wcf91]
- push af
- ld a, [wd0b5]
- push af
- xor a
- ld [wLowHealthAlarm], a
- ld [wChannelSoundIDs + Ch5], a
- dec a
- ld [wNewSoundID], a
- call PlaySound
- ld a, $1
- ld [H_AUTOBGTRANSFERENABLED], a
- ld a, SFX_TINK
- call PlaySound
- call Delay3
- xor a
- ld [H_AUTOBGTRANSFERENABLED], a
- ld [hTilesetType], a
- ld a, [wEvoOldSpecies]
- ld [wWholeScreenPaletteMonSpecies], a
- ld c, 0
- call EvolutionSetWholeScreenPalette
- ld a, [wEvoNewSpecies]
- ld [wcf91], a
- ld [wd0b5], a
- call Evolution_LoadPic
- ld de, vFrontPic
- ld hl, vBackPic
- ld bc, 7 * 7
- call CopyVideoData
- ld a, [wEvoOldSpecies]
- ld [wcf91], a
- ld [wd0b5], a
- call Evolution_LoadPic
- ld a, $1
- ld [H_AUTOBGTRANSFERENABLED], a
- ld a, [wEvoOldSpecies]
- call PlayCry
- call WaitForSoundToFinish
- ld c, BANK(Music_SafariZone)
- ld a, MUSIC_SAFARI_ZONE
- call PlayMusic
- ld c, 80
- call DelayFrames
- ld c, 1 ; set PAL_BLACK instead of mon palette
- call EvolutionSetWholeScreenPalette
- lb bc, $1, $10
-.animLoop
- push bc
- call Evolution_CheckForCancel
- jr c, .evolutionCancelled
- call Evolution_BackAndForthAnim
- pop bc
- inc b
- dec c
- dec c
- jr nz, .animLoop
- xor a
- ld [wEvoCancelled], a
- ld a, $31
- ld [wEvoMonTileOffset], a
- call Evolution_ChangeMonPic ; show the new species pic
- ld a, [wEvoNewSpecies]
-.done
- ld [wWholeScreenPaletteMonSpecies], a
- ld a, $ff
- ld [wNewSoundID], a
- call PlaySound
- ld a, [wWholeScreenPaletteMonSpecies]
- call PlayCry
- ld c, 0
- call EvolutionSetWholeScreenPalette
- pop af
- ld [wd0b5], a
- pop af
- ld [wcf91], a
- pop bc
- pop de
- pop hl
- ld a, [wEvoCancelled]
- and a
- ret z
- scf
- ret
-.evolutionCancelled
- pop bc
- ld a, 1
- ld [wEvoCancelled], a
- ld a, [wEvoOldSpecies]
- jr .done
-
-EvolutionSetWholeScreenPalette:
- ld b, SET_PAL_POKEMON_WHOLE_SCREEN
- jp RunPaletteCommand
-
-Evolution_LoadPic:
- call GetMonHeader
- coord hl, 7, 2
- jp LoadFlippedFrontSpriteByMonIndex
-
-Evolution_BackAndForthAnim:
-; show the mon change back and forth between the new and old species b times
- ld a, $31
- ld [wEvoMonTileOffset], a
- call Evolution_ChangeMonPic
- ld a, -$31
- ld [wEvoMonTileOffset], a
- call Evolution_ChangeMonPic
- dec b
- jr nz, Evolution_BackAndForthAnim
- ret
-
-Evolution_ChangeMonPic:
- push bc
- xor a
- ld [H_AUTOBGTRANSFERENABLED], a
- coord hl, 7, 2
- lb bc, 7, 7
- ld de, SCREEN_WIDTH - 7
-.loop
- push bc
-.innerLoop
- ld a, [wEvoMonTileOffset]
- add [hl]
- ld [hli], a
- dec c
- jr nz, .innerLoop
- pop bc
- add hl, de
- dec b
- jr nz, .loop
- ld a, 1
- ld [H_AUTOBGTRANSFERENABLED], a
- call Delay3
- pop bc
- ret
-
-Evolution_CheckForCancel:
- call DelayFrame
- push bc
- call JoypadLowSensitivity
- ld a, [hJoy5]
- pop bc
- and B_BUTTON
- jr nz, .pressedB
-.notAllowedToCancel
- dec c
- jr nz, Evolution_CheckForCancel
- and a
- ret
-.pressedB
- ld a, [wForceEvolution]
- and a
- jr nz, .notAllowedToCancel
- scf
- ret
--- a/engine/evolve_trade.asm
+++ /dev/null
@@ -1,44 +1,0 @@
-EvolveTradeMon:
-; Verify the TradeMon's species name before
-; attempting to initiate a trade evolution.
-
-; The names of the trade evolutions in Blue (JP)
-; are checked. In that version, TradeMons that
-; can evolve are Graveler and Haunter.
-
-; In localization, this check was translated
-; before monster names were finalized.
-; Then, Haunter's name was "Spectre".
-; Since its name no longer starts with
-; "SP", it is prevented from evolving.
-
-; This may have been why Red/Green's trades
-; were used instead, where none can evolve.
-
-; This was fixed in Yellow.
-
- ld a, [wInGameTradeReceiveMonName]
-
- ; GRAVELER
- cp "G"
- jr z, .ok
-
- ; "SPECTRE" (HAUNTER)
- cp "S"
- ret nz
- ld a, [wInGameTradeReceiveMonName + 1]
- cp "P"
- ret nz
-
-.ok
- ld a, [wPartyCount]
- dec a
- ld [wWhichPokemon], a
- ld a, $1
- ld [wForceEvolution], a
- ld a, LINK_STATE_TRADING
- ld [wLinkState], a
- callab TryEvolvingMon
- xor a ; LINK_STATE_NONE
- ld [wLinkState], a
- jp PlayDefaultMusic
--- a/engine/evos_moves.asm
+++ /dev/null
@@ -1,513 +1,0 @@
-; try to evolve the mon in [wWhichPokemon]
-TryEvolvingMon:
- ld hl, wCanEvolveFlags
- xor a
- ld [hl], a
- ld a, [wWhichPokemon]
- ld c, a
- ld b, FLAG_SET
- call Evolution_FlagAction
-
-; this is only called after battle
-; it is supposed to do level up evolutions, though there is a bug that allows item evolutions to occur
-EvolutionAfterBattle:
- ld a, [hTilesetType]
- push af
- xor a
- ld [wEvolutionOccurred], a
- dec a
- ld [wWhichPokemon], a
- push hl
- push bc
- push de
- ld hl, wPartyCount
- push hl
-
-Evolution_PartyMonLoop: ; loop over party mons
- ld hl, wWhichPokemon
- inc [hl]
- pop hl
- inc hl
- ld a, [hl]
- cp $ff ; have we reached the end of the party?
- jp z, .done
- ld [wEvoOldSpecies], a
- push hl
- ld a, [wWhichPokemon]
- ld c, a
- ld hl, wCanEvolveFlags
- ld b, FLAG_TEST
- call Evolution_FlagAction
- ld a, c
- and a ; is the mon's bit set?
- jp z, Evolution_PartyMonLoop ; if not, go to the next mon
- ld a, [wEvoOldSpecies]
- dec a
- ld b, 0
- ld hl, EvosMovesPointerTable
- add a
- rl b
- ld c, a
- add hl, bc
- ld a, [hli]
- ld h, [hl]
- ld l, a
- push hl
- ld a, [wcf91]
- push af
- xor a ; PLAYER_PARTY_DATA
- ld [wMonDataLocation], a
- call LoadMonData
- pop af
- ld [wcf91], a
- pop hl
-
-.evoEntryLoop ; loop over evolution entries
- ld a, [hli]
- and a ; have we reached the end of the evolution data?
- jr z, Evolution_PartyMonLoop
- ld b, a ; evolution type
- cp EV_TRADE
- jr z, .checkTradeEvo
-; not trade evolution
- ld a, [wLinkState]
- cp LINK_STATE_TRADING
- jr z, Evolution_PartyMonLoop ; if trading, go the next mon
- ld a, b
- cp EV_ITEM
- jr z, .checkItemEvo
- ld a, [wForceEvolution]
- and a
- jr nz, Evolution_PartyMonLoop
- ld a, b
- cp EV_LEVEL
- jr z, .checkLevel
-.checkTradeEvo
- ld a, [wLinkState]
- cp LINK_STATE_TRADING
- jp nz, .nextEvoEntry1 ; if not trading, go to the next evolution entry
- ld a, [hli] ; level requirement
- ld b, a
- ld a, [wLoadedMonLevel]
- cp b ; is the mon's level greater than the evolution requirement?
- jp c, Evolution_PartyMonLoop ; if so, go the next mon
- jr .doEvolution
-.checkItemEvo
- ld a, [hli]
- ld b, a ; evolution item
- ld a, [wcf91] ; this is supposed to be the last item used, but it is also used to hold species numbers
- cp b ; was the evolution item in this entry used?
- jp nz, .nextEvoEntry1 ; if not, go to the next evolution entry
-.checkLevel
- ld a, [hli] ; level requirement
- ld b, a
- ld a, [wLoadedMonLevel]
- cp b ; is the mon's level greater than the evolution requirement?
- jp c, .nextEvoEntry2 ; if so, go the next evolution entry
-.doEvolution
- ld [wCurEnemyLVL], a
- ld a, 1
- ld [wEvolutionOccurred], a
- push hl
- ld a, [hl]
- ld [wEvoNewSpecies], a
- ld a, [wWhichPokemon]
- ld hl, wPartyMonNicks
- call GetPartyMonName
- call CopyStringToCF4B
- ld hl, IsEvolvingText
- call PrintText
- ld c, 50
- call DelayFrames
- xor a
- ld [H_AUTOBGTRANSFERENABLED], a
- coord hl, 0, 0
- lb bc, 12, 20
- call ClearScreenArea
- ld a, $1
- ld [H_AUTOBGTRANSFERENABLED], a
- ld a, $ff
- ld [wUpdateSpritesEnabled], a
- call ClearSprites
- callab EvolveMon
- jp c, CancelledEvolution
- ld hl, EvolvedText
- call PrintText
- pop hl
- ld a, [hl]
- ld [wd0b5], a
- ld [wLoadedMonSpecies], a
- ld [wEvoNewSpecies], a
- ld a, MONSTER_NAME
- ld [wNameListType], a
- ld a, BANK(TrainerNames) ; bank is not used for monster names
- ld [wPredefBank], a
- call GetName
- push hl
- ld hl, IntoText
- call PrintText_NoCreatingTextBox
- ld a, SFX_GET_ITEM_2
- call PlaySoundWaitForCurrent
- call WaitForSoundToFinish
- ld c, 40
- call DelayFrames
- call ClearScreen
- call RenameEvolvedMon
- ld a, [wd11e]
- push af
- ld a, [wd0b5]
- ld [wd11e], a
- predef IndexToPokedex
- ld a, [wd11e]
- dec a
- ld hl, BaseStats
- ld bc, MonBaseStatsEnd - MonBaseStats
- call AddNTimes
- ld de, wMonHeader
- call CopyData
- ld a, [wd0b5]
- ld [wMonHIndex], a
- pop af
- ld [wd11e], a
- ld hl, wLoadedMonHPExp - 1
- ld de, wLoadedMonStats
- ld b, $1
- call CalcStats
- ld a, [wWhichPokemon]
- ld hl, wPartyMon1
- ld bc, wPartyMon2 - wPartyMon1
- call AddNTimes
- ld e, l
- ld d, h
- push hl
- push bc
- ld bc, wPartyMon1MaxHP - wPartyMon1
- add hl, bc
- ld a, [hli]
- ld b, a
- ld c, [hl]
- ld hl, wLoadedMonMaxHP + 1
- ld a, [hld]
- sub c
- ld c, a
- ld a, [hl]
- sbc b
- ld b, a
- ld hl, wLoadedMonHP + 1
- ld a, [hl]
- add c
- ld [hld], a
- ld a, [hl]
- adc b
- ld [hl], a
- dec hl
- pop bc
- call CopyData
- ld a, [wd0b5]
- ld [wd11e], a
- xor a
- ld [wMonDataLocation], a
- call LearnMoveFromLevelUp
- pop hl
- predef SetPartyMonTypes
- ld a, [wIsInBattle]
- and a
- call z, Evolution_ReloadTilesetTilePatterns
- predef IndexToPokedex
- ld a, [wd11e]
- dec a
- ld c, a
- ld b, FLAG_SET
- ld hl, wPokedexOwned
- push bc
- call Evolution_FlagAction
- pop bc
- ld hl, wPokedexSeen
- call Evolution_FlagAction
- pop de
- pop hl
- ld a, [wLoadedMonSpecies]
- ld [hl], a
- push hl
- ld l, e
- ld h, d
- jr .nextEvoEntry2
-
-.nextEvoEntry1
- inc hl
-
-.nextEvoEntry2
- inc hl
- jp .evoEntryLoop
-
-.done
- pop de
- pop bc
- pop hl
- pop af
- ld [hTilesetType], a
- ld a, [wLinkState]
- cp LINK_STATE_TRADING
- ret z
- ld a, [wIsInBattle]
- and a
- ret nz
- ld a, [wEvolutionOccurred]
- and a
- call nz, PlayDefaultMusic
- ret
-
-RenameEvolvedMon:
-; Renames the mon to its new, evolved form's standard name unless it had a
-; nickname, in which case the nickname is kept.
- ld a, [wd0b5]
- push af
- ld a, [wMonHIndex]
- ld [wd0b5], a
- call GetName
- pop af
- ld [wd0b5], a
- ld hl, wcd6d
- ld de, wcf4b
-.compareNamesLoop
- ld a, [de]
- inc de
- cp [hl]
- inc hl
- ret nz
- cp "@"
- jr nz, .compareNamesLoop
- ld a, [wWhichPokemon]
- ld bc, NAME_LENGTH
- ld hl, wPartyMonNicks
- call AddNTimes
- push hl
- call GetName
- ld hl, wcd6d
- pop de
- jp CopyData
-
-CancelledEvolution:
- ld hl, StoppedEvolvingText
- call PrintText
- call ClearScreen
- pop hl
- call Evolution_ReloadTilesetTilePatterns
- jp Evolution_PartyMonLoop
-
-EvolvedText:
- TX_FAR _EvolvedText
- db "@"
-
-IntoText:
- TX_FAR _IntoText
- db "@"
-
-StoppedEvolvingText:
- TX_FAR _StoppedEvolvingText
- db "@"
-
-IsEvolvingText:
- TX_FAR _IsEvolvingText
- db "@"
-
-Evolution_ReloadTilesetTilePatterns:
- ld a, [wLinkState]
- cp LINK_STATE_TRADING
- ret z
- jp ReloadTilesetTilePatterns
-
-LearnMoveFromLevelUp:
- ld hl, EvosMovesPointerTable
- ld a, [wd11e] ; species
- ld [wcf91], a
- dec a
- ld bc, 0
- ld hl, EvosMovesPointerTable
- add a
- rl b
- ld c, a
- add hl, bc
- ld a, [hli]
- ld h, [hl]
- ld l, a
-.skipEvolutionDataLoop ; loop to skip past the evolution data, which comes before the move data
- ld a, [hli]
- and a ; have we reached the end of the evolution data?
- jr nz, .skipEvolutionDataLoop ; if not, jump back up
-.learnSetLoop ; loop over the learn set until we reach a move that is learnt at the current level or the end of the list
- ld a, [hli]
- and a ; have we reached the end of the learn set?
- jr z, .done ; if we've reached the end of the learn set, jump
- ld b, a ; level the move is learnt at
- ld a, [wCurEnemyLVL]
- cp b ; is the move learnt at the mon's current level?
- ld a, [hli] ; move ID
- jr nz, .learnSetLoop
- ld d, a ; ID of move to learn
- ld a, [wMonDataLocation]
- and a
- jr nz, .next
-; If [wMonDataLocation] is 0 (PLAYER_PARTY_DATA), get the address of the mon's
-; current moves in party data. Every call to this function sets
-; [wMonDataLocation] to 0 because other data locations are not supported.
-; If it is not 0, this function will not work properly.
- ld hl, wPartyMon1Moves
- ld a, [wWhichPokemon]
- ld bc, wPartyMon2 - wPartyMon1
- call AddNTimes
-.next
- ld b, NUM_MOVES
-.checkCurrentMovesLoop ; check if the move to learn is already known
- ld a, [hli]
- cp d
- jr z, .done ; if already known, jump
- dec b
- jr nz, .checkCurrentMovesLoop
- ld a, d
- ld [wMoveNum], a
- ld [wd11e], a
- call GetMoveName
- call CopyStringToCF4B
- predef LearnMove
-.done
- ld a, [wcf91]
- ld [wd11e], a
- ret
-
-; writes the moves a mon has at level [wCurEnemyLVL] to [de]
-; move slots are being filled up sequentially and shifted if all slots are full
-WriteMonMoves:
- call GetPredefRegisters
- push hl
- push de
- push bc
- ld hl, EvosMovesPointerTable
- ld b, 0
- ld a, [wcf91] ; cur mon ID
- dec a
- add a
- rl b
- ld c, a
- add hl, bc
- ld a, [hli]
- ld h, [hl]
- ld l, a
-.skipEvoEntriesLoop
- ld a, [hli]
- and a
- jr nz, .skipEvoEntriesLoop
- jr .firstMove
-.nextMove
- pop de
-.nextMove2
- inc hl
-.firstMove
- ld a, [hli] ; read level of next move in learnset
- and a
- jp z, .done ; end of list
- ld b, a
- ld a, [wCurEnemyLVL]
- cp b
- jp c, .done ; mon level < move level (assumption: learnset is sorted by level)
- ld a, [wLearningMovesFromDayCare]
- and a
- jr z, .skipMinLevelCheck
- ld a, [wDayCareStartLevel]
- cp b
- jr nc, .nextMove2 ; min level >= move level
-
-.skipMinLevelCheck
-
-; check if the move is already known
- push de
- ld c, NUM_MOVES
-.alreadyKnowsCheckLoop
- ld a, [de]
- inc de
- cp [hl]
- jr z, .nextMove
- dec c
- jr nz, .alreadyKnowsCheckLoop
-
-; try to find an empty move slot
- pop de
- push de
- ld c, NUM_MOVES
-.findEmptySlotLoop
- ld a, [de]
- and a
- jr z, .writeMoveToSlot2
- inc de
- dec c
- jr nz, .findEmptySlotLoop
-
-; no empty move slots found
- pop de
- push de
- push hl
- ld h, d
- ld l, e
- call WriteMonMoves_ShiftMoveData ; shift all moves one up (deleting move 1)
- ld a, [wLearningMovesFromDayCare]
- and a
- jr z, .writeMoveToSlot
-
-; shift PP as well if learning moves from day care
- push de
- ld bc, wPartyMon1PP - (wPartyMon1Moves + 3)
- add hl, bc
- ld d, h
- ld e, l
- call WriteMonMoves_ShiftMoveData ; shift all move PP data one up
- pop de
-
-.writeMoveToSlot
- pop hl
-.writeMoveToSlot2
- ld a, [hl]
- ld [de], a
- ld a, [wLearningMovesFromDayCare]
- and a
- jr z, .nextMove
-
-; write move PP value if learning moves from day care
- push hl
- ld a, [hl]
- ld hl, wPartyMon1PP - wPartyMon1Moves
- add hl, de
- push hl
- dec a
- ld hl, Moves
- ld bc, MoveEnd - Moves
- call AddNTimes
- ld de, wBuffer
- ld a, BANK(Moves)
- call FarCopyData
- ld a, [wBuffer + 5]
- pop hl
- ld [hl], a
- pop hl
- jr .nextMove
-
-.done
- pop bc
- pop de
- pop hl
- ret
-
-; shifts all move data one up (freeing 4th move slot)
-WriteMonMoves_ShiftMoveData:
- ld c, NUM_MOVES - 1
-.loop
- inc de
- ld a, [de]
- ld [hli], a
- dec c
- jr nz, .loop
- ret
-
-Evolution_FlagAction:
- predef_jump FlagActionPredef
-
-INCLUDE "data/evos_moves.asm"
--- a/engine/experience.asm
+++ /dev/null
@@ -1,149 +1,0 @@
-; calculates the level a mon should be based on its current exp
-CalcLevelFromExperience::
- ld a, [wLoadedMonSpecies]
- ld [wd0b5], a
- call GetMonHeader
- ld d, $1 ; init level to 1
-.loop
- inc d ; increment level
- call CalcExperience
- push hl
- ld hl, wLoadedMonExp + 2 ; current exp
-; compare exp needed for level d with current exp
- ld a, [hExperience + 2]
- ld c, a
- ld a, [hld]
- sub c
- ld a, [hExperience + 1]
- ld c, a
- ld a, [hld]
- sbc c
- ld a, [hExperience]
- ld c, a
- ld a, [hl]
- sbc c
- pop hl
- jr nc, .loop ; if exp needed for level d is not greater than exp, try the next level
- dec d ; since the exp was too high on the last loop iteration, go back to the previous value and return
- ret
-
-; calculates the amount of experience needed for level d
-CalcExperience::
- ld a, [wMonHGrowthRate]
- add a
- add a
- ld c, a
- ld b, 0
- ld hl, GrowthRateTable
- add hl, bc
- call CalcDSquared
- ld a, d
- ld [H_MULTIPLIER], a
- call Multiply
- ld a, [hl]
- and $f0
- swap a
- ld [H_MULTIPLIER], a
- call Multiply
- ld a, [hli]
- and $f
- ld [H_DIVISOR], a
- ld b, $4
- call Divide
- ld a, [H_QUOTIENT + 1]
- push af
- ld a, [H_QUOTIENT + 2]
- push af
- ld a, [H_QUOTIENT + 3]
- push af
- call CalcDSquared
- ld a, [hl]
- and $7f
- ld [H_MULTIPLIER], a
- call Multiply
- ld a, [H_PRODUCT + 1]
- push af
- ld a, [H_PRODUCT + 2]
- push af
- ld a, [H_PRODUCT + 3]
- push af
- ld a, [hli]
- push af
- xor a
- ld [H_MULTIPLICAND], a
- ld [H_MULTIPLICAND + 1], a
- ld a, d
- ld [H_MULTIPLICAND + 2], a
- ld a, [hli]
- ld [H_MULTIPLIER], a
- call Multiply
- ld b, [hl]
- ld a, [H_PRODUCT + 3]
- sub b
- ld [H_PRODUCT + 3], a
- ld b, $0
- ld a, [H_PRODUCT + 2]
- sbc b
- ld [H_PRODUCT + 2], a
- ld a, [H_PRODUCT + 1]
- sbc b
- ld [H_PRODUCT + 1], a
-; The difference of the linear term and the constant term consists of 3 bytes
-; starting at H_PRODUCT + 1. Below, hExperience (an alias of that address) will
-; be used instead for the further work of adding or subtracting the squared
-; term and adding the cubed term.
- pop af
- and $80
- jr nz, .subtractSquaredTerm ; check sign
- pop bc
- ld a, [hExperience + 2]
- add b
- ld [hExperience + 2], a
- pop bc
- ld a, [hExperience + 1]
- adc b
- ld [hExperience + 1], a
- pop bc
- ld a, [hExperience]
- adc b
- ld [hExperience], a
- jr .addCubedTerm
-.subtractSquaredTerm
- pop bc
- ld a, [hExperience + 2]
- sub b
- ld [hExperience + 2], a
- pop bc
- ld a, [hExperience + 1]
- sbc b
- ld [hExperience + 1], a
- pop bc
- ld a, [hExperience]
- sbc b
- ld [hExperience], a
-.addCubedTerm
- pop bc
- ld a, [hExperience + 2]
- add b
- ld [hExperience + 2], a
- pop bc
- ld a, [hExperience + 1]
- adc b
- ld [hExperience + 1], a
- pop bc
- ld a, [hExperience]
- adc b
- ld [hExperience], a
- ret
-
-; calculates d*d
-CalcDSquared:
- xor a
- ld [H_MULTIPLICAND], a
- ld [H_MULTIPLICAND + 1], a
- ld a, d
- ld [H_MULTIPLICAND + 2], a
- ld [H_MULTIPLIER], a
- jp Multiply
-
-INCLUDE "data/growth_rates.asm"
--- a/engine/game_corner_slots.asm
+++ /dev/null
@@ -1,54 +1,0 @@
-StartSlotMachine:
- ld a, [wHiddenObjectFunctionArgument]
- cp $fd
- jr z, .printOutOfOrder
- cp $fe
- jr z, .printOutToLunch
- cp $ff
- jr z, .printSomeonesKeys
- callba AbleToPlaySlotsCheck
- ld a, [wCanPlaySlots]
- and a
- ret z
- ld a, [wLuckySlotHiddenObjectIndex]
- ld b, a
- ld a, [wHiddenObjectIndex]
- inc a
- cp b
- jr z, .match
- ld a, 253
- jr .next
-.match
- ld a, 250
-.next
- ld [wSlotMachineSevenAndBarModeChance], a
- ld a, [H_LOADEDROMBANK]
- ld [wSlotMachineSavedROMBank], a
- call PromptUserToPlaySlots
- ret
-.printOutOfOrder
- tx_pre_id GameCornerOutOfOrderText
- jr .printText
-.printOutToLunch
- tx_pre_id GameCornerOutToLunchText
- jr .printText
-.printSomeonesKeys
- tx_pre_id GameCornerSomeonesKeysText
-.printText
- push af
- call EnableAutoTextBoxDrawing
- pop af
- call PrintPredefTextID
- ret
-
-GameCornerOutOfOrderText::
- TX_FAR _GameCornerOutOfOrderText
- db "@"
-
-GameCornerOutToLunchText::
- TX_FAR _GameCornerOutToLunchText
- db "@"
-
-GameCornerSomeonesKeysText::
- TX_FAR _GameCornerSomeonesKeysText
- db "@"
--- a/engine/game_corner_slots2.asm
+++ /dev/null
@@ -1,31 +1,0 @@
-AbleToPlaySlotsCheck:
- ld a, [wSpriteStateData1 + 2]
- and $8
- jr z, .done ; not able
- ld b, COIN_CASE
- predef GetQuantityOfItemInBag
- ld a, b
- and a
- ld b, (GameCornerCoinCaseText_id - TextPredefs) / 2 + 1
- jr z, .printCoinCaseRequired
- ld hl, wPlayerCoins
- ld a, [hli]
- or [hl]
- jr nz, .done ; able to play
- ld b, (GameCornerNoCoinsText_id - TextPredefs) / 2 + 1
-.printCoinCaseRequired
- call EnableAutoTextBoxDrawing
- ld a, b
- call PrintPredefTextID
- xor a
-.done
- ld [wCanPlaySlots], a
- ret
-
-GameCornerCoinCaseText::
- TX_FAR _GameCornerCoinCaseText
- db "@"
-
-GameCornerNoCoinsText::
- TX_FAR _GameCornerNoCoinsText
- db "@"
--- a/engine/gamefreak.asm
+++ /dev/null
@@ -1,243 +1,0 @@
-LoadShootingStarGraphics:
- ld a, $f9
- ld [rOBP0], a
- ld a, $a4
- ld [rOBP1], a
- ld de, AnimationTileset2 + $30 ; star tile (top left quadrant)
- ld hl, vChars1 + $200
- lb bc, BANK(AnimationTileset2), $01
- call CopyVideoData
- ld de, AnimationTileset2 + $130 ; star tile (bottom left quadrant)
- ld hl, vChars1 + $210
- lb bc, BANK(AnimationTileset2), $01
- call CopyVideoData
- ld de, FallingStar
- ld hl, vChars1 + $220
- lb bc, BANK(FallingStar), (FallingStarEnd - FallingStar) / $10
- call CopyVideoData
- ld hl, GameFreakLogoOAMData
- ld de, wOAMBuffer + $60
- ld bc, GameFreakLogoOAMDataEnd - GameFreakLogoOAMData
- call CopyData
- ld hl, GameFreakShootingStarOAMData
- ld de, wOAMBuffer
- ld bc, GameFreakShootingStarOAMDataEnd - GameFreakShootingStarOAMData
- jp CopyData
-
-AnimateShootingStar:
- call LoadShootingStarGraphics
- ld a, SFX_SHOOTING_STAR
- call PlaySound
-
-; Move the big star down and left across the screen.
- ld hl, wOAMBuffer
- lb bc, $a0, $4
-.bigStarLoop
- push hl
- push bc
-.bigStarInnerLoop
- ld a, [hl] ; Y
- add 4
- ld [hli], a
- ld a, [hl] ; X
- add -4
- ld [hli], a
- inc hl
- inc hl
- dec c
- jr nz, .bigStarInnerLoop
- ld c, 1
- call CheckForUserInterruption
- pop bc
- pop hl
- ret c
- ld a, [hl]
- cp 80
- jr nz, .next
- jr .bigStarLoop
-.next
- cp b
- jr nz, .bigStarLoop
-
-; Clear big star OAM.
- ld hl, wOAMBuffer
- ld c, 4
- ld de, 4
-.clearOAMLoop
- ld [hl], 160
- add hl, de
- dec c
- jr nz, .clearOAMLoop
-
-; Make Gamefreak logo flash.
- ld b, 3
-.flashLogoLoop
- ld hl, rOBP0
- rrc [hl]
- rrc [hl]
- ld c, 10
- call CheckForUserInterruption
- ret c
- dec b
- jr nz, .flashLogoLoop
-
-; Copy 24 instances of the small stars OAM data.
-; Note that their coordinates put them off-screen.
- ld de, wOAMBuffer
- ld a, 24
-.initSmallStarsOAMLoop
- push af
- ld hl, SmallStarsOAM
- ld bc, SmallStarsOAMEnd - SmallStarsOAM
- call CopyData
- pop af
- dec a
- jr nz, .initSmallStarsOAMLoop
-
-; Animate the small stars falling from the Gamefreak logo.
- xor a
- ld [wMoveDownSmallStarsOAMCount], a
- ld hl, SmallStarsWaveCoordsPointerTable
- ld c, 6
-.smallStarsLoop
- ld a, [hli]
- ld e, a
- ld a, [hli]
- ld d, a
- push bc
- push hl
- ld hl, wOAMBuffer + $50
- ld c, 4
-.smallStarsInnerLoop ; introduce new wave of 4 small stars OAM entries
- ld a, [de]
- cp $ff
- jr z, .next2
- ld [hli], a ; Y
- inc de
- ld a, [de]
- ld [hli], a ; X
- inc de
- inc hl
- inc hl
- dec c
- jr nz, .smallStarsInnerLoop
- ld a, [wMoveDownSmallStarsOAMCount]
- cp 24
- jr z, .next2
- add 6 ; should be 4, but the extra 2 aren't visible on screen
- ld [wMoveDownSmallStarsOAMCount], a
-.next2
- call MoveDownSmallStars
- push af
-
-; shift the existing OAM entries down to make room for the next wave
- ld hl, wOAMBuffer + $10
- ld de, wOAMBuffer
- ld bc, $50
- call CopyData
-
- pop af
- pop hl
- pop bc
- ret c
- dec c
- jr nz, .smallStarsLoop
- and a
- ret
-
-SmallStarsOAM:
- db $00,$00,$A2,$90
-SmallStarsOAMEnd:
-
-SmallStarsWaveCoordsPointerTable:
- dw SmallStarsWave1Coords
- dw SmallStarsWave2Coords
- dw SmallStarsWave3Coords
- dw SmallStarsWave4Coords
- dw SmallStarsEmptyWave
- dw SmallStarsEmptyWave
-
-; The stars that fall from the Gamefreak logo come in 4 waves of 4 OAM entries.
-; These arrays contain the Y and X coordinates of each OAM entry.
-
-SmallStarsWave1Coords:
- db $68,$30
- db $68,$40
- db $68,$58
- db $68,$78
-
-SmallStarsWave2Coords:
- db $68,$38
- db $68,$48
- db $68,$60
- db $68,$70
-
-SmallStarsWave3Coords:
- db $68,$34
- db $68,$4C
- db $68,$54
- db $68,$64
-
-SmallStarsWave4Coords:
- db $68,$3C
- db $68,$5C
- db $68,$6C
- db $68,$74
-
-SmallStarsEmptyWave:
- db $FF
-
-MoveDownSmallStars:
- ld b, 8
-.loop
- ld hl, wOAMBuffer + $5c
- ld a, [wMoveDownSmallStarsOAMCount]
- ld de, -4
- ld c, a
-.innerLoop
- inc [hl] ; Y
- add hl, de
- dec c
- jr nz, .innerLoop
-; Toggle the palette so that the lower star in the small stars tile blinks in
-; and out.
- ld a, [rOBP1]
- xor %10100000
- ld [rOBP1], a
-
- ld c, 3
- call CheckForUserInterruption
- ret c
- dec b
- jr nz, .loop
- ret
-
-GameFreakLogoOAMData:
- db $48,$50,$8D,$00
- db $48,$58,$8E,$00
- db $50,$50,$8F,$00
- db $50,$58,$90,$00
- db $58,$50,$91,$00
- db $58,$58,$92,$00
- db $60,$30,$80,$00
- db $60,$38,$81,$00
- db $60,$40,$82,$00
- db $60,$48,$83,$00
- db $60,$50,$93,$00
- db $60,$58,$84,$00
- db $60,$60,$85,$00
- db $60,$68,$83,$00
- db $60,$70,$81,$00
- db $60,$78,$86,$00
-GameFreakLogoOAMDataEnd:
-
-GameFreakShootingStarOAMData:
- db $00,$A0,$A0,$10
- db $00,$A8,$A0,$30
- db $08,$A0,$A1,$10
- db $08,$A8,$A1,$30
-GameFreakShootingStarOAMDataEnd:
-
-FallingStar:
- INCBIN "gfx/intro_credits/falling_star.2bpp"
-FallingStarEnd:
--- a/engine/get_bag_item_quantity.asm
+++ /dev/null
@@ -1,18 +1,0 @@
-GetQuantityOfItemInBag:
-; In: b = item ID
-; Out: b = how many of that item are in the bag
- call GetPredefRegisters
- ld hl, wNumBagItems
-.loop
- inc hl
- ld a, [hli]
- cp $ff
- jr z, .notInBag
- cp b
- jr nz, .loop
- ld a, [hl]
- ld b, a
- ret
-.notInBag
- ld b, 0
- ret
--- /dev/null
+++ b/engine/gfx/hp_bar.asm
@@ -1,0 +1,270 @@
+HPBarLength:
+ call GetPredefRegisters
+
+; calculates bc * 48 / de, the number of pixels the HP bar has
+; the result is always at least 1
+GetHPBarLength:
+ push hl
+ xor a
+ ld hl, H_MULTIPLICAND
+ ld [hli], a
+ ld a, b
+ ld [hli], a
+ ld a, c
+ ld [hli], a
+ ld [hl], $30
+ call Multiply ; 48 * bc (hp bar is 48 pixels long)
+ ld a, d
+ and a
+ jr z, .maxHPSmaller256
+ srl d ; make HP in de fit into 1 byte by dividing by 4
+ rr e
+ srl d
+ rr e
+ ld a, [H_MULTIPLICAND+1]
+ ld b, a
+ ld a, [H_MULTIPLICAND+2]
+ srl b ; divide multiplication result as well
+ rr a
+ srl b
+ rr a
+ ld [H_MULTIPLICAND+2], a
+ ld a, b
+ ld [H_MULTIPLICAND+1], a
+.maxHPSmaller256
+ ld a, e
+ ld [H_DIVISOR], a
+ ld b, $4
+ call Divide
+ ld a, [H_MULTIPLICAND+2]
+ ld e, a ; e = bc * 48 / de (num of pixels of HP bar)
+ pop hl
+ and a
+ ret nz
+ ld e, $1 ; make result at least 1
+ ret
+
+; predef $48
+UpdateHPBar:
+UpdateHPBar2:
+ push hl
+ ld hl, wHPBarOldHP
+ ld a, [hli]
+ ld c, a ; old HP into bc
+ ld a, [hli]
+ ld b, a
+ ld a, [hli]
+ ld e, a ; new HP into de
+ ld d, [hl]
+ pop hl
+ push de
+ push bc
+ call UpdateHPBar_CalcHPDifference
+ ld a, e
+ ld [wHPBarHPDifference+1], a
+ ld a, d
+ ld [wHPBarHPDifference], a
+ pop bc
+ pop de
+ call UpdateHPBar_CompareNewHPToOldHP
+ ret z
+ ld a, $ff
+ jr c, .HPdecrease
+ ld a, $1
+.HPdecrease
+ ld [wHPBarDelta], a
+ call GetPredefRegisters
+ ld a, [wHPBarNewHP]
+ ld e, a
+ ld a, [wHPBarNewHP+1]
+ ld d, a
+.animateHPBarLoop
+ push de
+ ld a, [wHPBarOldHP]
+ ld c, a
+ ld a, [wHPBarOldHP+1]
+ ld b, a
+ call UpdateHPBar_CompareNewHPToOldHP
+ jr z, .animateHPBarDone
+ jr nc, .HPIncrease
+; HP decrease
+ dec bc ; subtract 1 HP
+ ld a, c
+ ld [wHPBarNewHP], a
+ ld a, b
+ ld [wHPBarNewHP+1], a
+ call UpdateHPBar_CalcOldNewHPBarPixels
+ ld a, e
+ sub d ; calc pixel difference
+ jr .ok
+.HPIncrease
+ inc bc ; add 1 HP
+ ld a, c
+ ld [wHPBarNewHP], a
+ ld a, b
+ ld [wHPBarNewHP+1], a
+ call UpdateHPBar_CalcOldNewHPBarPixels
+ ld a, d
+ sub e ; calc pixel difference
+.ok
+ call UpdateHPBar_PrintHPNumber
+ and a
+ jr z, .noPixelDifference
+ call UpdateHPBar_AnimateHPBar
+.noPixelDifference
+ ld a, [wHPBarNewHP]
+ ld [wHPBarOldHP], a
+ ld a, [wHPBarNewHP+1]
+ ld [wHPBarOldHP+1], a
+ pop de
+ jr .animateHPBarLoop
+.animateHPBarDone
+ pop de
+ ld a, e
+ ld [wHPBarOldHP], a
+ ld a, d
+ ld [wHPBarOldHP+1], a
+ or e
+ jr z, .monFainted
+ call UpdateHPBar_CalcOldNewHPBarPixels
+ ld d, e
+.monFainted
+ call UpdateHPBar_PrintHPNumber
+ ld a, $1
+ call UpdateHPBar_AnimateHPBar
+ jp Delay3
+
+; animates the HP bar going up or down for (a) ticks (two waiting frames each)
+; stops prematurely if bar is filled up
+; e: current health (in pixels) to start with
+UpdateHPBar_AnimateHPBar:
+ push hl
+.barAnimationLoop
+ push af
+ push de
+ ld d, $6
+ call DrawHPBar
+ ld c, 2
+ call DelayFrames
+ pop de
+ ld a, [wHPBarDelta] ; +1 or -1
+ add e
+ cp $31
+ jr nc, .barFilledUp
+ ld e, a
+ pop af
+ dec a
+ jr nz, .barAnimationLoop
+ pop hl
+ ret
+.barFilledUp
+ pop af
+ pop hl
+ ret
+
+; compares old HP and new HP and sets c and z flags accordingly
+UpdateHPBar_CompareNewHPToOldHP:
+ ld a, d
+ sub b
+ ret nz
+ ld a, e
+ sub c
+ ret
+
+; calcs HP difference between bc and de (into de)
+UpdateHPBar_CalcHPDifference:
+ ld a, d
+ sub b
+ jr c, .oldHPGreater
+ jr z, .testLowerByte
+.newHPGreater
+ ld a, e
+ sub c
+ ld e, a
+ ld a, d
+ sbc b
+ ld d, a
+ ret
+.oldHPGreater
+ ld a, c
+ sub e
+ ld e, a
+ ld a, b
+ sbc d
+ ld d, a
+ ret
+.testLowerByte
+ ld a, e
+ sub c
+ jr c, .oldHPGreater
+ jr nz, .newHPGreater
+ ld de, $0
+ ret
+
+UpdateHPBar_PrintHPNumber:
+ push af
+ push de
+ ld a, [wHPBarType]
+ and a
+ jr z, .done ; don't print number in enemy HUD
+; convert from little-endian to big-endian for PrintNumber
+ ld a, [wHPBarOldHP]
+ ld [wHPBarTempHP + 1], a
+ ld a, [wHPBarOldHP + 1]
+ ld [wHPBarTempHP], a
+ push hl
+ ld a, [hFlags_0xFFF6]
+ bit 0, a
+ jr z, .asm_fb15
+ ld de, $9
+ jr .next
+.asm_fb15
+ ld de, $15
+.next
+ add hl, de
+ push hl
+ ld a, " "
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ pop hl
+ ld de, wHPBarTempHP
+ lb bc, 2, 3
+ call PrintNumber
+ call DelayFrame
+ pop hl
+.done
+ pop de
+ pop af
+ ret
+
+; calcs number of HP bar pixels for old and new HP value
+; d: new pixels
+; e: old pixels
+UpdateHPBar_CalcOldNewHPBarPixels:
+ push hl
+ ld hl, wHPBarMaxHP
+ ld a, [hli] ; max HP into de
+ ld e, a
+ ld a, [hli]
+ ld d, a
+ ld a, [hli] ; old HP into bc
+ ld c, a
+ ld a, [hli]
+ ld b, a
+ ld a, [hli] ; new HP into hl
+ ld h, [hl]
+ ld l, a
+ push hl
+ push de
+ call GetHPBarLength ; calc num pixels for old HP
+ ld a, e
+ pop de
+ pop bc
+ push af
+ call GetHPBarLength ; calc num pixels for new HP
+ pop af
+ ld d, e
+ ld e, a
+ pop hl
+ ret
--- /dev/null
+++ b/engine/gfx/load_pokedex_tiles.asm
@@ -1,0 +1,11 @@
+; Loads tile patterns for tiles used in the pokedex.
+LoadPokedexTilePatterns:
+ call LoadHpBarAndStatusTilePatterns
+ ld de, PokedexTileGraphics
+ ld hl, vChars2 + $600
+ lb bc, BANK(PokedexTileGraphics), (PokedexTileGraphicsEnd - PokedexTileGraphics) / $10
+ call CopyVideoData
+ ld de, PokeballTileGraphics
+ ld hl, vChars2 + $720
+ lb bc, BANK(PokeballTileGraphics), $01
+ jp CopyVideoData ; load pokeball tile for marking caught mons
--- /dev/null
+++ b/engine/gfx/mon_icons.asm
@@ -1,0 +1,295 @@
+AnimatePartyMon_ForceSpeed1:
+ xor a
+ ld [wCurrentMenuItem], a
+ ld b, a
+ inc a
+ jr GetAnimationSpeed
+
+; wPartyMenuHPBarColors contains the party mon's health bar colors
+; 0: green
+; 1: yellow
+; 2: red
+AnimatePartyMon::
+ ld hl, wPartyMenuHPBarColors
+ ld a, [wCurrentMenuItem]
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hl]
+
+GetAnimationSpeed:
+ ld c, a
+ ld hl, PartyMonSpeeds
+ add hl, bc
+ ld a, [wOnSGB]
+ xor $1
+ add [hl]
+ ld c, a
+ add a
+ ld b, a
+ ld a, [wAnimCounter]
+ and a
+ jr z, .resetSprites
+ cp c
+ jr z, .animateSprite
+.incTimer
+ inc a
+ cp b
+ jr nz, .skipResetTimer
+ xor a ; reset timer
+.skipResetTimer
+ ld [wAnimCounter], a
+ jp DelayFrame
+.resetSprites
+ push bc
+ ld hl, wMonPartySpritesSavedOAM
+ ld de, wOAMBuffer
+ ld bc, $60
+ call CopyData
+ pop bc
+ xor a
+ jr .incTimer
+.animateSprite
+ push bc
+ ld hl, wOAMBuffer + $02 ; OAM tile id
+ ld bc, $10
+ ld a, [wCurrentMenuItem]
+ call AddNTimes
+ ld c, $40 ; amount to increase the tile id by
+ ld a, [hl]
+ cp $4 ; tile ID for ICON_BALL
+ jr z, .editCoords
+ cp $8 ; tile ID for ICON_HELIX
+ jr nz, .editTileIDS
+; ICON_BALL and ICON_HELIX only shake up and down
+.editCoords
+ dec hl
+ dec hl ; dec hl to the OAM y coord
+ ld c, $1 ; amount to increase the y coord by
+; otherwise, load a second sprite frame
+.editTileIDS
+ ld b, $4
+ ld de, $4
+.loop
+ ld a, [hl]
+ add c
+ ld [hl], a
+ add hl, de
+ dec b
+ jr nz, .loop
+ pop bc
+ ld a, c
+ jr .incTimer
+
+; Party mon animations cycle between 2 frames.
+; The members of the PartyMonSpeeds array specify the number of V-blanks
+; that each frame lasts for green HP, yellow HP, and red HP in order.
+; On the naming screen, the yellow HP speed is always used.
+PartyMonSpeeds:
+ db 5, 16, 32
+
+LoadMonPartySpriteGfx:
+; Load mon party sprite tile patterns into VRAM during V-blank.
+ ld hl, MonPartySpritePointers
+ ld a, $1c
+
+LoadAnimSpriteGfx:
+; Load animated sprite tile patterns into VRAM during V-blank. hl is the address
+; of an array of structures that contain arguments for CopyVideoData and a is
+; the number of structures in the array.
+ ld bc, $0
+.loop
+ push af
+ push bc
+ push hl
+ add hl, bc
+ ld a, [hli]
+ ld e, a
+ ld a, [hli]
+ ld d, a
+ ld a, [hli]
+ ld c, a
+ ld a, [hli]
+ ld b, a
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call CopyVideoData
+ pop hl
+ pop bc
+ ld a, $6
+ add c
+ ld c, a
+ pop af
+ dec a
+ jr nz, .loop
+ ret
+
+LoadMonPartySpriteGfxWithLCDDisabled:
+; Load mon party sprite tile patterns into VRAM immediately by disabling the
+; LCD.
+ call DisableLCD
+ ld hl, MonPartySpritePointers
+ ld a, $1c
+ ld bc, $0
+.loop
+ push af
+ push bc
+ push hl
+ add hl, bc
+ ld a, [hli]
+ ld e, a
+ ld a, [hli]
+ ld d, a
+ push de
+ ld a, [hli]
+ ld c, a
+ swap c
+ ld b, $0
+ ld a, [hli]
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ pop hl
+ call FarCopyData2
+ pop hl
+ pop bc
+ ld a, $6
+ add c
+ ld c, a
+ pop af
+ dec a
+ jr nz, .loop
+ jp EnableLCD
+
+INCLUDE "data/mon_party_sprite_pointers.asm"
+
+WriteMonPartySpriteOAMByPartyIndex:
+; Write OAM blocks for the party mon in [hPartyMonIndex].
+ push hl
+ push de
+ push bc
+ ld a, [hPartyMonIndex]
+ ld hl, wPartySpecies
+ ld e, a
+ ld d, 0
+ add hl, de
+ ld a, [hl]
+ call GetPartyMonSpriteID
+ ld [wOAMBaseTile], a
+ call WriteMonPartySpriteOAM
+ pop bc
+ pop de
+ pop hl
+ ret
+
+WriteMonPartySpriteOAMBySpecies:
+; Write OAM blocks for the party sprite of the species in
+; [wMonPartySpriteSpecies].
+ xor a
+ ld [hPartyMonIndex], a
+ ld a, [wMonPartySpriteSpecies]
+ call GetPartyMonSpriteID
+ ld [wOAMBaseTile], a
+ jr WriteMonPartySpriteOAM
+
+UnusedPartyMonSpriteFunction:
+; This function is unused and doesn't appear to do anything useful. It looks
+; like it may have been intended to load the tile patterns and OAM data for
+; the mon party sprite associated with the species in [wcf91].
+; However, its calculations are off and it loads garbage data.
+ ld a, [wcf91]
+ call GetPartyMonSpriteID
+ push af
+ ld hl, vSprites
+ call .LoadTilePatterns
+ pop af
+ add $54
+ ld hl, vSprites + $40
+ call .LoadTilePatterns
+ xor a
+ ld [wMonPartySpriteSpecies], a
+ jr WriteMonPartySpriteOAMBySpecies
+
+.LoadTilePatterns
+ push hl
+ add a
+ ld c, a
+ ld b, 0
+ ld hl, MonPartySpritePointers
+ add hl, bc
+ add hl, bc
+ add hl, bc
+ ld a, [hli]
+ ld e, a
+ ld a, [hli]
+ ld d, a
+ ld a, [hli]
+ ld c, a
+ ld a, [hli]
+ ld b, a
+ pop hl
+ jp CopyVideoData
+
+WriteMonPartySpriteOAM:
+; Write the OAM blocks for the first animation frame into the OAM buffer and
+; make a copy at wMonPartySpritesSavedOAM.
+ push af
+ ld c, $10
+ ld h, wOAMBuffer / $100
+ ld a, [hPartyMonIndex]
+ swap a
+ ld l, a
+ add $10
+ ld b, a
+ pop af
+ cp ICON_HELIX << 2
+ jr z, .helix
+ call WriteSymmetricMonPartySpriteOAM
+ jr .makeCopy
+.helix
+ call WriteAsymmetricMonPartySpriteOAM
+; Make a copy of the OAM buffer with the first animation frame written so that
+; we can flip back to it from the second frame by copying it back.
+.makeCopy
+ ld hl, wOAMBuffer
+ ld de, wMonPartySpritesSavedOAM
+ ld bc, $60
+ jp CopyData
+
+GetPartyMonSpriteID:
+ ld [wd11e], a
+ predef IndexToPokedex
+ ld a, [wd11e]
+ ld c, a
+ dec a
+ srl a
+ ld hl, MonPartyData
+ ld e, a
+ ld d, 0
+ add hl, de
+ ld a, [hl]
+ bit 0, c
+ jr nz, .skipSwap
+ swap a ; use lower nybble if pokedex num is even
+.skipSwap
+ and $f0
+ srl a
+ srl a
+ ret
+
+INCLUDE "data/mon_party_sprites.asm"
+
+INC_FRAME_1 EQUS "0, $20"
+INC_FRAME_2 EQUS "$20, $20"
+
+BugIconFrame1: INCBIN "gfx/icons/bug.2bpp", INC_FRAME_1
+PlantIconFrame1: INCBIN "gfx/icons/plant.2bpp", INC_FRAME_1
+BugIconFrame2: INCBIN "gfx/icons/bug.2bpp", INC_FRAME_2
+PlantIconFrame2: INCBIN "gfx/icons/plant.2bpp", INC_FRAME_2
+SnakeIconFrame1: INCBIN "gfx/icons/snake.2bpp", INC_FRAME_1
+QuadrupedIconFrame1: INCBIN "gfx/icons/quadruped.2bpp", INC_FRAME_1
+SnakeIconFrame2: INCBIN "gfx/icons/snake.2bpp", INC_FRAME_2
+QuadrupedIconFrame2: INCBIN "gfx/icons/quadruped.2bpp", INC_FRAME_2
+
+TradeBubbleIconGFX: INCBIN "gfx/trade/bubble.2bpp"
--- /dev/null
+++ b/engine/gfx/oam_dma.asm
@@ -1,0 +1,26 @@
+WriteDMACodeToHRAM::
+; Since no other memory is available during OAM DMA,
+; DMARoutine is copied to HRAM and executed there.
+ ld c, $ff80 % $100
+ ld b, DMARoutineEnd - DMARoutine
+ ld hl, DMARoutine
+.copy
+ ld a, [hli]
+ ld [$ff00+c], a
+ inc c
+ dec b
+ jr nz, .copy
+ ret
+
+DMARoutine:
+ ; initiate DMA
+ ld a, wOAMBuffer / $100
+ ld [rDMA], a
+
+ ; wait for DMA to finish
+ ld a, $28
+.wait
+ dec a
+ jr nz, .wait
+ ret
+DMARoutineEnd:
--- /dev/null
+++ b/engine/gfx/palettes.asm
@@ -1,0 +1,641 @@
+_RunPaletteCommand:
+ call GetPredefRegisters
+ ld a, b
+ cp $ff
+ jr nz, .next
+ ld a, [wDefaultPaletteCommand] ; use default command if command ID is $ff
+.next
+ cp UPDATE_PARTY_MENU_BLK_PACKET
+ jp z, UpdatePartyMenuBlkPacket
+ ld l, a
+ ld h, 0
+ add hl, hl
+ ld de, SetPalFunctions
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, SendSGBPackets
+ push de
+ jp hl
+
+SetPal_BattleBlack:
+ ld hl, PalPacket_Black
+ ld de, BlkPacket_Battle
+ ret
+
+; uses PalPacket_Empty to build a packet based on mon IDs and health color
+SetPal_Battle:
+ ld hl, PalPacket_Empty
+ ld de, wPalPacket
+ ld bc, $10
+ call CopyData
+ ld a, [wPlayerBattleStatus3]
+ ld hl, wBattleMonSpecies
+ call DeterminePaletteID
+ ld b, a
+ ld a, [wEnemyBattleStatus3]
+ ld hl, wEnemyMonSpecies2
+ call DeterminePaletteID
+ ld c, a
+ ld hl, wPalPacket + 1
+ ld a, [wPlayerHPBarColor]
+ add PAL_GREENBAR
+ ld [hli], a
+ inc hl
+ ld a, [wEnemyHPBarColor]
+ add PAL_GREENBAR
+ ld [hli], a
+ inc hl
+ ld a, b
+ ld [hli], a
+ inc hl
+ ld a, c
+ ld [hl], a
+ ld hl, wPalPacket
+ ld de, BlkPacket_Battle
+ ld a, SET_PAL_BATTLE
+ ld [wDefaultPaletteCommand], a
+ ret
+
+SetPal_TownMap:
+ ld hl, PalPacket_TownMap
+ ld de, BlkPacket_WholeScreen
+ ret
+
+; uses PalPacket_Empty to build a packet based the mon ID
+SetPal_StatusScreen:
+ ld hl, PalPacket_Empty
+ ld de, wPalPacket
+ ld bc, $10
+ call CopyData
+ ld a, [wcf91]
+ cp NUM_POKEMON_INDEXES + 1
+ jr c, .pokemon
+ ld a, $1 ; not pokemon
+.pokemon
+ call DeterminePaletteIDOutOfBattle
+ push af
+ ld hl, wPalPacket + 1
+ ld a, [wStatusScreenHPBarColor]
+ add PAL_GREENBAR
+ ld [hli], a
+ inc hl
+ pop af
+ ld [hl], a
+ ld hl, wPalPacket
+ ld de, BlkPacket_StatusScreen
+ ret
+
+SetPal_PartyMenu:
+ ld hl, PalPacket_PartyMenu
+ ld de, wPartyMenuBlkPacket
+ ret
+
+SetPal_Pokedex:
+ ld hl, PalPacket_Pokedex
+ ld de, wPalPacket
+ ld bc, $10
+ call CopyData
+ ld a, [wcf91]
+ call DeterminePaletteIDOutOfBattle
+ ld hl, wPalPacket + 3
+ ld [hl], a
+ ld hl, wPalPacket
+ ld de, BlkPacket_Pokedex
+ ret
+
+SetPal_Slots:
+ ld hl, PalPacket_Slots
+ ld de, BlkPacket_Slots
+ ret
+
+SetPal_TitleScreen:
+ ld hl, PalPacket_Titlescreen
+ ld de, BlkPacket_Titlescreen
+ ret
+
+; used mostly for menus and the Oak intro
+SetPal_Generic:
+ ld hl, PalPacket_Generic
+ ld de, BlkPacket_WholeScreen
+ ret
+
+SetPal_NidorinoIntro:
+ ld hl, PalPacket_NidorinoIntro
+ ld de, BlkPacket_NidorinoIntro
+ ret
+
+SetPal_GameFreakIntro:
+ ld hl, PalPacket_GameFreakIntro
+ ld de, BlkPacket_GameFreakIntro
+ ld a, SET_PAL_GENERIC
+ ld [wDefaultPaletteCommand], a
+ ret
+
+; uses PalPacket_Empty to build a packet based on the current map
+SetPal_Overworld:
+ ld hl, PalPacket_Empty
+ ld de, wPalPacket
+ ld bc, $10
+ call CopyData
+ ld a, [wCurMapTileset]
+ cp CEMETERY
+ jr z, .PokemonTowerOrAgatha
+ cp CAVERN
+ jr z, .caveOrBruno
+ ld a, [wCurMap]
+ cp REDS_HOUSE_1F
+ jr c, .townOrRoute
+ cp CERULEAN_CAVE_2F
+ jr c, .normalDungeonOrBuilding
+ cp NAME_RATERS_HOUSE
+ jr c, .caveOrBruno
+ cp LORELEIS_ROOM
+ jr z, .Lorelei
+ cp BRUNOS_ROOM
+ jr z, .caveOrBruno
+.normalDungeonOrBuilding
+ ld a, [wLastMap] ; town or route that current dungeon or building is located
+.townOrRoute
+ cp SAFFRON_CITY + 1
+ jr c, .town
+ ld a, PAL_ROUTE - 1
+.town
+ inc a ; a town's palette ID is its map ID + 1
+ ld hl, wPalPacket + 1
+ ld [hld], a
+ ld de, BlkPacket_WholeScreen
+ ld a, SET_PAL_OVERWORLD
+ ld [wDefaultPaletteCommand], a
+ ret
+.PokemonTowerOrAgatha
+ ld a, PAL_GREYMON - 1
+ jr .town
+.caveOrBruno
+ ld a, PAL_CAVE - 1
+ jr .town
+.Lorelei
+ xor a
+ jr .town
+
+; used when a Pokemon is the only thing on the screen
+; such as evolution, trading and the Hall of Fame
+SetPal_PokemonWholeScreen:
+ push bc
+ ld hl, PalPacket_Empty
+ ld de, wPalPacket
+ ld bc, $10
+ call CopyData
+ pop bc
+ ld a, c
+ and a
+ ld a, PAL_BLACK
+ jr nz, .next
+ ld a, [wWholeScreenPaletteMonSpecies]
+ call DeterminePaletteIDOutOfBattle
+.next
+ ld [wPalPacket + 1], a
+ ld hl, wPalPacket
+ ld de, BlkPacket_WholeScreen
+ ret
+
+SetPal_TrainerCard:
+ ld hl, BlkPacket_TrainerCard
+ ld de, wTrainerCardBlkPacket
+ ld bc, $40
+ call CopyData
+ ld de, BadgeBlkDataLengths
+ ld hl, wTrainerCardBlkPacket + 2
+ ld a, [wObtainedBadges]
+ ld c, 8
+.badgeLoop
+ srl a
+ push af
+ jr c, .haveBadge
+; The player doens't have the badge, so zero the badge's blk data.
+ push bc
+ ld a, [de]
+ ld c, a
+ xor a
+.zeroBadgeDataLoop
+ ld [hli], a
+ dec c
+ jr nz, .zeroBadgeDataLoop
+ pop bc
+ jr .nextBadge
+.haveBadge
+; The player does have the badge, so skip past the badge's blk data.
+ ld a, [de]
+.skipBadgeDataLoop
+ inc hl
+ dec a
+ jr nz, .skipBadgeDataLoop
+.nextBadge
+ pop af
+ inc de
+ dec c
+ jr nz, .badgeLoop
+ ld hl, PalPacket_TrainerCard
+ ld de, wTrainerCardBlkPacket
+ ret
+
+SetPalFunctions:
+ dw SetPal_BattleBlack
+ dw SetPal_Battle
+ dw SetPal_TownMap
+ dw SetPal_StatusScreen
+ dw SetPal_Pokedex
+ dw SetPal_Slots
+ dw SetPal_TitleScreen
+ dw SetPal_NidorinoIntro
+ dw SetPal_Generic
+ dw SetPal_Overworld
+ dw SetPal_PartyMenu
+ dw SetPal_PokemonWholeScreen
+ dw SetPal_GameFreakIntro
+ dw SetPal_TrainerCard
+
+; The length of the blk data of each badge on the Trainer Card.
+; The Rainbow Badge has 3 entries because of its many colors.
+BadgeBlkDataLengths:
+ db 6 ; Boulder Badge
+ db 6 ; Cascade Badge
+ db 6 ; Thunder Badge
+ db 6 * 3 ; Rainbow Badge
+ db 6 ; Soul Badge
+ db 6 ; Marsh Badge
+ db 6 ; Volcano Badge
+ db 6 ; Earth Badge
+
+DeterminePaletteID:
+ bit TRANSFORMED, a ; a is battle status 3
+ ld a, PAL_GREYMON ; if the mon has used Transform, use Ditto's palette
+ ret nz
+ ld a, [hl]
+DeterminePaletteIDOutOfBattle:
+ ld [wd11e], a
+ and a ; is the mon index 0?
+ jr z, .skipDexNumConversion
+ push bc
+ predef IndexToPokedex
+ pop bc
+ ld a, [wd11e]
+.skipDexNumConversion
+ ld e, a
+ ld d, 0
+ ld hl, MonsterPalettes ; not just for Pokemon, Trainers use it too
+ add hl, de
+ ld a, [hl]
+ ret
+
+InitPartyMenuBlkPacket:
+ ld hl, BlkPacket_PartyMenu
+ ld de, wPartyMenuBlkPacket
+ ld bc, $30
+ jp CopyData
+
+UpdatePartyMenuBlkPacket:
+; Update the blk packet with the palette of the HP bar that is
+; specified in [wWhichPartyMenuHPBar].
+ ld hl, wPartyMenuHPBarColors
+ ld a, [wWhichPartyMenuHPBar]
+ ld e, a
+ ld d, 0
+ add hl, de
+ ld e, l
+ ld d, h
+ ld a, [de]
+ and a
+ ld e, (1 << 2) | 1 ; green
+ jr z, .next
+ dec a
+ ld e, (2 << 2) | 2 ; yellow
+ jr z, .next
+ ld e, (3 << 2) | 3 ; red
+.next
+ push de
+ ld hl, wPartyMenuBlkPacket + 8 + 1
+ ld bc, 6
+ ld a, [wWhichPartyMenuHPBar]
+ call AddNTimes
+ pop de
+ ld [hl], e
+ ret
+
+SendSGBPacket:
+;check number of packets
+ ld a, [hl]
+ and $07
+ ret z
+; store number of packets in B
+ ld b, a
+.loop2
+; save B for later use
+ push bc
+; disable ReadJoypad to prevent it from interfering with sending the packet
+ ld a, 1
+ ld [hDisableJoypadPolling], a
+; send RESET signal (P14=LOW, P15=LOW)
+ xor a
+ ld [rJOYP], a
+; set P14=HIGH, P15=HIGH
+ ld a, $30
+ ld [rJOYP], a
+;load length of packets (16 bytes)
+ ld b, $10
+.nextByte
+;set bit counter (8 bits per byte)
+ ld e, $08
+; get next byte in the packet
+ ld a, [hli]
+ ld d, a
+.nextBit0
+ bit 0, d
+; if 0th bit is not zero set P14=HIGH,P15=LOW (send bit 1)
+ ld a, $10
+ jr nz, .next0
+; else (if 0th bit is zero) set P14=LOW,P15=HIGH (send bit 0)
+ ld a, $20
+.next0
+ ld [rJOYP], a
+; must set P14=HIGH,P15=HIGH between each "pulse"
+ ld a, $30
+ ld [rJOYP], a
+; rotation will put next bit in 0th position (so we can always use command
+; "bit 0,d" to fetch the bit that has to be sent)
+ rr d
+; decrease bit counter so we know when we have sent all 8 bits of current byte
+ dec e
+ jr nz, .nextBit0
+ dec b
+ jr nz, .nextByte
+; send bit 1 as a "stop bit" (end of parameter data)
+ ld a, $20
+ ld [rJOYP], a
+; set P14=HIGH,P15=HIGH
+ ld a, $30
+ ld [rJOYP], a
+ xor a
+ ld [hDisableJoypadPolling], a
+; wait for about 70000 cycles
+ call Wait7000
+; restore (previously pushed) number of packets
+ pop bc
+ dec b
+; return if there are no more packets
+ ret z
+; else send 16 more bytes
+ jr .loop2
+
+LoadSGB:
+ xor a
+ ld [wOnSGB], a
+ call CheckSGB
+ ret nc
+ ld a, 1
+ ld [wOnSGB], a
+ ld a, [wGBC]
+ and a
+ jr z, .notGBC
+ ret
+.notGBC
+ di
+ call PrepareSuperNintendoVRAMTransfer
+ ei
+ ld a, 1
+ ld [wCopyingSGBTileData], a
+ ld de, ChrTrnPacket
+ ld hl, SGBBorderGraphics
+ call CopyGfxToSuperNintendoVRAM
+ xor a
+ ld [wCopyingSGBTileData], a
+ ld de, PctTrnPacket
+ ld hl, BorderPalettes
+ call CopyGfxToSuperNintendoVRAM
+ xor a
+ ld [wCopyingSGBTileData], a
+ ld de, PalTrnPacket
+ ld hl, SuperPalettes
+ call CopyGfxToSuperNintendoVRAM
+ call ClearVram
+ ld hl, MaskEnCancelPacket
+ jp SendSGBPacket
+
+PrepareSuperNintendoVRAMTransfer:
+ ld hl, .packetPointers
+ ld c, 9
+.loop
+ push bc
+ ld a, [hli]
+ push hl
+ ld h, [hl]
+ ld l, a
+ call SendSGBPacket
+ pop hl
+ inc hl
+ pop bc
+ dec c
+ jr nz, .loop
+ ret
+
+.packetPointers
+; Only the first packet is needed.
+ dw MaskEnFreezePacket
+ dw DataSnd_72548
+ dw DataSnd_72558
+ dw DataSnd_72568
+ dw DataSnd_72578
+ dw DataSnd_72588
+ dw DataSnd_72598
+ dw DataSnd_725a8
+ dw DataSnd_725b8
+
+CheckSGB:
+; Returns whether the game is running on an SGB in carry.
+ ld hl, MltReq2Packet
+ di
+ call SendSGBPacket
+ ld a, 1
+ ld [hDisableJoypadPolling], a
+ ei
+ call Wait7000
+ ld a, [rJOYP]
+ and $3
+ cp $3
+ jr nz, .isSGB
+ ld a, $20
+ ld [rJOYP], a
+ ld a, [rJOYP]
+ ld a, [rJOYP]
+ call Wait7000
+ call Wait7000
+ ld a, $30
+ ld [rJOYP], a
+ call Wait7000
+ call Wait7000
+ ld a, $10
+ ld [rJOYP], a
+ ld a, [rJOYP]
+ ld a, [rJOYP]
+ ld a, [rJOYP]
+ ld a, [rJOYP]
+ ld a, [rJOYP]
+ ld a, [rJOYP]
+ call Wait7000
+ call Wait7000
+ ld a, $30
+ ld [rJOYP], a
+ ld a, [rJOYP]
+ ld a, [rJOYP]
+ ld a, [rJOYP]
+ call Wait7000
+ call Wait7000
+ ld a, [rJOYP]
+ and $3
+ cp $3
+ jr nz, .isSGB
+ call SendMltReq1Packet
+ and a
+ ret
+.isSGB
+ call SendMltReq1Packet
+ scf
+ ret
+
+SendMltReq1Packet:
+ ld hl, MltReq1Packet
+ call SendSGBPacket
+ jp Wait7000
+
+CopyGfxToSuperNintendoVRAM:
+ di
+ push de
+ call DisableLCD
+ ld a, $e4
+ ld [rBGP], a
+ ld de, vChars1
+ ld a, [wCopyingSGBTileData]
+ and a
+ jr z, .notCopyingTileData
+ call CopySGBBorderTiles
+ jr .next
+.notCopyingTileData
+ ld bc, $1000
+ call CopyData
+.next
+ ld hl, vBGMap0
+ ld de, $c
+ ld a, $80
+ ld c, $d
+.loop
+ ld b, $14
+.innerLoop
+ ld [hli], a
+ inc a
+ dec b
+ jr nz, .innerLoop
+ add hl, de
+ dec c
+ jr nz, .loop
+ ld a, $e3
+ ld [rLCDC], a
+ pop hl
+ call SendSGBPacket
+ xor a
+ ld [rBGP], a
+ ei
+ ret
+
+Wait7000:
+; Each loop takes 9 cycles so this routine actually waits 63000 cycles.
+ ld de, 7000
+.loop
+ nop
+ nop
+ nop
+ dec de
+ ld a, d
+ or e
+ jr nz, .loop
+ ret
+
+SendSGBPackets:
+ ld a, [wGBC]
+ and a
+ jr z, .notGBC
+ push de
+ call InitGBCPalettes
+ pop hl
+ call EmptyFunc5
+ ret
+.notGBC
+ push de
+ call SendSGBPacket
+ pop hl
+ jp SendSGBPacket
+
+InitGBCPalettes:
+ ld a, $80 ; index 0 with auto-increment
+ ld [rBGPI], a
+ inc hl
+ ld c, $20
+.loop
+ ld a, [hli]
+ inc hl
+ add a
+ add a
+ add a
+ ld de, SuperPalettes
+ add e
+ jr nc, .noCarry
+ inc d
+.noCarry
+ ld a, [de]
+ ld [rBGPD], a
+ dec c
+ jr nz, .loop
+ ret
+
+EmptyFunc5:
+ ret
+
+CopySGBBorderTiles:
+; SGB tile data is stored in a 4BPP planar format.
+; Each tile is 32 bytes. The first 16 bytes contain bit planes 1 and 2, while
+; the second 16 bytes contain bit planes 3 and 4.
+; This function converts 2BPP planar data into this format by mapping
+; 2BPP colors 0-3 to 4BPP colors 0-3. 4BPP colors 4-15 are not used.
+ ld b, 128
+
+.tileLoop
+
+; Copy bit planes 1 and 2 of the tile data.
+ ld c, 16
+.copyLoop
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .copyLoop
+
+; Zero bit planes 3 and 4.
+ ld c, 16
+ xor a
+.zeroLoop
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .zeroLoop
+
+ dec b
+ jr nz, .tileLoop
+ ret
+
+INCLUDE "data/sgb_packets.asm"
+
+INCLUDE "data/mon_palettes.asm"
+
+INCLUDE "data/super_palettes.asm"
+
+INCLUDE "data/sgb_border.asm"
--- /dev/null
+++ b/engine/gfx/screen_effects.asm
@@ -1,0 +1,71 @@
+; b = new colour for BG colour 0 (usually white) for 4 frames
+ChangeBGPalColor0_4Frames:
+ call GetPredefRegisters
+ ld a, [rBGP]
+ or b
+ ld [rBGP], a
+ ld c, 4
+ call DelayFrames
+ ld a, [rBGP]
+ and %11111100
+ ld [rBGP], a
+ ret
+
+PredefShakeScreenVertically:
+; Moves the window down and then back in a sequence of progressively smaller
+; numbers of pixels, starting at b.
+ call GetPredefRegisters
+ ld a, 1
+ ld [wDisableVBlankWYUpdate], a
+ xor a
+.loop
+ ld [$ff96], a
+ call .MutateWY
+ call .MutateWY
+ dec b
+ ld a, b
+ jr nz, .loop
+ xor a
+ ld [wDisableVBlankWYUpdate], a
+ ret
+
+.MutateWY
+ ld a, [$ff96]
+ xor b
+ ld [$ff96], a
+ ld [rWY], a
+ ld c, 3
+ jp DelayFrames
+
+PredefShakeScreenHorizontally:
+; Moves the window right and then back in a sequence of progressively smaller
+; numbers of pixels, starting at b.
+ call GetPredefRegisters
+ xor a
+.loop
+ ld [$ff97], a
+ call .MutateWX
+ ld c, 1
+ call DelayFrames
+ call .MutateWX
+ dec b
+ ld a, b
+ jr nz, .loop
+
+; restore normal WX
+ ld a, 7
+ ld [rWX], a
+ ret
+
+.MutateWX
+ ld a, [$ff97]
+ xor b
+ ld [$ff97], a
+ bit 7, a
+ jr z, .skipZeroing
+ xor a ; zero a if it's negative
+.skipZeroing
+ add 7
+ ld [rWX], a
+ ld c, 4
+ jp DelayFrames
--- /dev/null
+++ b/engine/gfx/sprite_oam.asm
@@ -1,0 +1,189 @@
+PrepareOAMData::
+; Determine OAM data for currently visible
+; sprites and write it to wOAMBuffer.
+
+ ld a, [wUpdateSpritesEnabled]
+ dec a
+ jr z, .updateEnabled
+
+ cp -1
+ ret nz
+ ld [wUpdateSpritesEnabled], a
+ jp HideSprites
+
+.updateEnabled
+ xor a
+ ld [hOAMBufferOffset], a
+
+.spriteLoop
+ ld [hSpriteOffset2], a
+
+ ld d, wSpriteStateData1 / $100
+ ld a, [hSpriteOffset2]
+ ld e, a
+ ld a, [de] ; c1x0
+ and a
+ jp z, .nextSprite
+
+ inc e
+ inc e
+ ld a, [de] ; c1x2 (facing/anim)
+ ld [wd5cd], a
+ cp $ff ; off-screen (don't draw)
+ jr nz, .visible
+
+ call GetSpriteScreenXY
+ jr .nextSprite
+
+.visible
+ cp $a0 ; is the sprite unchanging like an item ball or boulder?
+ jr c, .usefacing
+
+; unchanging
+ and $f
+ add $10 ; skip to the second half of the table which doesn't account for facing direction
+ jr .next
+
+.usefacing
+ and $f
+
+.next
+ ld l, a
+
+; get sprite priority
+ push de
+ inc d
+ ld a, e
+ add $5
+ ld e, a
+ ld a, [de] ; c2x7
+ and $80
+ ld [hSpritePriority], a ; temp store sprite priority
+ pop de
+
+; read the entry from the table
+ ld h, 0
+ ld bc, SpriteFacingAndAnimationTable
+ add hl, hl
+ add hl, hl
+ add hl, bc
+ ld a, [hli]
+ ld c, a
+ ld a, [hli]
+ ld b, a
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+
+ call GetSpriteScreenXY
+
+ ld a, [hOAMBufferOffset]
+ ld e, a
+ ld d, wOAMBuffer / $100
+
+.tileLoop
+ ld a, [hSpriteScreenY] ; temp for sprite Y position
+ add $10 ; Y=16 is top of screen (Y=0 is invisible)
+ add [hl] ; add Y offset from table
+ ld [de], a ; write new sprite OAM Y position
+ inc hl
+ ld a, [hSpriteScreenX] ; temp for sprite X position
+ add $8 ; X=8 is left of screen (X=0 is invisible)
+ add [hl] ; add X offset from table
+ inc e
+ ld [de], a ; write new sprite OAM X position
+ inc e
+ ld a, [bc] ; read pattern number offset (accommodates orientation (offset 0,4 or 8) and animation (offset 0 or $80))
+ inc bc
+ push bc
+ ld b, a
+
+ ld a, [wd5cd] ; temp copy of c1x2
+ swap a ; high nybble determines sprite used (0 is always player sprite, next are some npcs)
+ and $f
+
+ ; Sprites $a and $b have one face (and therefore 4 tiles instead of 12).
+ ; As a result, sprite $b's tile offset is less than normal.
+ cp $b
+ jr nz, .notFourTileSprite
+ ld a, $a * 12 + 4
+ jr .next2
+
+.notFourTileSprite
+ ; a *= 12
+ sla a
+ sla a
+ ld c, a
+ sla a
+ add c
+
+.next2
+ add b ; add the tile offset from the table (based on frame and facing direction)
+ pop bc
+ ld [de], a ; tile id
+ inc hl
+ inc e
+ ld a, [hl]
+ bit 1, a ; is the tile allowed to set the sprite priority bit?
+ jr z, .skipPriority
+ ld a, [hSpritePriority]
+ or [hl]
+.skipPriority
+ inc hl
+ ld [de], a
+ inc e
+ bit 0, a ; OAMFLAG_ENDOFDATA
+ jr z, .tileLoop
+
+ ld a, e
+ ld [hOAMBufferOffset], a
+
+.nextSprite
+ ld a, [hSpriteOffset2]
+ add $10
+ cp $100 % $100
+ jp nz, .spriteLoop
+
+ ; Clear unused OAM.
+ ld a, [hOAMBufferOffset]
+ ld l, a
+ ld h, wOAMBuffer / $100
+ ld de, $4
+ ld b, $a0
+ ld a, [wd736]
+ bit 6, a ; jumping down ledge or fishing animation?
+ ld a, $a0
+ jr z, .clear
+
+; Don't clear the last 4 entries because they are used for the shadow in the
+; jumping down ledge animation and the rod in the fishing animation.
+ ld a, $90
+
+.clear
+ cp l
+ ret z
+ ld [hl], b
+ add hl, de
+ jr .clear
+
+GetSpriteScreenXY:
+ inc e
+ inc e
+ ld a, [de] ; c1x4
+ ld [hSpriteScreenY], a
+ inc e
+ inc e
+ ld a, [de] ; c1x6
+ ld [hSpriteScreenX], a
+ ld a, 4
+ add e
+ ld e, a
+ ld a, [hSpriteScreenY]
+ add 4
+ and $f0
+ ld [de], a ; c1xa (y)
+ inc e
+ ld a, [hSpriteScreenX]
+ and $f0
+ ld [de], a ; c1xb (x)
+ ret
--- a/engine/give_pokemon.asm
+++ /dev/null
@@ -1,82 +1,0 @@
-_GivePokemon::
-; returns success in carry
-; and whether the mon was added to the party in [wAddedToParty]
- call EnableAutoTextBoxDrawing
- xor a
- ld [wAddedToParty], a
- ld a, [wPartyCount]
- cp PARTY_LENGTH
- jr c, .addToParty
- ld a, [wNumInBox]
- cp MONS_PER_BOX
- jr nc, .boxFull
-; add to box
- xor a
- ld [wEnemyBattleStatus3], a
- ld a, [wcf91]
- ld [wEnemyMonSpecies2], a
- callab LoadEnemyMonData
- call SetPokedexOwnedFlag
- callab SendNewMonToBox
- ld hl, wcf4b
- ld a, [wCurrentBoxNum]
- and $7f
- cp 9
- jr c, .singleDigitBoxNum
- sub 9
- ld [hl], "1"
- inc hl
- add "0"
- jr .next
-.singleDigitBoxNum
- add "1"
-.next
- ld [hli], a
- ld [hl], "@"
- ld hl, SentToBoxText
- call PrintText
- scf
- ret
-.boxFull
- ld hl, BoxIsFullText
- call PrintText
- and a
- ret
-.addToParty
- call SetPokedexOwnedFlag
- call AddPartyMon
- ld a, 1
- ld [wDoNotWaitForButtonPressAfterDisplayingText], a
- ld [wAddedToParty], a
- scf
- ret
-
-SetPokedexOwnedFlag:
- ld a, [wcf91]
- push af
- ld [wd11e], a
- predef IndexToPokedex
- ld a, [wd11e]
- dec a
- ld c, a
- ld hl, wPokedexOwned
- ld b, FLAG_SET
- predef FlagActionPredef
- pop af
- ld [wd11e], a
- call GetMonName
- ld hl, GotMonText
- jp PrintText
-
-GotMonText:
- TX_FAR _GotMonText
- TX_SFX_ITEM_1
- db "@"
-
-SentToBoxText:
- TX_FAR _SentToBoxText
- db "@"
-
-BoxIsFullText:
- TX_FAR _BoxIsFullText
- db "@"
--- a/engine/hall_of_fame.asm
+++ /dev/null
@@ -1,288 +1,0 @@
-AnimateHallOfFame:
- call HoFFadeOutScreenAndMusic
- call ClearScreen
- ld c, 100
- call DelayFrames
- call LoadFontTilePatterns
- call LoadTextBoxTilePatterns
- call DisableLCD
- ld hl, vBGMap0
- ld bc, $800
- ld a, " "
- call FillMemory
- call EnableLCD
- ld hl, rLCDC
- set 3, [hl]
- xor a
- ld hl, wHallOfFame
- ld bc, HOF_TEAM
- call FillMemory
- xor a
- ld [wUpdateSpritesEnabled], a
- ld [hTilesetType], a
- ld [wSpriteFlipped], a
- ld [wLetterPrintingDelayFlags], a ; no delay
- ld [wHoFMonOrPlayer], a ; mon
- inc a
- ld [H_AUTOBGTRANSFERENABLED], a
- ld hl, wNumHoFTeams
- ld a, [hl]
- inc a
- jr z, .skipInc ; don't wrap around to 0
- inc [hl]
-.skipInc
- ld a, $90
- ld [hWY], a
- ld c, BANK(Music_HallOfFame)
- ld a, MUSIC_HALL_OF_FAME
- call PlayMusic
- ld hl, wPartySpecies
- ld c, $ff
-.partyMonLoop
- ld a, [hli]
- cp $ff
- jr z, .doneShowingParty
- inc c
- push hl
- push bc
- ld [wHoFMonSpecies], a
- ld a, c
- ld [wHoFPartyMonIndex], a
- ld hl, wPartyMon1Level
- ld bc, wPartyMon2 - wPartyMon1
- call AddNTimes
- ld a, [hl]
- ld [wHoFMonLevel], a
- call HoFShowMonOrPlayer
- call HoFDisplayAndRecordMonInfo
- ld c, 80
- call DelayFrames
- coord hl, 2, 13
- ld b, 3
- ld c, 14
- call TextBoxBorder
- coord hl, 4, 15
- ld de, HallOfFameText
- call PlaceString
- ld c, 180
- call DelayFrames
- call GBFadeOutToWhite
- pop bc
- pop hl
- jr .partyMonLoop
-.doneShowingParty
- ld a, c
- inc a
- ld hl, wHallOfFame
- ld bc, HOF_MON
- call AddNTimes
- ld [hl], $ff
- call SaveHallOfFameTeams
- xor a
- ld [wHoFMonSpecies], a
- inc a
- ld [wHoFMonOrPlayer], a ; player
- call HoFShowMonOrPlayer
- call HoFDisplayPlayerStats
- call HoFFadeOutScreenAndMusic
- xor a
- ld [hWY], a
- ld hl, rLCDC
- res 3, [hl]
- ret
-
-HallOfFameText:
- db "HALL OF FAME@"
-
-HoFShowMonOrPlayer:
- call ClearScreen
- ld a, $d0
- ld [hSCY], a
- ld a, $c0
- ld [hSCX], a
- ld a, [wHoFMonSpecies]
- ld [wcf91], a
- ld [wd0b5], a
- ld [wBattleMonSpecies2], a
- ld [wWholeScreenPaletteMonSpecies], a
- ld a, [wHoFMonOrPlayer]
- and a
- jr z, .showMon
-; show player
- call HoFLoadPlayerPics
- jr .next1
-.showMon
- coord hl, 12, 5
- call GetMonHeader
- call LoadFrontSpriteByMonIndex
- predef LoadMonBackPic
-.next1
- ld b, SET_PAL_POKEMON_WHOLE_SCREEN
- ld c, 0
- call RunPaletteCommand
- ld a, %11100100
- ld [rBGP], a
- ld c, $31 ; back pic
- call HoFLoadMonPlayerPicTileIDs
- ld d, $a0
- ld e, 4
- ld a, [wOnSGB]
- and a
- jr z, .next2
- sla e ; scroll more slowly on SGB
-.next2
- call .ScrollPic ; scroll back pic left
- xor a
- ld [hSCY], a
- ld c, a ; front pic
- call HoFLoadMonPlayerPicTileIDs
- ld d, 0
- ld e, -4
-; scroll front pic right
-
-.ScrollPic
- call DelayFrame
- ld a, [hSCX]
- add e
- ld [hSCX], a
- cp d
- jr nz, .ScrollPic
- ret
-
-HoFDisplayAndRecordMonInfo:
- ld a, [wHoFPartyMonIndex]
- ld hl, wPartyMonNicks
- call GetPartyMonName
- call HoFDisplayMonInfo
- jp HoFRecordMonInfo
-
-HoFDisplayMonInfo:
- coord hl, 0, 2
- ld b, 9
- ld c, 10
- call TextBoxBorder
- coord hl, 2, 6
- ld de, HoFMonInfoText
- call PlaceString
- coord hl, 1, 4
- ld de, wcd6d
- call PlaceString
- ld a, [wHoFMonLevel]
- coord hl, 8, 7
- call PrintLevelCommon
- ld a, [wHoFMonSpecies]
- ld [wd0b5], a
- coord hl, 3, 9
- predef PrintMonType
- ld a, [wHoFMonSpecies]
- jp PlayCry
-
-HoFMonInfoText:
- db "LEVEL/"
- next "TYPE1/"
- next "TYPE2/@"
-
-HoFLoadPlayerPics:
- ld de, RedPicFront
- ld a, BANK(RedPicFront)
- call UncompressSpriteFromDE
- ld hl, sSpriteBuffer1
- ld de, sSpriteBuffer0
- ld bc, $310
- call CopyData
- ld de, vFrontPic
- call InterlaceMergeSpriteBuffers
- ld de, RedPicBack
- ld a, BANK(RedPicBack)
- call UncompressSpriteFromDE
- predef ScaleSpriteByTwo
- ld de, vBackPic
- call InterlaceMergeSpriteBuffers
- ld c, $1
-
-HoFLoadMonPlayerPicTileIDs:
-; c = base tile ID
- ld b, 0
- coord hl, 12, 5
- predef_jump CopyTileIDsFromList
-
-HoFDisplayPlayerStats:
- SetEvent EVENT_HALL_OF_FAME_DEX_RATING
- predef DisplayDexRating
- coord hl, 0, 4
- ld b, 6
- ld c, 10
- call TextBoxBorder
- coord hl, 5, 0
- ld b, 2
- ld c, 9
- call TextBoxBorder
- coord hl, 7, 2
- ld de, wPlayerName
- call PlaceString
- coord hl, 1, 6
- ld de, HoFPlayTimeText
- call PlaceString
- coord hl, 5, 7
- ld de, wPlayTimeHours
- lb bc, 1, 3
- call PrintNumber
- ld [hl], $6d
- inc hl
- ld de, wPlayTimeMinutes
- lb bc, LEADING_ZEROES | 1, 2
- call PrintNumber
- coord hl, 1, 9
- ld de, HoFMoneyText
- call PlaceString
- coord hl, 4, 10
- ld de, wPlayerMoney
- ld c, $a3
- call PrintBCDNumber
- ld hl, DexSeenOwnedText
- call HoFPrintTextAndDelay
- ld hl, DexRatingText
- call HoFPrintTextAndDelay
- ld hl, wDexRatingText
-
-HoFPrintTextAndDelay:
- call PrintText
- ld c, 120
- jp DelayFrames
-
-HoFPlayTimeText:
- db "PLAY TIME@"
-
-HoFMoneyText:
- db "MONEY@"
-
-DexSeenOwnedText:
- TX_FAR _DexSeenOwnedText
- db "@"
-
-DexRatingText:
- TX_FAR _DexRatingText
- db "@"
-
-HoFRecordMonInfo:
- ld hl, wHallOfFame
- ld bc, HOF_MON
- ld a, [wHoFPartyMonIndex]
- call AddNTimes
- ld a, [wHoFMonSpecies]
- ld [hli], a
- ld a, [wHoFMonLevel]
- ld [hli], a
- ld e, l
- ld d, h
- ld hl, wcd6d
- ld bc, NAME_LENGTH
- jp CopyData
-
-HoFFadeOutScreenAndMusic:
- ld a, 10
- ld [wAudioFadeOutCounterReloadValue], a
- ld [wAudioFadeOutCounter], a
- ld a, $ff
- ld [wAudioFadeOutControl], a
- jp GBFadeOutToWhite
--- a/engine/heal_party.asm
+++ /dev/null
@@ -1,99 +1,0 @@
-HealParty:
-; Restore HP and PP.
-
- ld hl, wPartySpecies
- ld de, wPartyMon1HP
-.healmon
- ld a, [hli]
- cp $ff
- jr z, .done
-
- push hl
- push de
-
- ld hl, wPartyMon1Status - wPartyMon1HP
- add hl, de
- xor a
- ld [hl], a
-
- push de
- ld b, NUM_MOVES ; A Pokémon has 4 moves
-.pp
- ld hl, wPartyMon1Moves - wPartyMon1HP
- add hl, de
-
- ld a, [hl]
- and a
- jr z, .nextmove
-
- dec a
- ld hl, wPartyMon1PP - wPartyMon1HP
- add hl, de
-
- push hl
- push de
- push bc
-
- ld hl, Moves
- ld bc, MoveEnd - Moves
- call AddNTimes
- ld de, wcd6d
- ld a, BANK(Moves)
- call FarCopyData
- ld a, [wcd6d + 5] ; PP is byte 5 of move data
-
- pop bc
- pop de
- pop hl
-
- inc de
- push bc
- ld b, a
- ld a, [hl]
- and $c0
- add b
- ld [hl], a
- pop bc
-
-.nextmove
- dec b
- jr nz, .pp
- pop de
-
- ld hl, wPartyMon1MaxHP - wPartyMon1HP
- add hl, de
- ld a, [hli]
- ld [de], a
- inc de
- ld a, [hl]
- ld [de], a
-
- pop de
- pop hl
-
- push hl
- ld bc, wPartyMon2 - wPartyMon1
- ld h, d
- ld l, e
- add hl, bc
- ld d, h
- ld e, l
- pop hl
- jr .healmon
-
-.done
- xor a
- ld [wWhichPokemon], a
- ld [wd11e], a
-
- ld a, [wPartyCount]
- ld b, a
-.ppup
- push bc
- call RestoreBonusPP
- pop bc
- ld hl, wWhichPokemon
- inc [hl]
- dec b
- jr nz, .ppup
- ret
--- a/engine/hidden_object_functions14.asm
+++ /dev/null
@@ -1,100 +1,0 @@
-PrintNotebookText:
- call EnableAutoTextBoxDrawing
- ld a, $1
- ld [wDoNotWaitForButtonPressAfterDisplayingText], a
- ld a, [wHiddenObjectFunctionArgument]
- jp PrintPredefTextID
-
-TMNotebook::
- TX_FAR TMNotebookText
- TX_WAIT
- db "@"
-
-ViridianSchoolNotebook::
- TX_ASM
- ld hl, ViridianSchoolNotebookText1
- call PrintText
- call TurnPageSchoolNotebook
- jr nz, .doneReading
- ld hl, ViridianSchoolNotebookText2
- call PrintText
- call TurnPageSchoolNotebook
- jr nz, .doneReading
- ld hl, ViridianSchoolNotebookText3
- call PrintText
- call TurnPageSchoolNotebook
- jr nz, .doneReading
- ld hl, ViridianSchoolNotebookText4
- call PrintText
- ld hl, ViridianSchoolNotebookText5
- call PrintText
-.doneReading
- jp TextScriptEnd
-
-TurnPageSchoolNotebook:
- ld hl, TurnPageText
- call PrintText
- call YesNoChoice
- ld a, [wCurrentMenuItem]
- and a
- ret
-
-TurnPageText:
- TX_FAR _TurnPageText
- db "@"
-
-ViridianSchoolNotebookText5:
- TX_FAR _ViridianSchoolNotebookText5
- TX_WAIT
- db "@"
-
-ViridianSchoolNotebookText1:
- TX_FAR _ViridianSchoolNotebookText1
- db "@"
-
-ViridianSchoolNotebookText2:
- TX_FAR _ViridianSchoolNotebookText2
- db "@"
-
-ViridianSchoolNotebookText3:
- TX_FAR _ViridianSchoolNotebookText3
- db "@"
-
-ViridianSchoolNotebookText4:
- TX_FAR _ViridianSchoolNotebookText4
- db "@"
-
-PrintFightingDojoText2:
- call EnableAutoTextBoxDrawing
- tx_pre_jump EnemiesOnEverySideText
-
-EnemiesOnEverySideText::
- TX_FAR _EnemiesOnEverySideText
- db "@"
-
-PrintFightingDojoText3:
- call EnableAutoTextBoxDrawing
- tx_pre_jump WhatGoesAroundComesAroundText
-
-WhatGoesAroundComesAroundText::
- TX_FAR _WhatGoesAroundComesAroundText
- db "@"
-
-PrintFightingDojoText:
- call EnableAutoTextBoxDrawing
- tx_pre_jump FightingDojoText
-
-FightingDojoText::
- TX_FAR _FightingDojoText
- db "@"
-
-PrintIndigoPlateauHQText:
- ld a, [wSpriteStateData1 + 9]
- cp SPRITE_FACING_UP
- ret nz
- call EnableAutoTextBoxDrawing
- tx_pre_jump IndigoPlateauHQText
-
-IndigoPlateauHQText::
- TX_FAR _IndigoPlateauHQText
- db "@"
--- a/engine/hidden_object_functions17.asm
+++ /dev/null
@@ -1,475 +1,0 @@
-PrintRedSNESText:
- call EnableAutoTextBoxDrawing
- tx_pre_jump RedBedroomSNESText
-
-RedBedroomSNESText::
- TX_FAR _RedBedroomSNESText
- db "@"
-
-OpenRedsPC:
- call EnableAutoTextBoxDrawing
- tx_pre_jump RedBedroomPCText
-
-RedBedroomPCText::
- TX_PLAYERS_PC
-
-Route15GateLeftBinoculars:
- ld a, [wSpriteStateData1 + 9]
- cp SPRITE_FACING_UP
- ret nz
- call EnableAutoTextBoxDrawing
- tx_pre Route15UpstairsBinocularsText
- ld a, ARTICUNO
- ld [wcf91], a
- call PlayCry
- jp DisplayMonFrontSpriteInBox
-
-Route15UpstairsBinocularsText::
- TX_FAR _Route15UpstairsBinocularsText
- db "@"
-
-AerodactylFossil:
- ld a, FOSSIL_AERODACTYL
- ld [wcf91], a
- call DisplayMonFrontSpriteInBox
- call EnableAutoTextBoxDrawing
- tx_pre AerodactylFossilText
- ret
-
-AerodactylFossilText::
- TX_FAR _AerodactylFossilText
- db "@"
-
-KabutopsFossil:
- ld a, FOSSIL_KABUTOPS
- ld [wcf91], a
- call DisplayMonFrontSpriteInBox
- call EnableAutoTextBoxDrawing
- tx_pre KabutopsFossilText
- ret
-
-KabutopsFossilText::
- TX_FAR _KabutopsFossilText
- db "@"
-
-DisplayMonFrontSpriteInBox:
-; Displays a pokemon's front sprite in a pop-up window.
-; [wcf91] = pokemon internal id number
- ld a, 1
- ld [H_AUTOBGTRANSFERENABLED], a
- call Delay3
- xor a
- ld [hWY], a
- call SaveScreenTilesToBuffer1
- ld a, MON_SPRITE_POPUP
- ld [wTextBoxID], a
- call DisplayTextBoxID
- call UpdateSprites
- ld a, [wcf91]
- ld [wd0b5], a
- call GetMonHeader
- ld de, vChars1 + $310
- call LoadMonFrontSprite
- ld a, $80
- ld [hStartTileID], a
- coord hl, 10, 11
- predef AnimateSendingOutMon
- call WaitForTextScrollButtonPress
- call LoadScreenTilesFromBuffer1
- call Delay3
- ld a, $90
- ld [hWY], a
- ret
-
-PrintBlackboardLinkCableText:
- call EnableAutoTextBoxDrawing
- ld a, $1
- ld [wDoNotWaitForButtonPressAfterDisplayingText], a
- ld a, [wHiddenObjectFunctionArgument]
- call PrintPredefTextID
- ret
-
-LinkCableHelp::
- TX_ASM
- call SaveScreenTilesToBuffer1
- ld hl, LinkCableHelpText1
- call PrintText
- xor a
- ld [wMenuItemOffset], a ; not used
- ld [wCurrentMenuItem], a
- ld [wLastMenuItem], a
- ld a, A_BUTTON | B_BUTTON
- ld [wMenuWatchedKeys], a
- ld a, 3
- ld [wMaxMenuItem], a
- ld a, 2
- ld [wTopMenuItemY], a
- ld a, 1
- ld [wTopMenuItemX], a
-.linkHelpLoop
- ld hl, wd730
- set 6, [hl]
- coord hl, 0, 0
- ld b, 8
- ld c, 13
- call TextBoxBorder
- coord hl, 2, 2
- ld de, HowToLinkText
- call PlaceString
- ld hl, LinkCableHelpText2
- call PrintText
- call HandleMenuInput
- bit 1, a ; pressed b
- jr nz, .exit
- ld a, [wCurrentMenuItem]
- cp 3 ; pressed a on "STOP READING"
- jr z, .exit
- ld hl, wd730
- res 6, [hl]
- ld hl, LinkCableInfoTexts
- add a
- ld d, 0
- ld e, a
- add hl, de
- ld a, [hli]
- ld h, [hl]
- ld l, a
- call PrintText
- jp .linkHelpLoop
-.exit
- ld hl, wd730
- res 6, [hl]
- call LoadScreenTilesFromBuffer1
- jp TextScriptEnd
-
-LinkCableHelpText1:
- TX_FAR _LinkCableHelpText1
- db "@"
-
-LinkCableHelpText2:
- TX_FAR _LinkCableHelpText2
- db "@"
-
-HowToLinkText:
- db "HOW TO LINK"
- next "COLOSSEUM"
- next "TRADE CENTER"
- next "STOP READING@"
-
-LinkCableInfoTexts:
- dw LinkCableInfoText1
- dw LinkCableInfoText2
- dw LinkCableInfoText3
-
-LinkCableInfoText1:
- TX_FAR _LinkCableInfoText1
- db "@"
-
-LinkCableInfoText2:
- TX_FAR _LinkCableInfoText2
- db "@"
-
-LinkCableInfoText3:
- TX_FAR _LinkCableInfoText3
- db "@"
-
-ViridianSchoolBlackboard::
- TX_ASM
- call SaveScreenTilesToBuffer1
- ld hl, ViridianSchoolBlackboardText1
- call PrintText
- xor a
- ld [wMenuItemOffset], a
- ld [wCurrentMenuItem], a
- ld [wLastMenuItem], a
- ld a, D_LEFT | D_RIGHT | A_BUTTON | B_BUTTON
- ld [wMenuWatchedKeys], a
- ld a, 2
- ld [wMaxMenuItem], a
- ld a, 2
- ld [wTopMenuItemY], a
- ld a, 1
- ld [wTopMenuItemX], a
-.blackboardLoop
- ld hl, wd730
- set 6, [hl]
- coord hl, 0, 0
- lb bc, 6, 10
- call TextBoxBorder
- coord hl, 1, 2
- ld de, StatusAilmentText1
- call PlaceString
- coord hl, 6, 2
- ld de, StatusAilmentText2
- call PlaceString
- ld hl, ViridianSchoolBlackboardText2
- call PrintText
- call HandleMenuInput ; pressing up and down is handled in here
- bit 1, a ; pressed b
- jr nz, .exitBlackboard
- bit 4, a ; pressed right
- jr z, .didNotPressRight
- ; move cursor to right column
- ld a, 2
- ld [wMaxMenuItem], a
- ld a, 2
- ld [wTopMenuItemY], a
- ld a, 6
- ld [wTopMenuItemX], a
- ld a, 3 ; in the the right column, use an offset to prevent overlap
- ld [wMenuItemOffset], a
- jr .blackboardLoop
-.didNotPressRight
- bit 5, a ; pressed left
- jr z, .didNotPressLeftOrRight
- ; move cursor to left column
- ld a, 2
- ld [wMaxMenuItem], a
- ld a, 2
- ld [wTopMenuItemY], a
- ld a, 1
- ld [wTopMenuItemX], a
- xor a
- ld [wMenuItemOffset], a
- jr .blackboardLoop
-.didNotPressLeftOrRight
- ld a, [wCurrentMenuItem]
- ld b, a
- ld a, [wMenuItemOffset]
- add b
- cp 5 ; cursor is pointing to "QUIT"
- jr z, .exitBlackboard
- ; we must have pressed a on a status condition
- ; so print the text
- ld hl, wd730
- res 6, [hl]
- ld hl, ViridianBlackboardStatusPointers
- add a
- ld d, 0
- ld e, a
- add hl, de
- ld a, [hli]
- ld h, [hl]
- ld l, a
- call PrintText
- jp .blackboardLoop
-.exitBlackboard
- ld hl, wd730
- res 6, [hl]
- call LoadScreenTilesFromBuffer1
- jp TextScriptEnd
-
-ViridianSchoolBlackboardText1:
- TX_FAR _ViridianSchoolBlackboardText1
- db "@"
-
-ViridianSchoolBlackboardText2:
- TX_FAR _ViridianSchoolBlackboardText2
- db "@"
-
-StatusAilmentText1:
- db " SLP"
- next " PSN"
- next " PAR@"
-
-StatusAilmentText2:
- db " BRN"
- next " FRZ"
- next " QUIT@@"
-
-ViridianBlackboardStatusPointers:
- dw ViridianBlackboardSleepText
- dw ViridianBlackboardPoisonText
- dw ViridianBlackboardPrlzText
- dw ViridianBlackboardBurnText
- dw ViridianBlackboardFrozenText
-
-ViridianBlackboardSleepText:
- TX_FAR _ViridianBlackboardSleepText
- db "@"
-
-ViridianBlackboardPoisonText:
- TX_FAR _ViridianBlackboardPoisonText
- db "@"
-
-ViridianBlackboardPrlzText:
- TX_FAR _ViridianBlackboardPrlzText
- db "@"
-
-ViridianBlackboardBurnText:
- TX_FAR _ViridianBlackboardBurnText
- db "@"
-
-ViridianBlackboardFrozenText:
- TX_FAR _ViridianBlackboardFrozenText
- db "@"
-
-PrintTrashText:
- call EnableAutoTextBoxDrawing
- tx_pre_jump VermilionGymTrashText
-
-VermilionGymTrashText::
- TX_FAR _VermilionGymTrashText
- db "@"
-
-GymTrashScript:
- call EnableAutoTextBoxDrawing
- ld a, [wHiddenObjectFunctionArgument]
- ld [wGymTrashCanIndex], a
-
-; Don't do the trash can puzzle if it's already been done.
- CheckEvent EVENT_2ND_LOCK_OPENED
- jr z, .ok
-
- tx_pre_jump VermilionGymTrashText
-
-.ok
- CheckEventReuseA EVENT_1ST_LOCK_OPENED
- jr nz, .trySecondLock
-
- ld a, [wFirstLockTrashCanIndex]
- ld b, a
- ld a, [wGymTrashCanIndex]
- cp b
- jr z, .openFirstLock
-
- tx_pre_id VermilionGymTrashText
- jr .done
-
-.openFirstLock
-; Next can is trying for the second switch.
- SetEvent EVENT_1ST_LOCK_OPENED
-
- ld hl, GymTrashCans
- ld a, [wGymTrashCanIndex]
- ; * 5
- ld b, a
- add a
- add a
- add b
-
- ld d, 0
- ld e, a
- add hl, de
- ld a, [hli]
-
-; There is a bug in this code. It should calculate a value in the range [0, 3]
-; but if the mask and random number don't have any 1 bits in common, then
-; the result of the AND will be 0. When 1 is subtracted from that, the value
-; will become $ff. This will result in 255 being added to hl, which will cause
-; hl to point to one of the zero bytes that pad the end of the ROM bank.
-; Trash can 0 was intended to be able to have the second lock only when the
-; first lock was in trash can 1 or 3. However, due to this bug, trash can 0 can
-; have the second lock regardless of which trash can had the first lock.
-
- ld [hGymTrashCanRandNumMask], a
- push hl
- call Random
- swap a
- ld b, a
- ld a, [hGymTrashCanRandNumMask]
- and b
- dec a
- pop hl
-
- ld d, 0
- ld e, a
- add hl, de
- ld a, [hl]
- and $f
- ld [wSecondLockTrashCanIndex], a
-
- tx_pre_id VermilionGymTrashSuccessText1
- jr .done
-
-.trySecondLock
- ld a, [wSecondLockTrashCanIndex]
- ld b, a
- ld a, [wGymTrashCanIndex]
- cp b
- jr z, .openSecondLock
-
-; Reset the cans.
- ResetEvent EVENT_1ST_LOCK_OPENED
- call Random
-
- and $e
- ld [wFirstLockTrashCanIndex], a
-
- tx_pre_id VermilionGymTrashFailText
- jr .done
-
-.openSecondLock
-; Completed the trash can puzzle.
- SetEvent EVENT_2ND_LOCK_OPENED
- ld hl, wCurrentMapScriptFlags
- set 6, [hl]
-
- tx_pre_id VermilionGymTrashSuccessText3
-
-.done
- jp PrintPredefTextID
-
-GymTrashCans:
-; byte 0: mask for random number
-; bytes 1-4: indices of the trash cans that can have the second lock
-; (but see the comment above explaining a bug regarding this)
-; Note that the mask is simply the number of valid trash can indices that
-; follow. The remaining bytes are filled with 0 to pad the length of each entry
-; to 5 bytes.
- db 2, 1, 3, 0, 0 ; 0
- db 3, 0, 2, 4, 0 ; 1
- db 2, 1, 5, 0, 0 ; 2
- db 3, 0, 4, 6, 0 ; 3
- db 4, 1, 3, 5, 7 ; 4
- db 3, 2, 4, 8, 0 ; 5
- db 3, 3, 7, 9, 0 ; 6
- db 4, 4, 6, 8, 10 ; 7
- db 3, 5, 7, 11, 0 ; 8
- db 3, 6, 10, 12, 0 ; 9
- db 4, 7, 9, 11, 13 ; 10
- db 3, 8, 10, 14, 0 ; 11
- db 2, 9, 13, 0, 0 ; 12
- db 3, 10, 12, 14, 0 ; 13
- db 2, 11, 13, 0, 0 ; 14
-
-VermilionGymTrashSuccessText1::
- TX_FAR _VermilionGymTrashSuccessText1
- TX_ASM
- call WaitForSoundToFinish
- ld a, SFX_SWITCH
- call PlaySound
- call WaitForSoundToFinish
- jp TextScriptEnd
-
-; unused
-VermilionGymTrashSuccessText2::
- TX_FAR _VermilionGymTrashSuccessText2
- db "@"
-
-; unused
-VermilionGymTrashSuccesPlaySfx:
- TX_ASM
- call WaitForSoundToFinish
- ld a, SFX_SWITCH
- call PlaySound
- call WaitForSoundToFinish
- jp TextScriptEnd
-
-VermilionGymTrashSuccessText3::
- TX_FAR _VermilionGymTrashSuccessText3
- TX_ASM
- call WaitForSoundToFinish
- ld a, SFX_GO_INSIDE
- call PlaySound
- call WaitForSoundToFinish
- jp TextScriptEnd
-
-VermilionGymTrashFailText::
- TX_FAR _VermilionGymTrashFailText
- TX_ASM
- call WaitForSoundToFinish
- ld a, SFX_DENIED
- call PlaySound
- call WaitForSoundToFinish
- jp TextScriptEnd
--- a/engine/hidden_object_functions18.asm
+++ /dev/null
@@ -1,198 +1,0 @@
-GymStatues:
-; if in a gym and have the corresponding badge, a = GymStatueText2_id and jp PrintPredefTextID
-; if in a gym and don’t have the corresponding badge, a = GymStatueText1_id and jp PrintPredefTextID
-; else ret
- call EnableAutoTextBoxDrawing
- ld a, [wSpriteStateData1 + 9]
- cp SPRITE_FACING_UP
- ret nz
- ld hl, .BadgeFlags
- ld a, [wCurMap]
- ld b, a
-.loop
- ld a, [hli]
- cp $ff
- ret z
- cp b
- jr z, .match
- inc hl
- jr .loop
-.match
- ld b, [hl]
- ld a, [wBeatGymFlags]
- and b
- cp b
- tx_pre_id GymStatueText2
- jr z, .haveBadge
- tx_pre_id GymStatueText1
-.haveBadge
- jp PrintPredefTextID
-
-.BadgeFlags:
- db PEWTER_GYM, %00000001
- db CERULEAN_GYM, %00000010
- db VERMILION_GYM,%00000100
- db CELADON_GYM, %00001000
- db FUCHSIA_GYM, %00010000
- db SAFFRON_GYM, %00100000
- db CINNABAR_GYM, %01000000
- db VIRIDIAN_GYM, %10000000
- db $ff
-
-GymStatueText1::
- TX_FAR _GymStatueText1
- db "@"
-
-GymStatueText2::
- TX_FAR _GymStatueText2
- db "@"
-
-PrintBenchGuyText:
- call EnableAutoTextBoxDrawing
- ld hl, BenchGuyTextPointers
- ld a, [wCurMap]
- ld b, a
-.loop
- ld a, [hli]
- cp $ff
- ret z
- cp b
- jr z, .match
- inc hl
- inc hl
- jr .loop
-.match
- ld a, [hli]
- ld b, a
- ld a, [wSpriteStateData1 + 9]
- cp b
- jr nz, .loop ; player isn't facing left at the bench guy
- ld a, [hl]
- jp PrintPredefTextID
-
-; format: db map id, player sprite facing direction, text id of PredefTextIDPointerTable
-BenchGuyTextPointers:
- db VIRIDIAN_POKECENTER, SPRITE_FACING_LEFT
- db_tx_pre ViridianCityPokecenterBenchGuyText
- db PEWTER_POKECENTER, SPRITE_FACING_LEFT
- db_tx_pre PewterCityPokecenterBenchGuyText
- db CERULEAN_POKECENTER, SPRITE_FACING_LEFT
- db_tx_pre CeruleanCityPokecenterBenchGuyText
- db LAVENDER_POKECENTER, SPRITE_FACING_LEFT
- db_tx_pre LavenderCityPokecenterBenchGuyText
- db VERMILION_POKECENTER, SPRITE_FACING_LEFT
- db_tx_pre VermilionCityPokecenterBenchGuyText
- db CELADON_POKECENTER, SPRITE_FACING_LEFT
- db_tx_pre CeladonCityPokecenterBenchGuyText
- db CELADON_HOTEL, SPRITE_FACING_LEFT
- db_tx_pre CeladonCityHotelText
- db FUCHSIA_POKECENTER, SPRITE_FACING_LEFT
- db_tx_pre FuchsiaCityPokecenterBenchGuyText
- db CINNABAR_POKECENTER, SPRITE_FACING_LEFT
- db_tx_pre CinnabarIslandPokecenterBenchGuyText
- db SAFFRON_POKECENTER, SPRITE_FACING_LEFT
- db_tx_pre SaffronCityPokecenterBenchGuyText
- db MT_MOON_POKECENTER, SPRITE_FACING_LEFT
- db_tx_pre MtMoonPokecenterBenchGuyText
- db ROCK_TUNNEL_POKECENTER,SPRITE_FACING_LEFT
- db_tx_pre RockTunnelPokecenterBenchGuyText
- db $FF
-
-ViridianCityPokecenterBenchGuyText::
- TX_FAR _ViridianCityPokecenterGuyText
- db "@"
-
-PewterCityPokecenterBenchGuyText::
- TX_FAR _PewterCityPokecenterGuyText
- db "@"
-
-CeruleanCityPokecenterBenchGuyText::
- TX_FAR _CeruleanPokecenterGuyText
- db "@"
-
-LavenderCityPokecenterBenchGuyText::
- TX_FAR _LavenderPokecenterGuyText
- db "@"
-
-MtMoonPokecenterBenchGuyText::
- TX_FAR _MtMoonPokecenterBenchGuyText
- db "@"
-
-RockTunnelPokecenterBenchGuyText::
- TX_FAR _RockTunnelPokecenterGuyText
- db "@"
-
-UnusedBenchGuyText1::
- TX_FAR _UnusedBenchGuyText1
- db "@"
-
-UnusedBenchGuyText2::
- TX_FAR _UnusedBenchGuyText2
- db "@"
-
-UnusedBenchGuyText3::
- TX_FAR _UnusedBenchGuyText3
- db "@"
-
-VermilionCityPokecenterBenchGuyText::
- TX_FAR _VermilionPokecenterGuyText
- db "@"
-
-CeladonCityPokecenterBenchGuyText::
- TX_FAR _CeladonCityPokecenterGuyText
- db "@"
-
-FuchsiaCityPokecenterBenchGuyText::
- TX_FAR _FuchsiaCityPokecenterGuyText
- db "@"
-
-CinnabarIslandPokecenterBenchGuyText::
- TX_FAR _CinnabarPokecenterGuyText
- db "@"
-
-SaffronCityPokecenterBenchGuyText::
- TX_ASM
- CheckEvent EVENT_BEAT_SILPH_CO_GIOVANNI
- ld hl, SaffronCityPokecenterBenchGuyText2
- jr nz, .asm_624f2
- ld hl, SaffronCityPokecenterBenchGuyText1
-.asm_624f2
- call PrintText
- jp TextScriptEnd
-
-SaffronCityPokecenterBenchGuyText1:
- TX_FAR _SaffronCityPokecenterGuyText1
- db "@"
-
-SaffronCityPokecenterBenchGuyText2:
- TX_FAR _SaffronCityPokecenterGuyText2
- db "@"
-
-CeladonCityHotelText::
- TX_FAR _CeladonCityHotelText
- db "@"
-
- ret
-
-UnusedPredefText::
- db "@"
-
-PrintBookcaseText:
- call EnableAutoTextBoxDrawing
- tx_pre_jump BookcaseText
-
-BookcaseText::
- TX_FAR _BookcaseText
- db "@"
-
-OpenPokemonCenterPC:
- ld a, [wSpriteStateData1 + 9]
- cp SPRITE_FACING_UP ; check to see if player is facing up
- ret nz
- call EnableAutoTextBoxDrawing
- ld a, $1
- ld [wAutoTextBoxDrawingControl], a
- tx_pre_jump PokemonCenterPCText
-
-PokemonCenterPCText::
- TX_POKECENTER_PC
--- a/engine/hidden_object_functions3.asm
+++ /dev/null
@@ -1,117 +1,0 @@
-; prints text for bookshelves in buildings without sign events
-PrintBookshelfText::
- ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction
- cp SPRITE_FACING_UP
- jr nz, .noMatch
-; facing up
- ld a, [wCurMapTileset]
- ld b, a
- aCoord 8, 7
- ld c, a
- ld hl, BookshelfTileIDs
-.loop
- ld a, [hli]
- cp $ff
- jr z, .noMatch
- cp b
- jr nz, .nextBookshelfEntry1
- ld a, [hli]
- cp c
- jr nz, .nextBookshelfEntry2
- ld a, [hl]
- push af
- call EnableAutoTextBoxDrawing
- pop af
- call PrintPredefTextID
- xor a
- ld [$ffdb], a
- ret
-.nextBookshelfEntry1
- inc hl
-.nextBookshelfEntry2
- inc hl
- jr .loop
-.noMatch
- ld a, $ff
- ld [$ffdb], a
- jpba PrintCardKeyText
-
-INCLUDE "data/bookshelf_tile_ids.asm"
-
-IndigoPlateauStatues::
- TX_ASM
- ld hl, IndigoPlateauStatuesText1
- call PrintText
- ld a, [wXCoord]
- bit 0, a
- ld hl, IndigoPlateauStatuesText2
- jr nz, .ok
- ld hl, IndigoPlateauStatuesText3
-.ok
- call PrintText
- jp TextScriptEnd
-
-IndigoPlateauStatuesText1:
- TX_FAR _IndigoPlateauStatuesText1
- db "@"
-
-IndigoPlateauStatuesText2:
- TX_FAR _IndigoPlateauStatuesText2
- db "@"
-
-IndigoPlateauStatuesText3:
- TX_FAR _IndigoPlateauStatuesText3
- db "@"
-
-BookOrSculptureText::
- TX_ASM
- ld hl, PokemonBooksText
- ld a, [wCurMapTileset]
- cp MANSION ; Celadon Mansion tileset
- jr nz, .ok
- aCoord 8, 6
- cp $38
- jr nz, .ok
- ld hl, DiglettSculptureText
-.ok
- call PrintText
- jp TextScriptEnd
-
-PokemonBooksText:
- TX_FAR _PokemonBooksText
- db "@"
-
-DiglettSculptureText:
- TX_FAR _DiglettSculptureText
- db "@"
-
-ElevatorText::
- TX_FAR _ElevatorText
- db "@"
-
-TownMapText::
- TX_FAR _TownMapText
- TX_BLINK
- TX_ASM
- ld a, $1
- ld [wDoNotWaitForButtonPressAfterDisplayingText], a
- ld hl, wd730
- set 6, [hl]
- call GBPalWhiteOutWithDelay3
- xor a
- ld [hWY], a
- inc a
- ld [H_AUTOBGTRANSFERENABLED], a
- call LoadFontTilePatterns
- callba DisplayTownMap
- ld hl, wd730
- res 6, [hl]
- ld de, TextScriptEnd
- push de
- ld a, [H_LOADEDROMBANK]
- push af
- jp CloseTextDisplay
-
-PokemonStuffText::
- TX_FAR _PokemonStuffText
- db "@"
--- a/engine/hidden_object_functions7.asm
+++ /dev/null
@@ -1,467 +1,0 @@
-PrintNewBikeText:
- call EnableAutoTextBoxDrawing
- tx_pre_jump NewBicycleText
-
-NewBicycleText::
- TX_FAR _NewBicycleText
- db "@"
-
-DisplayOakLabLeftPoster:
- call EnableAutoTextBoxDrawing
- tx_pre_jump PushStartText
-
-PushStartText::
- TX_FAR _PushStartText
- db "@"
-
-DisplayOakLabRightPoster:
- call EnableAutoTextBoxDrawing
- ld hl, wPokedexOwned
- ld b, wPokedexOwnedEnd - wPokedexOwned
- call CountSetBits
- ld a, [wNumSetBits]
- cp 2
- tx_pre_id SaveOptionText
- jr c, .ownLessThanTwo
- ; own two or more mon
- tx_pre_id StrengthsAndWeaknessesText
-.ownLessThanTwo
- jp PrintPredefTextID
-
-SaveOptionText::
- TX_FAR _SaveOptionText
- db "@"
-
-StrengthsAndWeaknessesText::
- TX_FAR _StrengthsAndWeaknessesText
- db "@"
-
-SafariZoneCheck::
- CheckEventHL EVENT_IN_SAFARI_ZONE ; if we are not in the Safari Zone,
- jr z, SafariZoneGameStillGoing ; don't bother printing game over text
- ld a, [wNumSafariBalls]
- and a
- jr z, SafariZoneGameOver
- jr SafariZoneGameStillGoing
-
-SafariZoneCheckSteps::
- ld a, [wSafariSteps]
- ld b, a
- ld a, [wSafariSteps + 1]
- ld c, a
- or b
- jr z, SafariZoneGameOver
- dec bc
- ld a, b
- ld [wSafariSteps], a
- ld a, c
- ld [wSafariSteps + 1], a
-SafariZoneGameStillGoing:
- xor a
- ld [wSafariZoneGameOver], a
- ret
-
-SafariZoneGameOver:
- call EnableAutoTextBoxDrawing
- xor a
- ld [wAudioFadeOutControl], a
- dec a
- call PlaySound
- ld c, BANK(SFX_Safari_Zone_PA)
- ld a, SFX_SAFARI_ZONE_PA
- call PlayMusic
-.waitForMusicToPlay
- ld a, [wChannelSoundIDs + Ch5]
- cp SFX_SAFARI_ZONE_PA
- jr nz, .waitForMusicToPlay
- ld a, TEXT_SAFARI_GAME_OVER
- ld [hSpriteIndexOrTextID], a
- call DisplayTextID
- xor a
- ld [wPlayerMovingDirection], a
- ld a, SAFARI_ZONE_GATE
- ld [hWarpDestinationMap], a
- ld a, $3
- ld [wDestinationWarpID], a
- ld a, $5
- ld [wSafariZoneGateCurScript], a
- SetEvent EVENT_SAFARI_GAME_OVER
- ld a, 1
- ld [wSafariZoneGameOver], a
- ret
-
-PrintSafariGameOverText::
- xor a
- ld [wJoyIgnore], a
- ld hl, SafariGameOverText
- jp PrintText
-
-SafariGameOverText:
- TX_ASM
- ld a, [wNumSafariBalls]
- and a
- jr z, .noMoreSafariBalls
- ld hl, TimesUpText
- call PrintText
-.noMoreSafariBalls
- ld hl, GameOverText
- call PrintText
- jp TextScriptEnd
-
-TimesUpText:
- TX_FAR _TimesUpText
- db "@"
-
-GameOverText:
- TX_FAR _GameOverText
- db "@"
-
-PrintCinnabarQuiz:
- ld a, [wSpriteStateData1 + 9]
- cp SPRITE_FACING_UP
- ret nz
- call EnableAutoTextBoxDrawing
- tx_pre_jump CinnabarGymQuiz
-
-CinnabarGymQuiz::
- TX_ASM
- xor a
- ld [wOpponentAfterWrongAnswer], a
- ld a, [wHiddenObjectFunctionArgument]
- push af
- and $f
- ld [hGymGateIndex], a
- pop af
- and $f0
- swap a
- ld [$ffdc], a
- ld hl, CinnabarGymQuizIntroText
- call PrintText
- ld a, [hGymGateIndex]
- dec a
- add a
- ld d, 0
- ld e, a
- ld hl, CinnabarQuizQuestions
- add hl, de
- ld a, [hli]
- ld h, [hl]
- ld l, a
- call PrintText
- ld a, 1
- ld [wDoNotWaitForButtonPressAfterDisplayingText], a
- call CinnabarGymQuiz_1ea92
- jp TextScriptEnd
-
-CinnabarGymQuizIntroText:
- TX_FAR _CinnabarGymQuizIntroText
- db "@"
-
-CinnabarQuizQuestions:
- dw CinnabarQuizQuestionsText1
- dw CinnabarQuizQuestionsText2
- dw CinnabarQuizQuestionsText3
- dw CinnabarQuizQuestionsText4
- dw CinnabarQuizQuestionsText5
- dw CinnabarQuizQuestionsText6
-
-CinnabarQuizQuestionsText1:
- TX_FAR _CinnabarQuizQuestionsText1
- db "@"
-
-CinnabarQuizQuestionsText2:
- TX_FAR _CinnabarQuizQuestionsText2
- db "@"
-
-CinnabarQuizQuestionsText3:
- TX_FAR _CinnabarQuizQuestionsText3
- db "@"
-
-CinnabarQuizQuestionsText4:
- TX_FAR _CinnabarQuizQuestionsText4
- db "@"
-
-CinnabarQuizQuestionsText5:
- TX_FAR _CinnabarQuizQuestionsText5
- db "@"
-
-CinnabarQuizQuestionsText6:
- TX_FAR _CinnabarQuizQuestionsText6
- db "@"
-
-CinnabarGymGateFlagAction:
- EventFlagAddress hl, EVENT_CINNABAR_GYM_GATE0_UNLOCKED
- predef_jump FlagActionPredef
-
-CinnabarGymQuiz_1ea92:
- call YesNoChoice
- ld a, [$ffdc]
- ld c, a
- ld a, [wCurrentMenuItem]
- cp c
- jr nz, .wrongAnswer
- ld hl, wCurrentMapScriptFlags
- set 5, [hl]
- ld a, [hGymGateIndex]
- ld [$ffe0], a
- ld hl, CinnabarGymQuizCorrectText
- call PrintText
- ld a, [$ffe0]
- AdjustEventBit EVENT_CINNABAR_GYM_GATE0_UNLOCKED, 0
- ld c, a
- ld b, FLAG_SET
- call CinnabarGymGateFlagAction
- jp UpdateCinnabarGymGateTileBlocks_
-.wrongAnswer
- call WaitForSoundToFinish
- ld a, SFX_DENIED
- call PlaySound
- call WaitForSoundToFinish
- ld hl, CinnabarGymQuizIncorrectText
- call PrintText
- ld a, [hGymGateIndex]
- add $2
- AdjustEventBit EVENT_BEAT_CINNABAR_GYM_TRAINER_0, 2
- ld c, a
- ld b, FLAG_TEST
- EventFlagAddress hl, EVENT_BEAT_CINNABAR_GYM_TRAINER_0
- predef FlagActionPredef
- ld a, c
- and a
- ret nz
- ld a, [hGymGateIndex]
- add $2
- ld [wOpponentAfterWrongAnswer], a
- ret
-
-CinnabarGymQuizCorrectText:
- TX_SFX_ITEM_1
- TX_FAR _CinnabarGymQuizCorrectText
- TX_BLINK
- TX_ASM
-
- ld a, [$ffe0]
- AdjustEventBit EVENT_CINNABAR_GYM_GATE0_UNLOCKED, 0
- ld c, a
- ld b, FLAG_TEST
- call CinnabarGymGateFlagAction
- ld a, c
- and a
- jp nz, TextScriptEnd
- call WaitForSoundToFinish
- ld a, SFX_GO_INSIDE
- call PlaySound
- call WaitForSoundToFinish
- jp TextScriptEnd
-
-CinnabarGymQuizIncorrectText:
- TX_FAR _CinnabarGymQuizIncorrectText
- db "@"
-
-UpdateCinnabarGymGateTileBlocks_::
-; Update the overworld map with open floor blocks or locked gate blocks
-; depending on event flags.
- ld a, 6
- ld [hGymGateIndex], a
-.loop
- ld a, [hGymGateIndex]
- dec a
- add a
- add a
- ld d, 0
- ld e, a
- ld hl, CinnabarGymGateCoords
- add hl, de
- ld a, [hli]
- ld b, [hl]
- ld c, a
- inc hl
- ld a, [hl]
- ld [wGymGateTileBlock], a
- push bc
- ld a, [hGymGateIndex]
- ld [$ffe0], a
- AdjustEventBit EVENT_CINNABAR_GYM_GATE0_UNLOCKED, 0
- ld c, a
- ld b, FLAG_TEST
- call CinnabarGymGateFlagAction
- ld a, c
- and a
- jr nz, .unlocked
- ld a, [wGymGateTileBlock]
- jr .next
-.unlocked
- ld a, $e
-.next
- pop bc
- ld [wNewTileBlockID], a
- predef ReplaceTileBlock
- ld hl, hGymGateIndex
- dec [hl]
- jr nz, .loop
- ret
-
-CinnabarGymGateCoords:
- ; format: x-coord, y-coord, direction, padding
- ; direction: $54 = horizontal gate, $5f = vertical gate
- db $09,$03,$54,$00
- db $06,$03,$54,$00
- db $06,$06,$54,$00
- db $03,$08,$5f,$00
- db $02,$06,$54,$00
- db $02,$03,$54,$00
-
-PrintMagazinesText:
- call EnableAutoTextBoxDrawing
- tx_pre MagazinesText
- ret
-
-MagazinesText::
- TX_FAR _MagazinesText
- db "@"
-
-BillsHousePC:
- call EnableAutoTextBoxDrawing
- ld a, [wSpriteStateData1 + 9]
- cp SPRITE_FACING_UP
- ret nz
- CheckEvent EVENT_LEFT_BILLS_HOUSE_AFTER_HELPING
- jr nz, .displayBillsHousePokemonList
- CheckEventReuseA EVENT_USED_CELL_SEPARATOR_ON_BILL
- jr nz, .displayBillsHouseMonitorText
- CheckEventReuseA EVENT_BILL_SAID_USE_CELL_SEPARATOR
- jr nz, .doCellSeparator
-.displayBillsHouseMonitorText
- tx_pre_jump BillsHouseMonitorText
-.doCellSeparator
- ld a, $1
- ld [wDoNotWaitForButtonPressAfterDisplayingText], a
- tx_pre BillsHouseInitiatedText
- ld c, 32
- call DelayFrames
- ld a, SFX_TINK
- call PlaySound
- call WaitForSoundToFinish
- ld c, 80
- call DelayFrames
- ld a, SFX_SHRINK
- call PlaySound
- call WaitForSoundToFinish
- ld c, 48
- call DelayFrames
- ld a, SFX_TINK
- call PlaySound
- call WaitForSoundToFinish
- ld c, 32
- call DelayFrames
- ld a, SFX_GET_ITEM_1
- call PlaySound
- call WaitForSoundToFinish
- call PlayDefaultMusic
- SetEvent EVENT_USED_CELL_SEPARATOR_ON_BILL
- ret
-.displayBillsHousePokemonList
- ld a, $1
- ld [wDoNotWaitForButtonPressAfterDisplayingText], a
- tx_pre BillsHousePokemonList
- ret
-
-BillsHouseMonitorText::
- TX_FAR _BillsHouseMonitorText
- db "@"
-
-BillsHouseInitiatedText::
- TX_FAR _BillsHouseInitiatedText
- TX_BLINK
- TX_ASM
- ld a, $ff
- ld [wNewSoundID], a
- call PlaySound
- ld c, 16
- call DelayFrames
- ld a, SFX_SWITCH
- call PlaySound
- call WaitForSoundToFinish
- ld c, 60
- call DelayFrames
- jp TextScriptEnd
-
-BillsHousePokemonList::
- TX_ASM
- call SaveScreenTilesToBuffer1
- ld hl, BillsHousePokemonListText1
- call PrintText
- xor a
- ld [wMenuItemOffset], a ; not used
- ld [wCurrentMenuItem], a
- ld [wLastMenuItem], a
- ld a, A_BUTTON | B_BUTTON
- ld [wMenuWatchedKeys], a
- ld a, 4
- ld [wMaxMenuItem], a
- ld a, 2
- ld [wTopMenuItemY], a
- ld a, 1
- ld [wTopMenuItemX], a
-.billsPokemonLoop
- ld hl, wd730
- set 6, [hl]
- coord hl, 0, 0
- ld b, 10
- ld c, 9
- call TextBoxBorder
- coord hl, 2, 2
- ld de, BillsMonListText
- call PlaceString
- ld hl, BillsHousePokemonListText2
- call PrintText
- call SaveScreenTilesToBuffer2
- call HandleMenuInput
- bit 1, a ; pressed b
- jr nz, .cancel
- ld a, [wCurrentMenuItem]
- add EEVEE
- cp EEVEE
- jr z, .displayPokedex
- cp FLAREON
- jr z, .displayPokedex
- cp JOLTEON
- jr z, .displayPokedex
- cp VAPOREON
- jr z, .displayPokedex
- jr .cancel
-.displayPokedex
- call DisplayPokedex
- call LoadScreenTilesFromBuffer2
- jr .billsPokemonLoop
-.cancel
- ld hl, wd730
- res 6, [hl]
- call LoadScreenTilesFromBuffer2
- jp TextScriptEnd
-
-BillsHousePokemonListText1:
- TX_FAR _BillsHousePokemonListText1
- db "@"
-
-BillsMonListText:
- db "EEVEE"
- next "FLAREON"
- next "JOLTEON"
- next "VAPOREON"
- next "CANCEL@"
-
-BillsHousePokemonListText2:
- TX_FAR _BillsHousePokemonListText2
- db "@"
-
-DisplayOakLabEmailText:
- ld a, [wSpriteStateData1 + 9]
- cp SPRITE_FACING_UP
- ret nz
- call EnableAutoTextBoxDrawing
- tx_pre_jump OakLabEmailText
-
-OakLabEmailText::
- TX_FAR _OakLabEmailText
- db "@"
--- a/engine/hp_bar.asm
+++ /dev/null
@@ -1,270 +1,0 @@
-HPBarLength:
- call GetPredefRegisters
-
-; calculates bc * 48 / de, the number of pixels the HP bar has
-; the result is always at least 1
-GetHPBarLength:
- push hl
- xor a
- ld hl, H_MULTIPLICAND
- ld [hli], a
- ld a, b
- ld [hli], a
- ld a, c
- ld [hli], a
- ld [hl], $30
- call Multiply ; 48 * bc (hp bar is 48 pixels long)
- ld a, d
- and a
- jr z, .maxHPSmaller256
- srl d ; make HP in de fit into 1 byte by dividing by 4
- rr e
- srl d
- rr e
- ld a, [H_MULTIPLICAND+1]
- ld b, a
- ld a, [H_MULTIPLICAND+2]
- srl b ; divide multiplication result as well
- rr a
- srl b
- rr a
- ld [H_MULTIPLICAND+2], a
- ld a, b
- ld [H_MULTIPLICAND+1], a
-.maxHPSmaller256
- ld a, e
- ld [H_DIVISOR], a
- ld b, $4
- call Divide
- ld a, [H_MULTIPLICAND+2]
- ld e, a ; e = bc * 48 / de (num of pixels of HP bar)
- pop hl
- and a
- ret nz
- ld e, $1 ; make result at least 1
- ret
-
-; predef $48
-UpdateHPBar:
-UpdateHPBar2:
- push hl
- ld hl, wHPBarOldHP
- ld a, [hli]
- ld c, a ; old HP into bc
- ld a, [hli]
- ld b, a
- ld a, [hli]
- ld e, a ; new HP into de
- ld d, [hl]
- pop hl
- push de
- push bc
- call UpdateHPBar_CalcHPDifference
- ld a, e
- ld [wHPBarHPDifference+1], a
- ld a, d
- ld [wHPBarHPDifference], a
- pop bc
- pop de
- call UpdateHPBar_CompareNewHPToOldHP
- ret z
- ld a, $ff
- jr c, .HPdecrease
- ld a, $1
-.HPdecrease
- ld [wHPBarDelta], a
- call GetPredefRegisters
- ld a, [wHPBarNewHP]
- ld e, a
- ld a, [wHPBarNewHP+1]
- ld d, a
-.animateHPBarLoop
- push de
- ld a, [wHPBarOldHP]
- ld c, a
- ld a, [wHPBarOldHP+1]
- ld b, a
- call UpdateHPBar_CompareNewHPToOldHP
- jr z, .animateHPBarDone
- jr nc, .HPIncrease
-; HP decrease
- dec bc ; subtract 1 HP
- ld a, c
- ld [wHPBarNewHP], a
- ld a, b
- ld [wHPBarNewHP+1], a
- call UpdateHPBar_CalcOldNewHPBarPixels
- ld a, e
- sub d ; calc pixel difference
- jr .ok
-.HPIncrease
- inc bc ; add 1 HP
- ld a, c
- ld [wHPBarNewHP], a
- ld a, b
- ld [wHPBarNewHP+1], a
- call UpdateHPBar_CalcOldNewHPBarPixels
- ld a, d
- sub e ; calc pixel difference
-.ok
- call UpdateHPBar_PrintHPNumber
- and a
- jr z, .noPixelDifference
- call UpdateHPBar_AnimateHPBar
-.noPixelDifference
- ld a, [wHPBarNewHP]
- ld [wHPBarOldHP], a
- ld a, [wHPBarNewHP+1]
- ld [wHPBarOldHP+1], a
- pop de
- jr .animateHPBarLoop
-.animateHPBarDone
- pop de
- ld a, e
- ld [wHPBarOldHP], a
- ld a, d
- ld [wHPBarOldHP+1], a
- or e
- jr z, .monFainted
- call UpdateHPBar_CalcOldNewHPBarPixels
- ld d, e
-.monFainted
- call UpdateHPBar_PrintHPNumber
- ld a, $1
- call UpdateHPBar_AnimateHPBar
- jp Delay3
-
-; animates the HP bar going up or down for (a) ticks (two waiting frames each)
-; stops prematurely if bar is filled up
-; e: current health (in pixels) to start with
-UpdateHPBar_AnimateHPBar:
- push hl
-.barAnimationLoop
- push af
- push de
- ld d, $6
- call DrawHPBar
- ld c, 2
- call DelayFrames
- pop de
- ld a, [wHPBarDelta] ; +1 or -1
- add e
- cp $31
- jr nc, .barFilledUp
- ld e, a
- pop af
- dec a
- jr nz, .barAnimationLoop
- pop hl
- ret
-.barFilledUp
- pop af
- pop hl
- ret
-
-; compares old HP and new HP and sets c and z flags accordingly
-UpdateHPBar_CompareNewHPToOldHP:
- ld a, d
- sub b
- ret nz
- ld a, e
- sub c
- ret
-
-; calcs HP difference between bc and de (into de)
-UpdateHPBar_CalcHPDifference:
- ld a, d
- sub b
- jr c, .oldHPGreater
- jr z, .testLowerByte
-.newHPGreater
- ld a, e
- sub c
- ld e, a
- ld a, d
- sbc b
- ld d, a
- ret
-.oldHPGreater
- ld a, c
- sub e
- ld e, a
- ld a, b
- sbc d
- ld d, a
- ret
-.testLowerByte
- ld a, e
- sub c
- jr c, .oldHPGreater
- jr nz, .newHPGreater
- ld de, $0
- ret
-
-UpdateHPBar_PrintHPNumber:
- push af
- push de
- ld a, [wHPBarType]
- and a
- jr z, .done ; don't print number in enemy HUD
-; convert from little-endian to big-endian for PrintNumber
- ld a, [wHPBarOldHP]
- ld [wHPBarTempHP + 1], a
- ld a, [wHPBarOldHP + 1]
- ld [wHPBarTempHP], a
- push hl
- ld a, [hFlags_0xFFF6]
- bit 0, a
- jr z, .asm_fb15
- ld de, $9
- jr .next
-.asm_fb15
- ld de, $15
-.next
- add hl, de
- push hl
- ld a, " "
- ld [hli], a
- ld [hli], a
- ld [hli], a
- pop hl
- ld de, wHPBarTempHP
- lb bc, 2, 3
- call PrintNumber
- call DelayFrame
- pop hl
-.done
- pop de
- pop af
- ret
-
-; calcs number of HP bar pixels for old and new HP value
-; d: new pixels
-; e: old pixels
-UpdateHPBar_CalcOldNewHPBarPixels:
- push hl
- ld hl, wHPBarMaxHP
- ld a, [hli] ; max HP into de
- ld e, a
- ld a, [hli]
- ld d, a
- ld a, [hli] ; old HP into bc
- ld c, a
- ld a, [hli]
- ld b, a
- ld a, [hli] ; new HP into hl
- ld h, [hl]
- ld l, a
- push hl
- push de
- call GetHPBarLength ; calc num pixels for old HP
- ld a, e
- pop de
- pop bc
- push af
- call GetHPBarLength ; calc num pixels for new HP
- pop af
- ld d, e
- ld e, a
- pop hl
- ret
--- a/engine/in_game_trades.asm
+++ /dev/null
@@ -1,330 +1,0 @@
-DoInGameTradeDialogue:
-; trigger the trade offer/action specified by wWhichTrade
- call SaveScreenTilesToBuffer2
- ld hl, TradeMons
- ld a, [wWhichTrade]
- ld b, a
- swap a
- sub b
- sub b
- ld c, a
- ld b, 0
- add hl, bc
- ld a, [hli]
- ld [wInGameTradeGiveMonSpecies], a
- ld a, [hli]
- ld [wInGameTradeReceiveMonSpecies], a
- ld a, [hli]
- push af
- ld de, wInGameTradeMonNick
- ld bc, NAME_LENGTH
- call CopyData
- pop af
- ld l, a
- ld h, 0
- ld de, InGameTradeTextPointers
- add hl, hl
- add hl, de
- ld a, [hli]
- ld [wInGameTradeTextPointerTablePointer], a
- ld a, [hl]
- ld [wInGameTradeTextPointerTablePointer + 1], a
- ld a, [wInGameTradeGiveMonSpecies]
- ld de, wInGameTradeGiveMonName
- call InGameTrade_GetMonName
- ld a, [wInGameTradeReceiveMonSpecies]
- ld de, wInGameTradeReceiveMonName
- call InGameTrade_GetMonName
- ld hl, wCompletedInGameTradeFlags
- ld a, [wWhichTrade]
- ld c, a
- ld b, FLAG_TEST
- predef FlagActionPredef
- ld a, c
- and a
- ld a, $4
- ld [wInGameTradeTextPointerTableIndex], a
- jr nz, .printText
-; if the trade hasn't been done yet
- xor a
- ld [wInGameTradeTextPointerTableIndex], a
- call .printText
- ld a, $1
- ld [wInGameTradeTextPointerTableIndex], a
- call YesNoChoice
- ld a, [wCurrentMenuItem]
- and a
- jr nz, .printText
- call InGameTrade_DoTrade
- jr c, .printText
- ld hl, TradedForText
- call PrintText
-.printText
- ld hl, wInGameTradeTextPointerTableIndex
- ld a, [hld] ; wInGameTradeTextPointerTableIndex
- ld e, a
- ld d, 0
- ld a, [hld] ; wInGameTradeTextPointerTablePointer + 1
- ld l, [hl] ; wInGameTradeTextPointerTablePointer
- ld h, a
- add hl, de
- add hl, de
- ld a, [hli]
- ld h, [hl]
- ld l, a
- jp PrintText
-
-; copies name of species a to hl
-InGameTrade_GetMonName:
- push de
- ld [wd11e], a
- call GetMonName
- ld hl, wcd6d
- pop de
- ld bc, NAME_LENGTH
- jp CopyData
-
-INCLUDE "data/trades.asm"
-
-InGameTrade_DoTrade:
- xor a ; NORMAL_PARTY_MENU
- ld [wPartyMenuTypeOrMessageID], a
- dec a
- ld [wUpdateSpritesEnabled], a
- call DisplayPartyMenu
- push af
- call InGameTrade_RestoreScreen
- pop af
- ld a, $1
- jp c, .tradeFailed ; jump if the player didn't select a pokemon
- ld a, [wInGameTradeGiveMonSpecies]
- ld b, a
- ld a, [wcf91]
- cp b
- ld a, $2
- jr nz, .tradeFailed ; jump if the selected mon's species is not the required one
- ld a, [wWhichPokemon]
- ld hl, wPartyMon1Level
- ld bc, wPartyMon2 - wPartyMon1
- call AddNTimes
- ld a, [hl]
- ld [wCurEnemyLVL], a
- ld hl, wCompletedInGameTradeFlags
- ld a, [wWhichTrade]
- ld c, a
- ld b, FLAG_SET
- predef FlagActionPredef
- ld hl, ConnectCableText
- call PrintText
- ld a, [wWhichPokemon]
- push af
- ld a, [wCurEnemyLVL]
- push af
- call LoadHpBarAndStatusTilePatterns
- call InGameTrade_PrepareTradeData
- predef InternalClockTradeAnim
- pop af
- ld [wCurEnemyLVL], a
- pop af
- ld [wWhichPokemon], a
- ld a, [wInGameTradeReceiveMonSpecies]
- ld [wcf91], a
- xor a
- ld [wMonDataLocation], a ; not used
- ld [wRemoveMonFromBox], a
- call RemovePokemon
- ld a, $80 ; prevent the player from naming the mon
- ld [wMonDataLocation], a
- call AddPartyMon
- call InGameTrade_CopyDataToReceivedMon
- callab EvolveTradeMon
- call ClearScreen
- call InGameTrade_RestoreScreen
- callba RedrawMapView
- and a
- ld a, $3
- jr .tradeSucceeded
-.tradeFailed
- scf
-.tradeSucceeded
- ld [wInGameTradeTextPointerTableIndex], a
- ret
-
-InGameTrade_RestoreScreen:
- call GBPalWhiteOutWithDelay3
- call RestoreScreenTilesAndReloadTilePatterns
- call ReloadTilesetTilePatterns
- call LoadScreenTilesFromBuffer2
- call Delay3
- call LoadGBPal
- ld c, 10
- call DelayFrames
- jpba LoadWildData
-
-InGameTrade_PrepareTradeData:
- ld hl, wTradedPlayerMonSpecies
- ld a, [wInGameTradeGiveMonSpecies]
- ld [hli], a ; wTradedPlayerMonSpecies
- ld a, [wInGameTradeReceiveMonSpecies]
- ld [hl], a ; wTradedEnemyMonSpecies
- ld hl, wPartyMonOT
- ld bc, NAME_LENGTH
- ld a, [wWhichPokemon]
- call AddNTimes
- ld de, wTradedPlayerMonOT
- ld bc, NAME_LENGTH
- call InGameTrade_CopyData
- ld hl, InGameTrade_TrainerString
- ld de, wTradedEnemyMonOT
- call InGameTrade_CopyData
- ld de, wLinkEnemyTrainerName
- call InGameTrade_CopyData
- ld hl, wPartyMon1OTID
- ld bc, wPartyMon2 - wPartyMon1
- ld a, [wWhichPokemon]
- call AddNTimes
- ld de, wTradedPlayerMonOTID
- ld bc, $2
- call InGameTrade_CopyData
- call Random
- ld hl, hRandomAdd
- ld de, wTradedEnemyMonOTID
- jp CopyData
-
-InGameTrade_CopyData:
- push hl
- push bc
- call CopyData
- pop bc
- pop hl
- ret
-
-InGameTrade_CopyDataToReceivedMon:
- ld hl, wPartyMonNicks
- ld bc, NAME_LENGTH
- call InGameTrade_GetReceivedMonPointer
- ld hl, wInGameTradeMonNick
- ld bc, NAME_LENGTH
- call CopyData
- ld hl, wPartyMonOT
- ld bc, NAME_LENGTH
- call InGameTrade_GetReceivedMonPointer
- ld hl, InGameTrade_TrainerString
- ld bc, NAME_LENGTH
- call CopyData
- ld hl, wPartyMon1OTID
- ld bc, wPartyMon2 - wPartyMon1
- call InGameTrade_GetReceivedMonPointer
- ld hl, wTradedEnemyMonOTID
- ld bc, $2
- jp CopyData
-
-; the received mon's index is (partyCount - 1),
-; so this adds bc to hl (partyCount - 1) times and moves the result to de
-InGameTrade_GetReceivedMonPointer:
- ld a, [wPartyCount]
- dec a
- call AddNTimes
- ld e, l
- ld d, h
- ret
-
-InGameTrade_TrainerString:
- ; "TRAINER@@@@@@@@@@"
- db $5d, "@@@@@@@@@@"
-
-InGameTradeTextPointers:
- dw TradeTextPointers1
- dw TradeTextPointers2
- dw TradeTextPointers3
-
-TradeTextPointers1:
- dw WannaTrade1Text
- dw NoTrade1Text
- dw WrongMon1Text
- dw Thanks1Text
- dw AfterTrade1Text
-
-TradeTextPointers2:
- dw WannaTrade2Text
- dw NoTrade2Text
- dw WrongMon2Text
- dw Thanks2Text
- dw AfterTrade2Text
-
-TradeTextPointers3:
- dw WannaTrade3Text
- dw NoTrade3Text
- dw WrongMon3Text
- dw Thanks3Text
- dw AfterTrade3Text
-
-ConnectCableText:
- TX_FAR _ConnectCableText
- db "@"
-
-TradedForText:
- TX_FAR _TradedForText
- TX_SFX_KEY_ITEM
- TX_DELAY
- db "@"
-
-WannaTrade1Text:
- TX_FAR _WannaTrade1Text
- db "@"
-
-NoTrade1Text:
- TX_FAR _NoTrade1Text
- db "@"
-
-WrongMon1Text:
- TX_FAR _WrongMon1Text
- db "@"
-
-Thanks1Text:
- TX_FAR _Thanks1Text
- db "@"
-
-AfterTrade1Text:
- TX_FAR _AfterTrade1Text
- db "@"
-
-WannaTrade2Text:
- TX_FAR _WannaTrade2Text
- db "@"
-
-NoTrade2Text:
- TX_FAR _NoTrade2Text
- db "@"
-
-WrongMon2Text:
- TX_FAR _WrongMon2Text
- db "@"
-
-Thanks2Text:
- TX_FAR _Thanks2Text
- db "@"
-
-AfterTrade2Text:
- TX_FAR _AfterTrade2Text
- db "@"
-
-WannaTrade3Text:
- TX_FAR _WannaTrade3Text
- db "@"
-
-NoTrade3Text:
- TX_FAR _NoTrade3Text
- db "@"
-
-WrongMon3Text:
- TX_FAR _WrongMon3Text
- db "@"
-
-Thanks3Text:
- TX_FAR _Thanks3Text
- db "@"
-
-AfterTrade3Text:
- TX_FAR _AfterTrade3Text
- db "@"
--- a/engine/init_player_data.asm
+++ /dev/null
@@ -1,55 +1,0 @@
-InitPlayerData:
-InitPlayerData2:
-
- call Random
- ld a, [hRandomSub]
- ld [wPlayerID], a
-
- call Random
- ld a, [hRandomAdd]
- ld [wPlayerID + 1], a
-
- ld a, $ff
- ld [wUnusedD71B], a
-
- ld hl, wPartyCount
- call InitializeEmptyList
- ld hl, wNumInBox
- call InitializeEmptyList
- ld hl, wNumBagItems
- call InitializeEmptyList
- ld hl, wNumBoxItems
- call InitializeEmptyList
-
-START_MONEY EQU $3000
- ld hl, wPlayerMoney + 1
- ld a, START_MONEY / $100
- ld [hld], a
- xor a
- ld [hli], a
- inc hl
- ld [hl], a
-
- ld [wMonDataLocation], a
-
- ld hl, wObtainedBadges
- ld [hli], a
-
- ld [hl], a
-
- ld hl, wPlayerCoins
- ld [hli], a
- ld [hl], a
-
- ld hl, wGameProgressFlags
- ld bc, wGameProgressFlagsEnd - wGameProgressFlags
- call FillMemory ; clear all game progress flags
-
- jp InitializeMissableObjectsFlags
-
-InitializeEmptyList:
- xor a ; count
- ld [hli], a
- dec a ; terminator
- ld [hl], a
- ret
--- a/engine/intro.asm
+++ /dev/null
@@ -1,470 +1,0 @@
-const_value = -1
- const MOVE_NIDORINO_RIGHT
- const MOVE_GENGAR_RIGHT
- const MOVE_GENGAR_LEFT
-
-ANIMATION_END EQU 80
-
-const_value = 3
- const GENGAR_INTRO_TILES1
- const GENGAR_INTRO_TILES2
- const GENGAR_INTRO_TILES3
-
-PlayIntro:
- xor a
- ld [hJoyHeld], a
- inc a
- ld [H_AUTOBGTRANSFERENABLED], a
- call PlayShootingStar
- call PlayIntroScene
- call GBFadeOutToWhite
- xor a
- ld [hSCX], a
- ld [H_AUTOBGTRANSFERENABLED], a
- call ClearSprites
- call DelayFrame
- ret
-
-PlayIntroScene:
- ld b, SET_PAL_NIDORINO_INTRO
- call RunPaletteCommand
- ldPal a, BLACK, DARK_GRAY, LIGHT_GRAY, WHITE
- ld [rBGP], a
- ld [rOBP0], a
- ld [rOBP1], a
- xor a
- ld [hSCX], a
- ld b, GENGAR_INTRO_TILES1
- call IntroCopyTiles
- ld a, 0
- ld [wBaseCoordX], a
- ld a, 80
- ld [wBaseCoordY], a
- lb bc, 6, 6
- call InitIntroNidorinoOAM
- lb de, 80 / 2, MOVE_NIDORINO_RIGHT
- call IntroMoveMon
- ret c
-
-; hip
- ld a, SFX_INTRO_HIP
- call PlaySound
- xor a
- ld [wIntroNidorinoBaseTile], a
- ld de, IntroNidorinoAnimation1
- call AnimateIntroNidorino
-; hop
- ld a, SFX_INTRO_HOP
- call PlaySound
- ld de, IntroNidorinoAnimation2
- call AnimateIntroNidorino
- ld c, 10
- call CheckForUserInterruption
- ret c
-
-; hip
- ld a, SFX_INTRO_HIP
- call PlaySound
- ld de, IntroNidorinoAnimation1
- call AnimateIntroNidorino
-; hop
- ld a, SFX_INTRO_HOP
- call PlaySound
- ld de, IntroNidorinoAnimation2
- call AnimateIntroNidorino
- ld c, 30
- call CheckForUserInterruption
- ret c
-
-; raise
- ld b, GENGAR_INTRO_TILES2
- call IntroCopyTiles
- ld a, SFX_INTRO_RAISE
- call PlaySound
- lb de, 8 / 2, MOVE_GENGAR_LEFT
- call IntroMoveMon
- ld c, 30
- call CheckForUserInterruption
- ret c
-
-; slash
- ld b, GENGAR_INTRO_TILES3
- call IntroCopyTiles
- ld a, SFX_INTRO_CRASH
- call PlaySound
- lb de, 16 / 2, MOVE_GENGAR_RIGHT
- call IntroMoveMon
-; hip
- ld a, SFX_INTRO_HIP
- call PlaySound
- ld a, (FightIntroFrontMon2 - FightIntroFrontMon) / BYTES_PER_TILE
- ld [wIntroNidorinoBaseTile], a
- ld de, IntroNidorinoAnimation3
- call AnimateIntroNidorino
- ld c, 30
- call CheckForUserInterruption
- ret c
-
- lb de, 8 / 2, MOVE_GENGAR_LEFT
- call IntroMoveMon
- ld b, GENGAR_INTRO_TILES1
- call IntroCopyTiles
- ld c, 60
- call CheckForUserInterruption
- ret c
-
-; hip
- ld a, SFX_INTRO_HIP
- call PlaySound
- xor a
- ld [wIntroNidorinoBaseTile], a
- ld de, IntroNidorinoAnimation4
- call AnimateIntroNidorino
-; hop
- ld a, SFX_INTRO_HOP
- call PlaySound
- ld de, IntroNidorinoAnimation5
- call AnimateIntroNidorino
- ld c, 20
- call CheckForUserInterruption
- ret c
-
- ld a, (FightIntroFrontMon2 - FightIntroFrontMon) / BYTES_PER_TILE
- ld [wIntroNidorinoBaseTile], a
- ld de, IntroNidorinoAnimation6
- call AnimateIntroNidorino
- ld c, 30
- call CheckForUserInterruption
- ret c
-
-; lunge
- ld a, SFX_INTRO_LUNGE
- call PlaySound
- ld a, (FightIntroFrontMon3 - FightIntroFrontMon) / BYTES_PER_TILE
- ld [wIntroNidorinoBaseTile], a
- ld de, IntroNidorinoAnimation7
- jp AnimateIntroNidorino
-
-AnimateIntroNidorino:
- ld a, [de]
- cp ANIMATION_END
- ret z
- ld [wBaseCoordY], a
- inc de
- ld a, [de]
- ld [wBaseCoordX], a
- push de
- ld c, 6 * 6
- call UpdateIntroNidorinoOAM
- ld c, 5
- call DelayFrames
- pop de
- inc de
- jr AnimateIntroNidorino
-
-UpdateIntroNidorinoOAM:
- ld hl, wOAMBuffer
- ld a, [wIntroNidorinoBaseTile]
- ld d, a
-.loop
- ld a, [wBaseCoordY]
- add [hl]
- ld [hli], a ; Y
- ld a, [wBaseCoordX]
- add [hl]
- ld [hli], a ; X
- ld a, d
- ld [hli], a ; tile
- inc hl
- inc d
- dec c
- jr nz, .loop
- ret
-
-InitIntroNidorinoOAM:
- ld hl, wOAMBuffer
- ld d, 0
-.loop
- push bc
- ld a, [wBaseCoordY]
- ld e, a
-.innerLoop
- ld a, e
- add 8
- ld e, a
- ld [hli], a ; Y
- ld a, [wBaseCoordX]
- ld [hli], a ; X
- ld a, d
- ld [hli], a ; tile
- ld a, OAM_BEHIND_BG
- ld [hli], a ; attributes
- inc d
- dec c
- jr nz, .innerLoop
- ld a, [wBaseCoordX]
- add 8
- ld [wBaseCoordX], a
- pop bc
- dec b
- jr nz, .loop
- ret
-
-IntroClearScreen:
- ld hl, vBGMap1
- ld bc, BG_MAP_WIDTH * SCREEN_HEIGHT
- jr IntroClearCommon
-
-IntroClearMiddleOfScreen:
-; clear the area of the tile map between the black bars on the top and bottom
- coord hl, 0, 4
- ld bc, SCREEN_WIDTH * 10
-
-IntroClearCommon:
- ld [hl], 0
- inc hl
- dec bc
- ld a, b
- or c
- jr nz, IntroClearCommon
- ret
-
-IntroPlaceBlackTiles:
- ld a, 1
-.loop
- ld [hli], a
- dec c
- jr nz, .loop
- ret
-
-IntroMoveMon:
-; d = number of times to move the mon (2 pixels each time)
- ld a, e
- cp MOVE_NIDORINO_RIGHT
- jr z, .moveNidorinoRight
- cp MOVE_GENGAR_LEFT
- jr z, .moveGengarLeft
-; move Gengar right
- ld a, [hSCX]
- dec a
- dec a
- jr .next
-.moveNidorinoRight
- push de
- ld a, 2
- ld [wBaseCoordX], a
- xor a
- ld [wBaseCoordY], a
- ld c, 6 * 6
- call UpdateIntroNidorinoOAM
- pop de
-.moveGengarLeft
- ld a, [hSCX]
- inc a
- inc a
-.next
- ld [hSCX], a
- push de
- ld c, 2
- call CheckForUserInterruption
- pop de
- ret c
- dec d
- jr nz, IntroMoveMon
- ret
-
-IntroCopyTiles:
- coord hl, 13, 7
-
-CopyTileIDsFromList_ZeroBaseTileID:
- ld c, 0
- predef_jump CopyTileIDsFromList
-
-PlayMoveSoundB:
-; unused
- predef GetMoveSoundB
- ld a, b
- jp PlaySound
-
-LoadIntroGraphics:
- ld hl, FightIntroBackMon
- ld de, vChars2
- ld bc, FightIntroBackMonEnd - FightIntroBackMon
- ld a, BANK(FightIntroBackMon)
- call FarCopyData2
- ld hl, GameFreakIntro
- ld de, vChars2 + (FightIntroBackMonEnd - FightIntroBackMon)
- ld bc, GameFreakIntroEnd - GameFreakIntro
- ld a, BANK(GameFreakIntro)
- call FarCopyData2
- ld hl, GameFreakIntro
- ld de, vChars1
- ld bc, GameFreakIntroEnd - GameFreakIntro
- ld a, BANK(GameFreakIntro)
- call FarCopyData2
- ld hl, FightIntroFrontMon
- ld de, vChars0
- ld bc, FightIntroFrontMonEnd - FightIntroFrontMon
- ld a, BANK(FightIntroFrontMon)
- jp FarCopyData2
-
-PlayShootingStar:
- ld b, SET_PAL_GAME_FREAK_INTRO
- call RunPaletteCommand
- callba LoadCopyrightAndTextBoxTiles
- ldPal a, BLACK, DARK_GRAY, LIGHT_GRAY, WHITE
- ld [rBGP], a
- ld c, 180
- call DelayFrames
- call ClearScreen
- call DisableLCD
- xor a
- ld [wCurOpponent], a
- call IntroDrawBlackBars
- call LoadIntroGraphics
- call EnableLCD
- ld hl, rLCDC
- res 5, [hl]
- set 3, [hl]
- ld c, 64
- call DelayFrames
- callba AnimateShootingStar
- push af
- pop af
- jr c, .next ; skip the delay if the user interrupted the animation
- ld c, 40
- call DelayFrames
-.next
- ld a, BANK(Music_IntroBattle)
- ld [wAudioROMBank], a
- ld [wAudioSavedROMBank], a
- ld a, MUSIC_INTRO_BATTLE
- ld [wNewSoundID], a
- call PlaySound
- call IntroClearMiddleOfScreen
- call ClearSprites
- jp Delay3
-
-IntroDrawBlackBars:
-; clear the screen and draw black bars on the top and bottom
- call IntroClearScreen
- coord hl, 0, 0
- ld c, SCREEN_WIDTH * 4
- call IntroPlaceBlackTiles
- coord hl, 0, 14
- ld c, SCREEN_WIDTH * 4
- call IntroPlaceBlackTiles
- ld hl, vBGMap1
- ld c, BG_MAP_WIDTH * 4
- call IntroPlaceBlackTiles
- ld hl, vBGMap1 + BG_MAP_WIDTH * 14
- ld c, BG_MAP_WIDTH * 4
- jp IntroPlaceBlackTiles
-
-EmptyFunc4:
- ret
-
-IntroNidorinoAnimation0:
- db 0, 0
- db ANIMATION_END
-
-IntroNidorinoAnimation1:
-; This is a sequence of pixel movements for part of the Nidorino animation. This
-; list describes how Nidorino should hop.
-; First byte is y movement, second byte is x movement
- db 0, 0
- db -2, 2
- db -1, 2
- db 1, 2
- db 2, 2
- db ANIMATION_END
-
-IntroNidorinoAnimation2:
-; This is a sequence of pixel movements for part of the Nidorino animation.
-; First byte is y movement, second byte is x movement
- db 0, 0
- db -2, -2
- db -1, -2
- db 1, -2
- db 2, -2
- db ANIMATION_END
-
-IntroNidorinoAnimation3:
-; This is a sequence of pixel movements for part of the Nidorino animation.
-; First byte is y movement, second byte is x movement
- db 0, 0
- db -12, 6
- db -8, 6
- db 8, 6
- db 12, 6
- db ANIMATION_END
-
-IntroNidorinoAnimation4:
-; This is a sequence of pixel movements for part of the Nidorino animation.
-; First byte is y movement, second byte is x movement
- db 0, 0
- db -8, -4
- db -4, -4
- db 4, -4
- db 8, -4
- db ANIMATION_END
-
-IntroNidorinoAnimation5:
-; This is a sequence of pixel movements for part of the Nidorino animation.
-; First byte is y movement, second byte is x movement
- db 0, 0
- db -8, 4
- db -4, 4
- db 4, 4
- db 8, 4
- db ANIMATION_END
-
-IntroNidorinoAnimation6:
-; This is a sequence of pixel movements for part of the Nidorino animation.
-; First byte is y movement, second byte is x movement
- db 0, 0
- db 2, 0
- db 2, 0
- db 0, 0
- db ANIMATION_END
-
-IntroNidorinoAnimation7:
-; This is a sequence of pixel movements for part of the Nidorino animation.
-; First byte is y movement, second byte is x movement
- db -8, -16
- db -7, -14
- db -6, -12
- db -4, -10
- db ANIMATION_END
-
-GameFreakIntro:
- INCBIN "gfx/intro_credits/gamefreak_presents.2bpp"
- INCBIN "gfx/intro_credits/gamefreak_logo.2bpp"
- ds 16, $00 ; blank tile
-GameFreakIntroEnd:
-
-FightIntroBackMon:
- INCBIN "gfx/intro_credits/gengar.2bpp"
-FightIntroBackMonEnd:
-
-FightIntroFrontMon:
-
-IF DEF(_RED)
- INCBIN "gfx/intro_credits/red_nidorino_1.2bpp"
-FightIntroFrontMon2:
- INCBIN "gfx/intro_credits/red_nidorino_2.2bpp"
-FightIntroFrontMon3:
- INCBIN "gfx/intro_credits/red_nidorino_3.2bpp"
-ENDC
-
-IF DEF(_BLUE)
- INCBIN "gfx/intro_credits/blue_jigglypuff_1.2bpp"
-FightIntroFrontMon2:
- INCBIN "gfx/intro_credits/blue_jigglypuff_2.2bpp"
-FightIntroFrontMon3:
- INCBIN "gfx/intro_credits/blue_jigglypuff_3.2bpp"
-ENDC
-
-FightIntroFrontMonEnd:
-
- ds 16, $00 ; blank tile
--- /dev/null
+++ b/engine/items/get_bag_item_quantity.asm
@@ -1,0 +1,18 @@
+GetQuantityOfItemInBag:
+; In: b = item ID
+; Out: b = how many of that item are in the bag
+ call GetPredefRegisters
+ ld hl, wNumBagItems
+.loop
+ inc hl
+ ld a, [hli]
+ cp $ff
+ jr z, .notInBag
+ cp b
+ jr nz, .loop
+ ld a, [hl]
+ ld b, a
+ ret
+.notInBag
+ ld b, 0
+ ret
--- /dev/null
+++ b/engine/items/item_effects.asm
@@ -1,0 +1,2986 @@
+UseItem_::
+ ld a, 1
+ ld [wActionResultOrTookBattleTurn], a ; initialise to success value
+ ld a, [wcf91] ;contains item_ID
+ cp HM_01
+ jp nc, ItemUseTMHM
+ ld hl, ItemUsePtrTable
+ dec a
+ add a
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+ItemUsePtrTable:
+ dw ItemUseBall ; MASTER_BALL
+ dw ItemUseBall ; ULTRA_BALL
+ dw ItemUseBall ; GREAT_BALL
+ dw ItemUseBall ; POKE_BALL
+ dw ItemUseTownMap ; TOWN_MAP
+ dw ItemUseBicycle ; BICYCLE
+ dw ItemUseSurfboard ; out-of-battle Surf effect
+ dw ItemUseBall ; SAFARI_BALL
+ dw ItemUsePokedex ; POKEDEX
+ dw ItemUseEvoStone ; MOON_STONE
+ dw ItemUseMedicine ; ANTIDOTE
+ dw ItemUseMedicine ; BURN_HEAL
+ dw ItemUseMedicine ; ICE_HEAL
+ dw ItemUseMedicine ; AWAKENING
+ dw ItemUseMedicine ; PARLYZ_HEAL
+ dw ItemUseMedicine ; FULL_RESTORE
+ dw ItemUseMedicine ; MAX_POTION
+ dw ItemUseMedicine ; HYPER_POTION
+ dw ItemUseMedicine ; SUPER_POTION
+ dw ItemUseMedicine ; POTION
+ dw ItemUseBait ; BOULDERBADGE
+ dw ItemUseRock ; CASCADEBADGE
+ dw UnusableItem ; THUNDERBADGE
+ dw UnusableItem ; RAINBOWBADGE
+ dw UnusableItem ; SOULBADGE
+ dw UnusableItem ; MARSHBADGE
+ dw UnusableItem ; VOLCANOBADGE
+ dw UnusableItem ; EARTHBADGE
+ dw ItemUseEscapeRope ; ESCAPE_ROPE
+ dw ItemUseRepel ; REPEL
+ dw UnusableItem ; OLD_AMBER
+ dw ItemUseEvoStone ; FIRE_STONE
+ dw ItemUseEvoStone ; THUNDER_STONE
+ dw ItemUseEvoStone ; WATER_STONE
+ dw ItemUseVitamin ; HP_UP
+ dw ItemUseVitamin ; PROTEIN
+ dw ItemUseVitamin ; IRON
+ dw ItemUseVitamin ; CARBOS
+ dw ItemUseVitamin ; CALCIUM
+ dw ItemUseVitamin ; RARE_CANDY
+ dw UnusableItem ; DOME_FOSSIL
+ dw UnusableItem ; HELIX_FOSSIL
+ dw UnusableItem ; SECRET_KEY
+ dw UnusableItem
+ dw UnusableItem ; BIKE_VOUCHER
+ dw ItemUseXAccuracy ; X_ACCURACY
+ dw ItemUseEvoStone ; LEAF_STONE
+ dw ItemUseCardKey ; CARD_KEY
+ dw UnusableItem ; NUGGET
+ dw UnusableItem ; ??? PP_UP
+ dw ItemUsePokedoll ; POKE_DOLL
+ dw ItemUseMedicine ; FULL_HEAL
+ dw ItemUseMedicine ; REVIVE
+ dw ItemUseMedicine ; MAX_REVIVE
+ dw ItemUseGuardSpec ; GUARD_SPEC
+ dw ItemUseSuperRepel ; SUPER_REPL
+ dw ItemUseMaxRepel ; MAX_REPEL
+ dw ItemUseDireHit ; DIRE_HIT
+ dw UnusableItem ; COIN
+ dw ItemUseMedicine ; FRESH_WATER
+ dw ItemUseMedicine ; SODA_POP
+ dw ItemUseMedicine ; LEMONADE
+ dw UnusableItem ; S_S_TICKET
+ dw UnusableItem ; GOLD_TEETH
+ dw ItemUseXStat ; X_ATTACK
+ dw ItemUseXStat ; X_DEFEND
+ dw ItemUseXStat ; X_SPEED
+ dw ItemUseXStat ; X_SPECIAL
+ dw ItemUseCoinCase ; COIN_CASE
+ dw ItemUseOaksParcel ; OAKS_PARCEL
+ dw ItemUseItemfinder ; ITEMFINDER
+ dw UnusableItem ; SILPH_SCOPE
+ dw ItemUsePokeflute ; POKE_FLUTE
+ dw UnusableItem ; LIFT_KEY
+ dw UnusableItem ; EXP_ALL
+ dw ItemUseOldRod ; OLD_ROD
+ dw ItemUseGoodRod ; GOOD_ROD
+ dw ItemUseSuperRod ; SUPER_ROD
+ dw ItemUsePPUp ; PP_UP (real one)
+ dw ItemUsePPRestore ; ETHER
+ dw ItemUsePPRestore ; MAX_ETHER
+ dw ItemUsePPRestore ; ELIXER
+ dw ItemUsePPRestore ; MAX_ELIXER
+
+ItemUseBall:
+
+; Balls can't be used out of battle.
+ ld a, [wIsInBattle]
+ and a
+ jp z, ItemUseNotTime
+
+; Balls can't catch trainers' Pokémon.
+ dec a
+ jp nz, ThrowBallAtTrainerMon
+
+; If this is for the old man battle, skip checking if the party & box are full.
+ ld a, [wBattleType]
+ dec a
+ jr z, .canUseBall
+
+ ld a, [wPartyCount] ; is party full?
+ cp PARTY_LENGTH
+ jr nz, .canUseBall
+ ld a, [wNumInBox] ; is box full?
+ cp MONS_PER_BOX
+ jp z, BoxFullCannotThrowBall
+
+.canUseBall
+ xor a
+ ld [wCapturedMonSpecies], a
+
+ ld a, [wBattleType]
+ cp BATTLE_TYPE_SAFARI
+ jr nz, .skipSafariZoneCode
+
+.safariZone
+ ld hl, wNumSafariBalls
+ dec [hl] ; remove a Safari Ball
+
+.skipSafariZoneCode
+ call RunDefaultPaletteCommand
+
+ ld a, $43 ; successful capture value
+ ld [wPokeBallAnimData], a
+
+ call LoadScreenTilesFromBuffer1
+ ld hl, ItemUseText00
+ call PrintText
+
+; If the player is fighting an unidentified ghost, set the value that indicates
+; the Pokémon can't be caught and skip the capture calculations.
+ callab IsGhostBattle
+ ld b, $10 ; can't be caught value
+ jp z, .setAnimData
+
+ ld a, [wBattleType]
+ dec a
+ jr nz, .notOldManBattle
+
+.oldManBattle
+ ld hl, wGrassRate
+ ld de, wPlayerName
+ ld bc, NAME_LENGTH
+ call CopyData ; save the player's name in the Wild Monster data (part of the Cinnabar Island Missingno. glitch)
+ jp .captured
+
+.notOldManBattle
+; If the player is fighting the ghost Marowak, set the value that indicates the
+; Pokémon can't be caught and skip the capture calculations.
+ ld a, [wCurMap]
+ cp POKEMON_TOWER_6F
+ jr nz, .loop
+ ld a, [wEnemyMonSpecies2]
+ cp MAROWAK
+ ld b, $10 ; can't be caught value
+ jp z, .setAnimData
+
+; Get the first random number. Let it be called Rand1.
+; Rand1 must be within a certain range according the kind of ball being thrown.
+; The ranges are as follows.
+; Poké Ball: [0, 255]
+; Great Ball: [0, 200]
+; Ultra/Safari Ball: [0, 150]
+; Loop until an acceptable number is found.
+
+.loop
+ call Random
+ ld b, a
+
+; Get the item ID.
+ ld hl, wcf91
+ ld a, [hl]
+
+; The Master Ball always succeeds.
+ cp MASTER_BALL
+ jp z, .captured
+
+; Anything will do for the basic Poké Ball.
+ cp POKE_BALL
+ jr z, .checkForAilments
+
+; If it's a Great/Ultra/Safari Ball and Rand1 is greater than 200, try again.
+ ld a, 200
+ cp b
+ jr c, .loop
+
+; Less than or equal to 200 is good enough for a Great Ball.
+ ld a, [hl]
+ cp GREAT_BALL
+ jr z, .checkForAilments
+
+; If it's an Ultra/Safari Ball and Rand1 is greater than 150, try again.
+ ld a, 150
+ cp b
+ jr c, .loop
+
+.checkForAilments
+; Pokémon can be caught more easily with a status ailment.
+; Depending on the status ailment, a certain value will be subtracted from
+; Rand1. Let this value be called Status.
+; The larger Status is, the more easily the Pokémon can be caught.
+; no status ailment: Status = 0
+; Burn/Paralysis/Poison: Status = 12
+; Freeze/Sleep: Status = 25
+; If Status is greater than Rand1, the Pokémon will be caught for sure.
+ ld a, [wEnemyMonStatus]
+ and a
+ jr z, .skipAilmentValueSubtraction ; no ailments
+ and 1 << FRZ | SLP
+ ld c, 12
+ jr z, .notFrozenOrAsleep
+ ld c, 25
+.notFrozenOrAsleep
+ ld a, b
+ sub c
+ jp c, .captured
+ ld b, a
+
+.skipAilmentValueSubtraction
+ push bc ; save (Rand1 - Status)
+
+; Calculate MaxHP * 255.
+ xor a
+ ld [H_MULTIPLICAND], a
+ ld hl, wEnemyMonMaxHP
+ ld a, [hli]
+ ld [H_MULTIPLICAND + 1], a
+ ld a, [hl]
+ ld [H_MULTIPLICAND + 2], a
+ ld a, 255
+ ld [H_MULTIPLIER], a
+ call Multiply
+
+; Determine BallFactor. It's 8 for Great Balls and 12 for the others.
+ ld a, [wcf91]
+ cp GREAT_BALL
+ ld a, 12
+ jr nz, .skip1
+ ld a, 8
+
+.skip1
+; Note that the results of all division operations are floored.
+
+; Calculate (MaxHP * 255) / BallFactor.
+ ld [H_DIVISOR], a
+ ld b, 4 ; number of bytes in dividend
+ call Divide
+
+; Divide the enemy's current HP by 4. HP is not supposed to exceed 999 so
+; the result should fit in a. If the division results in a quotient of 0,
+; change it to 1.
+ ld hl, wEnemyMonHP
+ ld a, [hli]
+ ld b, a
+ ld a, [hl]
+ srl b
+ rr a
+ srl b
+ rr a
+ and a
+ jr nz, .skip2
+ inc a
+
+.skip2
+; Let W = ((MaxHP * 255) / BallFactor) / max(HP / 4, 1). Calculate W.
+ ld [H_DIVISOR], a
+ ld b, 4
+ call Divide
+
+; If W > 255, store 255 in [H_QUOTIENT + 3].
+; Let X = min(W, 255) = [H_QUOTIENT + 3].
+ ld a, [H_QUOTIENT + 2]
+ and a
+ jr z, .skip3
+ ld a, 255
+ ld [H_QUOTIENT + 3], a
+
+.skip3
+ pop bc ; b = Rand1 - Status
+
+; If Rand1 - Status > CatchRate, the ball fails to capture the Pokémon.
+ ld a, [wEnemyMonActualCatchRate]
+ cp b
+ jr c, .failedToCapture
+
+; If W > 255, the ball captures the Pokémon.
+ ld a, [H_QUOTIENT + 2]
+ and a
+ jr nz, .captured
+
+ call Random ; Let this random number be called Rand2.
+
+; If Rand2 > X, the ball fails to capture the Pokémon.
+ ld b, a
+ ld a, [H_QUOTIENT + 3]
+ cp b
+ jr c, .failedToCapture
+
+.captured
+ jr .skipShakeCalculations
+
+.failedToCapture
+ ld a, [H_QUOTIENT + 3]
+ ld [wPokeBallCaptureCalcTemp], a ; Save X.
+
+; Calculate CatchRate * 100.
+ xor a
+ ld [H_MULTIPLICAND], a
+ ld [H_MULTIPLICAND + 1], a
+ ld a, [wEnemyMonActualCatchRate]
+ ld [H_MULTIPLICAND + 2], a
+ ld a, 100
+ ld [H_MULTIPLIER], a
+ call Multiply
+
+; Determine BallFactor2.
+; Poké Ball: BallFactor2 = 255
+; Great Ball: BallFactor2 = 200
+; Ultra/Safari Ball: BallFactor2 = 150
+ ld a, [wcf91]
+ ld b, 255
+ cp POKE_BALL
+ jr z, .skip4
+ ld b, 200
+ cp GREAT_BALL
+ jr z, .skip4
+ ld b, 150
+ cp ULTRA_BALL
+ jr z, .skip4
+
+.skip4
+; Let Y = (CatchRate * 100) / BallFactor2. Calculate Y.
+ ld a, b
+ ld [H_DIVISOR], a
+ ld b, 4
+ call Divide
+
+; If Y > 255, there are 3 shakes.
+; Note that this shouldn't be possible.
+; The maximum value of Y is (255 * 100) / 150 = 170.
+ ld a, [H_QUOTIENT + 2]
+ and a
+ ld b, $63 ; 3 shakes
+ jr nz, .setAnimData
+
+; Calculate X * Y.
+ ld a, [wPokeBallCaptureCalcTemp]
+ ld [H_MULTIPLIER], a
+ call Multiply
+
+; Calculate (X * Y) / 255.
+ ld a, 255
+ ld [H_DIVISOR], a
+ ld b, 4
+ call Divide
+
+; Determine Status2.
+; no status ailment: Status2 = 0
+; Burn/Paralysis/Poison: Status2 = 5
+; Freeze/Sleep: Status2 = 10
+ ld a, [wEnemyMonStatus]
+ and a
+ jr z, .skip5
+ and 1 << FRZ | SLP
+ ld b, 5
+ jr z, .addAilmentValue
+ ld b, 10
+
+.addAilmentValue
+; If the Pokémon has a status ailment, add Status2.
+ ld a, [H_QUOTIENT + 3]
+ add b
+ ld [H_QUOTIENT + 3], a
+
+.skip5
+; Finally determine the number of shakes.
+; Let Z = ((X * Y) / 255) + Status2 = [H_QUOTIENT + 3].
+; The number of shakes depend on the range Z is in.
+; 0 ≤ Z < 10: 0 shakes (the ball misses)
+; 10 ≤ Z < 30: 1 shake
+; 30 ≤ Z < 70: 2 shakes
+; 70 ≤ Z: 3 shakes
+ ld a, [H_QUOTIENT + 3]
+ cp 10
+ ld b, $20
+ jr c, .setAnimData
+ cp 30
+ ld b, $61
+ jr c, .setAnimData
+ cp 70
+ ld b, $62
+ jr c, .setAnimData
+ ld b, $63
+
+.setAnimData
+ ld a, b
+ ld [wPokeBallAnimData], a
+
+.skipShakeCalculations
+ ld c, 20
+ call DelayFrames
+
+; Do the animation.
+ ld a, TOSS_ANIM
+ ld [wAnimationID], a
+ xor a
+ ld [H_WHOSETURN], a
+ ld [wAnimationType], a
+ ld [wDamageMultipliers], a
+ ld a, [wWhichPokemon]
+ push af
+ ld a, [wcf91]
+ push af
+ predef MoveAnimation
+ pop af
+ ld [wcf91], a
+ pop af
+ ld [wWhichPokemon], a
+
+; Determine the message to display from the animation.
+ ld a, [wPokeBallAnimData]
+ cp $10
+ ld hl, ItemUseBallText00
+ jp z, .printMessage
+ cp $20
+ ld hl, ItemUseBallText01
+ jp z, .printMessage
+ cp $61
+ ld hl, ItemUseBallText02
+ jp z, .printMessage
+ cp $62
+ ld hl, ItemUseBallText03
+ jp z, .printMessage
+ cp $63
+ ld hl, ItemUseBallText04
+ jp z, .printMessage
+
+; Save current HP.
+ ld hl, wEnemyMonHP
+ ld a, [hli]
+ push af
+ ld a, [hli]
+ push af
+
+; Save status ailment.
+ inc hl
+ ld a, [hl]
+ push af
+
+ push hl
+
+; If the Pokémon is transformed, the Pokémon is assumed to be a Ditto.
+; This is a bug because a wild Pokémon could have used Transform via
+; Mirror Move even though the only wild Pokémon that knows Transform is Ditto.
+ ld hl, wEnemyBattleStatus3
+ bit TRANSFORMED, [hl]
+ jr z, .notTransformed
+ ld a, DITTO
+ ld [wEnemyMonSpecies2], a
+ jr .skip6
+
+.notTransformed
+; If the Pokémon is not transformed, set the transformed bit and copy the
+; DVs to wTransformedEnemyMonOriginalDVs so that LoadEnemyMonData won't generate
+; new DVs.
+ set TRANSFORMED, [hl]
+ ld hl, wTransformedEnemyMonOriginalDVs
+ ld a, [wEnemyMonDVs]
+ ld [hli], a
+ ld a, [wEnemyMonDVs + 1]
+ ld [hl], a
+
+.skip6
+ ld a, [wcf91]
+ push af
+ ld a, [wEnemyMonSpecies2]
+ ld [wcf91], a
+ ld a, [wEnemyMonLevel]
+ ld [wCurEnemyLVL], a
+ callab LoadEnemyMonData
+ pop af
+ ld [wcf91], a
+ pop hl
+ pop af
+ ld [hld], a
+ dec hl
+ pop af
+ ld [hld], a
+ pop af
+ ld [hl], a
+ ld a, [wEnemyMonSpecies]
+ ld [wCapturedMonSpecies], a
+ ld [wcf91], a
+ ld [wd11e], a
+ ld a, [wBattleType]
+ dec a ; is this the old man battle?
+ jr z, .oldManCaughtMon ; if so, don't give the player the caught Pokémon
+
+ ld hl, ItemUseBallText05
+ call PrintText
+
+; Add the caught Pokémon to the Pokédex.
+ predef IndexToPokedex
+ ld a, [wd11e]
+ dec a
+ ld c, a
+ ld b, FLAG_TEST
+ ld hl, wPokedexOwned
+ predef FlagActionPredef
+ ld a, c
+ push af
+ ld a, [wd11e]
+ dec a
+ ld c, a
+ ld b, FLAG_SET
+ predef FlagActionPredef
+ pop af
+
+ and a ; was the Pokémon already in the Pokédex?
+ jr nz, .skipShowingPokedexData ; if so, don't show the Pokédex data
+
+ ld hl, ItemUseBallText06
+ call PrintText
+ call ClearSprites
+ ld a, [wEnemyMonSpecies]
+ ld [wd11e], a
+ predef ShowPokedexData
+
+.skipShowingPokedexData
+ ld a, [wPartyCount]
+ cp PARTY_LENGTH ; is party full?
+ jr z, .sendToBox
+ xor a ; PLAYER_PARTY_DATA
+ ld [wMonDataLocation], a
+ call ClearSprites
+ call AddPartyMon
+ jr .done
+
+.sendToBox
+ call ClearSprites
+ call SendNewMonToBox
+ ld hl, ItemUseBallText07
+ CheckEvent EVENT_MET_BILL
+ jr nz, .printTransferredToPCText
+ ld hl, ItemUseBallText08
+.printTransferredToPCText
+ call PrintText
+ jr .done
+
+.oldManCaughtMon
+ ld hl, ItemUseBallText05
+
+.printMessage
+ call PrintText
+ call ClearSprites
+
+.done
+ ld a, [wBattleType]
+ and a ; is this the old man battle?
+ ret nz ; if so, don't remove a ball from the bag
+
+; Remove a ball from the bag.
+ ld hl, wNumBagItems
+ inc a
+ ld [wItemQuantity], a
+ jp RemoveItemFromInventory
+
+ItemUseBallText00:
+;"It dodged the thrown ball!"
+;"This pokemon can't be caught"
+ TX_FAR _ItemUseBallText00
+ db "@"
+ItemUseBallText01:
+;"You missed the pokemon!"
+ TX_FAR _ItemUseBallText01
+ db "@"
+ItemUseBallText02:
+;"Darn! The pokemon broke free!"
+ TX_FAR _ItemUseBallText02
+ db "@"
+ItemUseBallText03:
+;"Aww! It appeared to be caught!"
+ TX_FAR _ItemUseBallText03
+ db "@"
+ItemUseBallText04:
+;"Shoot! It was so close too!"
+ TX_FAR _ItemUseBallText04
+ db "@"
+ItemUseBallText05:
+;"All right! {MonName} was caught!"
+;play sound
+ TX_FAR _ItemUseBallText05
+ TX_SFX_CAUGHT_MON
+ TX_BLINK
+ db "@"
+ItemUseBallText07:
+;"X was transferred to Bill's PC"
+ TX_FAR _ItemUseBallText07
+ db "@"
+ItemUseBallText08:
+;"X was transferred to someone's PC"
+ TX_FAR _ItemUseBallText08
+ db "@"
+
+ItemUseBallText06:
+;"New DEX data will be added..."
+;play sound
+ TX_FAR _ItemUseBallText06
+ TX_SFX_DEX_PAGE_ADDED
+ TX_BLINK
+ db "@"
+
+ItemUseTownMap:
+ ld a, [wIsInBattle]
+ and a
+ jp nz, ItemUseNotTime
+ jpba DisplayTownMap
+
+ItemUseBicycle:
+ ld a, [wIsInBattle]
+ and a
+ jp nz, ItemUseNotTime
+ ld a, [wWalkBikeSurfState]
+ ld [wWalkBikeSurfStateCopy], a
+ cp 2 ; is the player surfing?
+ jp z, ItemUseNotTime
+ dec a ; is player already bicycling?
+ jr nz, .tryToGetOnBike
+.getOffBike
+ call ItemUseReloadOverworldData
+ xor a
+ ld [wWalkBikeSurfState], a ; change player state to walking
+ call PlayDefaultMusic ; play walking music
+ ld hl, GotOffBicycleText
+ jr .printText
+.tryToGetOnBike
+ call IsBikeRidingAllowed
+ jp nc, NoCyclingAllowedHere
+ call ItemUseReloadOverworldData
+ xor a ; no keys pressed
+ ld [hJoyHeld], a ; current joypad state
+ inc a
+ ld [wWalkBikeSurfState], a ; change player state to bicycling
+ ld hl, GotOnBicycleText
+ call PlayDefaultMusic ; play bike riding music
+.printText
+ jp PrintText
+
+; used for Surf out-of-battle effect
+ItemUseSurfboard:
+ ld a, [wWalkBikeSurfState]
+ ld [wWalkBikeSurfStateCopy], a
+ cp 2 ; is the player already surfing?
+ jr z, .tryToStopSurfing
+.tryToSurf
+ call IsNextTileShoreOrWater
+ jp c, SurfingAttemptFailed
+ ld hl, TilePairCollisionsWater
+ call CheckForTilePairCollisions
+ jp c, SurfingAttemptFailed
+.surf
+ call .makePlayerMoveForward
+ ld hl, wd730
+ set 7, [hl]
+ ld a, 2
+ ld [wWalkBikeSurfState], a ; change player state to surfing
+ call PlayDefaultMusic ; play surfing music
+ ld hl, SurfingGotOnText
+ jp PrintText
+.tryToStopSurfing
+ xor a
+ ld [hSpriteIndexOrTextID], a
+ ld d, 16 ; talking range in pixels (normal range)
+ call IsSpriteInFrontOfPlayer2
+ res 7, [hl]
+ ld a, [hSpriteIndexOrTextID]
+ and a ; is there a sprite in the way?
+ jr nz, .cannotStopSurfing
+ ld hl, TilePairCollisionsWater
+ call CheckForTilePairCollisions
+ jr c, .cannotStopSurfing
+ ld hl, wTilesetCollisionPtr ; pointer to list of passable tiles
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a ; hl now points to passable tiles
+ ld a, [wTileInFrontOfPlayer] ; tile in front of the player
+ ld b, a
+.passableTileLoop
+ ld a, [hli]
+ cp b
+ jr z, .stopSurfing
+ cp $ff
+ jr nz, .passableTileLoop
+.cannotStopSurfing
+ ld hl, SurfingNoPlaceToGetOffText
+ jp PrintText
+.stopSurfing
+ call .makePlayerMoveForward
+ ld hl, wd730
+ set 7, [hl]
+ xor a
+ ld [wWalkBikeSurfState], a ; change player state to walking
+ dec a
+ ld [wJoyIgnore], a
+ call PlayDefaultMusic ; play walking music
+ jp LoadWalkingPlayerSpriteGraphics
+; uses a simulated button press to make the player move forward
+.makePlayerMoveForward
+ ld a, [wPlayerDirection] ; direction the player is going
+ bit PLAYER_DIR_BIT_UP, a
+ ld b, D_UP
+ jr nz, .storeSimulatedButtonPress
+ bit PLAYER_DIR_BIT_DOWN, a
+ ld b, D_DOWN
+ jr nz, .storeSimulatedButtonPress
+ bit PLAYER_DIR_BIT_LEFT, a
+ ld b, D_LEFT
+ jr nz, .storeSimulatedButtonPress
+ ld b, D_RIGHT
+.storeSimulatedButtonPress
+ ld a, b
+ ld [wSimulatedJoypadStatesEnd], a
+ xor a
+ ld [wWastedByteCD39], a
+ inc a
+ ld [wSimulatedJoypadStatesIndex], a
+ ret
+
+SurfingGotOnText:
+ TX_FAR _SurfingGotOnText
+ db "@"
+
+SurfingNoPlaceToGetOffText:
+ TX_FAR _SurfingNoPlaceToGetOffText
+ db "@"
+
+ItemUsePokedex:
+ predef_jump ShowPokedexMenu
+
+ItemUseEvoStone:
+ ld a, [wIsInBattle]
+ and a
+ jp nz, ItemUseNotTime
+ ld a, [wWhichPokemon]
+ push af
+ ld a, [wcf91]
+ ld [wEvoStoneItemID], a
+ push af
+ ld a, EVO_STONE_PARTY_MENU
+ ld [wPartyMenuTypeOrMessageID], a
+ ld a, $ff
+ ld [wUpdateSpritesEnabled], a
+ call DisplayPartyMenu
+ pop bc
+ jr c, .canceledItemUse
+ ld a, b
+ ld [wcf91], a
+ ld a, $01
+ ld [wForceEvolution], a
+ ld a, SFX_HEAL_AILMENT
+ call PlaySoundWaitForCurrent
+ call WaitForSoundToFinish
+ callab TryEvolvingMon ; try to evolve pokemon
+ ld a, [wEvolutionOccurred]
+ and a
+ jr z, .noEffect
+ pop af
+ ld [wWhichPokemon], a
+ ld hl, wNumBagItems
+ ld a, 1 ; remove 1 stone
+ ld [wItemQuantity], a
+ jp RemoveItemFromInventory
+.noEffect
+ call ItemUseNoEffect
+.canceledItemUse
+ xor a
+ ld [wActionResultOrTookBattleTurn], a ; item not used
+ pop af
+ ret
+
+ItemUseVitamin:
+ ld a, [wIsInBattle]
+ and a
+ jp nz, ItemUseNotTime
+
+ItemUseMedicine:
+ ld a, [wPartyCount]
+ and a
+ jp z, .emptyParty
+ ld a, [wWhichPokemon]
+ push af
+ ld a, [wcf91]
+ push af
+ ld a, USE_ITEM_PARTY_MENU
+ ld [wPartyMenuTypeOrMessageID], a
+ ld a, $ff
+ ld [wUpdateSpritesEnabled], a
+ ld a, [wPseudoItemID]
+ and a ; using Softboiled?
+ jr z, .notUsingSoftboiled
+; if using softboiled
+ call GoBackToPartyMenu
+ jr .getPartyMonDataAddress
+.emptyParty
+ ld hl, .emptyPartyText
+ xor a
+ ld [wActionResultOrTookBattleTurn], a ; item use failed
+ jp PrintText
+.emptyPartyText
+ text "You don't have"
+ line "any #MON!"
+ prompt
+.notUsingSoftboiled
+ call DisplayPartyMenu
+.getPartyMonDataAddress
+ jp c, .canceledItemUse
+ ld hl, wPartyMons
+ ld bc, wPartyMon2 - wPartyMon1
+ ld a, [wWhichPokemon]
+ call AddNTimes
+ ld a, [wWhichPokemon]
+ ld [wUsedItemOnWhichPokemon], a
+ ld d, a
+ ld a, [wcf91]
+ ld e, a
+ ld [wd0b5], a
+ pop af
+ ld [wcf91], a
+ pop af
+ ld [wWhichPokemon], a
+ ld a, [wPseudoItemID]
+ and a ; using Softboiled?
+ jr z, .checkItemType
+; if using softboiled
+ ld a, [wWhichPokemon]
+ cp d ; is the pokemon trying to use softboiled on itself?
+ jr z, ItemUseMedicine ; if so, force another choice
+.checkItemType
+ ld a, [wcf91]
+ cp REVIVE
+ jr nc, .healHP ; if it's a Revive or Max Revive
+ cp FULL_HEAL
+ jr z, .cureStatusAilment ; if it's a Full Heal
+ cp HP_UP
+ jp nc, .useVitamin ; if it's a vitamin or Rare Candy
+ cp FULL_RESTORE
+ jr nc, .healHP ; if it's a Full Restore or one of the potions
+; fall through if it's one of the status-specific healing items
+.cureStatusAilment
+ ld bc, wPartyMon1Status - wPartyMon1
+ add hl, bc ; hl now points to status
+ ld a, [wcf91]
+ lb bc, ANTIDOTE_MSG, 1 << PSN
+ cp ANTIDOTE
+ jr z, .checkMonStatus
+ lb bc, BURN_HEAL_MSG, 1 << BRN
+ cp BURN_HEAL
+ jr z, .checkMonStatus
+ lb bc, ICE_HEAL_MSG, 1 << FRZ
+ cp ICE_HEAL
+ jr z, .checkMonStatus
+ lb bc, AWAKENING_MSG, SLP
+ cp AWAKENING
+ jr z, .checkMonStatus
+ lb bc, PARALYZ_HEAL_MSG, 1 << PAR
+ cp PARLYZ_HEAL
+ jr z, .checkMonStatus
+ lb bc, FULL_HEAL_MSG, $ff ; Full Heal
+.checkMonStatus
+ ld a, [hl] ; pokemon's status
+ and c ; does the pokemon have a status ailment the item can cure?
+ jp z, .healingItemNoEffect
+; if the pokemon has a status the item can heal
+ xor a
+ ld [hl], a ; remove the status ailment in the party data
+ ld a, b
+ ld [wPartyMenuTypeOrMessageID], a ; the message to display for the item used
+ ld a, [wPlayerMonNumber]
+ cp d ; is pokemon the item was used on active in battle?
+ jp nz, .doneHealing
+; if it is active in battle
+ xor a
+ ld [wBattleMonStatus], a ; remove the status ailment in the in-battle pokemon data
+ push hl
+ ld hl, wPlayerBattleStatus3
+ res BADLY_POISONED, [hl] ; heal Toxic status
+ pop hl
+ ld bc, wPartyMon1Stats - wPartyMon1Status
+ add hl, bc ; hl now points to party stats
+ ld de, wBattleMonStats
+ ld bc, NUM_STATS * 2
+ call CopyData ; copy party stats to in-battle stat data
+ predef DoubleOrHalveSelectedStats
+ jp .doneHealing
+.healHP
+ inc hl ; hl = address of current HP
+ ld a, [hli]
+ ld b, a
+ ld [wHPBarOldHP+1], a
+ ld a, [hl]
+ ld c, a
+ ld [wHPBarOldHP], a ; current HP stored at wHPBarOldHP (2 bytes, big-endian)
+ or b
+ jr nz, .notFainted
+.fainted
+ ld a, [wcf91]
+ cp REVIVE
+ jr z, .updateInBattleFaintedData
+ cp MAX_REVIVE
+ jr z, .updateInBattleFaintedData
+ jp .healingItemNoEffect
+.updateInBattleFaintedData
+ ld a, [wIsInBattle]
+ and a
+ jr z, .compareCurrentHPToMaxHP
+ push hl
+ push de
+ push bc
+ ld a, [wUsedItemOnWhichPokemon]
+ ld c, a
+ ld hl, wPartyFoughtCurrentEnemyFlags
+ ld b, FLAG_TEST
+ predef FlagActionPredef
+ ld a, c
+ and a
+ jr z, .next
+ ld a, [wUsedItemOnWhichPokemon]
+ ld c, a
+ ld hl, wPartyGainExpFlags
+ ld b, FLAG_SET
+ predef FlagActionPredef
+.next
+ pop bc
+ pop de
+ pop hl
+ jr .compareCurrentHPToMaxHP
+.notFainted
+ ld a, [wcf91]
+ cp REVIVE
+ jp z, .healingItemNoEffect
+ cp MAX_REVIVE
+ jp z, .healingItemNoEffect
+.compareCurrentHPToMaxHP
+ push hl
+ push bc
+ ld bc, wPartyMon1MaxHP - (wPartyMon1HP + 1)
+ add hl, bc ; hl now points to max HP
+ pop bc
+ ld a, [hli]
+ cp b
+ jr nz, .skipComparingLSB ; no need to compare the LSB's if the MSB's don't match
+ ld a, [hl]
+ cp c
+.skipComparingLSB
+ pop hl
+ jr nz, .notFullHP
+.fullHP ; if the pokemon's current HP equals its max HP
+ ld a, [wcf91]
+ cp FULL_RESTORE
+ jp nz, .healingItemNoEffect
+ inc hl
+ inc hl
+ ld a, [hld] ; status ailment
+ and a ; does the pokemon have a status ailment?
+ jp z, .healingItemNoEffect
+ ld a, FULL_HEAL
+ ld [wcf91], a
+ dec hl
+ dec hl
+ dec hl
+ jp .cureStatusAilment
+.notFullHP ; if the pokemon's current HP doesn't equal its max HP
+ xor a
+ ld [wLowHealthAlarm], a ;disable low health alarm
+ ld [wChannelSoundIDs + Ch5], a
+ push hl
+ push de
+ ld bc, wPartyMon1MaxHP - (wPartyMon1HP + 1)
+ add hl, bc ; hl now points to max HP
+ ld a, [hli]
+ ld [wHPBarMaxHP+1], a
+ ld a, [hl]
+ ld [wHPBarMaxHP], a ; max HP stored at wHPBarMaxHP (2 bytes, big-endian)
+ ld a, [wPseudoItemID]
+ and a ; using Softboiled?
+ jp z, .notUsingSoftboiled2
+; if using softboiled
+ ld hl, wHPBarMaxHP
+ ld a, [hli]
+ push af
+ ld a, [hli]
+ push af
+ ld a, [hli]
+ push af
+ ld a, [hl]
+ push af
+ ld hl, wPartyMon1MaxHP
+ ld a, [wWhichPokemon]
+ ld bc, wPartyMon2 - wPartyMon1
+ call AddNTimes
+ ld a, [hli]
+ ld [wHPBarMaxHP + 1], a
+ ld [H_DIVIDEND], a
+ ld a, [hl]
+ ld [wHPBarMaxHP], a
+ ld [H_DIVIDEND + 1], a
+ ld a, 5
+ ld [H_DIVISOR], a
+ ld b, 2 ; number of bytes
+ call Divide ; get 1/5 of max HP of pokemon that used Softboiled
+ ld bc, (wPartyMon1HP + 1) - (wPartyMon1MaxHP + 1)
+ add hl, bc ; hl now points to LSB of current HP of pokemon that used Softboiled
+; subtract 1/5 of max HP from current HP of pokemon that used Softboiled
+ ld a, [H_QUOTIENT + 3]
+ push af
+ ld b, a
+ ld a, [hl]
+ ld [wHPBarOldHP], a
+ sub b
+ ld [hld], a
+ ld [wHPBarNewHP], a
+ ld a, [H_QUOTIENT + 2]
+ ld b, a
+ ld a, [hl]
+ ld [wHPBarOldHP+1], a
+ sbc b
+ ld [hl], a
+ ld [wHPBarNewHP+1], a
+ coord hl, 4, 1
+ ld a, [wWhichPokemon]
+ ld bc, 2 * SCREEN_WIDTH
+ call AddNTimes ; calculate coordinates of HP bar of pokemon that used Softboiled
+ ld a, SFX_HEAL_HP
+ call PlaySoundWaitForCurrent
+ ld a, [hFlags_0xFFF6]
+ set 0, a
+ ld [hFlags_0xFFF6], a
+ ld a, $02
+ ld [wHPBarType], a
+ predef UpdateHPBar2 ; animate HP bar decrease of pokemon that used Softboiled
+ ld a, [hFlags_0xFFF6]
+ res 0, a
+ ld [hFlags_0xFFF6], a
+ pop af
+ ld b, a ; store heal amount (1/5 of max HP)
+ ld hl, wHPBarOldHP + 1
+ pop af
+ ld [hld], a
+ pop af
+ ld [hld], a
+ pop af
+ ld [hld], a
+ pop af
+ ld [hl], a
+ jr .addHealAmount
+.notUsingSoftboiled2
+ ld a, [wcf91]
+ cp SODA_POP
+ ld b, 60 ; Soda Pop heal amount
+ jr z, .addHealAmount
+ ld b, 80 ; Lemonade heal amount
+ jr nc, .addHealAmount
+ cp FRESH_WATER
+ ld b, 50 ; Fresh Water heal amount
+ jr z, .addHealAmount
+ cp SUPER_POTION
+ ld b, 200 ; Hyper Potion heal amount
+ jr c, .addHealAmount
+ ld b, 50 ; Super Potion heal amount
+ jr z, .addHealAmount
+ ld b, 20 ; Potion heal amount
+.addHealAmount
+ pop de
+ pop hl
+ ld a, [hl]
+ add b
+ ld [hld], a
+ ld [wHPBarNewHP], a
+ ld a, [hl]
+ ld [wHPBarNewHP+1], a
+ jr nc, .noCarry
+ inc [hl]
+ ld a, [hl]
+ ld [wHPBarNewHP + 1], a
+.noCarry
+ push de
+ inc hl
+ ld d, h
+ ld e, l ; de now points to current HP
+ ld hl, (wPartyMon1MaxHP + 1) - (wPartyMon1HP + 1)
+ add hl, de ; hl now points to max HP
+ ld a, [wcf91]
+ cp REVIVE
+ jr z, .setCurrentHPToHalfMaxHP
+ ld a, [hld]
+ ld b, a
+ ld a, [de]
+ sub b
+ dec de
+ ld b, [hl]
+ ld a, [de]
+ sbc b
+ jr nc, .setCurrentHPToMaxHp ; if current HP exceeds max HP after healing
+ ld a, [wcf91]
+ cp HYPER_POTION
+ jr c, .setCurrentHPToMaxHp ; if using a Full Restore or Max Potion
+ cp MAX_REVIVE
+ jr z, .setCurrentHPToMaxHp ; if using a Max Revive
+ jr .updateInBattleData
+.setCurrentHPToHalfMaxHP
+ dec hl
+ dec de
+ ld a, [hli]
+ srl a
+ ld [de], a
+ ld [wHPBarNewHP+1], a
+ ld a, [hl]
+ rr a
+ inc de
+ ld [de], a
+ ld [wHPBarNewHP], a
+ dec de
+ jr .doneHealingPartyHP
+.setCurrentHPToMaxHp
+ ld a, [hli]
+ ld [de], a
+ ld [wHPBarNewHP+1], a
+ inc de
+ ld a, [hl]
+ ld [de], a
+ ld [wHPBarNewHP], a
+ dec de
+.doneHealingPartyHP ; done updating the pokemon's current HP in the party data structure
+ ld a, [wcf91]
+ cp FULL_RESTORE
+ jr nz, .updateInBattleData
+ ld bc, wPartyMon1Status - (wPartyMon1MaxHP + 1)
+ add hl, bc
+ xor a
+ ld [hl], a ; remove the status ailment in the party data
+.updateInBattleData
+ ld h, d
+ ld l, e
+ pop de
+ ld a, [wPlayerMonNumber]
+ cp d ; is pokemon the item was used on active in battle?
+ jr nz, .calculateHPBarCoords
+; copy party HP to in-battle HP
+ ld a, [hli]
+ ld [wBattleMonHP], a
+ ld a, [hld]
+ ld [wBattleMonHP + 1], a
+ ld a, [wcf91]
+ cp FULL_RESTORE
+ jr nz, .calculateHPBarCoords
+ xor a
+ ld [wBattleMonStatus], a ; remove the status ailment in the in-battle pokemon data
+.calculateHPBarCoords
+ ld hl, wOAMBuffer + $90
+ ld bc, 2 * SCREEN_WIDTH
+ inc d
+.calculateHPBarCoordsLoop
+ add hl, bc
+ dec d
+ jr nz, .calculateHPBarCoordsLoop
+ jr .doneHealing
+.healingItemNoEffect
+ call ItemUseNoEffect
+ jp .done
+.doneHealing
+ ld a, [wPseudoItemID]
+ and a ; using Softboiled?
+ jr nz, .skipRemovingItem ; no item to remove if using Softboiled
+ push hl
+ call RemoveUsedItem
+ pop hl
+.skipRemovingItem
+ ld a, [wcf91]
+ cp FULL_RESTORE
+ jr c, .playStatusAilmentCuringSound
+ cp FULL_HEAL
+ jr z, .playStatusAilmentCuringSound
+ ld a, SFX_HEAL_HP
+ call PlaySoundWaitForCurrent
+ ld a, [hFlags_0xFFF6]
+ set 0, a
+ ld [hFlags_0xFFF6], a
+ ld a, $02
+ ld [wHPBarType], a
+ predef UpdateHPBar2 ; animate the HP bar lengthening
+ ld a, [hFlags_0xFFF6]
+ res 0, a
+ ld [hFlags_0xFFF6], a
+ ld a, REVIVE_MSG
+ ld [wPartyMenuTypeOrMessageID], a
+ ld a, [wcf91]
+ cp REVIVE
+ jr z, .showHealingItemMessage
+ cp MAX_REVIVE
+ jr z, .showHealingItemMessage
+ ld a, POTION_MSG
+ ld [wPartyMenuTypeOrMessageID], a
+ jr .showHealingItemMessage
+.playStatusAilmentCuringSound
+ ld a, SFX_HEAL_AILMENT
+ call PlaySoundWaitForCurrent
+.showHealingItemMessage
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call ClearScreen
+ dec a
+ ld [wUpdateSpritesEnabled], a
+ call RedrawPartyMenu ; redraws the party menu and displays the message
+ ld a, 1
+ ld [H_AUTOBGTRANSFERENABLED], a
+ ld c, 50
+ call DelayFrames
+ call WaitForTextScrollButtonPress
+ jr .done
+.canceledItemUse
+ xor a
+ ld [wActionResultOrTookBattleTurn], a ; item use failed
+ pop af
+ pop af
+.done
+ ld a, [wPseudoItemID]
+ and a ; using Softboiled?
+ ret nz ; if so, return
+ call GBPalWhiteOut
+ call z, RunDefaultPaletteCommand
+ ld a, [wIsInBattle]
+ and a
+ ret nz
+ jp ReloadMapData
+.useVitamin
+ push hl
+ ld a, [hl]
+ ld [wd0b5], a
+ ld [wd11e], a
+ ld bc, wPartyMon1Level - wPartyMon1
+ add hl, bc ; hl now points to level
+ ld a, [hl] ; a = level
+ ld [wCurEnemyLVL], a ; store level
+ call GetMonHeader
+ push de
+ ld a, d
+ ld hl, wPartyMonNicks
+ call GetPartyMonName
+ pop de
+ pop hl
+ ld a, [wcf91]
+ cp RARE_CANDY
+ jp z, .useRareCandy
+ push hl
+ sub HP_UP
+ add a
+ ld bc, wPartyMon1HPExp - wPartyMon1
+ add hl, bc
+ add l
+ ld l, a
+ jr nc, .noCarry2
+ inc h
+.noCarry2
+ ld a, 10
+ ld b, a
+ ld a, [hl] ; a = MSB of stat experience of the appropriate stat
+ cp 100 ; is there already at least 25600 (256 * 100) stat experience?
+ jr nc, .vitaminNoEffect ; if so, vitamins can't add any more
+ add b ; add 2560 (256 * 10) stat experience
+ jr nc, .noCarry3 ; a carry should be impossible here, so this will always jump
+ ld a, 255
+.noCarry3
+ ld [hl], a
+ pop hl
+ call .recalculateStats
+ ld hl, VitaminText
+ ld a, [wcf91]
+ sub HP_UP - 1
+ ld c, a
+.statNameLoop ; loop to get the address of the name of the stat the vitamin increases
+ dec c
+ jr z, .gotStatName
+.statNameInnerLoop
+ ld a, [hli]
+ ld b, a
+ ld a, $50
+ cp b
+ jr nz, .statNameInnerLoop
+ jr .statNameLoop
+.gotStatName
+ ld de, wcf4b
+ ld bc, 10
+ call CopyData ; copy the stat's name to wcf4b
+ ld a, SFX_HEAL_AILMENT
+ call PlaySound
+ ld hl, VitaminStatRoseText
+ call PrintText
+ jp RemoveUsedItem
+.vitaminNoEffect
+ pop hl
+ ld hl, VitaminNoEffectText
+ call PrintText
+ jp GBPalWhiteOut
+.recalculateStats
+ ld bc, wPartyMon1Stats - wPartyMon1
+ add hl, bc
+ ld d, h
+ ld e, l ; de now points to stats
+ ld bc, (wPartyMon1Exp + 2) - wPartyMon1Stats
+ add hl, bc ; hl now points to LSB of experience
+ ld b, 1
+ jp CalcStats ; recalculate stats
+.useRareCandy
+ push hl
+ ld bc, wPartyMon1Level - wPartyMon1
+ add hl, bc ; hl now points to level
+ ld a, [hl] ; a = level
+ cp MAX_LEVEL
+ jr z, .vitaminNoEffect ; can't raise level above 100
+ inc a
+ ld [hl], a ; store incremented level
+ ld [wCurEnemyLVL], a
+ push hl
+ push de
+ ld d, a
+ callab CalcExperience ; calculate experience for next level and store it at $ff96
+ pop de
+ pop hl
+ ld bc, wPartyMon1Exp - wPartyMon1Level
+ add hl, bc ; hl now points to MSB of experience
+; update experience to minimum for new level
+ ld a, [hExperience]
+ ld [hli], a
+ ld a, [hExperience + 1]
+ ld [hli], a
+ ld a, [hExperience + 2]
+ ld [hl], a
+ pop hl
+ ld a, [wWhichPokemon]
+ push af
+ ld a, [wcf91]
+ push af
+ push de
+ push hl
+ ld bc, wPartyMon1MaxHP - wPartyMon1
+ add hl, bc ; hl now points to MSB of max HP
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+ pop hl
+ push bc
+ push hl
+ call .recalculateStats
+ pop hl
+ ld bc, (wPartyMon1MaxHP + 1) - wPartyMon1
+ add hl, bc ; hl now points to LSB of max HP
+ pop bc
+ ld a, [hld]
+ sub c
+ ld c, a
+ ld a, [hl]
+ sbc b
+ ld b, a ; bc = the amount of max HP gained from leveling up
+; add the amount gained to the current HP
+ ld de, (wPartyMon1HP + 1) - wPartyMon1MaxHP
+ add hl, de ; hl now points to LSB of current HP
+ ld a, [hl]
+ add c
+ ld [hld], a
+ ld a, [hl]
+ adc b
+ ld [hl], a
+ ld a, RARE_CANDY_MSG
+ ld [wPartyMenuTypeOrMessageID], a
+ call RedrawPartyMenu
+ pop de
+ ld a, d
+ ld [wWhichPokemon], a
+ ld a, e
+ ld [wd11e], a
+ xor a ; PLAYER_PARTY_DATA
+ ld [wMonDataLocation], a
+ call LoadMonData
+ ld d, $01
+ callab PrintStatsBox ; display new stats text box
+ call WaitForTextScrollButtonPress ; wait for button press
+ xor a ; PLAYER_PARTY_DATA
+ ld [wMonDataLocation], a
+ predef LearnMoveFromLevelUp ; learn level up move, if any
+ xor a
+ ld [wForceEvolution], a
+ callab TryEvolvingMon ; evolve pokemon, if appropriate
+ ld a, $01
+ ld [wUpdateSpritesEnabled], a
+ pop af
+ ld [wcf91], a
+ pop af
+ ld [wWhichPokemon], a
+ jp RemoveUsedItem
+
+VitaminStatRoseText:
+ TX_FAR _VitaminStatRoseText
+ db "@"
+
+VitaminNoEffectText:
+ TX_FAR _VitaminNoEffectText
+ db "@"
+
+VitaminText:
+ db "HEALTH@"
+ db "ATTACK@"
+ db "DEFENSE@"
+ db "SPEED@"
+ db "SPECIAL@"
+
+ItemUseBait:
+ ld hl, ThrewBaitText
+ call PrintText
+ ld hl, wEnemyMonActualCatchRate ; catch rate
+ srl [hl] ; halve catch rate
+ ld a, BAIT_ANIM
+ ld hl, wSafariBaitFactor ; bait factor
+ ld de, wSafariEscapeFactor ; escape factor
+ jr BaitRockCommon
+
+ItemUseRock:
+ ld hl, ThrewRockText
+ call PrintText
+ ld hl, wEnemyMonActualCatchRate ; catch rate
+ ld a, [hl]
+ add a ; double catch rate
+ jr nc, .noCarry
+ ld a, $ff
+.noCarry
+ ld [hl], a
+ ld a, ROCK_ANIM
+ ld hl, wSafariEscapeFactor ; escape factor
+ ld de, wSafariBaitFactor ; bait factor
+
+BaitRockCommon:
+ ld [wAnimationID], a
+ xor a
+ ld [wAnimationType], a
+ ld [H_WHOSETURN], a
+ ld [de], a ; zero escape factor (for bait), zero bait factor (for rock)
+.randomLoop ; loop until a random number less than 5 is generated
+ call Random
+ and 7
+ cp 5
+ jr nc, .randomLoop
+ inc a ; increment the random number, giving a range from 1 to 5 inclusive
+ ld b, a
+ ld a, [hl]
+ add b ; increase bait factor (for bait), increase escape factor (for rock)
+ jr nc, .noCarry
+ ld a, $ff
+.noCarry
+ ld [hl], a
+ predef MoveAnimation ; do animation
+ ld c, 70
+ jp DelayFrames
+
+ThrewBaitText:
+ TX_FAR _ThrewBaitText
+ db "@"
+
+ThrewRockText:
+ TX_FAR _ThrewRockText
+ db "@"
+
+; also used for Dig out-of-battle effect
+ItemUseEscapeRope:
+ ld a, [wIsInBattle]
+ and a
+ jr nz, .notUsable
+ ld a, [wCurMap]
+ cp AGATHAS_ROOM
+ jr z, .notUsable
+ ld a, [wCurMapTileset]
+ ld b, a
+ ld hl, EscapeRopeTilesets
+.loop
+ ld a, [hli]
+ cp $ff
+ jr z, .notUsable
+ cp b
+ jr nz, .loop
+ ld hl, wd732
+ set 3, [hl]
+ set 6, [hl]
+ ld hl, wd72e
+ res 4, [hl]
+ ResetEvent EVENT_IN_SAFARI_ZONE
+ xor a
+ ld [wNumSafariBalls], a
+ ld [wSafariZoneGateCurScript], a
+ inc a
+ ld [wEscapedFromBattle], a
+ ld [wActionResultOrTookBattleTurn], a ; item used
+ ld a, [wPseudoItemID]
+ and a ; using Dig?
+ ret nz ; if so, return
+ call ItemUseReloadOverworldData
+ ld c, 30
+ call DelayFrames
+ jp RemoveUsedItem
+.notUsable
+ jp ItemUseNotTime
+
+EscapeRopeTilesets:
+ db FOREST, CEMETERY, CAVERN, FACILITY, INTERIOR
+ db $ff ; terminator
+
+ItemUseRepel:
+ ld b, 100
+
+ItemUseRepelCommon:
+ ld a, [wIsInBattle]
+ and a
+ jp nz, ItemUseNotTime
+ ld a, b
+ ld [wRepelRemainingSteps], a
+ jp PrintItemUseTextAndRemoveItem
+
+; handles X Accuracy item
+ItemUseXAccuracy:
+ ld a, [wIsInBattle]
+ and a
+ jp z, ItemUseNotTime
+ ld hl, wPlayerBattleStatus2
+ set USING_X_ACCURACY, [hl] ; X Accuracy bit
+ jp PrintItemUseTextAndRemoveItem
+
+; This function is bugged and never works. It always jumps to ItemUseNotTime.
+; The Card Key is handled in a different way.
+ItemUseCardKey:
+ xor a
+ ld [wUnusedD71F], a
+ call GetTileAndCoordsInFrontOfPlayer
+ ld a, [GetTileAndCoordsInFrontOfPlayer]
+ cp $18
+ jr nz, .next0
+ ld hl, CardKeyTable1
+ jr .next1
+.next0
+ cp $24
+ jr nz, .next2
+ ld hl, CardKeyTable2
+ jr .next1
+.next2
+ cp $5e
+ jp nz, ItemUseNotTime
+ ld hl, CardKeyTable3
+.next1
+ ld a, [wCurMap]
+ ld b, a
+.loop
+ ld a, [hli]
+ cp $ff
+ jp z, ItemUseNotTime
+ cp b
+ jr nz, .nextEntry1
+ ld a, [hli]
+ cp d
+ jr nz, .nextEntry2
+ ld a, [hli]
+ cp e
+ jr nz, .nextEntry3
+ ld a, [hl]
+ ld [wUnusedD71F], a
+ jr .done
+.nextEntry1
+ inc hl
+.nextEntry2
+ inc hl
+.nextEntry3
+ inc hl
+ jr .loop
+.done
+ ld hl, ItemUseText00
+ call PrintText
+ ld hl, wd728
+ set 7, [hl]
+ ret
+
+; These tables are probably supposed to be door locations in Silph Co.,
+; but they are unused.
+; The reason there are 3 tables is unknown.
+
+; Format:
+; 00: Map ID
+; 01: Y
+; 02: X
+; 03: ID?
+
+CardKeyTable1:
+ db SILPH_CO_2F,$04,$04,$00
+ db SILPH_CO_2F,$04,$05,$01
+ db SILPH_CO_4F,$0C,$04,$02
+ db SILPH_CO_4F,$0C,$05,$03
+ db SILPH_CO_7F,$06,$0A,$04
+ db SILPH_CO_7F,$06,$0B,$05
+ db SILPH_CO_9F,$04,$12,$06
+ db SILPH_CO_9F,$04,$13,$07
+ db SILPH_CO_10F,$08,$0A,$08
+ db SILPH_CO_10F,$08,$0B,$09
+ db $ff
+
+CardKeyTable2:
+ db SILPH_CO_3F,$08,$09,$0A
+ db SILPH_CO_3F,$09,$09,$0B
+ db SILPH_CO_5F,$04,$07,$0C
+ db SILPH_CO_5F,$05,$07,$0D
+ db SILPH_CO_6F,$0C,$05,$0E
+ db SILPH_CO_6F,$0D,$05,$0F
+ db SILPH_CO_8F,$08,$07,$10
+ db SILPH_CO_8F,$09,$07,$11
+ db SILPH_CO_9F,$08,$03,$12
+ db SILPH_CO_9F,$09,$03,$13
+ db $ff
+
+CardKeyTable3:
+ db SILPH_CO_11F,$08,$09,$14
+ db SILPH_CO_11F,$09,$09,$15
+ db $ff
+
+ItemUsePokedoll:
+ ld a, [wIsInBattle]
+ dec a
+ jp nz, ItemUseNotTime
+ ld a, $01
+ ld [wEscapedFromBattle], a
+ jp PrintItemUseTextAndRemoveItem
+
+ItemUseGuardSpec:
+ ld a, [wIsInBattle]
+ and a
+ jp z, ItemUseNotTime
+ ld hl, wPlayerBattleStatus2
+ set PROTECTED_BY_MIST, [hl] ; Mist bit
+ jp PrintItemUseTextAndRemoveItem
+
+ItemUseSuperRepel:
+ ld b, 200
+ jp ItemUseRepelCommon
+
+ItemUseMaxRepel:
+ ld b, 250
+ jp ItemUseRepelCommon
+
+ItemUseDireHit:
+ ld a, [wIsInBattle]
+ and a
+ jp z, ItemUseNotTime
+ ld hl, wPlayerBattleStatus2
+ set GETTING_PUMPED, [hl] ; Focus Energy bit
+ jp PrintItemUseTextAndRemoveItem
+
+ItemUseXStat:
+ ld a, [wIsInBattle]
+ and a
+ jr nz, .inBattle
+ call ItemUseNotTime
+ ld a, 2
+ ld [wActionResultOrTookBattleTurn], a ; item not used
+ ret
+.inBattle
+ ld hl, wPlayerMoveNum
+ ld a, [hli]
+ push af ; save [wPlayerMoveNum]
+ ld a, [hl]
+ push af ; save [wPlayerMoveEffect]
+ push hl
+ ld a, [wcf91]
+ sub X_ATTACK - ATTACK_UP1_EFFECT
+ ld [hl], a ; store player move effect
+ call PrintItemUseTextAndRemoveItem
+ ld a, XSTATITEM_ANIM ; X stat item animation ID
+ ld [wPlayerMoveNum], a
+ call LoadScreenTilesFromBuffer1 ; restore saved screen
+ call Delay3
+ xor a
+ ld [H_WHOSETURN], a ; set turn to player's turn
+ callba StatModifierUpEffect ; do stat increase move
+ pop hl
+ pop af
+ ld [hld], a ; restore [wPlayerMoveEffect]
+ pop af
+ ld [hl], a ; restore [wPlayerMoveNum]
+ ret
+
+ItemUsePokeflute:
+ ld a, [wIsInBattle]
+ and a
+ jr nz, .inBattle
+; if not in battle
+ call ItemUseReloadOverworldData
+ ld a, [wCurMap]
+ cp ROUTE_12
+ jr nz, .notRoute12
+ CheckEvent EVENT_BEAT_ROUTE12_SNORLAX
+ jr nz, .noSnorlaxToWakeUp
+; if the player hasn't beaten Route 12 Snorlax
+ ld hl, Route12SnorlaxFluteCoords
+ call ArePlayerCoordsInArray
+ jr nc, .noSnorlaxToWakeUp
+ ld hl, PlayedFluteHadEffectText
+ call PrintText
+ SetEvent EVENT_FIGHT_ROUTE12_SNORLAX
+ ret
+.notRoute12
+ cp ROUTE_16
+ jr nz, .noSnorlaxToWakeUp
+ CheckEvent EVENT_BEAT_ROUTE16_SNORLAX
+ jr nz, .noSnorlaxToWakeUp
+; if the player hasn't beaten Route 16 Snorlax
+ ld hl, Route16SnorlaxFluteCoords
+ call ArePlayerCoordsInArray
+ jr nc, .noSnorlaxToWakeUp
+ ld hl, PlayedFluteHadEffectText
+ call PrintText
+ SetEvent EVENT_FIGHT_ROUTE16_SNORLAX
+ ret
+.noSnorlaxToWakeUp
+ ld hl, PlayedFluteNoEffectText
+ jp PrintText
+.inBattle
+ xor a
+ ld [wWereAnyMonsAsleep], a
+ ld b, ~SLP & $ff
+ ld hl, wPartyMon1Status
+ call WakeUpEntireParty
+ ld a, [wIsInBattle]
+ dec a ; is it a trainer battle?
+ jr z, .skipWakingUpEnemyParty
+; if it's a trainer battle
+ ld hl, wEnemyMon1Status
+ call WakeUpEntireParty
+.skipWakingUpEnemyParty
+ ld hl, wBattleMonStatus
+ ld a, [hl]
+ and b ; remove Sleep status
+ ld [hl], a
+ ld hl, wEnemyMonStatus
+ ld a, [hl]
+ and b ; remove Sleep status
+ ld [hl], a
+ call LoadScreenTilesFromBuffer2 ; restore saved screen
+ ld a, [wWereAnyMonsAsleep]
+ and a ; were any pokemon asleep before playing the flute?
+ ld hl, PlayedFluteNoEffectText
+ jp z, PrintText ; if no pokemon were asleep
+; if some pokemon were asleep
+ ld hl, PlayedFluteHadEffectText
+ call PrintText
+ ld a, [wLowHealthAlarm]
+ and $80
+ jr nz, .skipMusic
+ call WaitForSoundToFinish ; wait for sound to end
+ callba Music_PokeFluteInBattle ; play in-battle pokeflute music
+.musicWaitLoop ; wait for music to finish playing
+ ld a, [wChannelSoundIDs + Ch7]
+ and a ; music off?
+ jr nz, .musicWaitLoop
+.skipMusic
+ ld hl, FluteWokeUpText
+ jp PrintText
+
+; wakes up all party pokemon
+; INPUT:
+; hl must point to status of first pokemon in party (player's or enemy's)
+; b must equal ~SLP
+; [wWereAnyMonsAsleep] should be initialized to 0
+; OUTPUT:
+; [wWereAnyMonsAsleep]: set to 1 if any pokemon were asleep
+WakeUpEntireParty:
+ ld de, 44
+ ld c, 6
+.loop
+ ld a, [hl]
+ push af
+ and SLP ; is pokemon asleep?
+ jr z, .notAsleep
+ ld a, 1
+ ld [wWereAnyMonsAsleep], a ; indicate that a pokemon had to be woken up
+.notAsleep
+ pop af
+ and b ; remove Sleep status
+ ld [hl], a
+ add hl, de
+ dec c
+ jr nz, .loop
+ ret
+
+; Format:
+; 00: Y
+; 01: X
+Route12SnorlaxFluteCoords:
+ db 62,9 ; one space West of Snorlax
+ db 61,10 ; one space North of Snorlax
+ db 63,10 ; one space South of Snorlax
+ db 62,11 ; one space East of Snorlax
+ db $ff ; terminator
+
+; Format:
+; 00: Y
+; 01: X
+Route16SnorlaxFluteCoords:
+ db 10,27 ; one space East of Snorlax
+ db 10,25 ; one space West of Snorlax
+ db $ff ; terminator
+
+PlayedFluteNoEffectText:
+ TX_FAR _PlayedFluteNoEffectText
+ db "@"
+
+FluteWokeUpText:
+ TX_FAR _FluteWokeUpText
+ db "@"
+
+PlayedFluteHadEffectText:
+ TX_FAR _PlayedFluteHadEffectText
+ TX_BLINK
+ TX_ASM
+ ld a, [wIsInBattle]
+ and a
+ jr nz, .done
+; play out-of-battle pokeflute music
+ ld a, $ff
+ call PlaySound ; turn off music
+ ld a, SFX_POKEFLUTE
+ ld c, BANK(SFX_Pokeflute)
+ call PlayMusic
+.musicWaitLoop ; wait for music to finish playing
+ ld a, [wChannelSoundIDs + Ch3]
+ cp SFX_POKEFLUTE
+ jr z, .musicWaitLoop
+ call PlayDefaultMusic ; start playing normal music again
+.done
+ jp TextScriptEnd ; end text
+
+ItemUseCoinCase:
+ ld a, [wIsInBattle]
+ and a
+ jp nz, ItemUseNotTime
+ ld hl, CoinCaseNumCoinsText
+ jp PrintText
+
+CoinCaseNumCoinsText:
+ TX_FAR _CoinCaseNumCoinsText
+ db "@"
+
+ItemUseOldRod:
+ call FishingInit
+ jp c, ItemUseNotTime
+ lb bc, 5, MAGIKARP
+ ld a, $1 ; set bite
+ jr RodResponse
+
+ItemUseGoodRod:
+ call FishingInit
+ jp c, ItemUseNotTime
+.RandomLoop
+ call Random
+ srl a
+ jr c, .SetBite
+ and %11
+ cp 2
+ jr nc, .RandomLoop
+ ; choose which monster appears
+ ld hl, GoodRodMons
+ add a
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld b, [hl]
+ inc hl
+ ld c, [hl]
+ and a
+.SetBite
+ ld a, 0
+ rla
+ xor 1
+ jr RodResponse
+
+INCLUDE "data/good_rod.asm"
+
+ItemUseSuperRod:
+ call FishingInit
+ jp c, ItemUseNotTime
+ call ReadSuperRodData
+ ld a, e
+RodResponse:
+ ld [wRodResponse], a
+
+ dec a ; is there a bite?
+ jr nz, .next
+ ; if yes, store level and species data
+ ld a, 1
+ ld [wMoveMissed], a
+ ld a, b ; level
+ ld [wCurEnemyLVL], a
+ ld a, c ; species
+ ld [wCurOpponent], a
+
+.next
+ ld hl, wWalkBikeSurfState
+ ld a, [hl] ; store the value in a
+ push af
+ push hl
+ ld [hl], 0
+ callba FishingAnim
+ pop hl
+ pop af
+ ld [hl], a
+ ret
+
+; checks if fishing is possible and if so, runs initialization code common to all rods
+; unsets carry if fishing is possible, sets carry if not
+FishingInit:
+ ld a, [wIsInBattle]
+ and a
+ jr z, .notInBattle
+ scf ; can't fish during battle
+ ret
+.notInBattle
+ call IsNextTileShoreOrWater
+ ret c
+ ld a, [wWalkBikeSurfState]
+ cp 2 ; Surfing?
+ jr z, .surfing
+ call ItemUseReloadOverworldData
+ ld hl, ItemUseText00
+ call PrintText
+ ld a, SFX_HEAL_AILMENT
+ call PlaySound
+ ld c, 80
+ call DelayFrames
+ and a
+ ret
+.surfing
+ scf ; can't fish when surfing
+ ret
+
+ItemUseOaksParcel:
+ jp ItemUseNotYoursToUse
+
+ItemUseItemfinder:
+ ld a, [wIsInBattle]
+ and a
+ jp nz, ItemUseNotTime
+ call ItemUseReloadOverworldData
+ callba HiddenItemNear ; check for hidden items
+ ld hl, ItemfinderFoundNothingText
+ jr nc, .printText ; if no hidden items
+ ld c, 4
+.loop
+ ld a, SFX_HEALING_MACHINE
+ call PlaySoundWaitForCurrent
+ ld a, SFX_PURCHASE
+ call PlaySoundWaitForCurrent
+ dec c
+ jr nz, .loop
+ ld hl, ItemfinderFoundItemText
+.printText
+ jp PrintText
+
+ItemfinderFoundItemText:
+ TX_FAR _ItemfinderFoundItemText
+ db "@"
+
+ItemfinderFoundNothingText:
+ TX_FAR _ItemfinderFoundNothingText
+ db "@"
+
+ItemUsePPUp:
+ ld a, [wIsInBattle]
+ and a
+ jp nz, ItemUseNotTime
+
+ItemUsePPRestore:
+ ld a, [wWhichPokemon]
+ push af
+ ld a, [wcf91]
+ ld [wPPRestoreItem], a
+.chooseMon
+ xor a
+ ld [wUpdateSpritesEnabled], a
+ ld a, USE_ITEM_PARTY_MENU
+ ld [wPartyMenuTypeOrMessageID], a
+ call DisplayPartyMenu
+ jr nc, .chooseMove
+ jp .itemNotUsed
+.chooseMove
+ ld a, [wPPRestoreItem]
+ cp ELIXER
+ jp nc, .useElixir ; if Elixir or Max Elixir
+ ld a, $02
+ ld [wMoveMenuType], a
+ ld hl, RaisePPWhichTechniqueText
+ ld a, [wPPRestoreItem]
+ cp ETHER ; is it a PP Up?
+ jr c, .printWhichTechniqueMessage ; if so, print the raise PP message
+ ld hl, RestorePPWhichTechniqueText ; otherwise, print the restore PP message
+.printWhichTechniqueMessage
+ call PrintText
+ xor a
+ ld [wPlayerMoveListIndex], a
+ callab MoveSelectionMenu ; move selection menu
+ ld a, 0
+ ld [wPlayerMoveListIndex], a
+ jr nz, .chooseMon
+ ld hl, wPartyMon1Moves
+ ld bc, wPartyMon2 - wPartyMon1
+ call GetSelectedMoveOffset
+ push hl
+ ld a, [hl]
+ ld [wd11e], a
+ call GetMoveName
+ call CopyStringToCF4B ; copy name to wcf4b
+ pop hl
+ ld a, [wPPRestoreItem]
+ cp ETHER
+ jr nc, .useEther ; if Ether or Max Ether
+.usePPUp
+ ld bc, wPartyMon1PP - wPartyMon1Moves
+ add hl, bc
+ ld a, [hl] ; move PP
+ cp 3 << 6 ; have 3 PP Ups already been used?
+ jr c, .PPNotMaxedOut
+ ld hl, PPMaxedOutText
+ call PrintText
+ jr .chooseMove
+.PPNotMaxedOut
+ ld a, [hl]
+ add 1 << 6 ; increase PP Up count by 1
+ ld [hl], a
+ ld a, 1 ; 1 PP Up used
+ ld [wd11e], a
+ call RestoreBonusPP ; add the bonus PP to current PP
+ ld hl, PPIncreasedText
+ call PrintText
+.done
+ pop af
+ ld [wWhichPokemon], a
+ call GBPalWhiteOut
+ call RunDefaultPaletteCommand
+ jp RemoveUsedItem
+.afterRestoringPP ; after using a (Max) Ether/Elixir
+ ld a, [wWhichPokemon]
+ ld b, a
+ ld a, [wPlayerMonNumber]
+ cp b ; is the pokemon whose PP was restored active in battle?
+ jr nz, .skipUpdatingInBattleData
+ ld hl, wPartyMon1PP
+ ld bc, wPartyMon2 - wPartyMon1
+ call AddNTimes
+ ld de, wBattleMonPP
+ ld bc, 4
+ call CopyData ; copy party data to in-battle data
+.skipUpdatingInBattleData
+ ld a, SFX_HEAL_AILMENT
+ call PlaySound
+ ld hl, PPRestoredText
+ call PrintText
+ jr .done
+.useEther
+ call .restorePP
+ jr nz, .afterRestoringPP
+ jp .noEffect
+; unsets zero flag if PP was restored, sets zero flag if not
+; however, this is bugged for Max Ethers and Max Elixirs (see below)
+.restorePP
+ xor a ; PLAYER_PARTY_DATA
+ ld [wMonDataLocation], a
+ call GetMaxPP
+ ld hl, wPartyMon1Moves
+ ld bc, wPartyMon2 - wPartyMon1
+ call GetSelectedMoveOffset
+ ld bc, wPartyMon1PP - wPartyMon1Moves
+ add hl, bc ; hl now points to move's PP
+ ld a, [wMaxPP]
+ ld b, a
+ ld a, [wPPRestoreItem]
+ cp MAX_ETHER
+ jr z, .fullyRestorePP
+ ld a, [hl] ; move PP
+ and %00111111 ; lower 6 bit bits store current PP
+ cp b ; does current PP equal max PP?
+ ret z ; if so, return
+ add 10 ; increase current PP by 10
+; b holds the max PP amount and b will hold the new PP amount.
+; So, if the new amount meets or exceeds the max amount,
+; cap the amount to the max amount by leaving b unchanged.
+; Otherwise, store the new amount in b.
+ cp b ; does the new amount meet or exceed the maximum?
+ jr nc, .storeNewAmount
+ ld b, a
+.storeNewAmount
+ ld a, [hl] ; move PP
+ and %11000000 ; PP Up counter bits
+ add b
+ ld [hl], a
+ ret
+.fullyRestorePP
+ ld a, [hl] ; move PP
+; Note that this code has a bug. It doesn't mask out the upper two bits, which
+; are used to count how many PP Ups have been used on the move. So, Max Ethers
+; and Max Elixirs will not be detected as having no effect on a move with full
+; PP if the move has had any PP Ups used on it.
+ cp b ; does current PP equal max PP?
+ ret z
+ jr .storeNewAmount
+.useElixir
+; decrement the item ID so that ELIXER becomes ETHER and MAX_ELIXER becomes MAX_ETHER
+ ld hl, wPPRestoreItem
+ dec [hl]
+ dec [hl]
+ xor a
+ ld hl, wCurrentMenuItem
+ ld [hli], a
+ ld [hl], a ; zero the counter for number of moves that had their PP restored
+ ld b, 4
+; loop through each move and restore PP
+.elixirLoop
+ push bc
+ ld hl, wPartyMon1Moves
+ ld bc, wPartyMon2 - wPartyMon1
+ call GetSelectedMoveOffset
+ ld a, [hl]
+ and a ; does the current slot have a move?
+ jr z, .nextMove
+ call .restorePP
+ jr z, .nextMove
+; if some PP was restored
+ ld hl, wTileBehindCursor ; counter for number of moves that had their PP restored
+ inc [hl]
+.nextMove
+ ld hl, wCurrentMenuItem
+ inc [hl]
+ pop bc
+ dec b
+ jr nz, .elixirLoop
+ ld a, [wTileBehindCursor]
+ and a ; did any moves have their PP restored?
+ jp nz, .afterRestoringPP
+.noEffect
+ call ItemUseNoEffect
+.itemNotUsed
+ call GBPalWhiteOut
+ call RunDefaultPaletteCommand
+ pop af
+ xor a
+ ld [wActionResultOrTookBattleTurn], a ; item use failed
+ ret
+
+RaisePPWhichTechniqueText:
+ TX_FAR _RaisePPWhichTechniqueText
+ db "@"
+
+RestorePPWhichTechniqueText:
+ TX_FAR _RestorePPWhichTechniqueText
+ db "@"
+
+PPMaxedOutText:
+ TX_FAR _PPMaxedOutText
+ db "@"
+
+PPIncreasedText:
+ TX_FAR _PPIncreasedText
+ db "@"
+
+PPRestoredText:
+ TX_FAR _PPRestoredText
+ db "@"
+
+; for items that can't be used from the Item menu
+UnusableItem:
+ jp ItemUseNotTime
+
+ItemUseTMHM:
+ ld a, [wIsInBattle]
+ and a
+ jp nz, ItemUseNotTime
+ ld a, [wcf91]
+ sub TM_01
+ push af
+ jr nc, .skipAdding
+ add 55 ; if item is an HM, add 55
+.skipAdding
+ inc a
+ ld [wd11e], a
+ predef TMToMove ; get move ID from TM/HM ID
+ ld a, [wd11e]
+ ld [wMoveNum], a
+ call GetMoveName
+ call CopyStringToCF4B ; copy name to wcf4b
+ pop af
+ ld hl, BootedUpTMText
+ jr nc, .printBootedUpMachineText
+ ld hl, BootedUpHMText
+.printBootedUpMachineText
+ call PrintText
+ ld hl, TeachMachineMoveText
+ call PrintText
+ coord hl, 14, 7
+ lb bc, 8, 15
+ ld a, TWO_OPTION_MENU
+ ld [wTextBoxID], a
+ call DisplayTextBoxID ; yes/no menu
+ ld a, [wCurrentMenuItem]
+ and a
+ jr z, .useMachine
+ ld a, 2
+ ld [wActionResultOrTookBattleTurn], a ; item not used
+ ret
+.useMachine
+ ld a, [wWhichPokemon]
+ push af
+ ld a, [wcf91]
+ push af
+.chooseMon
+ ld hl, wcf4b
+ ld de, wTempMoveNameBuffer
+ ld bc, 14
+ call CopyData ; save the move name because DisplayPartyMenu will overwrite it
+ ld a, $ff
+ ld [wUpdateSpritesEnabled], a
+ ld a, TMHM_PARTY_MENU
+ ld [wPartyMenuTypeOrMessageID], a
+ call DisplayPartyMenu
+ push af
+ ld hl, wTempMoveNameBuffer
+ ld de, wcf4b
+ ld bc, 14
+ call CopyData
+ pop af
+ jr nc, .checkIfAbleToLearnMove
+; if the player canceled teaching the move
+ pop af
+ pop af
+ call GBPalWhiteOutWithDelay3
+ call ClearSprites
+ call RunDefaultPaletteCommand
+ jp LoadScreenTilesFromBuffer1 ; restore saved screen
+.checkIfAbleToLearnMove
+ predef CanLearnTM ; check if the pokemon can learn the move
+ push bc
+ ld a, [wWhichPokemon]
+ ld hl, wPartyMonNicks
+ call GetPartyMonName
+ pop bc
+ ld a, c
+ and a ; can the pokemon learn the move?
+ jr nz, .checkIfAlreadyLearnedMove
+; if the pokemon can't learn the move
+ ld a, SFX_DENIED
+ call PlaySoundWaitForCurrent
+ ld hl, MonCannotLearnMachineMoveText
+ call PrintText
+ jr .chooseMon
+.checkIfAlreadyLearnedMove
+ callab CheckIfMoveIsKnown ; check if the pokemon already knows the move
+ jr c, .chooseMon
+ predef LearnMove ; teach move
+ pop af
+ ld [wcf91], a
+ pop af
+ ld [wWhichPokemon], a
+ ld a, b
+ and a
+ ret z
+ ld a, [wcf91]
+ call IsItemHM
+ ret c
+ jp RemoveUsedItem
+
+BootedUpTMText:
+ TX_FAR _BootedUpTMText
+ db "@"
+
+BootedUpHMText:
+ TX_FAR _BootedUpHMText
+ db "@"
+
+TeachMachineMoveText:
+ TX_FAR _TeachMachineMoveText
+ db "@"
+
+MonCannotLearnMachineMoveText:
+ TX_FAR _MonCannotLearnMachineMoveText
+ db "@"
+
+PrintItemUseTextAndRemoveItem:
+ ld hl, ItemUseText00
+ call PrintText
+ ld a, SFX_HEAL_AILMENT
+ call PlaySound
+ call WaitForTextScrollButtonPress ; wait for button press
+
+RemoveUsedItem:
+ ld hl, wNumBagItems
+ ld a, 1 ; one item
+ ld [wItemQuantity], a
+ jp RemoveItemFromInventory
+
+ItemUseNoEffect:
+ ld hl, ItemUseNoEffectText
+ jr ItemUseFailed
+
+ItemUseNotTime:
+ ld hl, ItemUseNotTimeText
+ jr ItemUseFailed
+
+ItemUseNotYoursToUse:
+ ld hl, ItemUseNotYoursToUseText
+ jr ItemUseFailed
+
+ThrowBallAtTrainerMon:
+ call RunDefaultPaletteCommand
+ call LoadScreenTilesFromBuffer1 ; restore saved screen
+ call Delay3
+ ld a, TOSS_ANIM
+ ld [wAnimationID], a
+ predef MoveAnimation ; do animation
+ ld hl, ThrowBallAtTrainerMonText1
+ call PrintText
+ ld hl, ThrowBallAtTrainerMonText2
+ call PrintText
+ jr RemoveUsedItem
+
+NoCyclingAllowedHere:
+ ld hl, NoCyclingAllowedHereText
+ jr ItemUseFailed
+
+BoxFullCannotThrowBall:
+ ld hl, BoxFullCannotThrowBallText
+ jr ItemUseFailed
+
+SurfingAttemptFailed:
+ ld hl, NoSurfingHereText
+
+ItemUseFailed:
+ xor a
+ ld [wActionResultOrTookBattleTurn], a ; item use failed
+ jp PrintText
+
+ItemUseNotTimeText:
+ TX_FAR _ItemUseNotTimeText
+ db "@"
+
+ItemUseNotYoursToUseText:
+ TX_FAR _ItemUseNotYoursToUseText
+ db "@"
+
+ItemUseNoEffectText:
+ TX_FAR _ItemUseNoEffectText
+ db "@"
+
+ThrowBallAtTrainerMonText1:
+ TX_FAR _ThrowBallAtTrainerMonText1
+ db "@"
+
+ThrowBallAtTrainerMonText2:
+ TX_FAR _ThrowBallAtTrainerMonText2
+ db "@"
+
+NoCyclingAllowedHereText:
+ TX_FAR _NoCyclingAllowedHereText
+ db "@"
+
+NoSurfingHereText:
+ TX_FAR _NoSurfingHereText
+ db "@"
+
+BoxFullCannotThrowBallText:
+ TX_FAR _BoxFullCannotThrowBallText
+ db "@"
+
+ItemUseText00:
+ TX_FAR _ItemUseText001
+ TX_LINE
+ TX_FAR _ItemUseText002
+ db "@"
+
+GotOnBicycleText:
+ TX_FAR _GotOnBicycleText1
+ TX_LINE
+ TX_FAR _GotOnBicycleText2
+ db "@"
+
+GotOffBicycleText:
+ TX_FAR _GotOffBicycleText1
+ TX_LINE
+ TX_FAR _GotOffBicycleText2
+ db "@"
+
+; restores bonus PP (from PP Ups) when healing at a pokemon center
+; also, when a PP Up is used, it increases the current PP by one PP Up bonus
+; INPUT:
+; [wWhichPokemon] = index of pokemon in party
+; [wCurrentMenuItem] = index of move (when using a PP Up)
+RestoreBonusPP:
+ ld hl, wPartyMon1Moves
+ ld bc, wPartyMon2 - wPartyMon1
+ ld a, [wWhichPokemon]
+ call AddNTimes
+ push hl
+ ld de, wNormalMaxPPList - 1
+ predef LoadMovePPs ; loads the normal max PP of each of the pokemon's moves to wNormalMaxPPList
+ pop hl
+ ld c, wPartyMon1PP - wPartyMon1Moves
+ ld b, 0
+ add hl, bc ; hl now points to move 1 PP
+ ld de, wNormalMaxPPList
+ ld b, 0 ; initialize move counter to zero
+; loop through the pokemon's moves
+.loop
+ inc b
+ ld a, b
+ cp 5 ; reached the end of the pokemon's moves?
+ ret z ; if so, return
+ ld a, [wUsingPPUp]
+ dec a ; using a PP Up?
+ jr nz, .skipMenuItemIDCheck
+; if using a PP Up, check if this is the move it's being used on
+ ld a, [wCurrentMenuItem]
+ inc a
+ cp b
+ jr nz, .nextMove
+.skipMenuItemIDCheck
+ ld a, [hl]
+ and %11000000 ; have any PP Ups been used?
+ call nz, AddBonusPP ; if so, add bonus PP
+.nextMove
+ inc hl
+ inc de
+ jr .loop
+
+; adds bonus PP from PP Ups to current PP
+; 1/5 of normal max PP (capped at 7) is added for each PP Up
+; INPUT:
+; [de] = normal max PP
+; [hl] = move PP
+AddBonusPP:
+ push bc
+ ld a, [de] ; normal max PP of move
+ ld [H_DIVIDEND + 3], a
+ xor a
+ ld [H_DIVIDEND], a
+ ld [H_DIVIDEND + 1], a
+ ld [H_DIVIDEND + 2], a
+ ld a, 5
+ ld [H_DIVISOR], a
+ ld b, 4
+ call Divide
+ ld a, [hl] ; move PP
+ ld b, a
+ swap a
+ and %00001111
+ srl a
+ srl a
+ ld c, a ; c = number of PP Ups used
+.loop
+ ld a, [H_QUOTIENT + 3]
+ cp 8 ; is the amount greater than or equal to 8?
+ jr c, .addAmount
+ ld a, 7 ; cap the amount at 7
+.addAmount
+ add b
+ ld b, a
+ ld a, [wUsingPPUp]
+ dec a ; is the player using a PP Up right now?
+ jr z, .done ; if so, only add the bonus once
+ dec c
+ jr nz, .loop
+.done
+ ld [hl], b
+ pop bc
+ ret
+
+; gets max PP of a pokemon's move (including PP from PP Ups)
+; INPUT:
+; [wWhichPokemon] = index of pokemon within party/box
+; [wMonDataLocation] = pokemon source
+; 00: player's party
+; 01: enemy's party
+; 02: current box
+; 03: daycare
+; 04: player's in-battle pokemon
+; [wCurrentMenuItem] = move index
+; OUTPUT:
+; [wMaxPP] = max PP
+GetMaxPP:
+ ld a, [wMonDataLocation]
+ and a
+ ld hl, wPartyMon1Moves
+ ld bc, wPartyMon2 - wPartyMon1
+ jr z, .sourceWithMultipleMon
+ ld hl, wEnemyMon1Moves
+ dec a
+ jr z, .sourceWithMultipleMon
+ ld hl, wBoxMon1Moves
+ ld bc, wBoxMon2 - wBoxMon1
+ dec a
+ jr z, .sourceWithMultipleMon
+ ld hl, wDayCareMonMoves
+ dec a
+ jr z, .sourceWithOneMon
+ ld hl, wBattleMonMoves ; player's in-battle pokemon
+.sourceWithOneMon
+ call GetSelectedMoveOffset2
+ jr .next
+.sourceWithMultipleMon
+ call GetSelectedMoveOffset
+.next
+ ld a, [hl]
+ dec a
+ push hl
+ ld hl, Moves
+ ld bc, MoveEnd - Moves
+ call AddNTimes
+ ld de, wcd6d
+ ld a, BANK(Moves)
+ call FarCopyData
+ ld de, wcd6d + 5 ; PP is byte 5 of move data
+ ld a, [de]
+ ld b, a ; b = normal max PP
+ pop hl
+ push bc
+ ld bc, wPartyMon1PP - wPartyMon1Moves ; PP offset if not player's in-battle pokemon data
+ ld a, [wMonDataLocation]
+ cp 4 ; player's in-battle pokemon?
+ jr nz, .addPPOffset
+ ld bc, wBattleMonPP - wBattleMonMoves ; PP offset if player's in-battle pokemon data
+.addPPOffset
+ add hl, bc
+ ld a, [hl] ; a = current PP
+ and %11000000 ; get PP Up count
+ pop bc
+ or b ; place normal max PP in 6 lower bits of a
+ ld h, d
+ ld l, e
+ inc hl ; hl = wcd73
+ ld [hl], a
+ xor a ; add the bonus for the existing PP Up count
+ ld [wUsingPPUp], a
+ call AddBonusPP ; add bonus PP from PP Ups
+ ld a, [hl]
+ and %00111111 ; mask out the PP Up count
+ ld [wMaxPP], a ; store max PP
+ ret
+
+GetSelectedMoveOffset:
+ ld a, [wWhichPokemon]
+ call AddNTimes
+
+GetSelectedMoveOffset2:
+ ld a, [wCurrentMenuItem]
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ret
+
+; 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_::
+ push hl
+ ld a, [wcf91]
+ call IsItemHM
+ pop hl
+ jr c, .tooImportantToToss
+ push hl
+ call IsKeyItem_
+ ld a, [wIsKeyItem]
+ pop hl
+ and a
+ jr nz, .tooImportantToToss
+ push hl
+ ld a, [wcf91]
+ ld [wd11e], a
+ call GetItemName
+ call CopyStringToCF4B ; copy name to wcf4b
+ ld hl, IsItOKToTossItemText
+ call PrintText
+ coord hl, 14, 7
+ lb bc, 8, 15
+ ld a, TWO_OPTION_MENU
+ ld [wTextBoxID], a
+ call DisplayTextBoxID ; yes/no menu
+ ld a, [wMenuExitMethod]
+ cp CHOSE_SECOND_ITEM
+ pop hl
+ scf
+ ret z ; return if the player chose No
+; if the player chose Yes
+ push hl
+ ld a, [wWhichPokemon]
+ call RemoveItemFromInventory
+ ld a, [wcf91]
+ ld [wd11e], a
+ call GetItemName
+ call CopyStringToCF4B ; copy name to wcf4b
+ ld hl, ThrewAwayItemText
+ call PrintText
+ pop hl
+ and a
+ ret
+.tooImportantToToss
+ push hl
+ ld hl, TooImportantToTossText
+ call PrintText
+ pop hl
+ scf
+ ret
+
+ThrewAwayItemText:
+ TX_FAR _ThrewAwayItemText
+ db "@"
+
+IsItOKToTossItemText:
+ TX_FAR _IsItOKToTossItemText
+ db "@"
+
+TooImportantToTossText:
+ TX_FAR _TooImportantToTossText
+ db "@"
+
+; 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_::
+ ld a, $01
+ ld [wIsKeyItem], a
+ ld a, [wcf91]
+ cp HM_01 ; is the item an HM or TM?
+ jr nc, .checkIfItemIsHM
+; if the item is not an HM or TM
+ push af
+ ld hl, KeyItemBitfield
+ ld de, wBuffer
+ ld bc, 15 ; only 11 bytes are actually used
+ call CopyData
+ pop af
+ dec a
+ ld c, a
+ ld hl, wBuffer
+ ld b, FLAG_TEST
+ predef FlagActionPredef
+ ld a, c
+ and a
+ ret nz
+.checkIfItemIsHM
+ ld a, [wcf91]
+ call IsItemHM
+ ret c
+ xor a
+ ld [wIsKeyItem], a
+ ret
+
+INCLUDE "data/key_items.asm"
+
+SendNewMonToBox:
+ ld de, wNumInBox
+ ld a, [de]
+ inc a
+ ld [de], a
+ ld a, [wcf91]
+ ld [wd0b5], a
+ ld c, a
+.asm_e7b1
+ inc de
+ ld a, [de]
+ ld b, a
+ ld a, c
+ ld c, b
+ ld [de], a
+ cp $ff
+ jr nz, .asm_e7b1
+ call GetMonHeader
+ ld hl, wBoxMonOT
+ ld bc, NAME_LENGTH
+ ld a, [wNumInBox]
+ dec a
+ jr z, .asm_e7ee
+ dec a
+ call AddNTimes
+ push hl
+ ld bc, NAME_LENGTH
+ add hl, bc
+ ld d, h
+ ld e, l
+ pop hl
+ ld a, [wNumInBox]
+ dec a
+ ld b, a
+.asm_e7db
+ push bc
+ push hl
+ ld bc, NAME_LENGTH
+ call CopyData
+ pop hl
+ ld d, h
+ ld e, l
+ ld bc, -NAME_LENGTH
+ add hl, bc
+ pop bc
+ dec b
+ jr nz, .asm_e7db
+.asm_e7ee
+ ld hl, wPlayerName
+ ld de, wBoxMonOT
+ ld bc, NAME_LENGTH
+ call CopyData
+ ld a, [wNumInBox]
+ dec a
+ jr z, .asm_e82a
+ ld hl, wBoxMonNicks
+ ld bc, NAME_LENGTH
+ dec a
+ call AddNTimes
+ push hl
+ ld bc, NAME_LENGTH
+ add hl, bc
+ ld d, h
+ ld e, l
+ pop hl
+ ld a, [wNumInBox]
+ dec a
+ ld b, a
+.asm_e817
+ push bc
+ push hl
+ ld bc, NAME_LENGTH
+ call CopyData
+ pop hl
+ ld d, h
+ ld e, l
+ ld bc, -NAME_LENGTH
+ add hl, bc
+ pop bc
+ dec b
+ jr nz, .asm_e817
+.asm_e82a
+ ld hl, wBoxMonNicks
+ ld a, NAME_MON_SCREEN
+ ld [wNamingScreenType], a
+ predef AskName
+ ld a, [wNumInBox]
+ dec a
+ jr z, .asm_e867
+ ld hl, wBoxMons
+ ld bc, wBoxMon2 - wBoxMon1
+ dec a
+ call AddNTimes
+ push hl
+ ld bc, wBoxMon2 - wBoxMon1
+ add hl, bc
+ ld d, h
+ ld e, l
+ pop hl
+ ld a, [wNumInBox]
+ dec a
+ ld b, a
+.asm_e854
+ push bc
+ push hl
+ ld bc, wBoxMon2 - wBoxMon1
+ call CopyData
+ pop hl
+ ld d, h
+ ld e, l
+ ld bc, wBoxMon1 - wBoxMon2
+ add hl, bc
+ pop bc
+ dec b
+ jr nz, .asm_e854
+.asm_e867
+ ld a, [wEnemyMonLevel]
+ ld [wEnemyMonBoxLevel], a
+ ld hl, wEnemyMon
+ ld de, wBoxMon1
+ ld bc, wEnemyMonDVs - wEnemyMon
+ call CopyData
+ ld hl, wPlayerID
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hl]
+ ld [de], a
+ inc de
+ push de
+ ld a, [wCurEnemyLVL]
+ ld d, a
+ callab CalcExperience
+ pop de
+ ld a, [hExperience]
+ ld [de], a
+ inc de
+ ld a, [hExperience + 1]
+ ld [de], a
+ inc de
+ ld a, [hExperience + 2]
+ ld [de], a
+ inc de
+ xor a
+ ld b, NUM_STATS * 2
+.asm_e89f
+ ld [de], a
+ inc de
+ dec b
+ jr nz, .asm_e89f
+ ld hl, wEnemyMonDVs
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hli]
+ ld [de], a
+ ld hl, wEnemyMonPP
+ ld b, NUM_MOVES
+.asm_e8b1
+ ld a, [hli]
+ inc de
+ ld [de], a
+ dec b
+ jr nz, .asm_e8b1
+ ret
+
+; checks if the tile in front of the player is a shore or water tile
+; used for surfing and fishing
+; unsets carry if it is, sets carry if not
+IsNextTileShoreOrWater:
+ ld a, [wCurMapTileset]
+ ld hl, WaterTilesets
+ ld de, 1
+ call IsInArray
+ jr nc, .notShoreOrWater
+ ld a, [wCurMapTileset]
+ cp SHIP_PORT ; Vermilion Dock tileset
+ ld a, [wTileInFrontOfPlayer] ; tile in front of player
+ jr z, .skipShoreTiles ; if it's the Vermilion Dock tileset
+ cp $48 ; eastern shore tile in Safari Zone
+ jr z, .shoreOrWater
+ cp $32 ; usual eastern shore tile
+ jr z, .shoreOrWater
+.skipShoreTiles
+ cp $14 ; water tile
+ jr z, .shoreOrWater
+.notShoreOrWater
+ scf
+ ret
+.shoreOrWater
+ and a
+ ret
+
+INCLUDE "data/water_tilesets.asm"
+
+ReadSuperRodData:
+; return e = 2 if no fish on this map
+; return e = 1 if a bite, bc = level,species
+; return e = 0 if no bite
+ ld a, [wCurMap]
+ ld de, 3 ; each fishing group is three bytes wide
+ ld hl, SuperRodData
+ call IsInArray
+ jr c, .ReadFishingGroup
+ ld e, $2 ; $2 if no fishing groups found
+ ret
+
+.ReadFishingGroup
+; hl points to the fishing group entry in the index
+ inc hl ; skip map id
+
+ ; read fishing group address
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+
+ ld b, [hl] ; how many mons in group
+ inc hl ; point to data
+ ld e, $0 ; no bite yet
+
+.RandomLoop
+ call Random
+ srl a
+ ret c ; 50% chance of no battle
+
+ and %11 ; 2-bit random number
+ cp b
+ jr nc, .RandomLoop ; if a is greater than the number of mons, regenerate
+
+ ; get the mon
+ add a
+ ld c, a
+ ld b, $0
+ add hl, bc
+ ld b, [hl] ; level
+ inc hl
+ ld c, [hl] ; species
+ ld e, $1 ; $1 if there's a bite
+ ret
+
+INCLUDE "data/super_rod.asm"
+
+; reloads map view and processes sprite data
+; for items that cause the overworld to be displayed
+ItemUseReloadOverworldData:
+ call LoadCurrentMapView
+ jp UpdateSprites
+
+; creates a list at wBuffer of maps where the mon in [wd11e] can be found.
+; this is used by the pokedex to display locations the mon can be found on the map.
+FindWildLocationsOfMon:
+ ld hl, WildDataPointers
+ ld de, wBuffer
+ ld c, $0
+.loop
+ inc hl
+ ld a, [hld]
+ inc a
+ jr z, .done
+ push hl
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [hli]
+ and a
+ call nz, CheckMapForMon ; land
+ ld a, [hli]
+ and a
+ call nz, CheckMapForMon ; water
+ pop hl
+ inc hl
+ inc hl
+ inc c
+ jr .loop
+.done
+ ld a, $ff ; list terminator
+ ld [de], a
+ ret
+
+CheckMapForMon:
+ inc hl
+ ld b, $a
+.loop
+ ld a, [wd11e]
+ cp [hl]
+ jr nz, .nextEntry
+ ld a, c
+ ld [de], a
+ inc de
+.nextEntry
+ inc hl
+ inc hl
+ dec b
+ jr nz, .loop
+ dec hl
+ ret
--- a/engine/items/items.asm
+++ /dev/null
@@ -1,2986 +1,0 @@
-UseItem_::
- ld a, 1
- ld [wActionResultOrTookBattleTurn], a ; initialise to success value
- ld a, [wcf91] ;contains item_ID
- cp HM_01
- jp nc, ItemUseTMHM
- ld hl, ItemUsePtrTable
- dec a
- add a
- ld c, a
- ld b, 0
- add hl, bc
- ld a, [hli]
- ld h, [hl]
- ld l, a
- jp hl
-
-ItemUsePtrTable:
- dw ItemUseBall ; MASTER_BALL
- dw ItemUseBall ; ULTRA_BALL
- dw ItemUseBall ; GREAT_BALL
- dw ItemUseBall ; POKE_BALL
- dw ItemUseTownMap ; TOWN_MAP
- dw ItemUseBicycle ; BICYCLE
- dw ItemUseSurfboard ; out-of-battle Surf effect
- dw ItemUseBall ; SAFARI_BALL
- dw ItemUsePokedex ; POKEDEX
- dw ItemUseEvoStone ; MOON_STONE
- dw ItemUseMedicine ; ANTIDOTE
- dw ItemUseMedicine ; BURN_HEAL
- dw ItemUseMedicine ; ICE_HEAL
- dw ItemUseMedicine ; AWAKENING
- dw ItemUseMedicine ; PARLYZ_HEAL
- dw ItemUseMedicine ; FULL_RESTORE
- dw ItemUseMedicine ; MAX_POTION
- dw ItemUseMedicine ; HYPER_POTION
- dw ItemUseMedicine ; SUPER_POTION
- dw ItemUseMedicine ; POTION
- dw ItemUseBait ; BOULDERBADGE
- dw ItemUseRock ; CASCADEBADGE
- dw UnusableItem ; THUNDERBADGE
- dw UnusableItem ; RAINBOWBADGE
- dw UnusableItem ; SOULBADGE
- dw UnusableItem ; MARSHBADGE
- dw UnusableItem ; VOLCANOBADGE
- dw UnusableItem ; EARTHBADGE
- dw ItemUseEscapeRope ; ESCAPE_ROPE
- dw ItemUseRepel ; REPEL
- dw UnusableItem ; OLD_AMBER
- dw ItemUseEvoStone ; FIRE_STONE
- dw ItemUseEvoStone ; THUNDER_STONE
- dw ItemUseEvoStone ; WATER_STONE
- dw ItemUseVitamin ; HP_UP
- dw ItemUseVitamin ; PROTEIN
- dw ItemUseVitamin ; IRON
- dw ItemUseVitamin ; CARBOS
- dw ItemUseVitamin ; CALCIUM
- dw ItemUseVitamin ; RARE_CANDY
- dw UnusableItem ; DOME_FOSSIL
- dw UnusableItem ; HELIX_FOSSIL
- dw UnusableItem ; SECRET_KEY
- dw UnusableItem
- dw UnusableItem ; BIKE_VOUCHER
- dw ItemUseXAccuracy ; X_ACCURACY
- dw ItemUseEvoStone ; LEAF_STONE
- dw ItemUseCardKey ; CARD_KEY
- dw UnusableItem ; NUGGET
- dw UnusableItem ; ??? PP_UP
- dw ItemUsePokedoll ; POKE_DOLL
- dw ItemUseMedicine ; FULL_HEAL
- dw ItemUseMedicine ; REVIVE
- dw ItemUseMedicine ; MAX_REVIVE
- dw ItemUseGuardSpec ; GUARD_SPEC
- dw ItemUseSuperRepel ; SUPER_REPL
- dw ItemUseMaxRepel ; MAX_REPEL
- dw ItemUseDireHit ; DIRE_HIT
- dw UnusableItem ; COIN
- dw ItemUseMedicine ; FRESH_WATER
- dw ItemUseMedicine ; SODA_POP
- dw ItemUseMedicine ; LEMONADE
- dw UnusableItem ; S_S_TICKET
- dw UnusableItem ; GOLD_TEETH
- dw ItemUseXStat ; X_ATTACK
- dw ItemUseXStat ; X_DEFEND
- dw ItemUseXStat ; X_SPEED
- dw ItemUseXStat ; X_SPECIAL
- dw ItemUseCoinCase ; COIN_CASE
- dw ItemUseOaksParcel ; OAKS_PARCEL
- dw ItemUseItemfinder ; ITEMFINDER
- dw UnusableItem ; SILPH_SCOPE
- dw ItemUsePokeflute ; POKE_FLUTE
- dw UnusableItem ; LIFT_KEY
- dw UnusableItem ; EXP_ALL
- dw ItemUseOldRod ; OLD_ROD
- dw ItemUseGoodRod ; GOOD_ROD
- dw ItemUseSuperRod ; SUPER_ROD
- dw ItemUsePPUp ; PP_UP (real one)
- dw ItemUsePPRestore ; ETHER
- dw ItemUsePPRestore ; MAX_ETHER
- dw ItemUsePPRestore ; ELIXER
- dw ItemUsePPRestore ; MAX_ELIXER
-
-ItemUseBall:
-
-; Balls can't be used out of battle.
- ld a, [wIsInBattle]
- and a
- jp z, ItemUseNotTime
-
-; Balls can't catch trainers' Pokémon.
- dec a
- jp nz, ThrowBallAtTrainerMon
-
-; If this is for the old man battle, skip checking if the party & box are full.
- ld a, [wBattleType]
- dec a
- jr z, .canUseBall
-
- ld a, [wPartyCount] ; is party full?
- cp PARTY_LENGTH
- jr nz, .canUseBall
- ld a, [wNumInBox] ; is box full?
- cp MONS_PER_BOX
- jp z, BoxFullCannotThrowBall
-
-.canUseBall
- xor a
- ld [wCapturedMonSpecies], a
-
- ld a, [wBattleType]
- cp BATTLE_TYPE_SAFARI
- jr nz, .skipSafariZoneCode
-
-.safariZone
- ld hl, wNumSafariBalls
- dec [hl] ; remove a Safari Ball
-
-.skipSafariZoneCode
- call RunDefaultPaletteCommand
-
- ld a, $43 ; successful capture value
- ld [wPokeBallAnimData], a
-
- call LoadScreenTilesFromBuffer1
- ld hl, ItemUseText00
- call PrintText
-
-; If the player is fighting an unidentified ghost, set the value that indicates
-; the Pokémon can't be caught and skip the capture calculations.
- callab IsGhostBattle
- ld b, $10 ; can't be caught value
- jp z, .setAnimData
-
- ld a, [wBattleType]
- dec a
- jr nz, .notOldManBattle
-
-.oldManBattle
- ld hl, wGrassRate
- ld de, wPlayerName
- ld bc, NAME_LENGTH
- call CopyData ; save the player's name in the Wild Monster data (part of the Cinnabar Island Missingno. glitch)
- jp .captured
-
-.notOldManBattle
-; If the player is fighting the ghost Marowak, set the value that indicates the
-; Pokémon can't be caught and skip the capture calculations.
- ld a, [wCurMap]
- cp POKEMON_TOWER_6F
- jr nz, .loop
- ld a, [wEnemyMonSpecies2]
- cp MAROWAK
- ld b, $10 ; can't be caught value
- jp z, .setAnimData
-
-; Get the first random number. Let it be called Rand1.
-; Rand1 must be within a certain range according the kind of ball being thrown.
-; The ranges are as follows.
-; Poké Ball: [0, 255]
-; Great Ball: [0, 200]
-; Ultra/Safari Ball: [0, 150]
-; Loop until an acceptable number is found.
-
-.loop
- call Random
- ld b, a
-
-; Get the item ID.
- ld hl, wcf91
- ld a, [hl]
-
-; The Master Ball always succeeds.
- cp MASTER_BALL
- jp z, .captured
-
-; Anything will do for the basic Poké Ball.
- cp POKE_BALL
- jr z, .checkForAilments
-
-; If it's a Great/Ultra/Safari Ball and Rand1 is greater than 200, try again.
- ld a, 200
- cp b
- jr c, .loop
-
-; Less than or equal to 200 is good enough for a Great Ball.
- ld a, [hl]
- cp GREAT_BALL
- jr z, .checkForAilments
-
-; If it's an Ultra/Safari Ball and Rand1 is greater than 150, try again.
- ld a, 150
- cp b
- jr c, .loop
-
-.checkForAilments
-; Pokémon can be caught more easily with a status ailment.
-; Depending on the status ailment, a certain value will be subtracted from
-; Rand1. Let this value be called Status.
-; The larger Status is, the more easily the Pokémon can be caught.
-; no status ailment: Status = 0
-; Burn/Paralysis/Poison: Status = 12
-; Freeze/Sleep: Status = 25
-; If Status is greater than Rand1, the Pokémon will be caught for sure.
- ld a, [wEnemyMonStatus]
- and a
- jr z, .skipAilmentValueSubtraction ; no ailments
- and 1 << FRZ | SLP
- ld c, 12
- jr z, .notFrozenOrAsleep
- ld c, 25
-.notFrozenOrAsleep
- ld a, b
- sub c
- jp c, .captured
- ld b, a
-
-.skipAilmentValueSubtraction
- push bc ; save (Rand1 - Status)
-
-; Calculate MaxHP * 255.
- xor a
- ld [H_MULTIPLICAND], a
- ld hl, wEnemyMonMaxHP
- ld a, [hli]
- ld [H_MULTIPLICAND + 1], a
- ld a, [hl]
- ld [H_MULTIPLICAND + 2], a
- ld a, 255
- ld [H_MULTIPLIER], a
- call Multiply
-
-; Determine BallFactor. It's 8 for Great Balls and 12 for the others.
- ld a, [wcf91]
- cp GREAT_BALL
- ld a, 12
- jr nz, .skip1
- ld a, 8
-
-.skip1
-; Note that the results of all division operations are floored.
-
-; Calculate (MaxHP * 255) / BallFactor.
- ld [H_DIVISOR], a
- ld b, 4 ; number of bytes in dividend
- call Divide
-
-; Divide the enemy's current HP by 4. HP is not supposed to exceed 999 so
-; the result should fit in a. If the division results in a quotient of 0,
-; change it to 1.
- ld hl, wEnemyMonHP
- ld a, [hli]
- ld b, a
- ld a, [hl]
- srl b
- rr a
- srl b
- rr a
- and a
- jr nz, .skip2
- inc a
-
-.skip2
-; Let W = ((MaxHP * 255) / BallFactor) / max(HP / 4, 1). Calculate W.
- ld [H_DIVISOR], a
- ld b, 4
- call Divide
-
-; If W > 255, store 255 in [H_QUOTIENT + 3].
-; Let X = min(W, 255) = [H_QUOTIENT + 3].
- ld a, [H_QUOTIENT + 2]
- and a
- jr z, .skip3
- ld a, 255
- ld [H_QUOTIENT + 3], a
-
-.skip3
- pop bc ; b = Rand1 - Status
-
-; If Rand1 - Status > CatchRate, the ball fails to capture the Pokémon.
- ld a, [wEnemyMonActualCatchRate]
- cp b
- jr c, .failedToCapture
-
-; If W > 255, the ball captures the Pokémon.
- ld a, [H_QUOTIENT + 2]
- and a
- jr nz, .captured
-
- call Random ; Let this random number be called Rand2.
-
-; If Rand2 > X, the ball fails to capture the Pokémon.
- ld b, a
- ld a, [H_QUOTIENT + 3]
- cp b
- jr c, .failedToCapture
-
-.captured
- jr .skipShakeCalculations
-
-.failedToCapture
- ld a, [H_QUOTIENT + 3]
- ld [wPokeBallCaptureCalcTemp], a ; Save X.
-
-; Calculate CatchRate * 100.
- xor a
- ld [H_MULTIPLICAND], a
- ld [H_MULTIPLICAND + 1], a
- ld a, [wEnemyMonActualCatchRate]
- ld [H_MULTIPLICAND + 2], a
- ld a, 100
- ld [H_MULTIPLIER], a
- call Multiply
-
-; Determine BallFactor2.
-; Poké Ball: BallFactor2 = 255
-; Great Ball: BallFactor2 = 200
-; Ultra/Safari Ball: BallFactor2 = 150
- ld a, [wcf91]
- ld b, 255
- cp POKE_BALL
- jr z, .skip4
- ld b, 200
- cp GREAT_BALL
- jr z, .skip4
- ld b, 150
- cp ULTRA_BALL
- jr z, .skip4
-
-.skip4
-; Let Y = (CatchRate * 100) / BallFactor2. Calculate Y.
- ld a, b
- ld [H_DIVISOR], a
- ld b, 4
- call Divide
-
-; If Y > 255, there are 3 shakes.
-; Note that this shouldn't be possible.
-; The maximum value of Y is (255 * 100) / 150 = 170.
- ld a, [H_QUOTIENT + 2]
- and a
- ld b, $63 ; 3 shakes
- jr nz, .setAnimData
-
-; Calculate X * Y.
- ld a, [wPokeBallCaptureCalcTemp]
- ld [H_MULTIPLIER], a
- call Multiply
-
-; Calculate (X * Y) / 255.
- ld a, 255
- ld [H_DIVISOR], a
- ld b, 4
- call Divide
-
-; Determine Status2.
-; no status ailment: Status2 = 0
-; Burn/Paralysis/Poison: Status2 = 5
-; Freeze/Sleep: Status2 = 10
- ld a, [wEnemyMonStatus]
- and a
- jr z, .skip5
- and 1 << FRZ | SLP
- ld b, 5
- jr z, .addAilmentValue
- ld b, 10
-
-.addAilmentValue
-; If the Pokémon has a status ailment, add Status2.
- ld a, [H_QUOTIENT + 3]
- add b
- ld [H_QUOTIENT + 3], a
-
-.skip5
-; Finally determine the number of shakes.
-; Let Z = ((X * Y) / 255) + Status2 = [H_QUOTIENT + 3].
-; The number of shakes depend on the range Z is in.
-; 0 ≤ Z < 10: 0 shakes (the ball misses)
-; 10 ≤ Z < 30: 1 shake
-; 30 ≤ Z < 70: 2 shakes
-; 70 ≤ Z: 3 shakes
- ld a, [H_QUOTIENT + 3]
- cp 10
- ld b, $20
- jr c, .setAnimData
- cp 30
- ld b, $61
- jr c, .setAnimData
- cp 70
- ld b, $62
- jr c, .setAnimData
- ld b, $63
-
-.setAnimData
- ld a, b
- ld [wPokeBallAnimData], a
-
-.skipShakeCalculations
- ld c, 20
- call DelayFrames
-
-; Do the animation.
- ld a, TOSS_ANIM
- ld [wAnimationID], a
- xor a
- ld [H_WHOSETURN], a
- ld [wAnimationType], a
- ld [wDamageMultipliers], a
- ld a, [wWhichPokemon]
- push af
- ld a, [wcf91]
- push af
- predef MoveAnimation
- pop af
- ld [wcf91], a
- pop af
- ld [wWhichPokemon], a
-
-; Determine the message to display from the animation.
- ld a, [wPokeBallAnimData]
- cp $10
- ld hl, ItemUseBallText00
- jp z, .printMessage
- cp $20
- ld hl, ItemUseBallText01
- jp z, .printMessage
- cp $61
- ld hl, ItemUseBallText02
- jp z, .printMessage
- cp $62
- ld hl, ItemUseBallText03
- jp z, .printMessage
- cp $63
- ld hl, ItemUseBallText04
- jp z, .printMessage
-
-; Save current HP.
- ld hl, wEnemyMonHP
- ld a, [hli]
- push af
- ld a, [hli]
- push af
-
-; Save status ailment.
- inc hl
- ld a, [hl]
- push af
-
- push hl
-
-; If the Pokémon is transformed, the Pokémon is assumed to be a Ditto.
-; This is a bug because a wild Pokémon could have used Transform via
-; Mirror Move even though the only wild Pokémon that knows Transform is Ditto.
- ld hl, wEnemyBattleStatus3
- bit TRANSFORMED, [hl]
- jr z, .notTransformed
- ld a, DITTO
- ld [wEnemyMonSpecies2], a
- jr .skip6
-
-.notTransformed
-; If the Pokémon is not transformed, set the transformed bit and copy the
-; DVs to wTransformedEnemyMonOriginalDVs so that LoadEnemyMonData won't generate
-; new DVs.
- set TRANSFORMED, [hl]
- ld hl, wTransformedEnemyMonOriginalDVs
- ld a, [wEnemyMonDVs]
- ld [hli], a
- ld a, [wEnemyMonDVs + 1]
- ld [hl], a
-
-.skip6
- ld a, [wcf91]
- push af
- ld a, [wEnemyMonSpecies2]
- ld [wcf91], a
- ld a, [wEnemyMonLevel]
- ld [wCurEnemyLVL], a
- callab LoadEnemyMonData
- pop af
- ld [wcf91], a
- pop hl
- pop af
- ld [hld], a
- dec hl
- pop af
- ld [hld], a
- pop af
- ld [hl], a
- ld a, [wEnemyMonSpecies]
- ld [wCapturedMonSpecies], a
- ld [wcf91], a
- ld [wd11e], a
- ld a, [wBattleType]
- dec a ; is this the old man battle?
- jr z, .oldManCaughtMon ; if so, don't give the player the caught Pokémon
-
- ld hl, ItemUseBallText05
- call PrintText
-
-; Add the caught Pokémon to the Pokédex.
- predef IndexToPokedex
- ld a, [wd11e]
- dec a
- ld c, a
- ld b, FLAG_TEST
- ld hl, wPokedexOwned
- predef FlagActionPredef
- ld a, c
- push af
- ld a, [wd11e]
- dec a
- ld c, a
- ld b, FLAG_SET
- predef FlagActionPredef
- pop af
-
- and a ; was the Pokémon already in the Pokédex?
- jr nz, .skipShowingPokedexData ; if so, don't show the Pokédex data
-
- ld hl, ItemUseBallText06
- call PrintText
- call ClearSprites
- ld a, [wEnemyMonSpecies]
- ld [wd11e], a
- predef ShowPokedexData
-
-.skipShowingPokedexData
- ld a, [wPartyCount]
- cp PARTY_LENGTH ; is party full?
- jr z, .sendToBox
- xor a ; PLAYER_PARTY_DATA
- ld [wMonDataLocation], a
- call ClearSprites
- call AddPartyMon
- jr .done
-
-.sendToBox
- call ClearSprites
- call SendNewMonToBox
- ld hl, ItemUseBallText07
- CheckEvent EVENT_MET_BILL
- jr nz, .printTransferredToPCText
- ld hl, ItemUseBallText08
-.printTransferredToPCText
- call PrintText
- jr .done
-
-.oldManCaughtMon
- ld hl, ItemUseBallText05
-
-.printMessage
- call PrintText
- call ClearSprites
-
-.done
- ld a, [wBattleType]
- and a ; is this the old man battle?
- ret nz ; if so, don't remove a ball from the bag
-
-; Remove a ball from the bag.
- ld hl, wNumBagItems
- inc a
- ld [wItemQuantity], a
- jp RemoveItemFromInventory
-
-ItemUseBallText00:
-;"It dodged the thrown ball!"
-;"This pokemon can't be caught"
- TX_FAR _ItemUseBallText00
- db "@"
-ItemUseBallText01:
-;"You missed the pokemon!"
- TX_FAR _ItemUseBallText01
- db "@"
-ItemUseBallText02:
-;"Darn! The pokemon broke free!"
- TX_FAR _ItemUseBallText02
- db "@"
-ItemUseBallText03:
-;"Aww! It appeared to be caught!"
- TX_FAR _ItemUseBallText03
- db "@"
-ItemUseBallText04:
-;"Shoot! It was so close too!"
- TX_FAR _ItemUseBallText04
- db "@"
-ItemUseBallText05:
-;"All right! {MonName} was caught!"
-;play sound
- TX_FAR _ItemUseBallText05
- TX_SFX_CAUGHT_MON
- TX_BLINK
- db "@"
-ItemUseBallText07:
-;"X was transferred to Bill's PC"
- TX_FAR _ItemUseBallText07
- db "@"
-ItemUseBallText08:
-;"X was transferred to someone's PC"
- TX_FAR _ItemUseBallText08
- db "@"
-
-ItemUseBallText06:
-;"New DEX data will be added..."
-;play sound
- TX_FAR _ItemUseBallText06
- TX_SFX_DEX_PAGE_ADDED
- TX_BLINK
- db "@"
-
-ItemUseTownMap:
- ld a, [wIsInBattle]
- and a
- jp nz, ItemUseNotTime
- jpba DisplayTownMap
-
-ItemUseBicycle:
- ld a, [wIsInBattle]
- and a
- jp nz, ItemUseNotTime
- ld a, [wWalkBikeSurfState]
- ld [wWalkBikeSurfStateCopy], a
- cp 2 ; is the player surfing?
- jp z, ItemUseNotTime
- dec a ; is player already bicycling?
- jr nz, .tryToGetOnBike
-.getOffBike
- call ItemUseReloadOverworldData
- xor a
- ld [wWalkBikeSurfState], a ; change player state to walking
- call PlayDefaultMusic ; play walking music
- ld hl, GotOffBicycleText
- jr .printText
-.tryToGetOnBike
- call IsBikeRidingAllowed
- jp nc, NoCyclingAllowedHere
- call ItemUseReloadOverworldData
- xor a ; no keys pressed
- ld [hJoyHeld], a ; current joypad state
- inc a
- ld [wWalkBikeSurfState], a ; change player state to bicycling
- ld hl, GotOnBicycleText
- call PlayDefaultMusic ; play bike riding music
-.printText
- jp PrintText
-
-; used for Surf out-of-battle effect
-ItemUseSurfboard:
- ld a, [wWalkBikeSurfState]
- ld [wWalkBikeSurfStateCopy], a
- cp 2 ; is the player already surfing?
- jr z, .tryToStopSurfing
-.tryToSurf
- call IsNextTileShoreOrWater
- jp c, SurfingAttemptFailed
- ld hl, TilePairCollisionsWater
- call CheckForTilePairCollisions
- jp c, SurfingAttemptFailed
-.surf
- call .makePlayerMoveForward
- ld hl, wd730
- set 7, [hl]
- ld a, 2
- ld [wWalkBikeSurfState], a ; change player state to surfing
- call PlayDefaultMusic ; play surfing music
- ld hl, SurfingGotOnText
- jp PrintText
-.tryToStopSurfing
- xor a
- ld [hSpriteIndexOrTextID], a
- ld d, 16 ; talking range in pixels (normal range)
- call IsSpriteInFrontOfPlayer2
- res 7, [hl]
- ld a, [hSpriteIndexOrTextID]
- and a ; is there a sprite in the way?
- jr nz, .cannotStopSurfing
- ld hl, TilePairCollisionsWater
- call CheckForTilePairCollisions
- jr c, .cannotStopSurfing
- ld hl, wTilesetCollisionPtr ; pointer to list of passable tiles
- ld a, [hli]
- ld h, [hl]
- ld l, a ; hl now points to passable tiles
- ld a, [wTileInFrontOfPlayer] ; tile in front of the player
- ld b, a
-.passableTileLoop
- ld a, [hli]
- cp b
- jr z, .stopSurfing
- cp $ff
- jr nz, .passableTileLoop
-.cannotStopSurfing
- ld hl, SurfingNoPlaceToGetOffText
- jp PrintText
-.stopSurfing
- call .makePlayerMoveForward
- ld hl, wd730
- set 7, [hl]
- xor a
- ld [wWalkBikeSurfState], a ; change player state to walking
- dec a
- ld [wJoyIgnore], a
- call PlayDefaultMusic ; play walking music
- jp LoadWalkingPlayerSpriteGraphics
-; uses a simulated button press to make the player move forward
-.makePlayerMoveForward
- ld a, [wPlayerDirection] ; direction the player is going
- bit PLAYER_DIR_BIT_UP, a
- ld b, D_UP
- jr nz, .storeSimulatedButtonPress
- bit PLAYER_DIR_BIT_DOWN, a
- ld b, D_DOWN
- jr nz, .storeSimulatedButtonPress
- bit PLAYER_DIR_BIT_LEFT, a
- ld b, D_LEFT
- jr nz, .storeSimulatedButtonPress
- ld b, D_RIGHT
-.storeSimulatedButtonPress
- ld a, b
- ld [wSimulatedJoypadStatesEnd], a
- xor a
- ld [wWastedByteCD39], a
- inc a
- ld [wSimulatedJoypadStatesIndex], a
- ret
-
-SurfingGotOnText:
- TX_FAR _SurfingGotOnText
- db "@"
-
-SurfingNoPlaceToGetOffText:
- TX_FAR _SurfingNoPlaceToGetOffText
- db "@"
-
-ItemUsePokedex:
- predef_jump ShowPokedexMenu
-
-ItemUseEvoStone:
- ld a, [wIsInBattle]
- and a
- jp nz, ItemUseNotTime
- ld a, [wWhichPokemon]
- push af
- ld a, [wcf91]
- ld [wEvoStoneItemID], a
- push af
- ld a, EVO_STONE_PARTY_MENU
- ld [wPartyMenuTypeOrMessageID], a
- ld a, $ff
- ld [wUpdateSpritesEnabled], a
- call DisplayPartyMenu
- pop bc
- jr c, .canceledItemUse
- ld a, b
- ld [wcf91], a
- ld a, $01
- ld [wForceEvolution], a
- ld a, SFX_HEAL_AILMENT
- call PlaySoundWaitForCurrent
- call WaitForSoundToFinish
- callab TryEvolvingMon ; try to evolve pokemon
- ld a, [wEvolutionOccurred]
- and a
- jr z, .noEffect
- pop af
- ld [wWhichPokemon], a
- ld hl, wNumBagItems
- ld a, 1 ; remove 1 stone
- ld [wItemQuantity], a
- jp RemoveItemFromInventory
-.noEffect
- call ItemUseNoEffect
-.canceledItemUse
- xor a
- ld [wActionResultOrTookBattleTurn], a ; item not used
- pop af
- ret
-
-ItemUseVitamin:
- ld a, [wIsInBattle]
- and a
- jp nz, ItemUseNotTime
-
-ItemUseMedicine:
- ld a, [wPartyCount]
- and a
- jp z, .emptyParty
- ld a, [wWhichPokemon]
- push af
- ld a, [wcf91]
- push af
- ld a, USE_ITEM_PARTY_MENU
- ld [wPartyMenuTypeOrMessageID], a
- ld a, $ff
- ld [wUpdateSpritesEnabled], a
- ld a, [wPseudoItemID]
- and a ; using Softboiled?
- jr z, .notUsingSoftboiled
-; if using softboiled
- call GoBackToPartyMenu
- jr .getPartyMonDataAddress
-.emptyParty
- ld hl, .emptyPartyText
- xor a
- ld [wActionResultOrTookBattleTurn], a ; item use failed
- jp PrintText
-.emptyPartyText
- text "You don't have"
- line "any #MON!"
- prompt
-.notUsingSoftboiled
- call DisplayPartyMenu
-.getPartyMonDataAddress
- jp c, .canceledItemUse
- ld hl, wPartyMons
- ld bc, wPartyMon2 - wPartyMon1
- ld a, [wWhichPokemon]
- call AddNTimes
- ld a, [wWhichPokemon]
- ld [wUsedItemOnWhichPokemon], a
- ld d, a
- ld a, [wcf91]
- ld e, a
- ld [wd0b5], a
- pop af
- ld [wcf91], a
- pop af
- ld [wWhichPokemon], a
- ld a, [wPseudoItemID]
- and a ; using Softboiled?
- jr z, .checkItemType
-; if using softboiled
- ld a, [wWhichPokemon]
- cp d ; is the pokemon trying to use softboiled on itself?
- jr z, ItemUseMedicine ; if so, force another choice
-.checkItemType
- ld a, [wcf91]
- cp REVIVE
- jr nc, .healHP ; if it's a Revive or Max Revive
- cp FULL_HEAL
- jr z, .cureStatusAilment ; if it's a Full Heal
- cp HP_UP
- jp nc, .useVitamin ; if it's a vitamin or Rare Candy
- cp FULL_RESTORE
- jr nc, .healHP ; if it's a Full Restore or one of the potions
-; fall through if it's one of the status-specific healing items
-.cureStatusAilment
- ld bc, wPartyMon1Status - wPartyMon1
- add hl, bc ; hl now points to status
- ld a, [wcf91]
- lb bc, ANTIDOTE_MSG, 1 << PSN
- cp ANTIDOTE
- jr z, .checkMonStatus
- lb bc, BURN_HEAL_MSG, 1 << BRN
- cp BURN_HEAL
- jr z, .checkMonStatus
- lb bc, ICE_HEAL_MSG, 1 << FRZ
- cp ICE_HEAL
- jr z, .checkMonStatus
- lb bc, AWAKENING_MSG, SLP
- cp AWAKENING
- jr z, .checkMonStatus
- lb bc, PARALYZ_HEAL_MSG, 1 << PAR
- cp PARLYZ_HEAL
- jr z, .checkMonStatus
- lb bc, FULL_HEAL_MSG, $ff ; Full Heal
-.checkMonStatus
- ld a, [hl] ; pokemon's status
- and c ; does the pokemon have a status ailment the item can cure?
- jp z, .healingItemNoEffect
-; if the pokemon has a status the item can heal
- xor a
- ld [hl], a ; remove the status ailment in the party data
- ld a, b
- ld [wPartyMenuTypeOrMessageID], a ; the message to display for the item used
- ld a, [wPlayerMonNumber]
- cp d ; is pokemon the item was used on active in battle?
- jp nz, .doneHealing
-; if it is active in battle
- xor a
- ld [wBattleMonStatus], a ; remove the status ailment in the in-battle pokemon data
- push hl
- ld hl, wPlayerBattleStatus3
- res BADLY_POISONED, [hl] ; heal Toxic status
- pop hl
- ld bc, wPartyMon1Stats - wPartyMon1Status
- add hl, bc ; hl now points to party stats
- ld de, wBattleMonStats
- ld bc, NUM_STATS * 2
- call CopyData ; copy party stats to in-battle stat data
- predef DoubleOrHalveSelectedStats
- jp .doneHealing
-.healHP
- inc hl ; hl = address of current HP
- ld a, [hli]
- ld b, a
- ld [wHPBarOldHP+1], a
- ld a, [hl]
- ld c, a
- ld [wHPBarOldHP], a ; current HP stored at wHPBarOldHP (2 bytes, big-endian)
- or b
- jr nz, .notFainted
-.fainted
- ld a, [wcf91]
- cp REVIVE
- jr z, .updateInBattleFaintedData
- cp MAX_REVIVE
- jr z, .updateInBattleFaintedData
- jp .healingItemNoEffect
-.updateInBattleFaintedData
- ld a, [wIsInBattle]
- and a
- jr z, .compareCurrentHPToMaxHP
- push hl
- push de
- push bc
- ld a, [wUsedItemOnWhichPokemon]
- ld c, a
- ld hl, wPartyFoughtCurrentEnemyFlags
- ld b, FLAG_TEST
- predef FlagActionPredef
- ld a, c
- and a
- jr z, .next
- ld a, [wUsedItemOnWhichPokemon]
- ld c, a
- ld hl, wPartyGainExpFlags
- ld b, FLAG_SET
- predef FlagActionPredef
-.next
- pop bc
- pop de
- pop hl
- jr .compareCurrentHPToMaxHP
-.notFainted
- ld a, [wcf91]
- cp REVIVE
- jp z, .healingItemNoEffect
- cp MAX_REVIVE
- jp z, .healingItemNoEffect
-.compareCurrentHPToMaxHP
- push hl
- push bc
- ld bc, wPartyMon1MaxHP - (wPartyMon1HP + 1)
- add hl, bc ; hl now points to max HP
- pop bc
- ld a, [hli]
- cp b
- jr nz, .skipComparingLSB ; no need to compare the LSB's if the MSB's don't match
- ld a, [hl]
- cp c
-.skipComparingLSB
- pop hl
- jr nz, .notFullHP
-.fullHP ; if the pokemon's current HP equals its max HP
- ld a, [wcf91]
- cp FULL_RESTORE
- jp nz, .healingItemNoEffect
- inc hl
- inc hl
- ld a, [hld] ; status ailment
- and a ; does the pokemon have a status ailment?
- jp z, .healingItemNoEffect
- ld a, FULL_HEAL
- ld [wcf91], a
- dec hl
- dec hl
- dec hl
- jp .cureStatusAilment
-.notFullHP ; if the pokemon's current HP doesn't equal its max HP
- xor a
- ld [wLowHealthAlarm], a ;disable low health alarm
- ld [wChannelSoundIDs + Ch5], a
- push hl
- push de
- ld bc, wPartyMon1MaxHP - (wPartyMon1HP + 1)
- add hl, bc ; hl now points to max HP
- ld a, [hli]
- ld [wHPBarMaxHP+1], a
- ld a, [hl]
- ld [wHPBarMaxHP], a ; max HP stored at wHPBarMaxHP (2 bytes, big-endian)
- ld a, [wPseudoItemID]
- and a ; using Softboiled?
- jp z, .notUsingSoftboiled2
-; if using softboiled
- ld hl, wHPBarMaxHP
- ld a, [hli]
- push af
- ld a, [hli]
- push af
- ld a, [hli]
- push af
- ld a, [hl]
- push af
- ld hl, wPartyMon1MaxHP
- ld a, [wWhichPokemon]
- ld bc, wPartyMon2 - wPartyMon1
- call AddNTimes
- ld a, [hli]
- ld [wHPBarMaxHP + 1], a
- ld [H_DIVIDEND], a
- ld a, [hl]
- ld [wHPBarMaxHP], a
- ld [H_DIVIDEND + 1], a
- ld a, 5
- ld [H_DIVISOR], a
- ld b, 2 ; number of bytes
- call Divide ; get 1/5 of max HP of pokemon that used Softboiled
- ld bc, (wPartyMon1HP + 1) - (wPartyMon1MaxHP + 1)
- add hl, bc ; hl now points to LSB of current HP of pokemon that used Softboiled
-; subtract 1/5 of max HP from current HP of pokemon that used Softboiled
- ld a, [H_QUOTIENT + 3]
- push af
- ld b, a
- ld a, [hl]
- ld [wHPBarOldHP], a
- sub b
- ld [hld], a
- ld [wHPBarNewHP], a
- ld a, [H_QUOTIENT + 2]
- ld b, a
- ld a, [hl]
- ld [wHPBarOldHP+1], a
- sbc b
- ld [hl], a
- ld [wHPBarNewHP+1], a
- coord hl, 4, 1
- ld a, [wWhichPokemon]
- ld bc, 2 * SCREEN_WIDTH
- call AddNTimes ; calculate coordinates of HP bar of pokemon that used Softboiled
- ld a, SFX_HEAL_HP
- call PlaySoundWaitForCurrent
- ld a, [hFlags_0xFFF6]
- set 0, a
- ld [hFlags_0xFFF6], a
- ld a, $02
- ld [wHPBarType], a
- predef UpdateHPBar2 ; animate HP bar decrease of pokemon that used Softboiled
- ld a, [hFlags_0xFFF6]
- res 0, a
- ld [hFlags_0xFFF6], a
- pop af
- ld b, a ; store heal amount (1/5 of max HP)
- ld hl, wHPBarOldHP + 1
- pop af
- ld [hld], a
- pop af
- ld [hld], a
- pop af
- ld [hld], a
- pop af
- ld [hl], a
- jr .addHealAmount
-.notUsingSoftboiled2
- ld a, [wcf91]
- cp SODA_POP
- ld b, 60 ; Soda Pop heal amount
- jr z, .addHealAmount
- ld b, 80 ; Lemonade heal amount
- jr nc, .addHealAmount
- cp FRESH_WATER
- ld b, 50 ; Fresh Water heal amount
- jr z, .addHealAmount
- cp SUPER_POTION
- ld b, 200 ; Hyper Potion heal amount
- jr c, .addHealAmount
- ld b, 50 ; Super Potion heal amount
- jr z, .addHealAmount
- ld b, 20 ; Potion heal amount
-.addHealAmount
- pop de
- pop hl
- ld a, [hl]
- add b
- ld [hld], a
- ld [wHPBarNewHP], a
- ld a, [hl]
- ld [wHPBarNewHP+1], a
- jr nc, .noCarry
- inc [hl]
- ld a, [hl]
- ld [wHPBarNewHP + 1], a
-.noCarry
- push de
- inc hl
- ld d, h
- ld e, l ; de now points to current HP
- ld hl, (wPartyMon1MaxHP + 1) - (wPartyMon1HP + 1)
- add hl, de ; hl now points to max HP
- ld a, [wcf91]
- cp REVIVE
- jr z, .setCurrentHPToHalfMaxHP
- ld a, [hld]
- ld b, a
- ld a, [de]
- sub b
- dec de
- ld b, [hl]
- ld a, [de]
- sbc b
- jr nc, .setCurrentHPToMaxHp ; if current HP exceeds max HP after healing
- ld a, [wcf91]
- cp HYPER_POTION
- jr c, .setCurrentHPToMaxHp ; if using a Full Restore or Max Potion
- cp MAX_REVIVE
- jr z, .setCurrentHPToMaxHp ; if using a Max Revive
- jr .updateInBattleData
-.setCurrentHPToHalfMaxHP
- dec hl
- dec de
- ld a, [hli]
- srl a
- ld [de], a
- ld [wHPBarNewHP+1], a
- ld a, [hl]
- rr a
- inc de
- ld [de], a
- ld [wHPBarNewHP], a
- dec de
- jr .doneHealingPartyHP
-.setCurrentHPToMaxHp
- ld a, [hli]
- ld [de], a
- ld [wHPBarNewHP+1], a
- inc de
- ld a, [hl]
- ld [de], a
- ld [wHPBarNewHP], a
- dec de
-.doneHealingPartyHP ; done updating the pokemon's current HP in the party data structure
- ld a, [wcf91]
- cp FULL_RESTORE
- jr nz, .updateInBattleData
- ld bc, wPartyMon1Status - (wPartyMon1MaxHP + 1)
- add hl, bc
- xor a
- ld [hl], a ; remove the status ailment in the party data
-.updateInBattleData
- ld h, d
- ld l, e
- pop de
- ld a, [wPlayerMonNumber]
- cp d ; is pokemon the item was used on active in battle?
- jr nz, .calculateHPBarCoords
-; copy party HP to in-battle HP
- ld a, [hli]
- ld [wBattleMonHP], a
- ld a, [hld]
- ld [wBattleMonHP + 1], a
- ld a, [wcf91]
- cp FULL_RESTORE
- jr nz, .calculateHPBarCoords
- xor a
- ld [wBattleMonStatus], a ; remove the status ailment in the in-battle pokemon data
-.calculateHPBarCoords
- ld hl, wOAMBuffer + $90
- ld bc, 2 * SCREEN_WIDTH
- inc d
-.calculateHPBarCoordsLoop
- add hl, bc
- dec d
- jr nz, .calculateHPBarCoordsLoop
- jr .doneHealing
-.healingItemNoEffect
- call ItemUseNoEffect
- jp .done
-.doneHealing
- ld a, [wPseudoItemID]
- and a ; using Softboiled?
- jr nz, .skipRemovingItem ; no item to remove if using Softboiled
- push hl
- call RemoveUsedItem
- pop hl
-.skipRemovingItem
- ld a, [wcf91]
- cp FULL_RESTORE
- jr c, .playStatusAilmentCuringSound
- cp FULL_HEAL
- jr z, .playStatusAilmentCuringSound
- ld a, SFX_HEAL_HP
- call PlaySoundWaitForCurrent
- ld a, [hFlags_0xFFF6]
- set 0, a
- ld [hFlags_0xFFF6], a
- ld a, $02
- ld [wHPBarType], a
- predef UpdateHPBar2 ; animate the HP bar lengthening
- ld a, [hFlags_0xFFF6]
- res 0, a
- ld [hFlags_0xFFF6], a
- ld a, REVIVE_MSG
- ld [wPartyMenuTypeOrMessageID], a
- ld a, [wcf91]
- cp REVIVE
- jr z, .showHealingItemMessage
- cp MAX_REVIVE
- jr z, .showHealingItemMessage
- ld a, POTION_MSG
- ld [wPartyMenuTypeOrMessageID], a
- jr .showHealingItemMessage
-.playStatusAilmentCuringSound
- ld a, SFX_HEAL_AILMENT
- call PlaySoundWaitForCurrent
-.showHealingItemMessage
- xor a
- ld [H_AUTOBGTRANSFERENABLED], a
- call ClearScreen
- dec a
- ld [wUpdateSpritesEnabled], a
- call RedrawPartyMenu ; redraws the party menu and displays the message
- ld a, 1
- ld [H_AUTOBGTRANSFERENABLED], a
- ld c, 50
- call DelayFrames
- call WaitForTextScrollButtonPress
- jr .done
-.canceledItemUse
- xor a
- ld [wActionResultOrTookBattleTurn], a ; item use failed
- pop af
- pop af
-.done
- ld a, [wPseudoItemID]
- and a ; using Softboiled?
- ret nz ; if so, return
- call GBPalWhiteOut
- call z, RunDefaultPaletteCommand
- ld a, [wIsInBattle]
- and a
- ret nz
- jp ReloadMapData
-.useVitamin
- push hl
- ld a, [hl]
- ld [wd0b5], a
- ld [wd11e], a
- ld bc, wPartyMon1Level - wPartyMon1
- add hl, bc ; hl now points to level
- ld a, [hl] ; a = level
- ld [wCurEnemyLVL], a ; store level
- call GetMonHeader
- push de
- ld a, d
- ld hl, wPartyMonNicks
- call GetPartyMonName
- pop de
- pop hl
- ld a, [wcf91]
- cp RARE_CANDY
- jp z, .useRareCandy
- push hl
- sub HP_UP
- add a
- ld bc, wPartyMon1HPExp - wPartyMon1
- add hl, bc
- add l
- ld l, a
- jr nc, .noCarry2
- inc h
-.noCarry2
- ld a, 10
- ld b, a
- ld a, [hl] ; a = MSB of stat experience of the appropriate stat
- cp 100 ; is there already at least 25600 (256 * 100) stat experience?
- jr nc, .vitaminNoEffect ; if so, vitamins can't add any more
- add b ; add 2560 (256 * 10) stat experience
- jr nc, .noCarry3 ; a carry should be impossible here, so this will always jump
- ld a, 255
-.noCarry3
- ld [hl], a
- pop hl
- call .recalculateStats
- ld hl, VitaminText
- ld a, [wcf91]
- sub HP_UP - 1
- ld c, a
-.statNameLoop ; loop to get the address of the name of the stat the vitamin increases
- dec c
- jr z, .gotStatName
-.statNameInnerLoop
- ld a, [hli]
- ld b, a
- ld a, $50
- cp b
- jr nz, .statNameInnerLoop
- jr .statNameLoop
-.gotStatName
- ld de, wcf4b
- ld bc, 10
- call CopyData ; copy the stat's name to wcf4b
- ld a, SFX_HEAL_AILMENT
- call PlaySound
- ld hl, VitaminStatRoseText
- call PrintText
- jp RemoveUsedItem
-.vitaminNoEffect
- pop hl
- ld hl, VitaminNoEffectText
- call PrintText
- jp GBPalWhiteOut
-.recalculateStats
- ld bc, wPartyMon1Stats - wPartyMon1
- add hl, bc
- ld d, h
- ld e, l ; de now points to stats
- ld bc, (wPartyMon1Exp + 2) - wPartyMon1Stats
- add hl, bc ; hl now points to LSB of experience
- ld b, 1
- jp CalcStats ; recalculate stats
-.useRareCandy
- push hl
- ld bc, wPartyMon1Level - wPartyMon1
- add hl, bc ; hl now points to level
- ld a, [hl] ; a = level
- cp MAX_LEVEL
- jr z, .vitaminNoEffect ; can't raise level above 100
- inc a
- ld [hl], a ; store incremented level
- ld [wCurEnemyLVL], a
- push hl
- push de
- ld d, a
- callab CalcExperience ; calculate experience for next level and store it at $ff96
- pop de
- pop hl
- ld bc, wPartyMon1Exp - wPartyMon1Level
- add hl, bc ; hl now points to MSB of experience
-; update experience to minimum for new level
- ld a, [hExperience]
- ld [hli], a
- ld a, [hExperience + 1]
- ld [hli], a
- ld a, [hExperience + 2]
- ld [hl], a
- pop hl
- ld a, [wWhichPokemon]
- push af
- ld a, [wcf91]
- push af
- push de
- push hl
- ld bc, wPartyMon1MaxHP - wPartyMon1
- add hl, bc ; hl now points to MSB of max HP
- ld a, [hli]
- ld b, a
- ld c, [hl]
- pop hl
- push bc
- push hl
- call .recalculateStats
- pop hl
- ld bc, (wPartyMon1MaxHP + 1) - wPartyMon1
- add hl, bc ; hl now points to LSB of max HP
- pop bc
- ld a, [hld]
- sub c
- ld c, a
- ld a, [hl]
- sbc b
- ld b, a ; bc = the amount of max HP gained from leveling up
-; add the amount gained to the current HP
- ld de, (wPartyMon1HP + 1) - wPartyMon1MaxHP
- add hl, de ; hl now points to LSB of current HP
- ld a, [hl]
- add c
- ld [hld], a
- ld a, [hl]
- adc b
- ld [hl], a
- ld a, RARE_CANDY_MSG
- ld [wPartyMenuTypeOrMessageID], a
- call RedrawPartyMenu
- pop de
- ld a, d
- ld [wWhichPokemon], a
- ld a, e
- ld [wd11e], a
- xor a ; PLAYER_PARTY_DATA
- ld [wMonDataLocation], a
- call LoadMonData
- ld d, $01
- callab PrintStatsBox ; display new stats text box
- call WaitForTextScrollButtonPress ; wait for button press
- xor a ; PLAYER_PARTY_DATA
- ld [wMonDataLocation], a
- predef LearnMoveFromLevelUp ; learn level up move, if any
- xor a
- ld [wForceEvolution], a
- callab TryEvolvingMon ; evolve pokemon, if appropriate
- ld a, $01
- ld [wUpdateSpritesEnabled], a
- pop af
- ld [wcf91], a
- pop af
- ld [wWhichPokemon], a
- jp RemoveUsedItem
-
-VitaminStatRoseText:
- TX_FAR _VitaminStatRoseText
- db "@"
-
-VitaminNoEffectText:
- TX_FAR _VitaminNoEffectText
- db "@"
-
-VitaminText:
- db "HEALTH@"
- db "ATTACK@"
- db "DEFENSE@"
- db "SPEED@"
- db "SPECIAL@"
-
-ItemUseBait:
- ld hl, ThrewBaitText
- call PrintText
- ld hl, wEnemyMonActualCatchRate ; catch rate
- srl [hl] ; halve catch rate
- ld a, BAIT_ANIM
- ld hl, wSafariBaitFactor ; bait factor
- ld de, wSafariEscapeFactor ; escape factor
- jr BaitRockCommon
-
-ItemUseRock:
- ld hl, ThrewRockText
- call PrintText
- ld hl, wEnemyMonActualCatchRate ; catch rate
- ld a, [hl]
- add a ; double catch rate
- jr nc, .noCarry
- ld a, $ff
-.noCarry
- ld [hl], a
- ld a, ROCK_ANIM
- ld hl, wSafariEscapeFactor ; escape factor
- ld de, wSafariBaitFactor ; bait factor
-
-BaitRockCommon:
- ld [wAnimationID], a
- xor a
- ld [wAnimationType], a
- ld [H_WHOSETURN], a
- ld [de], a ; zero escape factor (for bait), zero bait factor (for rock)
-.randomLoop ; loop until a random number less than 5 is generated
- call Random
- and 7
- cp 5
- jr nc, .randomLoop
- inc a ; increment the random number, giving a range from 1 to 5 inclusive
- ld b, a
- ld a, [hl]
- add b ; increase bait factor (for bait), increase escape factor (for rock)
- jr nc, .noCarry
- ld a, $ff
-.noCarry
- ld [hl], a
- predef MoveAnimation ; do animation
- ld c, 70
- jp DelayFrames
-
-ThrewBaitText:
- TX_FAR _ThrewBaitText
- db "@"
-
-ThrewRockText:
- TX_FAR _ThrewRockText
- db "@"
-
-; also used for Dig out-of-battle effect
-ItemUseEscapeRope:
- ld a, [wIsInBattle]
- and a
- jr nz, .notUsable
- ld a, [wCurMap]
- cp AGATHAS_ROOM
- jr z, .notUsable
- ld a, [wCurMapTileset]
- ld b, a
- ld hl, EscapeRopeTilesets
-.loop
- ld a, [hli]
- cp $ff
- jr z, .notUsable
- cp b
- jr nz, .loop
- ld hl, wd732
- set 3, [hl]
- set 6, [hl]
- ld hl, wd72e
- res 4, [hl]
- ResetEvent EVENT_IN_SAFARI_ZONE
- xor a
- ld [wNumSafariBalls], a
- ld [wSafariZoneGateCurScript], a
- inc a
- ld [wEscapedFromBattle], a
- ld [wActionResultOrTookBattleTurn], a ; item used
- ld a, [wPseudoItemID]
- and a ; using Dig?
- ret nz ; if so, return
- call ItemUseReloadOverworldData
- ld c, 30
- call DelayFrames
- jp RemoveUsedItem
-.notUsable
- jp ItemUseNotTime
-
-EscapeRopeTilesets:
- db FOREST, CEMETERY, CAVERN, FACILITY, INTERIOR
- db $ff ; terminator
-
-ItemUseRepel:
- ld b, 100
-
-ItemUseRepelCommon:
- ld a, [wIsInBattle]
- and a
- jp nz, ItemUseNotTime
- ld a, b
- ld [wRepelRemainingSteps], a
- jp PrintItemUseTextAndRemoveItem
-
-; handles X Accuracy item
-ItemUseXAccuracy:
- ld a, [wIsInBattle]
- and a
- jp z, ItemUseNotTime
- ld hl, wPlayerBattleStatus2
- set USING_X_ACCURACY, [hl] ; X Accuracy bit
- jp PrintItemUseTextAndRemoveItem
-
-; This function is bugged and never works. It always jumps to ItemUseNotTime.
-; The Card Key is handled in a different way.
-ItemUseCardKey:
- xor a
- ld [wUnusedD71F], a
- call GetTileAndCoordsInFrontOfPlayer
- ld a, [GetTileAndCoordsInFrontOfPlayer]
- cp $18
- jr nz, .next0
- ld hl, CardKeyTable1
- jr .next1
-.next0
- cp $24
- jr nz, .next2
- ld hl, CardKeyTable2
- jr .next1
-.next2
- cp $5e
- jp nz, ItemUseNotTime
- ld hl, CardKeyTable3
-.next1
- ld a, [wCurMap]
- ld b, a
-.loop
- ld a, [hli]
- cp $ff
- jp z, ItemUseNotTime
- cp b
- jr nz, .nextEntry1
- ld a, [hli]
- cp d
- jr nz, .nextEntry2
- ld a, [hli]
- cp e
- jr nz, .nextEntry3
- ld a, [hl]
- ld [wUnusedD71F], a
- jr .done
-.nextEntry1
- inc hl
-.nextEntry2
- inc hl
-.nextEntry3
- inc hl
- jr .loop
-.done
- ld hl, ItemUseText00
- call PrintText
- ld hl, wd728
- set 7, [hl]
- ret
-
-; These tables are probably supposed to be door locations in Silph Co.,
-; but they are unused.
-; The reason there are 3 tables is unknown.
-
-; Format:
-; 00: Map ID
-; 01: Y
-; 02: X
-; 03: ID?
-
-CardKeyTable1:
- db SILPH_CO_2F,$04,$04,$00
- db SILPH_CO_2F,$04,$05,$01
- db SILPH_CO_4F,$0C,$04,$02
- db SILPH_CO_4F,$0C,$05,$03
- db SILPH_CO_7F,$06,$0A,$04
- db SILPH_CO_7F,$06,$0B,$05
- db SILPH_CO_9F,$04,$12,$06
- db SILPH_CO_9F,$04,$13,$07
- db SILPH_CO_10F,$08,$0A,$08
- db SILPH_CO_10F,$08,$0B,$09
- db $ff
-
-CardKeyTable2:
- db SILPH_CO_3F,$08,$09,$0A
- db SILPH_CO_3F,$09,$09,$0B
- db SILPH_CO_5F,$04,$07,$0C
- db SILPH_CO_5F,$05,$07,$0D
- db SILPH_CO_6F,$0C,$05,$0E
- db SILPH_CO_6F,$0D,$05,$0F
- db SILPH_CO_8F,$08,$07,$10
- db SILPH_CO_8F,$09,$07,$11
- db SILPH_CO_9F,$08,$03,$12
- db SILPH_CO_9F,$09,$03,$13
- db $ff
-
-CardKeyTable3:
- db SILPH_CO_11F,$08,$09,$14
- db SILPH_CO_11F,$09,$09,$15
- db $ff
-
-ItemUsePokedoll:
- ld a, [wIsInBattle]
- dec a
- jp nz, ItemUseNotTime
- ld a, $01
- ld [wEscapedFromBattle], a
- jp PrintItemUseTextAndRemoveItem
-
-ItemUseGuardSpec:
- ld a, [wIsInBattle]
- and a
- jp z, ItemUseNotTime
- ld hl, wPlayerBattleStatus2
- set PROTECTED_BY_MIST, [hl] ; Mist bit
- jp PrintItemUseTextAndRemoveItem
-
-ItemUseSuperRepel:
- ld b, 200
- jp ItemUseRepelCommon
-
-ItemUseMaxRepel:
- ld b, 250
- jp ItemUseRepelCommon
-
-ItemUseDireHit:
- ld a, [wIsInBattle]
- and a
- jp z, ItemUseNotTime
- ld hl, wPlayerBattleStatus2
- set GETTING_PUMPED, [hl] ; Focus Energy bit
- jp PrintItemUseTextAndRemoveItem
-
-ItemUseXStat:
- ld a, [wIsInBattle]
- and a
- jr nz, .inBattle
- call ItemUseNotTime
- ld a, 2
- ld [wActionResultOrTookBattleTurn], a ; item not used
- ret
-.inBattle
- ld hl, wPlayerMoveNum
- ld a, [hli]
- push af ; save [wPlayerMoveNum]
- ld a, [hl]
- push af ; save [wPlayerMoveEffect]
- push hl
- ld a, [wcf91]
- sub X_ATTACK - ATTACK_UP1_EFFECT
- ld [hl], a ; store player move effect
- call PrintItemUseTextAndRemoveItem
- ld a, XSTATITEM_ANIM ; X stat item animation ID
- ld [wPlayerMoveNum], a
- call LoadScreenTilesFromBuffer1 ; restore saved screen
- call Delay3
- xor a
- ld [H_WHOSETURN], a ; set turn to player's turn
- callba StatModifierUpEffect ; do stat increase move
- pop hl
- pop af
- ld [hld], a ; restore [wPlayerMoveEffect]
- pop af
- ld [hl], a ; restore [wPlayerMoveNum]
- ret
-
-ItemUsePokeflute:
- ld a, [wIsInBattle]
- and a
- jr nz, .inBattle
-; if not in battle
- call ItemUseReloadOverworldData
- ld a, [wCurMap]
- cp ROUTE_12
- jr nz, .notRoute12
- CheckEvent EVENT_BEAT_ROUTE12_SNORLAX
- jr nz, .noSnorlaxToWakeUp
-; if the player hasn't beaten Route 12 Snorlax
- ld hl, Route12SnorlaxFluteCoords
- call ArePlayerCoordsInArray
- jr nc, .noSnorlaxToWakeUp
- ld hl, PlayedFluteHadEffectText
- call PrintText
- SetEvent EVENT_FIGHT_ROUTE12_SNORLAX
- ret
-.notRoute12
- cp ROUTE_16
- jr nz, .noSnorlaxToWakeUp
- CheckEvent EVENT_BEAT_ROUTE16_SNORLAX
- jr nz, .noSnorlaxToWakeUp
-; if the player hasn't beaten Route 16 Snorlax
- ld hl, Route16SnorlaxFluteCoords
- call ArePlayerCoordsInArray
- jr nc, .noSnorlaxToWakeUp
- ld hl, PlayedFluteHadEffectText
- call PrintText
- SetEvent EVENT_FIGHT_ROUTE16_SNORLAX
- ret
-.noSnorlaxToWakeUp
- ld hl, PlayedFluteNoEffectText
- jp PrintText
-.inBattle
- xor a
- ld [wWereAnyMonsAsleep], a
- ld b, ~SLP & $ff
- ld hl, wPartyMon1Status
- call WakeUpEntireParty
- ld a, [wIsInBattle]
- dec a ; is it a trainer battle?
- jr z, .skipWakingUpEnemyParty
-; if it's a trainer battle
- ld hl, wEnemyMon1Status
- call WakeUpEntireParty
-.skipWakingUpEnemyParty
- ld hl, wBattleMonStatus
- ld a, [hl]
- and b ; remove Sleep status
- ld [hl], a
- ld hl, wEnemyMonStatus
- ld a, [hl]
- and b ; remove Sleep status
- ld [hl], a
- call LoadScreenTilesFromBuffer2 ; restore saved screen
- ld a, [wWereAnyMonsAsleep]
- and a ; were any pokemon asleep before playing the flute?
- ld hl, PlayedFluteNoEffectText
- jp z, PrintText ; if no pokemon were asleep
-; if some pokemon were asleep
- ld hl, PlayedFluteHadEffectText
- call PrintText
- ld a, [wLowHealthAlarm]
- and $80
- jr nz, .skipMusic
- call WaitForSoundToFinish ; wait for sound to end
- callba Music_PokeFluteInBattle ; play in-battle pokeflute music
-.musicWaitLoop ; wait for music to finish playing
- ld a, [wChannelSoundIDs + Ch7]
- and a ; music off?
- jr nz, .musicWaitLoop
-.skipMusic
- ld hl, FluteWokeUpText
- jp PrintText
-
-; wakes up all party pokemon
-; INPUT:
-; hl must point to status of first pokemon in party (player's or enemy's)
-; b must equal ~SLP
-; [wWereAnyMonsAsleep] should be initialized to 0
-; OUTPUT:
-; [wWereAnyMonsAsleep]: set to 1 if any pokemon were asleep
-WakeUpEntireParty:
- ld de, 44
- ld c, 6
-.loop
- ld a, [hl]
- push af
- and SLP ; is pokemon asleep?
- jr z, .notAsleep
- ld a, 1
- ld [wWereAnyMonsAsleep], a ; indicate that a pokemon had to be woken up
-.notAsleep
- pop af
- and b ; remove Sleep status
- ld [hl], a
- add hl, de
- dec c
- jr nz, .loop
- ret
-
-; Format:
-; 00: Y
-; 01: X
-Route12SnorlaxFluteCoords:
- db 62,9 ; one space West of Snorlax
- db 61,10 ; one space North of Snorlax
- db 63,10 ; one space South of Snorlax
- db 62,11 ; one space East of Snorlax
- db $ff ; terminator
-
-; Format:
-; 00: Y
-; 01: X
-Route16SnorlaxFluteCoords:
- db 10,27 ; one space East of Snorlax
- db 10,25 ; one space West of Snorlax
- db $ff ; terminator
-
-PlayedFluteNoEffectText:
- TX_FAR _PlayedFluteNoEffectText
- db "@"
-
-FluteWokeUpText:
- TX_FAR _FluteWokeUpText
- db "@"
-
-PlayedFluteHadEffectText:
- TX_FAR _PlayedFluteHadEffectText
- TX_BLINK
- TX_ASM
- ld a, [wIsInBattle]
- and a
- jr nz, .done
-; play out-of-battle pokeflute music
- ld a, $ff
- call PlaySound ; turn off music
- ld a, SFX_POKEFLUTE
- ld c, BANK(SFX_Pokeflute)
- call PlayMusic
-.musicWaitLoop ; wait for music to finish playing
- ld a, [wChannelSoundIDs + Ch3]
- cp SFX_POKEFLUTE
- jr z, .musicWaitLoop
- call PlayDefaultMusic ; start playing normal music again
-.done
- jp TextScriptEnd ; end text
-
-ItemUseCoinCase:
- ld a, [wIsInBattle]
- and a
- jp nz, ItemUseNotTime
- ld hl, CoinCaseNumCoinsText
- jp PrintText
-
-CoinCaseNumCoinsText:
- TX_FAR _CoinCaseNumCoinsText
- db "@"
-
-ItemUseOldRod:
- call FishingInit
- jp c, ItemUseNotTime
- lb bc, 5, MAGIKARP
- ld a, $1 ; set bite
- jr RodResponse
-
-ItemUseGoodRod:
- call FishingInit
- jp c, ItemUseNotTime
-.RandomLoop
- call Random
- srl a
- jr c, .SetBite
- and %11
- cp 2
- jr nc, .RandomLoop
- ; choose which monster appears
- ld hl, GoodRodMons
- add a
- ld c, a
- ld b, 0
- add hl, bc
- ld b, [hl]
- inc hl
- ld c, [hl]
- and a
-.SetBite
- ld a, 0
- rla
- xor 1
- jr RodResponse
-
-INCLUDE "data/good_rod.asm"
-
-ItemUseSuperRod:
- call FishingInit
- jp c, ItemUseNotTime
- call ReadSuperRodData
- ld a, e
-RodResponse:
- ld [wRodResponse], a
-
- dec a ; is there a bite?
- jr nz, .next
- ; if yes, store level and species data
- ld a, 1
- ld [wMoveMissed], a
- ld a, b ; level
- ld [wCurEnemyLVL], a
- ld a, c ; species
- ld [wCurOpponent], a
-
-.next
- ld hl, wWalkBikeSurfState
- ld a, [hl] ; store the value in a
- push af
- push hl
- ld [hl], 0
- callba FishingAnim
- pop hl
- pop af
- ld [hl], a
- ret
-
-; checks if fishing is possible and if so, runs initialization code common to all rods
-; unsets carry if fishing is possible, sets carry if not
-FishingInit:
- ld a, [wIsInBattle]
- and a
- jr z, .notInBattle
- scf ; can't fish during battle
- ret
-.notInBattle
- call IsNextTileShoreOrWater
- ret c
- ld a, [wWalkBikeSurfState]
- cp 2 ; Surfing?
- jr z, .surfing
- call ItemUseReloadOverworldData
- ld hl, ItemUseText00
- call PrintText
- ld a, SFX_HEAL_AILMENT
- call PlaySound
- ld c, 80
- call DelayFrames
- and a
- ret
-.surfing
- scf ; can't fish when surfing
- ret
-
-ItemUseOaksParcel:
- jp ItemUseNotYoursToUse
-
-ItemUseItemfinder:
- ld a, [wIsInBattle]
- and a
- jp nz, ItemUseNotTime
- call ItemUseReloadOverworldData
- callba HiddenItemNear ; check for hidden items
- ld hl, ItemfinderFoundNothingText
- jr nc, .printText ; if no hidden items
- ld c, 4
-.loop
- ld a, SFX_HEALING_MACHINE
- call PlaySoundWaitForCurrent
- ld a, SFX_PURCHASE
- call PlaySoundWaitForCurrent
- dec c
- jr nz, .loop
- ld hl, ItemfinderFoundItemText
-.printText
- jp PrintText
-
-ItemfinderFoundItemText:
- TX_FAR _ItemfinderFoundItemText
- db "@"
-
-ItemfinderFoundNothingText:
- TX_FAR _ItemfinderFoundNothingText
- db "@"
-
-ItemUsePPUp:
- ld a, [wIsInBattle]
- and a
- jp nz, ItemUseNotTime
-
-ItemUsePPRestore:
- ld a, [wWhichPokemon]
- push af
- ld a, [wcf91]
- ld [wPPRestoreItem], a
-.chooseMon
- xor a
- ld [wUpdateSpritesEnabled], a
- ld a, USE_ITEM_PARTY_MENU
- ld [wPartyMenuTypeOrMessageID], a
- call DisplayPartyMenu
- jr nc, .chooseMove
- jp .itemNotUsed
-.chooseMove
- ld a, [wPPRestoreItem]
- cp ELIXER
- jp nc, .useElixir ; if Elixir or Max Elixir
- ld a, $02
- ld [wMoveMenuType], a
- ld hl, RaisePPWhichTechniqueText
- ld a, [wPPRestoreItem]
- cp ETHER ; is it a PP Up?
- jr c, .printWhichTechniqueMessage ; if so, print the raise PP message
- ld hl, RestorePPWhichTechniqueText ; otherwise, print the restore PP message
-.printWhichTechniqueMessage
- call PrintText
- xor a
- ld [wPlayerMoveListIndex], a
- callab MoveSelectionMenu ; move selection menu
- ld a, 0
- ld [wPlayerMoveListIndex], a
- jr nz, .chooseMon
- ld hl, wPartyMon1Moves
- ld bc, wPartyMon2 - wPartyMon1
- call GetSelectedMoveOffset
- push hl
- ld a, [hl]
- ld [wd11e], a
- call GetMoveName
- call CopyStringToCF4B ; copy name to wcf4b
- pop hl
- ld a, [wPPRestoreItem]
- cp ETHER
- jr nc, .useEther ; if Ether or Max Ether
-.usePPUp
- ld bc, wPartyMon1PP - wPartyMon1Moves
- add hl, bc
- ld a, [hl] ; move PP
- cp 3 << 6 ; have 3 PP Ups already been used?
- jr c, .PPNotMaxedOut
- ld hl, PPMaxedOutText
- call PrintText
- jr .chooseMove
-.PPNotMaxedOut
- ld a, [hl]
- add 1 << 6 ; increase PP Up count by 1
- ld [hl], a
- ld a, 1 ; 1 PP Up used
- ld [wd11e], a
- call RestoreBonusPP ; add the bonus PP to current PP
- ld hl, PPIncreasedText
- call PrintText
-.done
- pop af
- ld [wWhichPokemon], a
- call GBPalWhiteOut
- call RunDefaultPaletteCommand
- jp RemoveUsedItem
-.afterRestoringPP ; after using a (Max) Ether/Elixir
- ld a, [wWhichPokemon]
- ld b, a
- ld a, [wPlayerMonNumber]
- cp b ; is the pokemon whose PP was restored active in battle?
- jr nz, .skipUpdatingInBattleData
- ld hl, wPartyMon1PP
- ld bc, wPartyMon2 - wPartyMon1
- call AddNTimes
- ld de, wBattleMonPP
- ld bc, 4
- call CopyData ; copy party data to in-battle data
-.skipUpdatingInBattleData
- ld a, SFX_HEAL_AILMENT
- call PlaySound
- ld hl, PPRestoredText
- call PrintText
- jr .done
-.useEther
- call .restorePP
- jr nz, .afterRestoringPP
- jp .noEffect
-; unsets zero flag if PP was restored, sets zero flag if not
-; however, this is bugged for Max Ethers and Max Elixirs (see below)
-.restorePP
- xor a ; PLAYER_PARTY_DATA
- ld [wMonDataLocation], a
- call GetMaxPP
- ld hl, wPartyMon1Moves
- ld bc, wPartyMon2 - wPartyMon1
- call GetSelectedMoveOffset
- ld bc, wPartyMon1PP - wPartyMon1Moves
- add hl, bc ; hl now points to move's PP
- ld a, [wMaxPP]
- ld b, a
- ld a, [wPPRestoreItem]
- cp MAX_ETHER
- jr z, .fullyRestorePP
- ld a, [hl] ; move PP
- and %00111111 ; lower 6 bit bits store current PP
- cp b ; does current PP equal max PP?
- ret z ; if so, return
- add 10 ; increase current PP by 10
-; b holds the max PP amount and b will hold the new PP amount.
-; So, if the new amount meets or exceeds the max amount,
-; cap the amount to the max amount by leaving b unchanged.
-; Otherwise, store the new amount in b.
- cp b ; does the new amount meet or exceed the maximum?
- jr nc, .storeNewAmount
- ld b, a
-.storeNewAmount
- ld a, [hl] ; move PP
- and %11000000 ; PP Up counter bits
- add b
- ld [hl], a
- ret
-.fullyRestorePP
- ld a, [hl] ; move PP
-; Note that this code has a bug. It doesn't mask out the upper two bits, which
-; are used to count how many PP Ups have been used on the move. So, Max Ethers
-; and Max Elixirs will not be detected as having no effect on a move with full
-; PP if the move has had any PP Ups used on it.
- cp b ; does current PP equal max PP?
- ret z
- jr .storeNewAmount
-.useElixir
-; decrement the item ID so that ELIXER becomes ETHER and MAX_ELIXER becomes MAX_ETHER
- ld hl, wPPRestoreItem
- dec [hl]
- dec [hl]
- xor a
- ld hl, wCurrentMenuItem
- ld [hli], a
- ld [hl], a ; zero the counter for number of moves that had their PP restored
- ld b, 4
-; loop through each move and restore PP
-.elixirLoop
- push bc
- ld hl, wPartyMon1Moves
- ld bc, wPartyMon2 - wPartyMon1
- call GetSelectedMoveOffset
- ld a, [hl]
- and a ; does the current slot have a move?
- jr z, .nextMove
- call .restorePP
- jr z, .nextMove
-; if some PP was restored
- ld hl, wTileBehindCursor ; counter for number of moves that had their PP restored
- inc [hl]
-.nextMove
- ld hl, wCurrentMenuItem
- inc [hl]
- pop bc
- dec b
- jr nz, .elixirLoop
- ld a, [wTileBehindCursor]
- and a ; did any moves have their PP restored?
- jp nz, .afterRestoringPP
-.noEffect
- call ItemUseNoEffect
-.itemNotUsed
- call GBPalWhiteOut
- call RunDefaultPaletteCommand
- pop af
- xor a
- ld [wActionResultOrTookBattleTurn], a ; item use failed
- ret
-
-RaisePPWhichTechniqueText:
- TX_FAR _RaisePPWhichTechniqueText
- db "@"
-
-RestorePPWhichTechniqueText:
- TX_FAR _RestorePPWhichTechniqueText
- db "@"
-
-PPMaxedOutText:
- TX_FAR _PPMaxedOutText
- db "@"
-
-PPIncreasedText:
- TX_FAR _PPIncreasedText
- db "@"
-
-PPRestoredText:
- TX_FAR _PPRestoredText
- db "@"
-
-; for items that can't be used from the Item menu
-UnusableItem:
- jp ItemUseNotTime
-
-ItemUseTMHM:
- ld a, [wIsInBattle]
- and a
- jp nz, ItemUseNotTime
- ld a, [wcf91]
- sub TM_01
- push af
- jr nc, .skipAdding
- add 55 ; if item is an HM, add 55
-.skipAdding
- inc a
- ld [wd11e], a
- predef TMToMove ; get move ID from TM/HM ID
- ld a, [wd11e]
- ld [wMoveNum], a
- call GetMoveName
- call CopyStringToCF4B ; copy name to wcf4b
- pop af
- ld hl, BootedUpTMText
- jr nc, .printBootedUpMachineText
- ld hl, BootedUpHMText
-.printBootedUpMachineText
- call PrintText
- ld hl, TeachMachineMoveText
- call PrintText
- coord hl, 14, 7
- lb bc, 8, 15
- ld a, TWO_OPTION_MENU
- ld [wTextBoxID], a
- call DisplayTextBoxID ; yes/no menu
- ld a, [wCurrentMenuItem]
- and a
- jr z, .useMachine
- ld a, 2
- ld [wActionResultOrTookBattleTurn], a ; item not used
- ret
-.useMachine
- ld a, [wWhichPokemon]
- push af
- ld a, [wcf91]
- push af
-.chooseMon
- ld hl, wcf4b
- ld de, wTempMoveNameBuffer
- ld bc, 14
- call CopyData ; save the move name because DisplayPartyMenu will overwrite it
- ld a, $ff
- ld [wUpdateSpritesEnabled], a
- ld a, TMHM_PARTY_MENU
- ld [wPartyMenuTypeOrMessageID], a
- call DisplayPartyMenu
- push af
- ld hl, wTempMoveNameBuffer
- ld de, wcf4b
- ld bc, 14
- call CopyData
- pop af
- jr nc, .checkIfAbleToLearnMove
-; if the player canceled teaching the move
- pop af
- pop af
- call GBPalWhiteOutWithDelay3
- call ClearSprites
- call RunDefaultPaletteCommand
- jp LoadScreenTilesFromBuffer1 ; restore saved screen
-.checkIfAbleToLearnMove
- predef CanLearnTM ; check if the pokemon can learn the move
- push bc
- ld a, [wWhichPokemon]
- ld hl, wPartyMonNicks
- call GetPartyMonName
- pop bc
- ld a, c
- and a ; can the pokemon learn the move?
- jr nz, .checkIfAlreadyLearnedMove
-; if the pokemon can't learn the move
- ld a, SFX_DENIED
- call PlaySoundWaitForCurrent
- ld hl, MonCannotLearnMachineMoveText
- call PrintText
- jr .chooseMon
-.checkIfAlreadyLearnedMove
- callab CheckIfMoveIsKnown ; check if the pokemon already knows the move
- jr c, .chooseMon
- predef LearnMove ; teach move
- pop af
- ld [wcf91], a
- pop af
- ld [wWhichPokemon], a
- ld a, b
- and a
- ret z
- ld a, [wcf91]
- call IsItemHM
- ret c
- jp RemoveUsedItem
-
-BootedUpTMText:
- TX_FAR _BootedUpTMText
- db "@"
-
-BootedUpHMText:
- TX_FAR _BootedUpHMText
- db "@"
-
-TeachMachineMoveText:
- TX_FAR _TeachMachineMoveText
- db "@"
-
-MonCannotLearnMachineMoveText:
- TX_FAR _MonCannotLearnMachineMoveText
- db "@"
-
-PrintItemUseTextAndRemoveItem:
- ld hl, ItemUseText00
- call PrintText
- ld a, SFX_HEAL_AILMENT
- call PlaySound
- call WaitForTextScrollButtonPress ; wait for button press
-
-RemoveUsedItem:
- ld hl, wNumBagItems
- ld a, 1 ; one item
- ld [wItemQuantity], a
- jp RemoveItemFromInventory
-
-ItemUseNoEffect:
- ld hl, ItemUseNoEffectText
- jr ItemUseFailed
-
-ItemUseNotTime:
- ld hl, ItemUseNotTimeText
- jr ItemUseFailed
-
-ItemUseNotYoursToUse:
- ld hl, ItemUseNotYoursToUseText
- jr ItemUseFailed
-
-ThrowBallAtTrainerMon:
- call RunDefaultPaletteCommand
- call LoadScreenTilesFromBuffer1 ; restore saved screen
- call Delay3
- ld a, TOSS_ANIM
- ld [wAnimationID], a
- predef MoveAnimation ; do animation
- ld hl, ThrowBallAtTrainerMonText1
- call PrintText
- ld hl, ThrowBallAtTrainerMonText2
- call PrintText
- jr RemoveUsedItem
-
-NoCyclingAllowedHere:
- ld hl, NoCyclingAllowedHereText
- jr ItemUseFailed
-
-BoxFullCannotThrowBall:
- ld hl, BoxFullCannotThrowBallText
- jr ItemUseFailed
-
-SurfingAttemptFailed:
- ld hl, NoSurfingHereText
-
-ItemUseFailed:
- xor a
- ld [wActionResultOrTookBattleTurn], a ; item use failed
- jp PrintText
-
-ItemUseNotTimeText:
- TX_FAR _ItemUseNotTimeText
- db "@"
-
-ItemUseNotYoursToUseText:
- TX_FAR _ItemUseNotYoursToUseText
- db "@"
-
-ItemUseNoEffectText:
- TX_FAR _ItemUseNoEffectText
- db "@"
-
-ThrowBallAtTrainerMonText1:
- TX_FAR _ThrowBallAtTrainerMonText1
- db "@"
-
-ThrowBallAtTrainerMonText2:
- TX_FAR _ThrowBallAtTrainerMonText2
- db "@"
-
-NoCyclingAllowedHereText:
- TX_FAR _NoCyclingAllowedHereText
- db "@"
-
-NoSurfingHereText:
- TX_FAR _NoSurfingHereText
- db "@"
-
-BoxFullCannotThrowBallText:
- TX_FAR _BoxFullCannotThrowBallText
- db "@"
-
-ItemUseText00:
- TX_FAR _ItemUseText001
- TX_LINE
- TX_FAR _ItemUseText002
- db "@"
-
-GotOnBicycleText:
- TX_FAR _GotOnBicycleText1
- TX_LINE
- TX_FAR _GotOnBicycleText2
- db "@"
-
-GotOffBicycleText:
- TX_FAR _GotOffBicycleText1
- TX_LINE
- TX_FAR _GotOffBicycleText2
- db "@"
-
-; restores bonus PP (from PP Ups) when healing at a pokemon center
-; also, when a PP Up is used, it increases the current PP by one PP Up bonus
-; INPUT:
-; [wWhichPokemon] = index of pokemon in party
-; [wCurrentMenuItem] = index of move (when using a PP Up)
-RestoreBonusPP:
- ld hl, wPartyMon1Moves
- ld bc, wPartyMon2 - wPartyMon1
- ld a, [wWhichPokemon]
- call AddNTimes
- push hl
- ld de, wNormalMaxPPList - 1
- predef LoadMovePPs ; loads the normal max PP of each of the pokemon's moves to wNormalMaxPPList
- pop hl
- ld c, wPartyMon1PP - wPartyMon1Moves
- ld b, 0
- add hl, bc ; hl now points to move 1 PP
- ld de, wNormalMaxPPList
- ld b, 0 ; initialize move counter to zero
-; loop through the pokemon's moves
-.loop
- inc b
- ld a, b
- cp 5 ; reached the end of the pokemon's moves?
- ret z ; if so, return
- ld a, [wUsingPPUp]
- dec a ; using a PP Up?
- jr nz, .skipMenuItemIDCheck
-; if using a PP Up, check if this is the move it's being used on
- ld a, [wCurrentMenuItem]
- inc a
- cp b
- jr nz, .nextMove
-.skipMenuItemIDCheck
- ld a, [hl]
- and %11000000 ; have any PP Ups been used?
- call nz, AddBonusPP ; if so, add bonus PP
-.nextMove
- inc hl
- inc de
- jr .loop
-
-; adds bonus PP from PP Ups to current PP
-; 1/5 of normal max PP (capped at 7) is added for each PP Up
-; INPUT:
-; [de] = normal max PP
-; [hl] = move PP
-AddBonusPP:
- push bc
- ld a, [de] ; normal max PP of move
- ld [H_DIVIDEND + 3], a
- xor a
- ld [H_DIVIDEND], a
- ld [H_DIVIDEND + 1], a
- ld [H_DIVIDEND + 2], a
- ld a, 5
- ld [H_DIVISOR], a
- ld b, 4
- call Divide
- ld a, [hl] ; move PP
- ld b, a
- swap a
- and %00001111
- srl a
- srl a
- ld c, a ; c = number of PP Ups used
-.loop
- ld a, [H_QUOTIENT + 3]
- cp 8 ; is the amount greater than or equal to 8?
- jr c, .addAmount
- ld a, 7 ; cap the amount at 7
-.addAmount
- add b
- ld b, a
- ld a, [wUsingPPUp]
- dec a ; is the player using a PP Up right now?
- jr z, .done ; if so, only add the bonus once
- dec c
- jr nz, .loop
-.done
- ld [hl], b
- pop bc
- ret
-
-; gets max PP of a pokemon's move (including PP from PP Ups)
-; INPUT:
-; [wWhichPokemon] = index of pokemon within party/box
-; [wMonDataLocation] = pokemon source
-; 00: player's party
-; 01: enemy's party
-; 02: current box
-; 03: daycare
-; 04: player's in-battle pokemon
-; [wCurrentMenuItem] = move index
-; OUTPUT:
-; [wMaxPP] = max PP
-GetMaxPP:
- ld a, [wMonDataLocation]
- and a
- ld hl, wPartyMon1Moves
- ld bc, wPartyMon2 - wPartyMon1
- jr z, .sourceWithMultipleMon
- ld hl, wEnemyMon1Moves
- dec a
- jr z, .sourceWithMultipleMon
- ld hl, wBoxMon1Moves
- ld bc, wBoxMon2 - wBoxMon1
- dec a
- jr z, .sourceWithMultipleMon
- ld hl, wDayCareMonMoves
- dec a
- jr z, .sourceWithOneMon
- ld hl, wBattleMonMoves ; player's in-battle pokemon
-.sourceWithOneMon
- call GetSelectedMoveOffset2
- jr .next
-.sourceWithMultipleMon
- call GetSelectedMoveOffset
-.next
- ld a, [hl]
- dec a
- push hl
- ld hl, Moves
- ld bc, MoveEnd - Moves
- call AddNTimes
- ld de, wcd6d
- ld a, BANK(Moves)
- call FarCopyData
- ld de, wcd6d + 5 ; PP is byte 5 of move data
- ld a, [de]
- ld b, a ; b = normal max PP
- pop hl
- push bc
- ld bc, wPartyMon1PP - wPartyMon1Moves ; PP offset if not player's in-battle pokemon data
- ld a, [wMonDataLocation]
- cp 4 ; player's in-battle pokemon?
- jr nz, .addPPOffset
- ld bc, wBattleMonPP - wBattleMonMoves ; PP offset if player's in-battle pokemon data
-.addPPOffset
- add hl, bc
- ld a, [hl] ; a = current PP
- and %11000000 ; get PP Up count
- pop bc
- or b ; place normal max PP in 6 lower bits of a
- ld h, d
- ld l, e
- inc hl ; hl = wcd73
- ld [hl], a
- xor a ; add the bonus for the existing PP Up count
- ld [wUsingPPUp], a
- call AddBonusPP ; add bonus PP from PP Ups
- ld a, [hl]
- and %00111111 ; mask out the PP Up count
- ld [wMaxPP], a ; store max PP
- ret
-
-GetSelectedMoveOffset:
- ld a, [wWhichPokemon]
- call AddNTimes
-
-GetSelectedMoveOffset2:
- ld a, [wCurrentMenuItem]
- ld c, a
- ld b, 0
- add hl, bc
- ret
-
-; 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_::
- push hl
- ld a, [wcf91]
- call IsItemHM
- pop hl
- jr c, .tooImportantToToss
- push hl
- call IsKeyItem_
- ld a, [wIsKeyItem]
- pop hl
- and a
- jr nz, .tooImportantToToss
- push hl
- ld a, [wcf91]
- ld [wd11e], a
- call GetItemName
- call CopyStringToCF4B ; copy name to wcf4b
- ld hl, IsItOKToTossItemText
- call PrintText
- coord hl, 14, 7
- lb bc, 8, 15
- ld a, TWO_OPTION_MENU
- ld [wTextBoxID], a
- call DisplayTextBoxID ; yes/no menu
- ld a, [wMenuExitMethod]
- cp CHOSE_SECOND_ITEM
- pop hl
- scf
- ret z ; return if the player chose No
-; if the player chose Yes
- push hl
- ld a, [wWhichPokemon]
- call RemoveItemFromInventory
- ld a, [wcf91]
- ld [wd11e], a
- call GetItemName
- call CopyStringToCF4B ; copy name to wcf4b
- ld hl, ThrewAwayItemText
- call PrintText
- pop hl
- and a
- ret
-.tooImportantToToss
- push hl
- ld hl, TooImportantToTossText
- call PrintText
- pop hl
- scf
- ret
-
-ThrewAwayItemText:
- TX_FAR _ThrewAwayItemText
- db "@"
-
-IsItOKToTossItemText:
- TX_FAR _IsItOKToTossItemText
- db "@"
-
-TooImportantToTossText:
- TX_FAR _TooImportantToTossText
- db "@"
-
-; 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_::
- ld a, $01
- ld [wIsKeyItem], a
- ld a, [wcf91]
- cp HM_01 ; is the item an HM or TM?
- jr nc, .checkIfItemIsHM
-; if the item is not an HM or TM
- push af
- ld hl, KeyItemBitfield
- ld de, wBuffer
- ld bc, 15 ; only 11 bytes are actually used
- call CopyData
- pop af
- dec a
- ld c, a
- ld hl, wBuffer
- ld b, FLAG_TEST
- predef FlagActionPredef
- ld a, c
- and a
- ret nz
-.checkIfItemIsHM
- ld a, [wcf91]
- call IsItemHM
- ret c
- xor a
- ld [wIsKeyItem], a
- ret
-
-INCLUDE "data/key_items.asm"
-
-SendNewMonToBox:
- ld de, wNumInBox
- ld a, [de]
- inc a
- ld [de], a
- ld a, [wcf91]
- ld [wd0b5], a
- ld c, a
-.asm_e7b1
- inc de
- ld a, [de]
- ld b, a
- ld a, c
- ld c, b
- ld [de], a
- cp $ff
- jr nz, .asm_e7b1
- call GetMonHeader
- ld hl, wBoxMonOT
- ld bc, NAME_LENGTH
- ld a, [wNumInBox]
- dec a
- jr z, .asm_e7ee
- dec a
- call AddNTimes
- push hl
- ld bc, NAME_LENGTH
- add hl, bc
- ld d, h
- ld e, l
- pop hl
- ld a, [wNumInBox]
- dec a
- ld b, a
-.asm_e7db
- push bc
- push hl
- ld bc, NAME_LENGTH
- call CopyData
- pop hl
- ld d, h
- ld e, l
- ld bc, -NAME_LENGTH
- add hl, bc
- pop bc
- dec b
- jr nz, .asm_e7db
-.asm_e7ee
- ld hl, wPlayerName
- ld de, wBoxMonOT
- ld bc, NAME_LENGTH
- call CopyData
- ld a, [wNumInBox]
- dec a
- jr z, .asm_e82a
- ld hl, wBoxMonNicks
- ld bc, NAME_LENGTH
- dec a
- call AddNTimes
- push hl
- ld bc, NAME_LENGTH
- add hl, bc
- ld d, h
- ld e, l
- pop hl
- ld a, [wNumInBox]
- dec a
- ld b, a
-.asm_e817
- push bc
- push hl
- ld bc, NAME_LENGTH
- call CopyData
- pop hl
- ld d, h
- ld e, l
- ld bc, -NAME_LENGTH
- add hl, bc
- pop bc
- dec b
- jr nz, .asm_e817
-.asm_e82a
- ld hl, wBoxMonNicks
- ld a, NAME_MON_SCREEN
- ld [wNamingScreenType], a
- predef AskName
- ld a, [wNumInBox]
- dec a
- jr z, .asm_e867
- ld hl, wBoxMons
- ld bc, wBoxMon2 - wBoxMon1
- dec a
- call AddNTimes
- push hl
- ld bc, wBoxMon2 - wBoxMon1
- add hl, bc
- ld d, h
- ld e, l
- pop hl
- ld a, [wNumInBox]
- dec a
- ld b, a
-.asm_e854
- push bc
- push hl
- ld bc, wBoxMon2 - wBoxMon1
- call CopyData
- pop hl
- ld d, h
- ld e, l
- ld bc, wBoxMon1 - wBoxMon2
- add hl, bc
- pop bc
- dec b
- jr nz, .asm_e854
-.asm_e867
- ld a, [wEnemyMonLevel]
- ld [wEnemyMonBoxLevel], a
- ld hl, wEnemyMon
- ld de, wBoxMon1
- ld bc, wEnemyMonDVs - wEnemyMon
- call CopyData
- ld hl, wPlayerID
- ld a, [hli]
- ld [de], a
- inc de
- ld a, [hl]
- ld [de], a
- inc de
- push de
- ld a, [wCurEnemyLVL]
- ld d, a
- callab CalcExperience
- pop de
- ld a, [hExperience]
- ld [de], a
- inc de
- ld a, [hExperience + 1]
- ld [de], a
- inc de
- ld a, [hExperience + 2]
- ld [de], a
- inc de
- xor a
- ld b, NUM_STATS * 2
-.asm_e89f
- ld [de], a
- inc de
- dec b
- jr nz, .asm_e89f
- ld hl, wEnemyMonDVs
- ld a, [hli]
- ld [de], a
- inc de
- ld a, [hli]
- ld [de], a
- ld hl, wEnemyMonPP
- ld b, NUM_MOVES
-.asm_e8b1
- ld a, [hli]
- inc de
- ld [de], a
- dec b
- jr nz, .asm_e8b1
- ret
-
-; checks if the tile in front of the player is a shore or water tile
-; used for surfing and fishing
-; unsets carry if it is, sets carry if not
-IsNextTileShoreOrWater:
- ld a, [wCurMapTileset]
- ld hl, WaterTilesets
- ld de, 1
- call IsInArray
- jr nc, .notShoreOrWater
- ld a, [wCurMapTileset]
- cp SHIP_PORT ; Vermilion Dock tileset
- ld a, [wTileInFrontOfPlayer] ; tile in front of player
- jr z, .skipShoreTiles ; if it's the Vermilion Dock tileset
- cp $48 ; eastern shore tile in Safari Zone
- jr z, .shoreOrWater
- cp $32 ; usual eastern shore tile
- jr z, .shoreOrWater
-.skipShoreTiles
- cp $14 ; water tile
- jr z, .shoreOrWater
-.notShoreOrWater
- scf
- ret
-.shoreOrWater
- and a
- ret
-
-INCLUDE "data/water_tilesets.asm"
-
-ReadSuperRodData:
-; return e = 2 if no fish on this map
-; return e = 1 if a bite, bc = level,species
-; return e = 0 if no bite
- ld a, [wCurMap]
- ld de, 3 ; each fishing group is three bytes wide
- ld hl, SuperRodData
- call IsInArray
- jr c, .ReadFishingGroup
- ld e, $2 ; $2 if no fishing groups found
- ret
-
-.ReadFishingGroup
-; hl points to the fishing group entry in the index
- inc hl ; skip map id
-
- ; read fishing group address
- ld a, [hli]
- ld h, [hl]
- ld l, a
-
- ld b, [hl] ; how many mons in group
- inc hl ; point to data
- ld e, $0 ; no bite yet
-
-.RandomLoop
- call Random
- srl a
- ret c ; 50% chance of no battle
-
- and %11 ; 2-bit random number
- cp b
- jr nc, .RandomLoop ; if a is greater than the number of mons, regenerate
-
- ; get the mon
- add a
- ld c, a
- ld b, $0
- add hl, bc
- ld b, [hl] ; level
- inc hl
- ld c, [hl] ; species
- ld e, $1 ; $1 if there's a bite
- ret
-
-INCLUDE "data/super_rod.asm"
-
-; reloads map view and processes sprite data
-; for items that cause the overworld to be displayed
-ItemUseReloadOverworldData:
- call LoadCurrentMapView
- jp UpdateSprites
-
-; creates a list at wBuffer of maps where the mon in [wd11e] can be found.
-; this is used by the pokedex to display locations the mon can be found on the map.
-FindWildLocationsOfMon:
- ld hl, WildDataPointers
- ld de, wBuffer
- ld c, $0
-.loop
- inc hl
- ld a, [hld]
- inc a
- jr z, .done
- push hl
- ld a, [hli]
- ld h, [hl]
- ld l, a
- ld a, [hli]
- and a
- call nz, CheckMapForMon ; land
- ld a, [hli]
- and a
- call nz, CheckMapForMon ; water
- pop hl
- inc hl
- inc hl
- inc c
- jr .loop
-.done
- ld a, $ff ; list terminator
- ld [de], a
- ret
-
-CheckMapForMon:
- inc hl
- ld b, $a
-.loop
- ld a, [wd11e]
- cp [hl]
- jr nz, .nextEntry
- ld a, c
- ld [de], a
- inc de
-.nextEntry
- inc hl
- inc hl
- dec b
- jr nz, .loop
- dec hl
- ret
--- /dev/null
+++ b/engine/items/subtract_paid_money.asm
@@ -1,0 +1,17 @@
+; subtracts the amount the player paid from their money
+; OUTPUT: carry = 0(success) or 1(fail because there is not enough money)
+SubtractAmountPaidFromMoney_::
+ ld de, wPlayerMoney
+ ld hl, hMoney ; total price of items
+ ld c, 3 ; length of money in bytes
+ call StringCmp
+ ret c
+ ld de, wPlayerMoney + 2
+ ld hl, hMoney + 2 ; total price of items
+ ld c, 3 ; length of money in bytes
+ predef SubBCDPredef ; subtract total price from money
+ ld a, MONEY_BOX
+ ld [wTextBoxID], a
+ call DisplayTextBoxID ; redraw money text box
+ and a
+ ret
--- /dev/null
+++ b/engine/items/town_map.asm
@@ -1,0 +1,618 @@
+DisplayTownMap:
+ call LoadTownMap
+ ld hl, wUpdateSpritesEnabled
+ ld a, [hl]
+ push af
+ ld [hl], $ff
+ push hl
+ ld a, $1
+ ld [hJoy7], a
+ ld a, [wCurMap]
+ push af
+ ld b, $0
+ call DrawPlayerOrBirdSprite ; player sprite
+ coord hl, 1, 0
+ ld de, wcd6d
+ call PlaceString
+ ld hl, wOAMBuffer
+ ld de, wTileMapBackup
+ ld bc, $10
+ call CopyData
+ ld hl, vSprites + $40
+ ld de, TownMapCursor
+ lb bc, BANK(TownMapCursor), (TownMapCursorEnd - TownMapCursor) / $8
+ call CopyVideoDataDouble
+ xor a
+ ld [wWhichTownMapLocation], a
+ pop af
+ jr .enterLoop
+
+.townMapLoop
+ coord hl, 0, 0
+ lb bc, 1, 20
+ call ClearScreenArea
+ ld hl, TownMapOrder
+ ld a, [wWhichTownMapLocation]
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hl]
+.enterLoop
+ ld de, wTownMapCoords
+ call LoadTownMapEntry
+ ld a, [de]
+ push hl
+ call TownMapCoordsToOAMCoords
+ ld a, $4
+ ld [wOAMBaseTile], a
+ ld hl, wOAMBuffer + $10
+ call WriteTownMapSpriteOAM ; town map cursor sprite
+ pop hl
+ ld de, wcd6d
+.copyMapName
+ ld a, [hli]
+ ld [de], a
+ inc de
+ cp $50
+ jr nz, .copyMapName
+ coord hl, 1, 0
+ ld de, wcd6d
+ call PlaceString
+ ld hl, wOAMBuffer + $10
+ ld de, wTileMapBackup + 16
+ ld bc, $10
+ call CopyData
+.inputLoop
+ call TownMapSpriteBlinkingAnimation
+ call JoypadLowSensitivity
+ ld a, [hJoy5]
+ ld b, a
+ and A_BUTTON | B_BUTTON | D_UP | D_DOWN
+ jr z, .inputLoop
+ ld a, SFX_TINK
+ call PlaySound
+ bit 6, b
+ jr nz, .pressedUp
+ bit 7, b
+ jr nz, .pressedDown
+ xor a
+ ld [wTownMapSpriteBlinkingEnabled], a
+ ld [hJoy7], a
+ ld [wAnimCounter], a
+ call ExitTownMap
+ pop hl
+ pop af
+ ld [hl], a
+ ret
+.pressedUp
+ ld a, [wWhichTownMapLocation]
+ inc a
+ cp TownMapOrderEnd - TownMapOrder ; number of list items + 1
+ jr nz, .noOverflow
+ xor a
+.noOverflow
+ ld [wWhichTownMapLocation], a
+ jp .townMapLoop
+.pressedDown
+ ld a, [wWhichTownMapLocation]
+ dec a
+ cp -1
+ jr nz, .noUnderflow
+ ld a, TownMapOrderEnd - TownMapOrder - 1 ; number of list items
+.noUnderflow
+ ld [wWhichTownMapLocation], a
+ jp .townMapLoop
+
+INCLUDE "data/town_map_order.asm"
+
+TownMapCursor:
+ INCBIN "gfx/town_map/town_map_cursor.1bpp"
+TownMapCursorEnd:
+
+LoadTownMap_Nest:
+ call LoadTownMap
+ ld hl, wUpdateSpritesEnabled
+ ld a, [hl]
+ push af
+ ld [hl], $ff
+ push hl
+ call DisplayWildLocations
+ call GetMonName
+ coord hl, 1, 0
+ call PlaceString
+ ld h, b
+ ld l, c
+ ld de, MonsNestText
+ call PlaceString
+ call WaitForTextScrollButtonPress
+ call ExitTownMap
+ pop hl
+ pop af
+ ld [hl], a
+ ret
+
+MonsNestText:
+ db "'s NEST@"
+
+LoadTownMap_Fly::
+ call ClearSprites
+ call LoadTownMap
+ call LoadPlayerSpriteGraphics
+ call LoadFontTilePatterns
+ ld de, BirdSprite
+ ld hl, vSprites + $40
+ lb bc, BANK(BirdSprite), $c
+ call CopyVideoData
+ ld de, TownMapUpArrow
+ ld hl, vChars1 + $6d0
+ lb bc, BANK(TownMapUpArrow), (TownMapUpArrowEnd - TownMapUpArrow) / $8
+ call CopyVideoDataDouble
+ call BuildFlyLocationsList
+ ld hl, wUpdateSpritesEnabled
+ ld a, [hl]
+ push af
+ ld [hl], $ff
+ push hl
+ coord hl, 0, 0
+ ld de, ToText
+ call PlaceString
+ ld a, [wCurMap]
+ ld b, $0
+ call DrawPlayerOrBirdSprite
+ ld hl, wFlyLocationsList
+ coord de, 18, 0
+.townMapFlyLoop
+ ld a, " "
+ ld [de], a
+ push hl
+ push hl
+ coord hl, 3, 0
+ lb bc, 1, 15
+ call ClearScreenArea
+ pop hl
+ ld a, [hl]
+ ld b, $4
+ call DrawPlayerOrBirdSprite ; draw bird sprite
+ coord hl, 3, 0
+ ld de, wcd6d
+ call PlaceString
+ ld c, 15
+ call DelayFrames
+ coord hl, 18, 0
+ ld [hl], "▲"
+ coord hl, 19, 0
+ ld [hl], "▼"
+ pop hl
+.inputLoop
+ push hl
+ call DelayFrame
+ call JoypadLowSensitivity
+ ld a, [hJoy5]
+ ld b, a
+ pop hl
+ and A_BUTTON | B_BUTTON | D_UP | D_DOWN
+ jr z, .inputLoop
+ bit 0, b
+ jr nz, .pressedA
+ ld a, SFX_TINK
+ call PlaySound
+ bit 6, b
+ jr nz, .pressedUp
+ bit 7, b
+ jr nz, .pressedDown
+ jr .pressedB
+.pressedA
+ ld a, SFX_HEAL_AILMENT
+ call PlaySound
+ ld a, [hl]
+ ld [wDestinationMap], a
+ ld hl, wd732
+ set 3, [hl]
+ inc hl
+ set 7, [hl]
+.pressedB
+ xor a
+ ld [wTownMapSpriteBlinkingEnabled], a
+ call GBPalWhiteOutWithDelay3
+ pop hl
+ pop af
+ ld [hl], a
+ ret
+.pressedUp
+ coord de, 18, 0
+ inc hl
+ ld a, [hl]
+ cp $ff
+ jr z, .wrapToStartOfList
+ cp $fe
+ jr z, .pressedUp ; skip past unvisited towns
+ jp .townMapFlyLoop
+.wrapToStartOfList
+ ld hl, wFlyLocationsList
+ jp .townMapFlyLoop
+.pressedDown
+ coord de, 19, 0
+ dec hl
+ ld a, [hl]
+ cp $ff
+ jr z, .wrapToEndOfList
+ cp $fe
+ jr z, .pressedDown ; skip past unvisited towns
+ jp .townMapFlyLoop
+.wrapToEndOfList
+ ld hl, wFlyLocationsList + 11
+ jr .pressedDown
+
+ToText:
+ db "To@"
+
+BuildFlyLocationsList:
+ ld hl, wFlyLocationsList - 1
+ ld [hl], $ff
+ inc hl
+ ld a, [wTownVisitedFlag]
+ ld e, a
+ ld a, [wTownVisitedFlag + 1]
+ ld d, a
+ ld bc, SAFFRON_CITY + 1
+.loop
+ srl d
+ rr e
+ ld a, $fe ; store $fe if the town hasn't been visited
+ jr nc, .notVisited
+ ld a, b ; store the map number of the town if it has been visited
+.notVisited
+ ld [hl], a
+ inc hl
+ inc b
+ dec c
+ jr nz, .loop
+ ld [hl], $ff
+ ret
+
+TownMapUpArrow:
+ INCBIN "gfx/town_map/up_arrow.1bpp"
+TownMapUpArrowEnd:
+
+LoadTownMap:
+ call GBPalWhiteOutWithDelay3
+ call ClearScreen
+ call UpdateSprites
+ coord hl, 0, 0
+ ld b, $12
+ ld c, $12
+ call TextBoxBorder
+ call DisableLCD
+ ld hl, WorldMapTileGraphics
+ ld de, vChars2 + $600
+ ld bc, WorldMapTileGraphicsEnd - WorldMapTileGraphics
+ ld a, BANK(WorldMapTileGraphics)
+ call FarCopyData2
+ ld hl, MonNestIcon
+ ld de, vSprites + $40
+ ld bc, MonNestIconEnd - MonNestIcon
+ ld a, BANK(MonNestIcon)
+ call FarCopyDataDouble
+ coord hl, 0, 0
+ ld de, CompressedMap
+.nextTile
+ ld a, [de]
+ and a
+ jr z, .done
+ ld b, a
+ and $f
+ ld c, a
+ ld a, b
+ swap a
+ and $f
+ add $60
+.writeRunLoop
+ ld [hli], a
+ dec c
+ jr nz, .writeRunLoop
+ inc de
+ jr .nextTile
+.done
+ call EnableLCD
+ ld b, SET_PAL_TOWN_MAP
+ call RunPaletteCommand
+ call Delay3
+ call GBPalNormal
+ xor a
+ ld [wAnimCounter], a
+ inc a
+ ld [wTownMapSpriteBlinkingEnabled], a
+ ret
+
+CompressedMap:
+ INCBIN "gfx/town_map/town_map.rle"
+
+ExitTownMap:
+; clear town map graphics data and load usual graphics data
+ xor a
+ ld [wTownMapSpriteBlinkingEnabled], a
+ call GBPalWhiteOut
+ call ClearScreen
+ call ClearSprites
+ call LoadPlayerSpriteGraphics
+ call LoadFontTilePatterns
+ call UpdateSprites
+ jp RunDefaultPaletteCommand
+
+DrawPlayerOrBirdSprite:
+; a = map number
+; b = OAM base tile
+ push af
+ ld a, b
+ ld [wOAMBaseTile], a
+ pop af
+ ld de, wTownMapCoords
+ call LoadTownMapEntry
+ ld a, [de]
+ push hl
+ call TownMapCoordsToOAMCoords
+ call WritePlayerOrBirdSpriteOAM
+ pop hl
+ ld de, wcd6d
+.loop
+ ld a, [hli]
+ ld [de], a
+ inc de
+ cp "@"
+ jr nz, .loop
+ ld hl, wOAMBuffer
+ ld de, wTileMapBackup
+ ld bc, $a0
+ jp CopyData
+
+DisplayWildLocations:
+ callba FindWildLocationsOfMon
+ call ZeroOutDuplicatesInList
+ ld hl, wOAMBuffer
+ ld de, wTownMapCoords
+.loop
+ ld a, [de]
+ cp $ff
+ jr z, .exitLoop
+ and a
+ jr z, .nextEntry
+ push hl
+ call LoadTownMapEntry
+ pop hl
+ ld a, [de]
+ cp $19 ; Cerulean Cave's coordinates
+ jr z, .nextEntry ; skip Cerulean Cave
+ call TownMapCoordsToOAMCoords
+ ld a, $4 ; nest icon tile no.
+ ld [hli], a
+ xor a
+ ld [hli], a
+.nextEntry
+ inc de
+ jr .loop
+.exitLoop
+ ld a, l
+ and a ; were any OAM entries written?
+ jr nz, .drawPlayerSprite
+; if no OAM entries were written, print area unknown text
+ coord hl, 1, 7
+ ld b, 2
+ ld c, 15
+ call TextBoxBorder
+ coord hl, 2, 9
+ ld de, AreaUnknownText
+ call PlaceString
+ jr .done
+.drawPlayerSprite
+ ld a, [wCurMap]
+ ld b, $0
+ call DrawPlayerOrBirdSprite
+.done
+ ld hl, wOAMBuffer
+ ld de, wTileMapBackup
+ ld bc, $a0
+ jp CopyData
+
+AreaUnknownText:
+ db " AREA UNKNOWN@"
+
+TownMapCoordsToOAMCoords:
+; in: lower nybble of a = x, upper nybble of a = y
+; out: b and [hl] = (y * 8) + 24, c and [hl+1] = (x * 8) + 24
+ push af
+ and $f0
+ srl a
+ add 24
+ ld b, a
+ ld [hli], a
+ pop af
+ and $f
+ swap a
+ srl a
+ add 24
+ ld c, a
+ ld [hli], a
+ ret
+
+WritePlayerOrBirdSpriteOAM:
+ ld a, [wOAMBaseTile]
+ and a
+ ld hl, wOAMBuffer + $90 ; for player sprite
+ jr z, WriteTownMapSpriteOAM
+ ld hl, wOAMBuffer + $80 ; for bird sprite
+
+WriteTownMapSpriteOAM:
+ push hl
+
+; Subtract 4 from c (X coord) and 4 from b (Y coord). However, the carry from c
+; is added to b, so the net result is that only 3 is subtracted from b.
+ lb hl, -4, -4
+ add hl, bc
+
+ ld b, h
+ ld c, l
+ pop hl
+
+WriteAsymmetricMonPartySpriteOAM:
+; Writes 4 OAM blocks for a helix mon party sprite, since it does not have
+; a vertical line of symmetry.
+ lb de, 2, 2
+.loop
+ push de
+ push bc
+.innerLoop
+ ld a, b
+ ld [hli], a
+ ld a, c
+ ld [hli], a
+ ld a, [wOAMBaseTile]
+ ld [hli], a
+ inc a
+ ld [wOAMBaseTile], a
+ xor a
+ ld [hli], a
+ inc d
+ ld a, 8
+ add c
+ ld c, a
+ dec e
+ jr nz, .innerLoop
+ pop bc
+ pop de
+ ld a, 8
+ add b
+ ld b, a
+ dec d
+ jr nz, .loop
+ ret
+
+WriteSymmetricMonPartySpriteOAM:
+; Writes 4 OAM blocks for a mon party sprite other than a helix. All the
+; sprites other than the helix one have a vertical line of symmetry which allows
+; the X-flip OAM bit to be used so that only 2 rather than 4 tile patterns are
+; needed.
+ xor a
+ ld [wSymmetricSpriteOAMAttributes], a
+ lb de, 2, 2
+.loop
+ push de
+ push bc
+.innerLoop
+ ld a, b
+ ld [hli], a ; Y
+ ld a, c
+ ld [hli], a ; X
+ ld a, [wOAMBaseTile]
+ ld [hli], a ; tile
+ ld a, [wSymmetricSpriteOAMAttributes]
+ ld [hli], a ; attributes
+ xor (1 << OAM_X_FLIP)
+ ld [wSymmetricSpriteOAMAttributes], a
+ inc d
+ ld a, 8
+ add c
+ ld c, a
+ dec e
+ jr nz, .innerLoop
+ pop bc
+ pop de
+ push hl
+ ld hl, wOAMBaseTile
+ inc [hl]
+ inc [hl]
+ pop hl
+ ld a, 8
+ add b
+ ld b, a
+ dec d
+ jr nz, .loop
+ ret
+
+ZeroOutDuplicatesInList:
+; replace duplicate bytes in the list of wild pokemon locations with 0
+ ld de, wBuffer
+.loop
+ ld a, [de]
+ inc de
+ cp $ff
+ ret z
+ ld c, a
+ ld l, e
+ ld h, d
+.zeroDuplicatesLoop
+ ld a, [hl]
+ cp $ff
+ jr z, .loop
+ cp c
+ jr nz, .skipZeroing
+ xor a
+ ld [hl], a
+.skipZeroing
+ inc hl
+ jr .zeroDuplicatesLoop
+
+LoadTownMapEntry:
+; in: a = map number
+; out: lower nybble of [de] = x, upper nybble of [de] = y, hl = address of name
+ cp REDS_HOUSE_1F
+ jr c, .external
+ ld bc, 4
+ ld hl, InternalMapEntries
+.loop
+ cp [hl]
+ jr c, .foundEntry
+ add hl, bc
+ jr .loop
+.foundEntry
+ inc hl
+ jr .readEntry
+.external
+ ld hl, ExternalMapEntries
+ ld c, a
+ ld b, 0
+ add hl, bc
+ add hl, bc
+ add hl, bc
+.readEntry
+ ld a, [hli]
+ ld [de], a
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ret
+
+INCLUDE "data/town_map_entries.asm"
+
+INCLUDE "text/map_names.asm"
+
+MonNestIcon:
+ INCBIN "gfx/town_map/mon_nest_icon.1bpp"
+MonNestIconEnd:
+
+TownMapSpriteBlinkingAnimation::
+ ld a, [wAnimCounter]
+ inc a
+ cp 25
+ jr z, .hideSprites
+ cp 50
+ jr nz, .done
+; show sprites when the counter reaches 50
+ ld hl, wTileMapBackup
+ ld de, wOAMBuffer
+ ld bc, $90
+ call CopyData
+ xor a
+ jr .done
+.hideSprites
+ ld hl, wOAMBuffer
+ ld b, $24
+ ld de, $4
+.hideSpritesLoop
+ ld [hl], $a0
+ add hl, de
+ dec b
+ jr nz, .hideSpritesLoop
+ ld a, 25
+.done
+ ld [wAnimCounter], a
+ jp DelayFrame
--- a/engine/learn_move.asm
+++ /dev/null
@@ -1,226 +1,0 @@
-LearnMove:
- call SaveScreenTilesToBuffer1
- ld a, [wWhichPokemon]
- ld hl, wPartyMonNicks
- call GetPartyMonName
- ld hl, wcd6d
- ld de, wLearnMoveMonName
- ld bc, NAME_LENGTH
- call CopyData
-
-DontAbandonLearning:
- ld hl, wPartyMon1Moves
- ld bc, wPartyMon2Moves - wPartyMon1Moves
- ld a, [wWhichPokemon]
- call AddNTimes
- ld d, h
- ld e, l
- ld b, NUM_MOVES
-.findEmptyMoveSlotLoop
- ld a, [hl]
- and a
- jr z, .next
- inc hl
- dec b
- jr nz, .findEmptyMoveSlotLoop
- push de
- call TryingToLearn
- pop de
- jp c, AbandonLearning
- push hl
- push de
- ld [wd11e], a
- call GetMoveName
- ld hl, OneTwoAndText
- call PrintText
- pop de
- pop hl
-.next
- ld a, [wMoveNum]
- ld [hl], a
- ld bc, wPartyMon1PP - wPartyMon1Moves
- add hl, bc
- push hl
- push de
- dec a
- ld hl, Moves
- ld bc, MoveEnd - Moves
- call AddNTimes
- ld de, wBuffer
- ld a, BANK(Moves)
- call FarCopyData
- ld a, [wBuffer + 5] ; a = move's max PP
- pop de
- pop hl
- ld [hl], a
- ld a, [wIsInBattle]
- and a
- jp z, PrintLearnedMove
- ld a, [wWhichPokemon]
- ld b, a
- ld a, [wPlayerMonNumber]
- cp b
- jp nz, PrintLearnedMove
- ld h, d
- ld l, e
- ld de, wBattleMonMoves
- ld bc, NUM_MOVES
- call CopyData
- ld bc, wPartyMon1PP - wPartyMon1OTID
- add hl, bc
- ld de, wBattleMonPP
- ld bc, NUM_MOVES
- call CopyData
- jp PrintLearnedMove
-
-AbandonLearning:
- ld hl, AbandonLearningText
- call PrintText
- coord hl, 14, 7
- lb bc, 8, 15
- ld a, TWO_OPTION_MENU
- ld [wTextBoxID], a
- call DisplayTextBoxID ; yes/no menu
- ld a, [wCurrentMenuItem]
- and a
- jp nz, DontAbandonLearning
- ld hl, DidNotLearnText
- call PrintText
- ld b, 0
- ret
-
-PrintLearnedMove:
- ld hl, LearnedMove1Text
- call PrintText
- ld b, 1
- ret
-
-TryingToLearn:
- push hl
- ld hl, TryingToLearnText
- call PrintText
- coord hl, 14, 7
- lb bc, 8, 15
- ld a, TWO_OPTION_MENU
- ld [wTextBoxID], a
- call DisplayTextBoxID ; yes/no menu
- pop hl
- ld a, [wCurrentMenuItem]
- rra
- ret c
- ld bc, -NUM_MOVES
- add hl, bc
- push hl
- ld de, wMoves
- ld bc, NUM_MOVES
- call CopyData
- callab FormatMovesString
- pop hl
-.loop
- push hl
- ld hl, WhichMoveToForgetText
- call PrintText
- coord hl, 4, 7
- ld b, 4
- ld c, 14
- call TextBoxBorder
- coord hl, 6, 8
- ld de, wMovesString
- ld a, [hFlags_0xFFF6]
- set 2, a
- ld [hFlags_0xFFF6], a
- call PlaceString
- ld a, [hFlags_0xFFF6]
- res 2, a
- ld [hFlags_0xFFF6], a
- ld hl, wTopMenuItemY
- ld a, 8
- ld [hli], a ; wTopMenuItemY
- ld a, 5
- ld [hli], a ; wTopMenuItemX
- xor a
- ld [hli], a ; wCurrentMenuItem
- inc hl
- ld a, [wNumMovesMinusOne]
- ld [hli], a ; wMaxMenuItem
- ld a, A_BUTTON | B_BUTTON
- ld [hli], a ; wMenuWatchedKeys
- ld [hl], 0 ; wLastMenuItem
- ld hl, hFlags_0xFFF6
- set 1, [hl]
- call HandleMenuInput
- ld hl, hFlags_0xFFF6
- res 1, [hl]
- push af
- call LoadScreenTilesFromBuffer1
- pop af
- pop hl
- bit 1, a ; pressed b
- jr nz, .cancel
- push hl
- ld a, [wCurrentMenuItem]
- ld c, a
- ld b, 0
- add hl, bc
- ld a, [hl]
- push af
- push bc
- call IsMoveHM
- pop bc
- pop de
- ld a, d
- jr c, .hm
- pop hl
- add hl, bc
- and a
- ret
-.hm
- ld hl, HMCantDeleteText
- call PrintText
- pop hl
- jr .loop
-.cancel
- scf
- ret
-
-LearnedMove1Text:
- TX_FAR _LearnedMove1Text
- TX_SFX_ITEM_1 ; plays SFX_GET_ITEM_1 in the party menu (rare candy) and plays SFX_LEVEL_UP in battle
- TX_BLINK
- db "@"
-
-WhichMoveToForgetText:
- TX_FAR _WhichMoveToForgetText
- db "@"
-
-AbandonLearningText:
- TX_FAR _AbandonLearningText
- db "@"
-
-DidNotLearnText:
- TX_FAR _DidNotLearnText
- db "@"
-
-TryingToLearnText:
- TX_FAR _TryingToLearnText
- db "@"
-
-OneTwoAndText:
- TX_FAR _OneTwoAndText
- TX_DELAY
- TX_ASM
- ld a, SFX_SWAP
- call PlaySoundWaitForCurrent
- ld hl, PoofText
- ret
-
-PoofText:
- TX_FAR _PoofText
- TX_DELAY
-ForgotAndText:
- TX_FAR _ForgotAndText
- db "@"
-
-HMCantDeleteText:
- TX_FAR _HMCantDeleteText
- db "@"
--- /dev/null
+++ b/engine/link/cable_club.asm
@@ -1,0 +1,977 @@
+; performs the appropriate action when the player uses the gameboy on the table in the Colosseum or Trade Center
+; In the Colosseum, it starts a battle. In the Trade Center, it displays the trade selection screen.
+; Before doing either action, it swaps random numbers, trainer names and party data with the other gameboy.
+CableClub_DoBattleOrTrade:
+ ld c, 80
+ call DelayFrames
+ call ClearScreen
+ call UpdateSprites
+ call LoadFontTilePatterns
+ call LoadHpBarAndStatusTilePatterns
+ call LoadTrainerInfoTextBoxTiles
+ coord hl, 3, 8
+ ld b, 2
+ ld c, 12
+ call CableClub_TextBoxBorder
+ coord hl, 4, 10
+ ld de, PleaseWaitString
+ call PlaceString
+ ld hl, wPlayerNumHits
+ xor a
+ ld [hli], a
+ ld [hl], $50
+ ; fall through
+
+; This is called after completing a trade.
+CableClub_DoBattleOrTradeAgain:
+ ld hl, wSerialPlayerDataBlock
+ ld a, SERIAL_PREAMBLE_BYTE
+ ld b, 6
+.writePlayerDataBlockPreambleLoop
+ ld [hli], a
+ dec b
+ jr nz, .writePlayerDataBlockPreambleLoop
+ ld hl, wSerialRandomNumberListBlock
+ ld a, SERIAL_PREAMBLE_BYTE
+ ld b, 7
+.writeRandomNumberListPreambleLoop
+ ld [hli], a
+ dec b
+ jr nz, .writeRandomNumberListPreambleLoop
+ ld b, 10
+.generateRandomNumberListLoop
+ call Random
+ cp SERIAL_PREAMBLE_BYTE ; all the random numbers have to be less than the preamble byte
+ jr nc, .generateRandomNumberListLoop
+ ld [hli], a
+ dec b
+ jr nz, .generateRandomNumberListLoop
+ ld hl, wSerialPartyMonsPatchList
+ ld a, SERIAL_PREAMBLE_BYTE
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ ld b, $c8
+ xor a
+.zeroPlayerDataPatchListLoop
+ ld [hli], a
+ dec b
+ jr nz, .zeroPlayerDataPatchListLoop
+ ld hl, wGrassRate
+ ld bc, wTrainerHeaderPtr - wGrassRate
+.zeroEnemyPartyLoop
+ xor a
+ ld [hli], a
+ dec bc
+ ld a, b
+ or c
+ jr nz, .zeroEnemyPartyLoop
+ ld hl, wPartyMons - 1
+ ld de, wSerialPartyMonsPatchList + 10
+ ld bc, 0
+.patchPartyMonsLoop
+ inc c
+ ld a, c
+ cp SERIAL_PREAMBLE_BYTE
+ jr z, .startPatchListPart2
+ ld a, b
+ dec a ; are we in part 2 of the patch list?
+ jr nz, .checkPlayerDataByte ; jump if in part 1
+; if we're in part 2
+ ld a, c
+ cp (wPartyMonOT - (wPartyMons - 1)) - (SERIAL_PREAMBLE_BYTE - 1)
+ jr z, .finishedPatchingPlayerData
+.checkPlayerDataByte
+ inc hl
+ ld a, [hl]
+ cp SERIAL_NO_DATA_BYTE
+ jr nz, .patchPartyMonsLoop
+; if the player data byte matches SERIAL_NO_DATA_BYTE, patch it with $FF and record the offset in the patch list
+ ld a, c
+ ld [de], a
+ inc de
+ ld [hl], $ff
+ jr .patchPartyMonsLoop
+.startPatchListPart2
+ ld a, SERIAL_PATCH_LIST_PART_TERMINATOR
+ ld [de], a ; end of part 1
+ inc de
+ lb bc, 1, 0
+ jr .patchPartyMonsLoop
+.finishedPatchingPlayerData
+ ld a, SERIAL_PATCH_LIST_PART_TERMINATOR
+ ld [de], a ; end of part 2
+ call Serial_SyncAndExchangeNybble
+ ld a, [hSerialConnectionStatus]
+ cp USING_INTERNAL_CLOCK
+ jr nz, .skipSendingTwoZeroBytes
+; if using internal clock
+; send two zero bytes for syncing purposes?
+ call Delay3
+ xor a
+ ld [hSerialSendData], a
+ ld a, START_TRANSFER_INTERNAL_CLOCK
+ ld [rSC], a
+ call DelayFrame
+ xor a
+ ld [hSerialSendData], a
+ ld a, START_TRANSFER_INTERNAL_CLOCK
+ ld [rSC], a
+.skipSendingTwoZeroBytes
+ call Delay3
+ ld a, (1 << SERIAL)
+ ld [rIE], a
+ ld hl, wSerialRandomNumberListBlock
+ ld de, wSerialOtherGameboyRandomNumberListBlock
+ ld bc, $11
+ call Serial_ExchangeBytes
+ ld a, SERIAL_NO_DATA_BYTE
+ ld [de], a
+ ld hl, wSerialPlayerDataBlock
+ ld de, wSerialEnemyDataBlock
+ ld bc, $1a8
+ call Serial_ExchangeBytes
+ ld a, SERIAL_NO_DATA_BYTE
+ ld [de], a
+ ld hl, wSerialPartyMonsPatchList
+ ld de, wSerialEnemyMonsPatchList
+ ld bc, $c8
+ call Serial_ExchangeBytes
+ ld a, (1 << SERIAL) | (1 << TIMER) | (1 << VBLANK)
+ ld [rIE], a
+ ld a, $ff
+ call PlaySound
+ ld a, [hSerialConnectionStatus]
+ cp USING_INTERNAL_CLOCK
+ jr z, .skipCopyingRandomNumberList ; the list generated by the gameboy clocking the connection is used by both gameboys
+ ld hl, wSerialOtherGameboyRandomNumberListBlock
+.findStartOfRandomNumberListLoop
+ ld a, [hli]
+ and a
+ jr z, .findStartOfRandomNumberListLoop
+ cp SERIAL_PREAMBLE_BYTE
+ jr z, .findStartOfRandomNumberListLoop
+ cp SERIAL_NO_DATA_BYTE
+ jr z, .findStartOfRandomNumberListLoop
+ dec hl
+ ld de, wLinkBattleRandomNumberList
+ ld c, 10
+.copyRandomNumberListLoop
+ ld a, [hli]
+ cp SERIAL_NO_DATA_BYTE
+ jr z, .copyRandomNumberListLoop
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .copyRandomNumberListLoop
+.skipCopyingRandomNumberList
+ ld hl, wSerialEnemyDataBlock + 3
+.findStartOfEnemyNameLoop
+ ld a, [hli]
+ and a
+ jr z, .findStartOfEnemyNameLoop
+ cp SERIAL_PREAMBLE_BYTE
+ jr z, .findStartOfEnemyNameLoop
+ cp SERIAL_NO_DATA_BYTE
+ jr z, .findStartOfEnemyNameLoop
+ dec hl
+ ld de, wLinkEnemyTrainerName
+ ld c, NAME_LENGTH
+.copyEnemyNameLoop
+ ld a, [hli]
+ cp SERIAL_NO_DATA_BYTE
+ jr z, .copyEnemyNameLoop
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .copyEnemyNameLoop
+ ld de, wEnemyPartyCount
+ ld bc, wTrainerHeaderPtr - wEnemyPartyCount
+.copyEnemyPartyLoop
+ ld a, [hli]
+ cp SERIAL_NO_DATA_BYTE
+ jr z, .copyEnemyPartyLoop
+ ld [de], a
+ inc de
+ dec bc
+ ld a, b
+ or c
+ jr nz, .copyEnemyPartyLoop
+ ld de, wSerialPartyMonsPatchList
+ ld hl, wPartyMons
+ ld c, 2 ; patch list has 2 parts
+.unpatchPartyMonsLoop
+ ld a, [de]
+ inc de
+ and a
+ jr z, .unpatchPartyMonsLoop
+ cp SERIAL_PREAMBLE_BYTE
+ jr z, .unpatchPartyMonsLoop
+ cp SERIAL_NO_DATA_BYTE
+ jr z, .unpatchPartyMonsLoop
+ cp SERIAL_PATCH_LIST_PART_TERMINATOR
+ jr z, .finishedPartyMonsPatchListPart
+ push hl
+ push bc
+ ld b, 0
+ dec a
+ ld c, a
+ add hl, bc
+ ld a, SERIAL_NO_DATA_BYTE
+ ld [hl], a
+ pop bc
+ pop hl
+ jr .unpatchPartyMonsLoop
+.finishedPartyMonsPatchListPart
+ ld hl, wPartyMons + (SERIAL_PREAMBLE_BYTE - 1)
+ dec c ; is there another part?
+ jr nz, .unpatchPartyMonsLoop
+ ld de, wSerialEnemyMonsPatchList
+ ld hl, wEnemyMons
+ ld c, 2 ; patch list has 2 parts
+.unpatchEnemyMonsLoop
+ ld a, [de]
+ inc de
+ and a
+ jr z, .unpatchEnemyMonsLoop
+ cp SERIAL_PREAMBLE_BYTE
+ jr z, .unpatchEnemyMonsLoop
+ cp SERIAL_NO_DATA_BYTE
+ jr z, .unpatchEnemyMonsLoop
+ cp SERIAL_PATCH_LIST_PART_TERMINATOR
+ jr z, .finishedEnemyMonsPatchListPart
+ push hl
+ push bc
+ ld b, 0
+ dec a
+ ld c, a
+ add hl, bc
+ ld a, SERIAL_NO_DATA_BYTE
+ ld [hl], a
+ pop bc
+ pop hl
+ jr .unpatchEnemyMonsLoop
+.finishedEnemyMonsPatchListPart
+ ld hl, wEnemyMons + (SERIAL_PREAMBLE_BYTE - 1)
+ dec c
+ jr nz, .unpatchEnemyMonsLoop
+ ld a, wEnemyMonOT % $100
+ ld [wUnusedCF8D], a
+ ld a, wEnemyMonOT / $100
+ ld [wUnusedCF8D + 1], a
+ xor a
+ ld [wTradeCenterPointerTableIndex], a
+ ld a, $ff
+ call PlaySound
+ ld a, [hSerialConnectionStatus]
+ cp USING_INTERNAL_CLOCK
+ ld c, 66
+ call z, DelayFrames ; delay if using internal clock
+ ld a, [wLinkState]
+ cp LINK_STATE_START_BATTLE
+ ld a, LINK_STATE_TRADING
+ ld [wLinkState], a
+ jr nz, .trading
+ ld a, LINK_STATE_BATTLING
+ ld [wLinkState], a
+ ld a, OPP_SONY1
+ ld [wCurOpponent], a
+ call ClearScreen
+ call Delay3
+ ld hl, wOptions
+ res 7, [hl]
+ predef InitOpponent
+ predef HealParty
+ jp ReturnToCableClubRoom
+.trading
+ ld c, BANK(Music_GameCorner)
+ ld a, MUSIC_GAME_CORNER
+ call PlayMusic
+ jr CallCurrentTradeCenterFunction
+
+PleaseWaitString:
+ db "PLEASE WAIT!@"
+
+CallCurrentTradeCenterFunction:
+ ld hl, TradeCenterPointerTable
+ ld b, 0
+ ld a, [wTradeCenterPointerTableIndex]
+ cp $ff
+ jp z, DisplayTitleScreen
+ add a
+ ld c, a
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+TradeCenter_SelectMon:
+ call ClearScreen
+ call LoadTrainerInfoTextBoxTiles
+ call TradeCenter_DrawPartyLists
+ call TradeCenter_DrawCancelBox
+ xor a
+ ld hl, wSerialSyncAndExchangeNybbleReceiveData
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+ ld [wMenuWatchMovingOutOfBounds], a
+ ld [wCurrentMenuItem], a
+ ld [wLastMenuItem], a
+ ld [wMenuJoypadPollCount], a
+ inc a
+ ld [wSerialExchangeNybbleSendData], a
+ jp .playerMonMenu
+.enemyMonMenu
+ xor a
+ ld [wMenuWatchMovingOutOfBounds], a
+ inc a
+ ld [wWhichTradeMonSelectionMenu], a
+ ld a, D_DOWN | D_LEFT | A_BUTTON
+ ld [wMenuWatchedKeys], a
+ ld a, [wEnemyPartyCount]
+ ld [wMaxMenuItem], a
+ ld a, 9
+ ld [wTopMenuItemY], a
+ ld a, 1
+ ld [wTopMenuItemX], a
+.enemyMonMenu_HandleInput
+ ld hl, hFlags_0xFFF6
+ set 1, [hl]
+ call HandleMenuInput
+ ld hl, hFlags_0xFFF6
+ res 1, [hl]
+ and a
+ jp z, .getNewInput
+ bit 0, a ; A button pressed?
+ jr z, .enemyMonMenu_ANotPressed
+; if A button pressed
+ ld a, [wMaxMenuItem]
+ ld c, a
+ ld a, [wCurrentMenuItem]
+ cp c
+ jr c, .displayEnemyMonStats
+ ld a, [wMaxMenuItem]
+ dec a
+ ld [wCurrentMenuItem], a
+.displayEnemyMonStats
+ ld a, INIT_ENEMYOT_LIST
+ ld [wInitListType], a
+ callab InitList ; the list isn't used
+ ld hl, wEnemyMons
+ call TradeCenter_DisplayStats
+ jp .getNewInput
+.enemyMonMenu_ANotPressed
+ bit 5, a ; Left pressed?
+ jr z, .enemyMonMenu_LeftNotPressed
+; if Left pressed, switch back to the player mon menu
+ xor a ; player mon menu
+ ld [wWhichTradeMonSelectionMenu], a
+ ld a, [wMenuCursorLocation]
+ ld l, a
+ ld a, [wMenuCursorLocation + 1]
+ ld h, a
+ ld a, [wTileBehindCursor]
+ ld [hl], a
+ ld a, [wCurrentMenuItem]
+ ld b, a
+ ld a, [wPartyCount]
+ dec a
+ cp b
+ jr nc, .playerMonMenu
+ ld [wCurrentMenuItem], a
+ jr .playerMonMenu
+.enemyMonMenu_LeftNotPressed
+ bit 7, a ; Down pressed?
+ jp z, .getNewInput
+ jp .selectedCancelMenuItem ; jump if Down pressed
+.playerMonMenu
+ xor a ; player mon menu
+ ld [wWhichTradeMonSelectionMenu], a
+ ld [wMenuWatchMovingOutOfBounds], a
+ ld a, D_DOWN | D_RIGHT | A_BUTTON
+ ld [wMenuWatchedKeys], a
+ ld a, [wPartyCount]
+ ld [wMaxMenuItem], a
+ ld a, 1
+ ld [wTopMenuItemY], a
+ ld a, 1
+ ld [wTopMenuItemX], a
+ coord hl, 1, 1
+ lb bc, 6, 1
+ call ClearScreenArea
+.playerMonMenu_HandleInput
+ ld hl, hFlags_0xFFF6
+ set 1, [hl]
+ call HandleMenuInput
+ ld hl, hFlags_0xFFF6
+ res 1, [hl]
+ and a ; was anything pressed?
+ jr nz, .playerMonMenu_SomethingPressed
+ jp .getNewInput
+.playerMonMenu_SomethingPressed
+ bit 0, a ; A button pressed?
+ jr z, .playerMonMenu_ANotPressed
+ jp .chosePlayerMon ; jump if A button pressed
+; unreachable code
+ ld a, INIT_PLAYEROT_LIST
+ ld [wInitListType], a
+ callab InitList ; the list isn't used
+ call TradeCenter_DisplayStats
+ jp .getNewInput
+.playerMonMenu_ANotPressed
+ bit 4, a ; Right pressed?
+ jr z, .playerMonMenu_RightNotPressed
+; if Right pressed, switch to the enemy mon menu
+ ld a, $1 ; enemy mon menu
+ ld [wWhichTradeMonSelectionMenu], a
+ ld a, [wMenuCursorLocation]
+ ld l, a
+ ld a, [wMenuCursorLocation + 1]
+ ld h, a
+ ld a, [wTileBehindCursor]
+ ld [hl], a
+ ld a, [wCurrentMenuItem]
+ ld b, a
+ ld a, [wEnemyPartyCount]
+ dec a
+ cp b
+ jr nc, .notPastLastEnemyMon
+; when switching to the enemy mon menu, if the menu selection would be past the last enemy mon, select the last enemy mon
+ ld [wCurrentMenuItem], a
+.notPastLastEnemyMon
+ jp .enemyMonMenu
+.playerMonMenu_RightNotPressed
+ bit 7, a ; Down pressed?
+ jr z, .getNewInput
+ jp .selectedCancelMenuItem ; jump if Down pressed
+.getNewInput
+ ld a, [wWhichTradeMonSelectionMenu]
+ and a
+ jp z, .playerMonMenu_HandleInput
+ jp .enemyMonMenu_HandleInput
+.chosePlayerMon
+ call SaveScreenTilesToBuffer1
+ call PlaceUnfilledArrowMenuCursor
+ ld a, [wMaxMenuItem]
+ ld c, a
+ ld a, [wCurrentMenuItem]
+ cp c
+ jr c, .displayStatsTradeMenu
+ ld a, [wMaxMenuItem]
+ dec a
+.displayStatsTradeMenu
+ push af
+ coord hl, 0, 14
+ ld b, 2
+ ld c, 18
+ call CableClub_TextBoxBorder
+ coord hl, 2, 16
+ ld de, .statsTrade
+ call PlaceString
+ xor a
+ ld [wCurrentMenuItem], a
+ ld [wLastMenuItem], a
+ ld [wMenuJoypadPollCount], a
+ ld [wMaxMenuItem], a
+ ld a, 16
+ ld [wTopMenuItemY], a
+.selectStatsMenuItem
+ ld a, " "
+ Coorda 11, 16
+ ld a, D_RIGHT | B_BUTTON | A_BUTTON
+ ld [wMenuWatchedKeys], a
+ ld a, 1
+ ld [wTopMenuItemX], a
+ call HandleMenuInput
+ bit 4, a ; Right pressed?
+ jr nz, .selectTradeMenuItem
+ bit 1, a ; B button pressed?
+ jr z, .displayPlayerMonStats
+.cancelPlayerMonChoice
+ pop af
+ ld [wCurrentMenuItem], a
+ call LoadScreenTilesFromBuffer1
+ jp .playerMonMenu
+.selectTradeMenuItem
+ ld a, " "
+ Coorda 1, 16
+ ld a, D_LEFT | B_BUTTON | A_BUTTON
+ ld [wMenuWatchedKeys], a
+ ld a, 11
+ ld [wTopMenuItemX], a
+ call HandleMenuInput
+ bit 5, a ; Left pressed?
+ jr nz, .selectStatsMenuItem
+ bit 1, a ; B button pressed?
+ jr nz, .cancelPlayerMonChoice
+ jr .choseTrade
+.displayPlayerMonStats
+ pop af
+ ld [wCurrentMenuItem], a
+ ld a, INIT_PLAYEROT_LIST
+ ld [wInitListType], a
+ callab InitList ; the list isn't used
+ call TradeCenter_DisplayStats
+ call LoadScreenTilesFromBuffer1
+ jp .playerMonMenu
+.choseTrade
+ call PlaceUnfilledArrowMenuCursor
+ pop af
+ ld [wCurrentMenuItem], a
+ ld [wTradingWhichPlayerMon], a
+ ld [wSerialExchangeNybbleSendData], a
+ call Serial_PrintWaitingTextAndSyncAndExchangeNybble
+ ld a, [wSerialSyncAndExchangeNybbleReceiveData]
+ cp $f
+ jp z, CallCurrentTradeCenterFunction ; go back to the beginning of the trade selection menu if the other person cancelled
+ ld [wTradingWhichEnemyMon], a
+ call TradeCenter_PlaceSelectedEnemyMonMenuCursor
+ ld a, $1 ; TradeCenter_Trade
+ ld [wTradeCenterPointerTableIndex], a
+ jp CallCurrentTradeCenterFunction
+.statsTrade
+ db "STATS TRADE@"
+.selectedCancelMenuItem
+ ld a, [wCurrentMenuItem]
+ ld b, a
+ ld a, [wMaxMenuItem]
+ cp b
+ jp nz, .getNewInput
+ ld a, [wMenuCursorLocation]
+ ld l, a
+ ld a, [wMenuCursorLocation + 1]
+ ld h, a
+ ld a, " "
+ ld [hl], a
+.cancelMenuItem_Loop
+ ld a, "▶" ; filled arrow cursor
+ Coorda 1, 16
+.cancelMenuItem_JoypadLoop
+ call JoypadLowSensitivity
+ ld a, [hJoy5]
+ and a ; pressed anything?
+ jr z, .cancelMenuItem_JoypadLoop
+ bit 0, a ; A button pressed?
+ jr nz, .cancelMenuItem_APressed
+ bit 6, a ; Up pressed?
+ jr z, .cancelMenuItem_JoypadLoop
+; if Up pressed
+ ld a, " "
+ Coorda 1, 16
+ ld a, [wPartyCount]
+ dec a
+ ld [wCurrentMenuItem], a
+ jp .playerMonMenu
+.cancelMenuItem_APressed
+ ld a, "▷" ; unfilled arrow cursor
+ Coorda 1, 16
+ ld a, $f
+ ld [wSerialExchangeNybbleSendData], a
+ call Serial_PrintWaitingTextAndSyncAndExchangeNybble
+ ld a, [wSerialSyncAndExchangeNybbleReceiveData]
+ cp $f ; did the other person choose Cancel too?
+ jr nz, .cancelMenuItem_Loop
+ ; fall through
+
+ReturnToCableClubRoom:
+ call GBPalWhiteOutWithDelay3
+ ld hl, wFontLoaded
+ ld a, [hl]
+ push af
+ push hl
+ res 0, [hl]
+ xor a
+ ld [wd72d], a
+ dec a
+ ld [wDestinationWarpID], a
+ call LoadMapData
+ callba ClearVariablesOnEnterMap
+ pop hl
+ pop af
+ ld [hl], a
+ call GBFadeInFromWhite
+ ret
+
+TradeCenter_DrawCancelBox:
+ coord hl, 11, 15
+ ld a, $7e
+ ld bc, 2 * SCREEN_WIDTH + 9
+ call FillMemory
+ coord hl, 0, 15
+ ld b, 1
+ ld c, 9
+ call CableClub_TextBoxBorder
+ coord hl, 2, 16
+ ld de, CancelTextString
+ jp PlaceString
+
+CancelTextString:
+ db "CANCEL@"
+
+TradeCenter_PlaceSelectedEnemyMonMenuCursor:
+ ld a, [wSerialSyncAndExchangeNybbleReceiveData]
+ coord hl, 1, 9
+ ld bc, SCREEN_WIDTH
+ call AddNTimes
+ ld [hl], "▷" ; cursor
+ ret
+
+TradeCenter_DisplayStats:
+ ld a, [wCurrentMenuItem]
+ ld [wWhichPokemon], a
+ predef StatusScreen
+ predef StatusScreen2
+ call GBPalNormal
+ call LoadTrainerInfoTextBoxTiles
+ call TradeCenter_DrawPartyLists
+ jp TradeCenter_DrawCancelBox
+
+TradeCenter_DrawPartyLists:
+ coord hl, 0, 0
+ ld b, 6
+ ld c, 18
+ call CableClub_TextBoxBorder
+ coord hl, 0, 8
+ ld b, 6
+ ld c, 18
+ call CableClub_TextBoxBorder
+ coord hl, 5, 0
+ ld de, wPlayerName
+ call PlaceString
+ coord hl, 5, 8
+ ld de, wLinkEnemyTrainerName
+ call PlaceString
+ coord hl, 2, 1
+ ld de, wPartySpecies
+ call TradeCenter_PrintPartyListNames
+ coord hl, 2, 9
+ ld de, wEnemyPartyMons
+ ; fall through
+
+TradeCenter_PrintPartyListNames:
+ ld c, $0
+.loop
+ ld a, [de]
+ cp $ff
+ ret z
+ ld [wd11e], a
+ push bc
+ push hl
+ push de
+ push hl
+ ld a, c
+ ld [$ff95], a
+ call GetMonName
+ pop hl
+ call PlaceString
+ pop de
+ inc de
+ pop hl
+ ld bc, 20
+ add hl, bc
+ pop bc
+ inc c
+ jr .loop
+
+TradeCenter_Trade:
+ ld c, 100
+ call DelayFrames
+ xor a
+ ld [wSerialExchangeNybbleSendData + 1], a ; unnecessary
+ ld [wSerialExchangeNybbleReceiveData], a
+ ld [wMenuWatchMovingOutOfBounds], a
+ ld [wMenuJoypadPollCount], a
+ coord hl, 0, 12
+ ld b, 4
+ ld c, 18
+ call CableClub_TextBoxBorder
+ ld a, [wTradingWhichPlayerMon]
+ ld hl, wPartySpecies
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hl]
+ ld [wd11e], a
+ call GetMonName
+ ld hl, wcd6d
+ ld de, wNameOfPlayerMonToBeTraded
+ ld bc, NAME_LENGTH
+ call CopyData
+ ld a, [wTradingWhichEnemyMon]
+ ld hl, wEnemyPartyMons
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hl]
+ ld [wd11e], a
+ call GetMonName
+ ld hl, WillBeTradedText
+ coord bc, 1, 14
+ call TextCommandProcessor
+ call SaveScreenTilesToBuffer1
+ coord hl, 10, 7
+ lb bc, 8, 11
+ ld a, TRADE_CANCEL_MENU
+ ld [wTwoOptionMenuID], a
+ ld a, TWO_OPTION_MENU
+ ld [wTextBoxID], a
+ call DisplayTextBoxID
+ call LoadScreenTilesFromBuffer1
+ ld a, [wCurrentMenuItem]
+ and a
+ jr z, .tradeConfirmed
+; if trade cancelled
+ ld a, $1
+ ld [wSerialExchangeNybbleSendData], a
+ coord hl, 0, 12
+ ld b, 4
+ ld c, 18
+ call CableClub_TextBoxBorder
+ coord hl, 1, 14
+ ld de, TradeCanceled
+ call PlaceString
+ call Serial_PrintWaitingTextAndSyncAndExchangeNybble
+ jp .tradeCancelled
+.tradeConfirmed
+ ld a, $2
+ ld [wSerialExchangeNybbleSendData], a
+ call Serial_PrintWaitingTextAndSyncAndExchangeNybble
+ ld a, [wSerialSyncAndExchangeNybbleReceiveData]
+ dec a ; did the other person cancel?
+ jr nz, .doTrade
+; if the other person cancelled
+ coord hl, 0, 12
+ ld b, 4
+ ld c, 18
+ call CableClub_TextBoxBorder
+ coord hl, 1, 14
+ ld de, TradeCanceled
+ call PlaceString
+ jp .tradeCancelled
+.doTrade
+ ld a, [wTradingWhichPlayerMon]
+ ld hl, wPartyMonOT
+ call SkipFixedLengthTextEntries
+ ld de, wTradedPlayerMonOT
+ ld bc, NAME_LENGTH
+ call CopyData
+ ld hl, wPartyMon1Species
+ ld a, [wTradingWhichPlayerMon]
+ ld bc, wPartyMon2 - wPartyMon1
+ call AddNTimes
+ ld bc, wPartyMon1OTID - wPartyMon1
+ add hl, bc
+ ld a, [hli]
+ ld [wTradedPlayerMonOTID], a
+ ld a, [hl]
+ ld [wTradedPlayerMonOTID + 1], a
+ ld a, [wTradingWhichEnemyMon]
+ ld hl, wEnemyMonOT
+ call SkipFixedLengthTextEntries
+ ld de, wTradedEnemyMonOT
+ ld bc, NAME_LENGTH
+ call CopyData
+ ld hl, wEnemyMons
+ ld a, [wTradingWhichEnemyMon]
+ ld bc, wEnemyMon2 - wEnemyMon1
+ call AddNTimes
+ ld bc, wEnemyMon1OTID - wEnemyMon1
+ add hl, bc
+ ld a, [hli]
+ ld [wTradedEnemyMonOTID], a
+ ld a, [hl]
+ ld [wTradedEnemyMonOTID + 1], a
+ ld a, [wTradingWhichPlayerMon]
+ ld [wWhichPokemon], a
+ ld hl, wPartySpecies
+ ld b, 0
+ ld c, a
+ add hl, bc
+ ld a, [hl]
+ ld [wTradedPlayerMonSpecies], a
+ xor a
+ ld [wRemoveMonFromBox], a
+ call RemovePokemon
+ ld a, [wTradingWhichEnemyMon]
+ ld c, a
+ ld [wWhichPokemon], a
+ ld hl, wEnemyPartyMons
+ ld d, 0
+ ld e, a
+ add hl, de
+ ld a, [hl]
+ ld [wcf91], a
+ ld hl, wEnemyMons
+ ld a, c
+ ld bc, wEnemyMon2 - wEnemyMon1
+ call AddNTimes
+ ld de, wLoadedMon
+ ld bc, wEnemyMon2 - wEnemyMon1
+ call CopyData
+ call AddEnemyMonToPlayerParty
+ ld a, [wPartyCount]
+ dec a
+ ld [wWhichPokemon], a
+ ld a, $1
+ ld [wForceEvolution], a
+ ld a, [wTradingWhichEnemyMon]
+ ld hl, wEnemyPartyMons
+ ld b, 0
+ ld c, a
+ add hl, bc
+ ld a, [hl]
+ ld [wTradedEnemyMonSpecies], a
+ ld a, 10
+ ld [wAudioFadeOutControl], a
+ ld a, BANK(Music_SafariZone)
+ ld [wAudioSavedROMBank], a
+ ld a, MUSIC_SAFARI_ZONE
+ ld [wNewSoundID], a
+ call PlaySound
+ ld c, 100
+ call DelayFrames
+ call ClearScreen
+ call LoadHpBarAndStatusTilePatterns
+ xor a
+ ld [wUnusedCC5B], a
+ ld a, [hSerialConnectionStatus]
+ cp USING_EXTERNAL_CLOCK
+ jr z, .usingExternalClock
+ predef InternalClockTradeAnim
+ jr .tradeCompleted
+.usingExternalClock
+ predef ExternalClockTradeAnim
+.tradeCompleted
+ callab TryEvolvingMon
+ call ClearScreen
+ call LoadTrainerInfoTextBoxTiles
+ call Serial_PrintWaitingTextAndSyncAndExchangeNybble
+ ld c, 40
+ call DelayFrames
+ coord hl, 0, 12
+ ld b, 4
+ ld c, 18
+ call CableClub_TextBoxBorder
+ coord hl, 1, 14
+ ld de, TradeCompleted
+ call PlaceString
+ predef SaveSAVtoSRAM2
+ ld c, 50
+ call DelayFrames
+ xor a
+ ld [wTradeCenterPointerTableIndex], a
+ jp CableClub_DoBattleOrTradeAgain
+.tradeCancelled
+ ld c, 100
+ call DelayFrames
+ xor a ; TradeCenter_SelectMon
+ ld [wTradeCenterPointerTableIndex], a
+ jp CallCurrentTradeCenterFunction
+
+WillBeTradedText:
+ TX_FAR _WillBeTradedText
+ db "@"
+
+TradeCompleted:
+ db "Trade completed!@"
+
+TradeCanceled:
+ db "Too bad! The trade"
+ next "was canceled!@"
+
+TradeCenterPointerTable:
+ dw TradeCenter_SelectMon
+ dw TradeCenter_Trade
+
+CableClub_Run:
+ ld a, [wLinkState]
+ cp LINK_STATE_START_TRADE
+ jr z, .doBattleOrTrade
+ cp LINK_STATE_START_BATTLE
+ jr z, .doBattleOrTrade
+ cp LINK_STATE_RESET ; this is never used
+ ret nz
+ predef EmptyFunc3
+ jp Init
+.doBattleOrTrade
+ call CableClub_DoBattleOrTrade
+ ld hl, Club_GFX
+ ld a, h
+ ld [wTilesetGfxPtr + 1], a
+ ld a, l
+ ld [wTilesetGfxPtr], a
+ ld a, Bank(Club_GFX)
+ ld [wTilesetBank], a
+ ld hl, Club_Coll
+ ld a, h
+ ld [wTilesetCollisionPtr + 1], a
+ ld a, l
+ ld [wTilesetCollisionPtr], a
+ xor a
+ ld [wGrassRate], a
+ inc a ; LINK_STATE_IN_CABLE_CLUB
+ ld [wLinkState], a
+ ld [hJoy5], a
+ ld a, 10
+ ld [wAudioFadeOutControl], a
+ ld a, BANK(Music_Celadon)
+ ld [wAudioSavedROMBank], a
+ ld a, MUSIC_CELADON
+ ld [wNewSoundID], a
+ jp PlaySound
+
+EmptyFunc3:
+ ret
+
+Diploma_TextBoxBorder:
+ call GetPredefRegisters
+
+; b = height
+; c = width
+CableClub_TextBoxBorder:
+ push hl
+ ld a, $78 ; border upper left corner tile
+ ld [hli], a
+ inc a ; border top horizontal line tile
+ call CableClub_DrawHorizontalLine
+ inc a ; border upper right corner tile
+ ld [hl], a
+ pop hl
+ ld de, 20
+ add hl, de
+.loop
+ push hl
+ ld a, $7b ; border left vertical line tile
+ ld [hli], a
+ ld a, " "
+ call CableClub_DrawHorizontalLine
+ ld [hl], $77 ; border right vertical line tile
+ pop hl
+ ld de, 20
+ add hl, de
+ dec b
+ jr nz, .loop
+ ld a, $7c ; border lower left corner tile
+ ld [hli], a
+ ld a, $76 ; border bottom horizontal line tile
+ call CableClub_DrawHorizontalLine
+ ld [hl], $7d ; border lower right corner tile
+ ret
+
+; c = width
+CableClub_DrawHorizontalLine:
+ ld d, c
+.loop
+ ld [hli], a
+ dec d
+ jr nz, .loop
+ ret
+
+LoadTrainerInfoTextBoxTiles:
+ ld de, TrainerInfoTextBoxTileGraphics
+ ld hl, vChars2 + $760
+ lb bc, BANK(TrainerInfoTextBoxTileGraphics), (TrainerInfoTextBoxTileGraphicsEnd - TrainerInfoTextBoxTileGraphics) / $10
+ jp CopyVideoData
--- /dev/null
+++ b/engine/link/cable_club_npc.asm
@@ -1,0 +1,151 @@
+CableClubNPC::
+ ld hl, CableClubNPCWelcomeText
+ call PrintText
+ CheckEvent EVENT_GOT_POKEDEX
+ jp nz, .receivedPokedex
+; if the player hasn't received the pokedex
+ ld c, 60
+ call DelayFrames
+ ld hl, CableClubNPCMakingPreparationsText
+ call PrintText
+ jp .didNotConnect
+.receivedPokedex
+ ld a, $1
+ ld [wMenuJoypadPollCount], a
+ ld a, 90
+ ld [wLinkTimeoutCounter], a
+.establishConnectionLoop
+ ld a, [hSerialConnectionStatus]
+ cp USING_INTERNAL_CLOCK
+ jr z, .establishedConnection
+ cp USING_EXTERNAL_CLOCK
+ jr z, .establishedConnection
+ ld a, CONNECTION_NOT_ESTABLISHED
+ ld [hSerialConnectionStatus], a
+ ld a, ESTABLISH_CONNECTION_WITH_EXTERNAL_CLOCK
+ ld [rSB], a
+ xor a
+ ld [hSerialReceiveData], a
+ ld a, START_TRANSFER_EXTERNAL_CLOCK
+ ld [rSC], a
+ ld a, [wLinkTimeoutCounter]
+ dec a
+ ld [wLinkTimeoutCounter], a
+ jr z, .failedToEstablishConnection
+ ld a, ESTABLISH_CONNECTION_WITH_INTERNAL_CLOCK
+ ld [rSB], a
+ ld a, START_TRANSFER_INTERNAL_CLOCK
+ ld [rSC], a
+ call DelayFrame
+ jr .establishConnectionLoop
+.establishedConnection
+ call Serial_SendZeroByte
+ call DelayFrame
+ call Serial_SendZeroByte
+ ld c, 50
+ call DelayFrames
+ ld hl, CableClubNPCPleaseApplyHereHaveToSaveText
+ call PrintText
+ xor a
+ ld [wMenuJoypadPollCount], a
+ call YesNoChoice
+ ld a, $1
+ ld [wMenuJoypadPollCount], a
+ ld a, [wCurrentMenuItem]
+ and a
+ jr nz, .choseNo
+ callab SaveSAVtoSRAM
+ call WaitForSoundToFinish
+ ld a, SFX_SAVE
+ call PlaySoundWaitForCurrent
+ ld hl, CableClubNPCPleaseWaitText
+ call PrintText
+ ld hl, wUnknownSerialCounter
+ ld a, $3
+ ld [hli], a
+ xor a
+ ld [hl], a
+ ld [hSerialReceivedNewData], a
+ ld [wSerialExchangeNybbleSendData], a
+ call Serial_SyncAndExchangeNybble
+ ld hl, wUnknownSerialCounter
+ ld a, [hli]
+ inc a
+ jr nz, .connected
+ ld a, [hl]
+ inc a
+ jr nz, .connected
+ ld b, 10
+.syncLoop
+ call DelayFrame
+ call Serial_SendZeroByte
+ dec b
+ jr nz, .syncLoop
+ call CloseLinkConnection
+ ld hl, CableClubNPCLinkClosedBecauseOfInactivityText
+ call PrintText
+ jr .didNotConnect
+.failedToEstablishConnection
+ ld hl, CableClubNPCAreaReservedFor2FriendsLinkedByCableText
+ call PrintText
+ jr .didNotConnect
+.choseNo
+ call CloseLinkConnection
+ ld hl, CableClubNPCPleaseComeAgainText
+ call PrintText
+.didNotConnect
+ xor a
+ ld hl, wUnknownSerialCounter
+ ld [hli], a
+ ld [hl], a
+ ld hl, wd72e
+ res 6, [hl]
+ xor a
+ ld [wMenuJoypadPollCount], a
+ ret
+.connected
+ xor a
+ ld [hld], a
+ ld [hl], a
+ jpab LinkMenu
+
+CableClubNPCAreaReservedFor2FriendsLinkedByCableText:
+ TX_FAR _CableClubNPCAreaReservedFor2FriendsLinkedByCableText
+ db "@"
+
+CableClubNPCWelcomeText:
+ TX_FAR _CableClubNPCWelcomeText
+ db "@"
+
+CableClubNPCPleaseApplyHereHaveToSaveText:
+ TX_FAR _CableClubNPCPleaseApplyHereHaveToSaveText
+ db "@"
+
+CableClubNPCPleaseWaitText:
+ TX_FAR _CableClubNPCPleaseWaitText
+ TX_DELAY
+ db "@"
+
+CableClubNPCLinkClosedBecauseOfInactivityText:
+ TX_FAR _CableClubNPCLinkClosedBecauseOfInactivityText
+ db "@"
+
+CableClubNPCPleaseComeAgainText:
+ TX_FAR _CableClubNPCPleaseComeAgainText
+ db "@"
+
+CableClubNPCMakingPreparationsText:
+ TX_FAR _CableClubNPCMakingPreparationsText
+ db "@"
+
+CloseLinkConnection:
+ call Delay3
+ ld a, CONNECTION_NOT_ESTABLISHED
+ ld [hSerialConnectionStatus], a
+ ld a, ESTABLISH_CONNECTION_WITH_EXTERNAL_CLOCK
+ ld [rSB], a
+ xor a
+ ld [hSerialReceiveData], a
+ ld a, START_TRANSFER_EXTERNAL_CLOCK
+ ld [rSC], a
+ ret
--- /dev/null
+++ b/engine/link/print_waiting_text.asm
@@ -1,0 +1,20 @@
+PrintWaitingText::
+ coord hl, 3, 10
+ ld b, $1
+ ld c, $b
+ ld a, [wIsInBattle]
+ and a
+ jr z, .asm_4c17
+ call TextBoxBorder
+ jr .asm_4c1a
+.asm_4c17
+ call CableClub_TextBoxBorder
+.asm_4c1a
+ coord hl, 4, 11
+ ld de, WaitingText
+ call PlaceString
+ ld c, 50
+ jp DelayFrames
+
+WaitingText:
+ db "Waiting...!@"
--- a/engine/load_mon_data.asm
+++ /dev/null
@@ -1,49 +1,0 @@
-LoadMonData_::
-; Load monster [wWhichPokemon] from list [wMonDataLocation]:
-; 0: partymon
-; 1: enemymon
-; 2: boxmon
-; 3: daycaremon
-; Return monster id at wcf91 and its data at wLoadedMon.
-; Also load base stats at wMonHeader for convenience.
-
- ld a, [wDayCareMonSpecies]
- ld [wcf91], a
- ld a, [wMonDataLocation]
- cp DAYCARE_DATA
- jr z, .GetMonHeader
-
- ld a, [wWhichPokemon]
- ld e, a
- callab GetMonSpecies
-
-.GetMonHeader
- ld a, [wcf91]
- ld [wd0b5], a ; input for GetMonHeader
- call GetMonHeader
-
- ld hl, wPartyMons
- ld bc, wPartyMon2 - wPartyMon1
- ld a, [wMonDataLocation]
- cp ENEMY_PARTY_DATA
- jr c, .getMonEntry
-
- ld hl, wEnemyMons
- jr z, .getMonEntry
-
- cp 2
- ld hl, wBoxMons
- ld bc, wBoxMon2 - wBoxMon1
- jr z, .getMonEntry
-
- ld hl, wDayCareMon
- jr .copyMonData
-
-.getMonEntry
- ld a, [wWhichPokemon]
- call AddNTimes
-
-.copyMonData
- ld de, wLoadedMon
- ld bc, wPartyMon2 - wPartyMon1
- jp CopyData
--- a/engine/load_pokedex_tiles.asm
+++ /dev/null
@@ -1,11 +1,0 @@
-; Loads tile patterns for tiles used in the pokedex.
-LoadPokedexTilePatterns:
- call LoadHpBarAndStatusTilePatterns
- ld de, PokedexTileGraphics
- ld hl, vChars2 + $600
- lb bc, BANK(PokedexTileGraphics), (PokedexTileGraphicsEnd - PokedexTileGraphics) / $10
- call CopyVideoData
- ld de, PokeballTileGraphics
- ld hl, vChars2 + $720
- lb bc, BANK(PokeballTileGraphics), $01
- jp CopyVideoData ; load pokeball tile for marking caught mons
--- /dev/null
+++ b/engine/math/bcd.asm
@@ -1,0 +1,214 @@
+DivideBCDPredef::
+DivideBCDPredef2::
+DivideBCDPredef3::
+DivideBCDPredef4::
+ call GetPredefRegisters
+
+DivideBCD::
+ xor a
+ ld [hDivideBCDBuffer], a
+ ld [hDivideBCDBuffer+1], a
+ ld [hDivideBCDBuffer+2], a
+ ld d, $1
+.mulBy10Loop
+; multiply the divisor by 10 until the leading digit is nonzero
+; to set up the standard long division algorithm
+ ld a, [hDivideBCDDivisor]
+ and $f0
+ jr nz, .next
+ inc d
+ ld a, [hDivideBCDDivisor]
+ swap a
+ and $f0
+ ld b, a
+ ld a, [hDivideBCDDivisor+1]
+ swap a
+ ld [hDivideBCDDivisor+1], a
+ and $f
+ or b
+ ld [hDivideBCDDivisor], a
+ ld a, [hDivideBCDDivisor+1]
+ and $f0
+ ld b, a
+ ld a, [hDivideBCDDivisor+2]
+ swap a
+ ld [hDivideBCDDivisor+2], a
+ and $f
+ or b
+ ld [hDivideBCDDivisor+1], a
+ ld a, [hDivideBCDDivisor+2]
+ and $f0
+ ld [hDivideBCDDivisor+2], a
+ jr .mulBy10Loop
+.next
+ push de
+ push de
+ call DivideBCD_getNextDigit
+ pop de
+ ld a, b
+ swap a
+ and $f0
+ ld [hDivideBCDBuffer], a
+ dec d
+ jr z, .next2
+ push de
+ call DivideBCD_divDivisorBy10
+ call DivideBCD_getNextDigit
+ pop de
+ ld a, [hDivideBCDBuffer]
+ or b
+ ld [hDivideBCDBuffer], a
+ dec d
+ jr z, .next2
+ push de
+ call DivideBCD_divDivisorBy10
+ call DivideBCD_getNextDigit
+ pop de
+ ld a, b
+ swap a
+ and $f0
+ ld [hDivideBCDBuffer+1], a
+ dec d
+ jr z, .next2
+ push de
+ call DivideBCD_divDivisorBy10
+ call DivideBCD_getNextDigit
+ pop de
+ ld a, [hDivideBCDBuffer+1]
+ or b
+ ld [hDivideBCDBuffer+1], a
+ dec d
+ jr z, .next2
+ push de
+ call DivideBCD_divDivisorBy10
+ call DivideBCD_getNextDigit
+ pop de
+ ld a, b
+ swap a
+ and $f0
+ ld [hDivideBCDBuffer+2], a
+ dec d
+ jr z, .next2
+ push de
+ call DivideBCD_divDivisorBy10
+ call DivideBCD_getNextDigit
+ pop de
+ ld a, [hDivideBCDBuffer+2]
+ or b
+ ld [hDivideBCDBuffer+2], a
+.next2
+ ld a, [hDivideBCDBuffer]
+ ld [hDivideBCDQuotient], a ; the same memory location as hDivideBCDDivisor
+ ld a, [hDivideBCDBuffer+1]
+ ld [hDivideBCDQuotient+1], a
+ ld a, [hDivideBCDBuffer+2]
+ ld [hDivideBCDQuotient+2], a
+ pop de
+ ld a, $6
+ sub d
+ and a
+ ret z
+.divResultBy10loop
+ push af
+ call DivideBCD_divDivisorBy10
+ pop af
+ dec a
+ jr nz, .divResultBy10loop
+ ret
+
+DivideBCD_divDivisorBy10:
+ ld a, [hDivideBCDDivisor+2]
+ swap a
+ and $f
+ ld b, a
+ ld a, [hDivideBCDDivisor+1]
+ swap a
+ ld [hDivideBCDDivisor+1], a
+ and $f0
+ or b
+ ld [hDivideBCDDivisor+2], a
+ ld a, [hDivideBCDDivisor+1]
+ and $f
+ ld b, a
+ ld a, [hDivideBCDDivisor]
+ swap a
+ ld [hDivideBCDDivisor], a
+ and $f0
+ or b
+ ld [hDivideBCDDivisor+1], a
+ ld a, [hDivideBCDDivisor]
+ and $f
+ ld [hDivideBCDDivisor], a
+ ret
+
+DivideBCD_getNextDigit:
+ ld bc, $3
+.loop
+ ld de, hMoney ; the dividend
+ ld hl, hDivideBCDDivisor
+ push bc
+ call StringCmp
+ pop bc
+ ret c
+ inc b
+ ld de, hMoney+2 ; since SubBCD works starting from the least significant digit
+ ld hl, hDivideBCDDivisor+2
+ push bc
+ call SubBCD
+ pop bc
+ jr .loop
+
+
+AddBCDPredef::
+ call GetPredefRegisters
+
+AddBCD::
+ and a
+ ld b, c
+.add
+ ld a, [de]
+ adc [hl]
+ daa
+ ld [de], a
+ dec de
+ dec hl
+ dec c
+ jr nz, .add
+ jr nc, .done
+ ld a, $99
+ inc de
+.fill
+ ld [de], a
+ inc de
+ dec b
+ jr nz, .fill
+.done
+ ret
+
+
+SubBCDPredef::
+ call GetPredefRegisters
+
+SubBCD::
+ and a
+ ld b, c
+.sub
+ ld a, [de]
+ sbc [hl]
+ daa
+ ld [de], a
+ dec de
+ dec hl
+ dec c
+ jr nz, .sub
+ jr nc, .done
+ ld a, $00
+ inc de
+.fill
+ ld [de], a
+ inc de
+ dec b
+ jr nz, .fill
+ scf
+.done
+ ret
--- /dev/null
+++ b/engine/math/multiply_divide.asm
@@ -1,0 +1,143 @@
+_Multiply::
+ ld a, $8
+ ld b, a
+ xor a
+ ld [H_PRODUCT], a
+ ld [H_MULTIPLYBUFFER], a
+ ld [H_MULTIPLYBUFFER+1], a
+ ld [H_MULTIPLYBUFFER+2], a
+ ld [H_MULTIPLYBUFFER+3], a
+.loop
+ ld a, [H_MULTIPLIER]
+ srl a
+ ld [H_MULTIPLIER], a ; (aliases: H_DIVISOR, H_MULTIPLIER, H_POWEROFTEN)
+ jr nc, .smallMultiplier
+ ld a, [H_MULTIPLYBUFFER+3]
+ ld c, a
+ ld a, [H_MULTIPLICAND+2]
+ add c
+ ld [H_MULTIPLYBUFFER+3], a
+ ld a, [H_MULTIPLYBUFFER+2]
+ ld c, a
+ ld a, [H_MULTIPLICAND+1]
+ adc c
+ ld [H_MULTIPLYBUFFER+2], a
+ ld a, [H_MULTIPLYBUFFER+1]
+ ld c, a
+ ld a, [H_MULTIPLICAND] ; (aliases: H_MULTIPLICAND)
+ adc c
+ ld [H_MULTIPLYBUFFER+1], a
+ ld a, [H_MULTIPLYBUFFER]
+ ld c, a
+ ld a, [H_PRODUCT] ; (aliases: H_PRODUCT, H_PASTLEADINGZEROES, H_QUOTIENT)
+ adc c
+ ld [H_MULTIPLYBUFFER], a
+.smallMultiplier
+ dec b
+ jr z, .done
+ ld a, [H_MULTIPLICAND+2]
+ sla a
+ ld [H_MULTIPLICAND+2], a
+ ld a, [H_MULTIPLICAND+1]
+ rl a
+ ld [H_MULTIPLICAND+1], a
+ ld a, [H_MULTIPLICAND]
+ rl a
+ ld [H_MULTIPLICAND], a
+ ld a, [H_PRODUCT]
+ rl a
+ ld [H_PRODUCT], a
+ jr .loop
+.done
+ ld a, [H_MULTIPLYBUFFER+3]
+ ld [H_PRODUCT+3], a
+ ld a, [H_MULTIPLYBUFFER+2]
+ ld [H_PRODUCT+2], a
+ ld a, [H_MULTIPLYBUFFER+1]
+ ld [H_PRODUCT+1], a
+ ld a, [H_MULTIPLYBUFFER]
+ ld [H_PRODUCT], a
+ ret
+
+_Divide::
+ xor a
+ ld [H_DIVIDEBUFFER], a
+ ld [H_DIVIDEBUFFER+1], a
+ ld [H_DIVIDEBUFFER+2], a
+ ld [H_DIVIDEBUFFER+3], a
+ ld [H_DIVIDEBUFFER+4], a
+ ld a, $9
+ ld e, a
+.asm_37db3
+ ld a, [H_DIVIDEBUFFER]
+ ld c, a
+ ld a, [H_DIVIDEND+1] ; (aliases: H_MULTIPLICAND)
+ sub c
+ ld d, a
+ ld a, [H_DIVISOR] ; (aliases: H_DIVISOR, H_MULTIPLIER, H_POWEROFTEN)
+ ld c, a
+ ld a, [H_DIVIDEND] ; (aliases: H_PRODUCT, H_PASTLEADINGZEROES, H_QUOTIENT)
+ sbc c
+ jr c, .asm_37dce
+ ld [H_DIVIDEND], a ; (aliases: H_PRODUCT, H_PASTLEADINGZEROES, H_QUOTIENT)
+ ld a, d
+ ld [H_DIVIDEND+1], a ; (aliases: H_MULTIPLICAND)
+ ld a, [H_DIVIDEBUFFER+4]
+ inc a
+ ld [H_DIVIDEBUFFER+4], a
+ jr .asm_37db3
+.asm_37dce
+ ld a, b
+ cp $1
+ jr z, .asm_37e18
+ ld a, [H_DIVIDEBUFFER+4]
+ sla a
+ ld [H_DIVIDEBUFFER+4], a
+ ld a, [H_DIVIDEBUFFER+3]
+ rl a
+ ld [H_DIVIDEBUFFER+3], a
+ ld a, [H_DIVIDEBUFFER+2]
+ rl a
+ ld [H_DIVIDEBUFFER+2], a
+ ld a, [H_DIVIDEBUFFER+1]
+ rl a
+ ld [H_DIVIDEBUFFER+1], a
+ dec e
+ jr nz, .asm_37e04
+ ld a, $8
+ ld e, a
+ ld a, [H_DIVIDEBUFFER]
+ ld [H_DIVISOR], a ; (aliases: H_DIVISOR, H_MULTIPLIER, H_POWEROFTEN)
+ xor a
+ ld [H_DIVIDEBUFFER], a
+ ld a, [H_DIVIDEND+1] ; (aliases: H_MULTIPLICAND)
+ ld [H_DIVIDEND], a ; (aliases: H_PRODUCT, H_PASTLEADINGZEROES, H_QUOTIENT)
+ ld a, [H_DIVIDEND+2]
+ ld [H_DIVIDEND+1], a ; (aliases: H_MULTIPLICAND)
+ ld a, [H_DIVIDEND+3]
+ ld [H_DIVIDEND+2], a
+.asm_37e04
+ ld a, e
+ cp $1
+ jr nz, .asm_37e0a
+ dec b
+.asm_37e0a
+ ld a, [H_DIVISOR] ; (aliases: H_DIVISOR, H_MULTIPLIER, H_POWEROFTEN)
+ srl a
+ ld [H_DIVISOR], a ; (aliases: H_DIVISOR, H_MULTIPLIER, H_POWEROFTEN)
+ ld a, [H_DIVIDEBUFFER]
+ rr a
+ ld [H_DIVIDEBUFFER], a
+ jr .asm_37db3
+.asm_37e18
+ ld a, [H_DIVIDEND+1] ; (aliases: H_MULTIPLICAND)
+ ld [H_REMAINDER], a ; (aliases: H_DIVISOR, H_MULTIPLIER, H_POWEROFTEN)
+ ld a, [H_DIVIDEBUFFER+4]
+ ld [H_QUOTIENT+3], a
+ ld a, [H_DIVIDEBUFFER+3]
+ ld [H_QUOTIENT+2], a
+ ld a, [H_DIVIDEBUFFER+2]
+ ld [H_QUOTIENT+1], a ; (aliases: H_MULTIPLICAND)
+ ld a, [H_DIVIDEBUFFER+1]
+ ld [H_DIVIDEND], a ; (aliases: H_PRODUCT, H_PASTLEADINGZEROES, H_QUOTIENT)
+ ret
--- /dev/null
+++ b/engine/math/random.asm
@@ -1,0 +1,13 @@
+Random_::
+; Generate a random 16-bit value.
+ ld a, [rDIV]
+ ld b, a
+ ld a, [hRandomAdd]
+ adc b
+ ld [hRandomAdd], a
+ ld a, [rDIV]
+ ld b, a
+ ld a, [hRandomSub]
+ sbc b
+ ld [hRandomSub], a
+ ret
--- a/engine/menu/bills_pc.asm
+++ /dev/null
@@ -1,554 +1,0 @@
-DisplayPCMainMenu::
- xor a
- ld [H_AUTOBGTRANSFERENABLED], a
- call SaveScreenTilesToBuffer2
- ld a, [wNumHoFTeams]
- and a
- jr nz, .leaguePCAvailable
- CheckEvent EVENT_GOT_POKEDEX
- jr z, .noOaksPC
- ld a, [wNumHoFTeams]
- and a
- jr nz, .leaguePCAvailable
- coord hl, 0, 0
- ld b, 8
- ld c, 14
- jr .next
-.noOaksPC
- coord hl, 0, 0
- ld b, 6
- ld c, 14
- jr .next
-.leaguePCAvailable
- coord hl, 0, 0
- ld b, 10
- ld c, 14
-.next
- call TextBoxBorder
- call UpdateSprites
- ld a, 3
- ld [wMaxMenuItem], a
- CheckEvent EVENT_MET_BILL
- jr nz, .metBill
- coord hl, 2, 2
- ld de, SomeonesPCText
- jr .next2
-.metBill
- coord hl, 2, 2
- ld de, BillsPCText
-.next2
- call PlaceString
- coord hl, 2, 4
- ld de, wPlayerName
- call PlaceString
- ld l, c
- ld h, b
- ld de, PlayersPCText
- call PlaceString
- CheckEvent EVENT_GOT_POKEDEX
- jr z, .noOaksPC2
- coord hl, 2, 6
- ld de, OaksPCText
- call PlaceString
- ld a, [wNumHoFTeams]
- and a
- jr z, .noLeaguePC
- ld a, 4
- ld [wMaxMenuItem], a
- coord hl, 2, 8
- ld de, PKMNLeaguePCText
- call PlaceString
- coord hl, 2, 10
- ld de, LogOffPCText
- jr .next3
-.noLeaguePC
- coord hl, 2, 8
- ld de, LogOffPCText
- jr .next3
-.noOaksPC2
- ld a, $2
- ld [wMaxMenuItem], a
- coord hl, 2, 6
- ld de, LogOffPCText
-.next3
- call PlaceString
- ld a, A_BUTTON | B_BUTTON
- ld [wMenuWatchedKeys], a
- ld a, 2
- ld [wTopMenuItemY], a
- ld a, 1
- ld [wTopMenuItemX], a
- xor a
- ld [wCurrentMenuItem], a
- ld [wLastMenuItem], a
- ld a, 1
- ld [H_AUTOBGTRANSFERENABLED], a
- ret
-
-SomeonesPCText: db "SOMEONE's PC@"
-BillsPCText: db "BILL's PC@"
-PlayersPCText: db "'s PC@"
-OaksPCText: db "PROF.OAK's PC@"
-PKMNLeaguePCText: db "<pkmn>LEAGUE@"
-LogOffPCText: db "LOG OFF@"
-
-BillsPC_::
- ld hl, wd730
- set 6, [hl]
- xor a
- ld [wParentMenuItem], a
- inc a ; MONSTER_NAME
- ld [wNameListType], a
- call LoadHpBarAndStatusTilePatterns
- ld a, [wListScrollOffset]
- push af
- ld a, [wFlags_0xcd60]
- bit 3, a ; accessing Bill's PC through another PC?
- jr nz, BillsPCMenu
-; accessing it directly
- ld a, SFX_TURN_ON_PC
- call PlaySound
- ld hl, SwitchOnText
- call PrintText
-
-BillsPCMenu:
- ld a, [wParentMenuItem]
- ld [wCurrentMenuItem], a
- ld hl, vChars2 + $780
- ld de, PokeballTileGraphics
- lb bc, BANK(PokeballTileGraphics), $01
- call CopyVideoData
- call LoadScreenTilesFromBuffer2DisableBGTransfer
- coord hl, 0, 0
- ld b, 10
- ld c, 12
- call TextBoxBorder
- coord hl, 2, 2
- ld de, BillsPCMenuText
- call PlaceString
- ld hl, wTopMenuItemY
- ld a, 2
- ld [hli], a ; wTopMenuItemY
- dec a
- ld [hli], a ; wTopMenuItemX
- inc hl
- inc hl
- ld a, 4
- ld [hli], a ; wMaxMenuItem
- ld a, A_BUTTON | B_BUTTON
- ld [hli], a ; wMenuWatchedKeys
- xor a
- ld [hli], a ; wLastMenuItem
- ld [hli], a ; wPartyAndBillsPCSavedMenuItem
- ld hl, wListScrollOffset
- ld [hli], a ; wListScrollOffset
- ld [hl], a ; wMenuWatchMovingOutOfBounds
- ld [wPlayerMonNumber], a
- ld hl, WhatText
- call PrintText
- coord hl, 9, 14
- ld b, 2
- ld c, 9
- call TextBoxBorder
- ld a, [wCurrentBoxNum]
- and $7f
- cp 9
- jr c, .singleDigitBoxNum
-; two digit box num
- sub 9
- coord hl, 17, 16
- ld [hl], "1"
- add "0"
- jr .next
-.singleDigitBoxNum
- add "1"
-.next
- Coorda 18, 16
- coord hl, 10, 16
- ld de, BoxNoPCText
- call PlaceString
- ld a, 1
- ld [H_AUTOBGTRANSFERENABLED], a
- call Delay3
- call HandleMenuInput
- bit 1, a
- jp nz, ExitBillsPC ; b button
- call PlaceUnfilledArrowMenuCursor
- ld a, [wCurrentMenuItem]
- ld [wParentMenuItem], a
- and a
- jp z, BillsPCWithdraw ; withdraw
- cp $1
- jp z, BillsPCDeposit ; deposit
- cp $2
- jp z, BillsPCRelease ; release
- cp $3
- jp z, BillsPCChangeBox ; change box
-
-ExitBillsPC:
- ld a, [wFlags_0xcd60]
- bit 3, a ; accessing Bill's PC through another PC?
- jr nz, .next
-; accessing it directly
- call LoadTextBoxTilePatterns
- ld a, SFX_TURN_OFF_PC
- call PlaySound
- call WaitForSoundToFinish
-.next
- ld hl, wFlags_0xcd60
- res 5, [hl]
- call LoadScreenTilesFromBuffer2
- pop af
- ld [wListScrollOffset], a
- ld hl, wd730
- res 6, [hl]
- ret
-
-BillsPCDeposit:
- ld a, [wPartyCount]
- dec a
- jr nz, .partyLargeEnough
- ld hl, CantDepositLastMonText
- call PrintText
- jp BillsPCMenu
-.partyLargeEnough
- ld a, [wNumInBox]
- cp MONS_PER_BOX
- jr nz, .boxNotFull
- ld hl, BoxFullText
- call PrintText
- jp BillsPCMenu
-.boxNotFull
- ld hl, wPartyCount
- call DisplayMonListMenu
- jp c, BillsPCMenu
- call DisplayDepositWithdrawMenu
- jp nc, BillsPCMenu
- ld a, [wcf91]
- call GetCryData
- call PlaySoundWaitForCurrent
- ld a, PARTY_TO_BOX
- ld [wMoveMonType], a
- call MoveMon
- xor a
- ld [wRemoveMonFromBox], a
- call RemovePokemon
- call WaitForSoundToFinish
- ld hl, wBoxNumString
- ld a, [wCurrentBoxNum]
- and $7f
- cp 9
- jr c, .singleDigitBoxNum
- sub 9
- ld [hl], "1"
- inc hl
- add "0"
- jr .next
-.singleDigitBoxNum
- add "1"
-.next
- ld [hli], a
- ld [hl], "@"
- ld hl, MonWasStoredText
- call PrintText
- jp BillsPCMenu
-
-BillsPCWithdraw:
- ld a, [wNumInBox]
- and a
- jr nz, .boxNotEmpty
- ld hl, NoMonText
- call PrintText
- jp BillsPCMenu
-.boxNotEmpty
- ld a, [wPartyCount]
- cp PARTY_LENGTH
- jr nz, .partyNotFull
- ld hl, CantTakeMonText
- call PrintText
- jp BillsPCMenu
-.partyNotFull
- ld hl, wNumInBox
- call DisplayMonListMenu
- jp c, BillsPCMenu
- call DisplayDepositWithdrawMenu
- jp nc, BillsPCMenu
- ld a, [wWhichPokemon]
- ld hl, wBoxMonNicks
- call GetPartyMonName
- ld a, [wcf91]
- call GetCryData
- call PlaySoundWaitForCurrent
- xor a ; BOX_TO_PARTY
- ld [wMoveMonType], a
- call MoveMon
- ld a, 1
- ld [wRemoveMonFromBox], a
- call RemovePokemon
- call WaitForSoundToFinish
- ld hl, MonIsTakenOutText
- call PrintText
- jp BillsPCMenu
-
-BillsPCRelease:
- ld a, [wNumInBox]
- and a
- jr nz, .loop
- ld hl, NoMonText
- call PrintText
- jp BillsPCMenu
-.loop
- ld hl, wNumInBox
- call DisplayMonListMenu
- jp c, BillsPCMenu
- ld hl, OnceReleasedText
- call PrintText
- call YesNoChoice
- ld a, [wCurrentMenuItem]
- and a
- jr nz, .loop
- inc a
- ld [wRemoveMonFromBox], a
- call RemovePokemon
- call WaitForSoundToFinish
- ld a, [wcf91]
- call PlayCry
- ld hl, MonWasReleasedText
- call PrintText
- jp BillsPCMenu
-
-BillsPCChangeBox:
- callba ChangeBox
- jp BillsPCMenu
-
-DisplayMonListMenu:
- ld a, l
- ld [wListPointer], a
- ld a, h
- ld [wListPointer + 1], a
- xor a
- ld [wPrintItemPrices], a
- ld [wListMenuID], a
- inc a ; MONSTER_NAME
- ld [wNameListType], a
- ld a, [wPartyAndBillsPCSavedMenuItem]
- ld [wCurrentMenuItem], a
- call DisplayListMenuID
- ld a, [wCurrentMenuItem]
- ld [wPartyAndBillsPCSavedMenuItem], a
- ret
-
-BillsPCMenuText:
- db "WITHDRAW <pkmn>"
- next "DEPOSIT <pkmn>"
- next "RELEASE <pkmn>"
- next "CHANGE BOX"
- next "SEE YA!"
- db "@"
-
-BoxNoPCText:
- db "BOX No.@"
-
-KnowsHMMove::
-; returns whether mon with party index [wWhichPokemon] knows an HM move
- ld hl, wPartyMon1Moves
- ld bc, wPartyMon2 - wPartyMon1
- jr .next
-; unreachable
- ld hl, wBoxMon1Moves
- ld bc, wBoxMon2 - wBoxMon1
-.next
- ld a, [wWhichPokemon]
- call AddNTimes
- ld b, NUM_MOVES
-.loop
- ld a, [hli]
- push hl
- push bc
- ld hl, HMMoveArray
- ld de, 1
- call IsInArray
- pop bc
- pop hl
- ret c
- dec b
- jr nz, .loop
- and a
- ret
-
-HMMoveArray:
- db CUT
- db FLY
- db SURF
- db STRENGTH
- db FLASH
- db -1
-
-DisplayDepositWithdrawMenu:
- coord hl, 9, 10
- ld b, 6
- ld c, 9
- call TextBoxBorder
- ld a, [wParentMenuItem]
- and a ; was the Deposit or Withdraw item selected in the parent menu?
- ld de, DepositPCText
- jr nz, .next
- ld de, WithdrawPCText
-.next
- coord hl, 11, 12
- call PlaceString
- coord hl, 11, 14
- ld de, StatsCancelPCText
- call PlaceString
- ld hl, wTopMenuItemY
- ld a, 12
- ld [hli], a ; wTopMenuItemY
- ld a, 10
- ld [hli], a ; wTopMenuItemX
- xor a
- ld [hli], a ; wCurrentMenuItem
- inc hl
- ld a, 2
- ld [hli], a ; wMaxMenuItem
- ld a, A_BUTTON | B_BUTTON
- ld [hli], a ; wMenuWatchedKeys
- xor a
- ld [hl], a ; wLastMenuItem
- ld hl, wListScrollOffset
- ld [hli], a ; wListScrollOffset
- ld [hl], a ; wMenuWatchMovingOutOfBounds
- ld [wPlayerMonNumber], a
- ld [wPartyAndBillsPCSavedMenuItem], a
-.loop
- call HandleMenuInput
- bit 1, a ; pressed B?
- jr nz, .exit
- ld a, [wCurrentMenuItem]
- and a
- jr z, .choseDepositWithdraw
- dec a
- jr z, .viewStats
-.exit
- and a
- ret
-.choseDepositWithdraw
- scf
- ret
-.viewStats
- call SaveScreenTilesToBuffer1
- ld a, [wParentMenuItem]
- and a
- ld a, PLAYER_PARTY_DATA
- jr nz, .next2
- ld a, BOX_DATA
-.next2
- ld [wMonDataLocation], a
- predef StatusScreen
- predef StatusScreen2
- call LoadScreenTilesFromBuffer1
- call ReloadTilesetTilePatterns
- call RunDefaultPaletteCommand
- call LoadGBPal
- jr .loop
-
-DepositPCText: db "DEPOSIT@"
-WithdrawPCText: db "WITHDRAW@"
-StatsCancelPCText:
- db "STATS"
- next "CANCEL@"
-
-SwitchOnText:
- TX_FAR _SwitchOnText
- db "@"
-
-WhatText:
- TX_FAR _WhatText
- db "@"
-
-DepositWhichMonText:
- TX_FAR _DepositWhichMonText
- db "@"
-
-MonWasStoredText:
- TX_FAR _MonWasStoredText
- db "@"
-
-CantDepositLastMonText:
- TX_FAR _CantDepositLastMonText
- db "@"
-
-BoxFullText:
- TX_FAR _BoxFullText
- db "@"
-
-MonIsTakenOutText:
- TX_FAR _MonIsTakenOutText
- db "@"
-
-NoMonText:
- TX_FAR _NoMonText
- db "@"
-
-CantTakeMonText:
- TX_FAR _CantTakeMonText
- db "@"
-
-ReleaseWhichMonText:
- TX_FAR _ReleaseWhichMonText
- db "@"
-
-OnceReleasedText:
- TX_FAR _OnceReleasedText
- db "@"
-
-MonWasReleasedText:
- TX_FAR _MonWasReleasedText
- db "@"
-
-CableClubLeftGameboy::
- ld a, [hSerialConnectionStatus]
- cp USING_EXTERNAL_CLOCK
- ret z
- ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction
- cp SPRITE_FACING_RIGHT
- ret nz
- ld a, [wCurMap]
- cp TRADE_CENTER
- ld a, LINK_STATE_START_TRADE
- jr z, .next
- inc a ; LINK_STATE_START_BATTLE
-.next
- ld [wLinkState], a
- call EnableAutoTextBoxDrawing
- tx_pre_jump JustAMomentText
-
-CableClubRightGameboy::
- ld a, [hSerialConnectionStatus]
- cp USING_INTERNAL_CLOCK
- ret z
- ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction
- cp SPRITE_FACING_LEFT
- ret nz
- ld a, [wCurMap]
- cp TRADE_CENTER
- ld a, LINK_STATE_START_TRADE
- jr z, .next
- inc a ; LINK_STATE_START_BATTLE
-.next
- ld [wLinkState], a
- call EnableAutoTextBoxDrawing
- tx_pre_jump JustAMomentText
-
-JustAMomentText::
- TX_FAR _JustAMomentText
- db "@"
-
- ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction
- cp SPRITE_FACING_UP
- ret nz
- call EnableAutoTextBoxDrawing
- tx_pre_jump OpenBillsPCText
-
-OpenBillsPCText::
- TX_BILLS_PC
-
--- a/engine/menu/diploma.asm
+++ /dev/null
@@ -1,113 +1,0 @@
-DisplayDiploma::
- call SaveScreenTilesToBuffer2
- call GBPalWhiteOutWithDelay3
- call ClearScreen
- xor a
- ld [wUpdateSpritesEnabled], a
- ld hl, wd730
- set 6, [hl]
- call DisableLCD
- ld hl, CircleTile
- ld de, vChars2 + $700
- ld bc, $0010
- ld a, BANK(CircleTile)
- call FarCopyData2
- coord hl, 0, 0
- lb bc, 16, 18
- predef Diploma_TextBoxBorder
- ld hl, DiplomaTextPointersAndCoords
- ld c, $5
-.asm_56715
- push bc
- ld a, [hli]
- ld e, a
- ld a, [hli]
- ld d, a
- ld a, [hli]
- push hl
- ld h, [hl]
- ld l, a
- call PlaceString
- pop hl
- inc hl
- pop bc
- dec c
- jr nz, .asm_56715
- coord hl, 10, 4
- ld de, wPlayerName
- call PlaceString
- callba DrawPlayerCharacter
-
-; Move the player 33 pixels right and set the priority bit so he appears
-; behind the background layer.
- ld hl, wOAMBuffer + $01
- lb bc, $80, $28
-.adjustPlayerGfxLoop
- ld a, [hl] ; X
- add 33
- ld [hli], a
- inc hl
- ld a, b
- ld [hli], a ; attributes
- inc hl
- dec c
- jr nz, .adjustPlayerGfxLoop
-
- call EnableLCD
- callba LoadTrainerInfoTextBoxTiles
- ld b, SET_PAL_GENERIC
- call RunPaletteCommand
- call Delay3
- call GBPalNormal
- ld a, $90
- ld [rOBP0], a
- call WaitForTextScrollButtonPress
- ld hl, wd730
- res 6, [hl]
- call GBPalWhiteOutWithDelay3
- call RestoreScreenTilesAndReloadTilePatterns
- call Delay3
- jp GBPalNormal
-
-UnusedPlayerNameLengthFunc:
-; Unused function that does a calculation involving the length of the player's
-; name.
- ld hl, wPlayerName
- ld bc, $ff00
-.loop
- ld a, [hli]
- cp "@"
- ret z
- dec c
- jr .loop
-
-DiplomaTextPointersAndCoords:
- dw DiplomaText
- dwCoord 5, 2
- dw DiplomaPlayer
- dwCoord 3, 4
- dw DiplomaEmptyText
- dwCoord 15, 4
- dw DiplomaCongrats
- dwCoord 2, 6
- dw DiplomaGameFreak
- dwCoord 9, 16
-
-DiplomaText:
- db $70,"Diploma",$70,"@"
-
-DiplomaPlayer:
- db "Player@"
-
-DiplomaEmptyText:
- db "@"
-
-DiplomaCongrats:
- db "Congrats! This"
- next "diploma certifies"
- next "that you have"
- next "completed your"
- next "#DEX.@"
-
-DiplomaGameFreak:
- db "GAME FREAK@"
--- a/engine/menu/draw_badges.asm
+++ /dev/null
@@ -1,120 +1,0 @@
-DrawBadges:
-; Draw 4x2 gym leader faces, with the faces replaced by
-; badges if they are owned. Used in the player status screen.
-
-; In Japanese versions, names are displayed above faces.
-; Instead of removing relevant code, the name graphics were erased.
-
-; Tile ids for face/badge graphics.
- ld de, wBadgeOrFaceTiles
- ld hl, .FaceBadgeTiles
- ld bc, 8
- call CopyData
-
-; Booleans for each badge.
- ld hl, wTempObtainedBadgesBooleans
- ld bc, 8
- xor a
- call FillMemory
-
-; Alter these based on owned badges.
- ld de, wTempObtainedBadgesBooleans
- ld hl, wBadgeOrFaceTiles
- ld a, [wObtainedBadges]
- ld b, a
- ld c, 8
-.CheckBadge
- srl b
- jr nc, .NextBadge
- ld a, [hl]
- add 4 ; Badge graphics are after each face
- ld [hl], a
- ld a, 1
- ld [de], a
-.NextBadge
- inc hl
- inc de
- dec c
- jr nz, .CheckBadge
-
-; Draw two rows of badges.
- ld hl, wBadgeNumberTile
- ld a, $d8 ; [1]
- ld [hli], a
- ld [hl], $60 ; First name
-
- coord hl, 2, 11
- ld de, wTempObtainedBadgesBooleans
- call .DrawBadgeRow
-
- coord hl, 2, 14
- ld de, wTempObtainedBadgesBooleans + 4
-; call .DrawBadgeRow
-; ret
-
-.DrawBadgeRow
-; Draw 4 badges.
-
- ld c, 4
-.DrawBadge
- push de
- push hl
-
-; Badge no.
- ld a, [wBadgeNumberTile]
- ld [hli], a
- inc a
- ld [wBadgeNumberTile], a
-
-; Names aren't printed if the badge is owned.
- ld a, [de]
- and a
- ld a, [wBadgeNameTile]
- jr nz, .SkipName
- call .PlaceTiles
- jr .PlaceBadge
-
-.SkipName
- inc a
- inc a
- inc hl
-
-.PlaceBadge
- ld [wBadgeNameTile], a
- ld de, SCREEN_WIDTH - 1
- add hl, de
- ld a, [wBadgeOrFaceTiles]
- call .PlaceTiles
- add hl, de
- call .PlaceTiles
-
-; Shift badge array back one byte.
- push bc
- ld hl, wBadgeOrFaceTiles + 1
- ld de, wBadgeOrFaceTiles
- ld bc, 8
- call CopyData
- pop bc
-
- pop hl
- ld de, 4
- add hl, de
-
- pop de
- inc de
- dec c
- jr nz, .DrawBadge
- ret
-
-.PlaceTiles
- ld [hli], a
- inc a
- ld [hl], a
- inc a
- ret
-
-.FaceBadgeTiles
- db $20, $28, $30, $38, $40, $48, $50, $58
-
-GymLeaderFaceAndBadgeTileGraphics:
- INCBIN "gfx/trainer_card/badges.2bpp"
--- a/engine/menu/draw_start_menu.asm
+++ /dev/null
@@ -1,89 +1,0 @@
-; function that displays the start menu
-DrawStartMenu::
- CheckEvent EVENT_GOT_POKEDEX
-; menu with pokedex
- coord hl, 10, 0
- ld b, $0e
- ld c, $08
- jr nz, .drawTextBoxBorder
-; shorter menu if the player doesn't have the pokedex
- coord hl, 10, 0
- ld b, $0c
- ld c, $08
-.drawTextBoxBorder
- call TextBoxBorder
- ld a, D_DOWN | D_UP | START | B_BUTTON | A_BUTTON
- ld [wMenuWatchedKeys], a
- ld a, $02
- ld [wTopMenuItemY], a ; Y position of first menu choice
- ld a, $0b
- ld [wTopMenuItemX], a ; X position of first menu choice
- ld a, [wBattleAndStartSavedMenuItem] ; remembered menu selection from last time
- ld [wCurrentMenuItem], a
- ld [wLastMenuItem], a
- xor a
- ld [wMenuWatchMovingOutOfBounds], a
- ld hl, wd730
- set 6, [hl] ; no pauses between printing each letter
- coord hl, 12, 2
- CheckEvent EVENT_GOT_POKEDEX
-; case for not having pokedex
- ld a, $06
- jr z, .storeMenuItemCount
-; case for having pokedex
- ld de, StartMenuPokedexText
- call PrintStartMenuItem
- ld a, $07
-.storeMenuItemCount
- ld [wMaxMenuItem], a ; number of menu items
- ld de, StartMenuPokemonText
- call PrintStartMenuItem
- ld de, StartMenuItemText
- call PrintStartMenuItem
- ld de, wPlayerName ; player's name
- call PrintStartMenuItem
- ld a, [wd72e]
- bit 6, a ; is the player using the link feature?
-; case for not using link feature
- ld de, StartMenuSaveText
- jr z, .printSaveOrResetText
-; case for using link feature
- ld de, StartMenuResetText
-.printSaveOrResetText
- call PrintStartMenuItem
- ld de, StartMenuOptionText
- call PrintStartMenuItem
- ld de, StartMenuExitText
- call PlaceString
- ld hl, wd730
- res 6, [hl] ; turn pauses between printing letters back on
- ret
-
-StartMenuPokedexText:
- db "POKéDEX@"
-
-StartMenuPokemonText:
- db "POKéMON@"
-
-StartMenuItemText:
- db "ITEM@"
-
-StartMenuSaveText:
- db "SAVE@"
-
-StartMenuResetText:
- db "RESET@"
-
-StartMenuExitText:
- db "EXIT@"
-
-StartMenuOptionText:
- db "OPTION@"
-
-PrintStartMenuItem:
- push hl
- call PlaceString
- pop hl
- ld de, SCREEN_WIDTH * 2
- add hl, de
- ret
--- a/engine/menu/league_pc.asm
+++ /dev/null
@@ -1,120 +1,0 @@
-PKMNLeaguePC:
- ld hl, AccessedHoFPCText
- call PrintText
- ld hl, wd730
- set 6, [hl]
- push hl
- ld a, [wUpdateSpritesEnabled]
- push af
- ld a, [hTilesetType]
- push af
- xor a
- ld [hTilesetType], a
- ld [wSpriteFlipped], a
- ld [wUpdateSpritesEnabled], a
- ld [wHoFTeamIndex2], a
- ld [wHoFTeamNo], a
- ld a, [wNumHoFTeams]
- ld b, a
- cp HOF_TEAM_CAPACITY + 1
- jr c, .loop
-; If the total number of hall of fame teams is greater than the storage
-; capacity, then calculate the number of the first team that is still recorded.
- ld b, HOF_TEAM_CAPACITY
- sub b
- ld [wHoFTeamNo], a
-.loop
- ld hl, wHoFTeamNo
- inc [hl]
- push bc
- ld a, [wHoFTeamIndex2]
- ld [wHoFTeamIndex], a
- callba LoadHallOfFameTeams
- call LeaguePCShowTeam
- pop bc
- jr c, .doneShowingTeams
- ld hl, wHoFTeamIndex2
- inc [hl]
- ld a, [hl]
- cp b
- jr nz, .loop
-.doneShowingTeams
- pop af
- ld [hTilesetType], a
- pop af
- ld [wUpdateSpritesEnabled], a
- pop hl
- res 6, [hl]
- call GBPalWhiteOutWithDelay3
- call ClearScreen
- call RunDefaultPaletteCommand
- jp GBPalNormal
-
-LeaguePCShowTeam:
- ld c, PARTY_LENGTH
-.loop
- push bc
- call LeaguePCShowMon
- call WaitForTextScrollButtonPress
- ld a, [hJoyHeld]
- bit 1, a
- jr nz, .exit
- ld hl, wHallOfFame + HOF_MON
- ld de, wHallOfFame
- ld bc, HOF_TEAM - HOF_MON
- call CopyData
- pop bc
- ld a, [wHallOfFame + 0]
- cp $ff
- jr z, .done
- dec c
- jr nz, .loop
-.done
- and a
- ret
-.exit
- pop bc
- scf
- ret
-
-LeaguePCShowMon:
- call GBPalWhiteOutWithDelay3
- call ClearScreen
- ld hl, wHallOfFame
- ld a, [hli]
- ld [wHoFMonSpecies], a
- ld [wcf91], a
- ld [wd0b5], a
- ld [wBattleMonSpecies2], a
- ld [wWholeScreenPaletteMonSpecies], a
- ld a, [hli]
- ld [wHoFMonLevel], a
- ld de, wcd6d
- ld bc, NAME_LENGTH
- call CopyData
- ld b, SET_PAL_POKEMON_WHOLE_SCREEN
- ld c, 0
- call RunPaletteCommand
- coord hl, 12, 5
- call GetMonHeader
- call LoadFrontSpriteByMonIndex
- call GBPalNormal
- coord hl, 0, 13
- ld b, 2
- ld c, $12
- call TextBoxBorder
- coord hl, 1, 15
- ld de, HallOfFameNoText
- call PlaceString
- coord hl, 16, 15
- ld de, wHoFTeamNo
- lb bc, 1, 3
- call PrintNumber
- jpba HoFDisplayMonInfo
-
-HallOfFameNoText:
- db "HALL OF FAME No @"
-
-AccessedHoFPCText:
- TX_FAR _AccessedHoFPCText
- db "@"
--- a/engine/menu/main_menu.asm
+++ /dev/null
@@ -1,712 +1,0 @@
-MainMenu:
-; Check save file
- call InitOptions
- xor a
- ld [wOptionsInitialized], a
- inc a
- ld [wSaveFileStatus], a
- call CheckForPlayerNameInSRAM
- jr nc, .mainMenuLoop
-
- predef LoadSAV
-
-.mainMenuLoop
- ld c, 20
- call DelayFrames
- xor a ; LINK_STATE_NONE
- ld [wLinkState], a
- ld hl, wPartyAndBillsPCSavedMenuItem
- ld [hli], a
- ld [hli], a
- ld [hli], a
- ld [hl], a
- ld [wDefaultMap], a
- ld hl, wd72e
- res 6, [hl]
- call ClearScreen
- call RunDefaultPaletteCommand
- call LoadTextBoxTilePatterns
- call LoadFontTilePatterns
- ld hl, wd730
- set 6, [hl]
- ld a, [wSaveFileStatus]
- cp 1
- jr z, .noSaveFile
-; there's a save file
- coord hl, 0, 0
- ld b, 6
- ld c, 13
- call TextBoxBorder
- coord hl, 2, 2
- ld de, ContinueText
- call PlaceString
- jr .next2
-.noSaveFile
- coord hl, 0, 0
- ld b, 4
- ld c, 13
- call TextBoxBorder
- coord hl, 2, 2
- ld de, NewGameText
- call PlaceString
-.next2
- ld hl, wd730
- res 6, [hl]
- call UpdateSprites
- xor a
- ld [wCurrentMenuItem], a
- ld [wLastMenuItem], a
- ld [wMenuJoypadPollCount], a
- inc a
- ld [wTopMenuItemX], a
- inc a
- ld [wTopMenuItemY], a
- ld a, A_BUTTON | B_BUTTON | START
- ld [wMenuWatchedKeys], a
- ld a, [wSaveFileStatus]
- ld [wMaxMenuItem], a
- call HandleMenuInput
- bit 1, a ; pressed B?
- jp nz, DisplayTitleScreen ; if so, go back to the title screen
- ld c, 20
- call DelayFrames
- ld a, [wCurrentMenuItem]
- ld b, a
- ld a, [wSaveFileStatus]
- cp 2
- jp z, .skipInc
-; If there's no save file, increment the current menu item so that the numbers
-; are the same whether or not there's a save file.
- inc b
-.skipInc
- ld a, b
- and a
- jr z, .choseContinue
- cp 1
- jp z, StartNewGame
- call DisplayOptionMenu
- ld a, 1
- ld [wOptionsInitialized], a
- jp .mainMenuLoop
-.choseContinue
- call DisplayContinueGameInfo
- ld hl, wCurrentMapScriptFlags
- set 5, [hl]
-.inputLoop
- xor a
- ld [hJoyPressed], a
- ld [hJoyReleased], a
- ld [hJoyHeld], a
- call Joypad
- ld a, [hJoyHeld]
- bit 0, a
- jr nz, .pressedA
- bit 1, a
- jp nz, .mainMenuLoop ; pressed B
- jr .inputLoop
-.pressedA
- call GBPalWhiteOutWithDelay3
- call ClearScreen
- ld a, PLAYER_DIR_DOWN
- ld [wPlayerDirection], a
- ld c, 10
- call DelayFrames
- ld a, [wNumHoFTeams]
- and a
- jp z, SpecialEnterMap
- ld a, [wCurMap] ; map ID
- cp HALL_OF_FAME
- jp nz, SpecialEnterMap
- xor a
- ld [wDestinationMap], a
- ld hl, wd732
- set 2, [hl] ; fly warp or dungeon warp
- call SpecialWarpIn
- jp SpecialEnterMap
-
-InitOptions:
- ld a, 1 ; no delay
- ld [wLetterPrintingDelayFlags], a
- ld a, 3 ; medium speed
- ld [wOptions], a
- ret
-
-LinkMenu:
- xor a
- ld [wLetterPrintingDelayFlags], a
- ld hl, wd72e
- set 6, [hl]
- ld hl, TextTerminator_6b20
- call PrintText
- call SaveScreenTilesToBuffer1
- ld hl, WhereWouldYouLikeText
- call PrintText
- coord hl, 5, 5
- ld b, $6
- ld c, $d
- call TextBoxBorder
- call UpdateSprites
- coord hl, 7, 7
- ld de, CableClubOptionsText
- call PlaceString
- xor a
- ld [wUnusedCD37], a
- ld [wd72d], a
- ld hl, wTopMenuItemY
- ld a, $7
- ld [hli], a
- ld a, $6
- ld [hli], a
- xor a
- ld [hli], a
- inc hl
- ld a, $2
- ld [hli], a
- inc a
- ; ld a, A_BUTTON | B_BUTTON
- ld [hli], a ; wMenuWatchedKeys
- xor a
- ld [hl], a
-.waitForInputLoop
- call HandleMenuInput
- and A_BUTTON | B_BUTTON
- add a
- add a
- ld b, a
- ld a, [wCurrentMenuItem]
- add b
- add $d0
- ld [wLinkMenuSelectionSendBuffer], a
- ld [wLinkMenuSelectionSendBuffer + 1], a
-.exchangeMenuSelectionLoop
- call Serial_ExchangeLinkMenuSelection
- ld a, [wLinkMenuSelectionReceiveBuffer]
- ld b, a
- and $f0
- cp $d0
- jr z, .asm_5c7d
- ld a, [wLinkMenuSelectionReceiveBuffer + 1]
- ld b, a
- and $f0
- cp $d0
- jr nz, .exchangeMenuSelectionLoop
-.asm_5c7d
- ld a, b
- and $c ; did the enemy press A or B?
- jr nz, .enemyPressedAOrB
-; the enemy didn't press A or B
- ld a, [wLinkMenuSelectionSendBuffer]
- and $c ; did the player press A or B?
- jr z, .waitForInputLoop ; if neither the player nor the enemy pressed A or B, try again
- jr .doneChoosingMenuSelection ; if the player pressed A or B but the enemy didn't, use the player's selection
-.enemyPressedAOrB
- ld a, [wLinkMenuSelectionSendBuffer]
- and $c ; did the player press A or B?
- jr z, .useEnemyMenuSelection ; if the enemy pressed A or B but the player didn't, use the enemy's selection
-; the enemy and the player both pressed A or B
-; The gameboy that is clocking the connection wins.
- ld a, [hSerialConnectionStatus]
- cp USING_INTERNAL_CLOCK
- jr z, .doneChoosingMenuSelection
-.useEnemyMenuSelection
- ld a, b
- ld [wLinkMenuSelectionSendBuffer], a
- and $3
- ld [wCurrentMenuItem], a
-.doneChoosingMenuSelection
- ld a, [hSerialConnectionStatus]
- cp USING_INTERNAL_CLOCK
- jr nz, .skipStartingTransfer
- call DelayFrame
- call DelayFrame
- ld a, START_TRANSFER_INTERNAL_CLOCK
- ld [rSC], a
-.skipStartingTransfer
- ld b, $7f
- ld c, $7f
- ld d, $ec
- ld a, [wLinkMenuSelectionSendBuffer]
- and (B_BUTTON << 2) ; was B button pressed?
- jr nz, .updateCursorPosition
-; A button was pressed
- ld a, [wCurrentMenuItem]
- cp $2
- jr z, .updateCursorPosition
- ld c, d
- ld d, b
- dec a
- jr z, .updateCursorPosition
- ld b, c
- ld c, d
-.updateCursorPosition
- ld a, b
- Coorda 6, 7
- ld a, c
- Coorda 6, 9
- ld a, d
- Coorda 6, 11
- ld c, 40
- call DelayFrames
- call LoadScreenTilesFromBuffer1
- ld a, [wLinkMenuSelectionSendBuffer]
- and (B_BUTTON << 2) ; was B button pressed?
- jr nz, .choseCancel ; cancel if B pressed
- ld a, [wCurrentMenuItem]
- cp $2
- jr z, .choseCancel
- xor a
- ld [wWalkBikeSurfState], a ; start walking
- ld a, [wCurrentMenuItem]
- and a
- ld a, COLOSSEUM
- jr nz, .next
- ld a, TRADE_CENTER
-.next
- ld [wd72d], a
- ld hl, PleaseWaitText
- call PrintText
- ld c, 50
- call DelayFrames
- ld hl, wd732
- res 1, [hl]
- ld a, [wDefaultMap]
- ld [wDestinationMap], a
- call SpecialWarpIn
- ld c, 20
- call DelayFrames
- xor a
- ld [wMenuJoypadPollCount], a
- ld [wSerialExchangeNybbleSendData], a
- inc a ; LINK_STATE_IN_CABLE_CLUB
- ld [wLinkState], a
- ld [wEnteringCableClub], a
- jr SpecialEnterMap
-.choseCancel
- xor a
- ld [wMenuJoypadPollCount], a
- call Delay3
- call CloseLinkConnection
- ld hl, LinkCanceledText
- call PrintText
- ld hl, wd72e
- res 6, [hl]
- ret
-
-WhereWouldYouLikeText:
- TX_FAR _WhereWouldYouLikeText
- db "@"
-
-PleaseWaitText:
- TX_FAR _PleaseWaitText
- db "@"
-
-LinkCanceledText:
- TX_FAR _LinkCanceledText
- db "@"
-
-StartNewGame:
- ld hl, wd732
- res 1, [hl]
- call OakSpeech
- ld c, 20
- call DelayFrames
-
-; enter map after using a special warp or loading the game from the main menu
-SpecialEnterMap::
- xor a
- ld [hJoyPressed], a
- ld [hJoyHeld], a
- ld [hJoy5], a
- ld [wd72d], a
- ld hl, wd732
- set 0, [hl] ; count play time
- call ResetPlayerSpriteData
- ld c, 20
- call DelayFrames
- ld a, [wEnteringCableClub]
- and a
- ret nz
- jp EnterMap
-
-ContinueText:
- db "CONTINUE", $4e
-
-NewGameText:
- db "NEW GAME"
- next "OPTION@"
-
-CableClubOptionsText:
- db "TRADE CENTER"
- next "COLOSSEUM"
- next "CANCEL@"
-
-DisplayContinueGameInfo:
- xor a
- ld [H_AUTOBGTRANSFERENABLED], a
- coord hl, 4, 7
- ld b, 8
- ld c, 14
- call TextBoxBorder
- coord hl, 5, 9
- ld de, SaveScreenInfoText
- call PlaceString
- coord hl, 12, 9
- ld de, wPlayerName
- call PlaceString
- coord hl, 17, 11
- call PrintNumBadges
- coord hl, 16, 13
- call PrintNumOwnedMons
- coord hl, 13, 15
- call PrintPlayTime
- ld a, 1
- ld [H_AUTOBGTRANSFERENABLED], a
- ld c, 30
- jp DelayFrames
-
-PrintSaveScreenText:
- xor a
- ld [H_AUTOBGTRANSFERENABLED], a
- coord hl, 4, 0
- ld b, $8
- ld c, $e
- call TextBoxBorder
- call LoadTextBoxTilePatterns
- call UpdateSprites
- coord hl, 5, 2
- ld de, SaveScreenInfoText
- call PlaceString
- coord hl, 12, 2
- ld de, wPlayerName
- call PlaceString
- coord hl, 17, 4
- call PrintNumBadges
- coord hl, 16, 6
- call PrintNumOwnedMons
- coord hl, 13, 8
- call PrintPlayTime
- ld a, $1
- ld [H_AUTOBGTRANSFERENABLED], a
- ld c, 30
- jp DelayFrames
-
-PrintNumBadges:
- push hl
- ld hl, wObtainedBadges
- ld b, $1
- call CountSetBits
- pop hl
- ld de, wNumSetBits
- lb bc, 1, 2
- jp PrintNumber
-
-PrintNumOwnedMons:
- push hl
- ld hl, wPokedexOwned
- ld b, wPokedexOwnedEnd - wPokedexOwned
- call CountSetBits
- pop hl
- ld de, wNumSetBits
- lb bc, 1, 3
- jp PrintNumber
-
-PrintPlayTime:
- ld de, wPlayTimeHours
- lb bc, 1, 3
- call PrintNumber
- ld [hl], $6d
- inc hl
- ld de, wPlayTimeMinutes
- lb bc, LEADING_ZEROES | 1, 2
- jp PrintNumber
-
-SaveScreenInfoText:
- db "PLAYER"
- next "BADGES "
- next "#DEX "
- next "TIME@"
-
-DisplayOptionMenu:
- coord hl, 0, 0
- ld b, 3
- ld c, 18
- call TextBoxBorder
- coord hl, 0, 5
- ld b, 3
- ld c, 18
- call TextBoxBorder
- coord hl, 0, 10
- ld b, 3
- ld c, 18
- call TextBoxBorder
- coord hl, 1, 1
- ld de, TextSpeedOptionText
- call PlaceString
- coord hl, 1, 6
- ld de, BattleAnimationOptionText
- call PlaceString
- coord hl, 1, 11
- ld de, BattleStyleOptionText
- call PlaceString
- coord hl, 2, 16
- ld de, OptionMenuCancelText
- call PlaceString
- xor a
- ld [wCurrentMenuItem], a
- ld [wLastMenuItem], a
- inc a
- ld [wLetterPrintingDelayFlags], a
- ld [wOptionsCancelCursorX], a
- ld a, 3 ; text speed cursor Y coordinate
- ld [wTopMenuItemY], a
- call SetCursorPositionsFromOptions
- ld a, [wOptionsTextSpeedCursorX] ; text speed cursor X coordinate
- ld [wTopMenuItemX], a
- ld a, $01
- ld [H_AUTOBGTRANSFERENABLED], a ; enable auto background transfer
- call Delay3
-.loop
- call PlaceMenuCursor
- call SetOptionsFromCursorPositions
-.getJoypadStateLoop
- call JoypadLowSensitivity
- ld a, [hJoy5]
- ld b, a
- and A_BUTTON | B_BUTTON | START | D_RIGHT | D_LEFT | D_UP | D_DOWN ; any key besides select pressed?
- jr z, .getJoypadStateLoop
- bit 1, b ; B button pressed?
- jr nz, .exitMenu
- bit 3, b ; Start button pressed?
- jr nz, .exitMenu
- bit 0, b ; A button pressed?
- jr z, .checkDirectionKeys
- ld a, [wTopMenuItemY]
- cp 16 ; is the cursor on Cancel?
- jr nz, .loop
-.exitMenu
- ld a, SFX_PRESS_AB
- call PlaySound
- ret
-.eraseOldMenuCursor
- ld [wTopMenuItemX], a
- call EraseMenuCursor
- jp .loop
-.checkDirectionKeys
- ld a, [wTopMenuItemY]
- bit 7, b ; Down pressed?
- jr nz, .downPressed
- bit 6, b ; Up pressed?
- jr nz, .upPressed
- cp 8 ; cursor in Battle Animation section?
- jr z, .cursorInBattleAnimation
- cp 13 ; cursor in Battle Style section?
- jr z, .cursorInBattleStyle
- cp 16 ; cursor on Cancel?
- jr z, .loop
-.cursorInTextSpeed
- bit 5, b ; Left pressed?
- jp nz, .pressedLeftInTextSpeed
- jp .pressedRightInTextSpeed
-.downPressed
- cp 16
- ld b, -13
- ld hl, wOptionsTextSpeedCursorX
- jr z, .updateMenuVariables
- ld b, 5
- cp 3
- inc hl
- jr z, .updateMenuVariables
- cp 8
- inc hl
- jr z, .updateMenuVariables
- ld b, 3
- inc hl
- jr .updateMenuVariables
-.upPressed
- cp 8
- ld b, -5
- ld hl, wOptionsTextSpeedCursorX
- jr z, .updateMenuVariables
- cp 13
- inc hl
- jr z, .updateMenuVariables
- cp 16
- ld b, -3
- inc hl
- jr z, .updateMenuVariables
- ld b, 13
- inc hl
-.updateMenuVariables
- add b
- ld [wTopMenuItemY], a
- ld a, [hl]
- ld [wTopMenuItemX], a
- call PlaceUnfilledArrowMenuCursor
- jp .loop
-.cursorInBattleAnimation
- ld a, [wOptionsBattleAnimCursorX] ; battle animation cursor X coordinate
- xor $0b ; toggle between 1 and 10
- ld [wOptionsBattleAnimCursorX], a
- jp .eraseOldMenuCursor
-.cursorInBattleStyle
- ld a, [wOptionsBattleStyleCursorX] ; battle style cursor X coordinate
- xor $0b ; toggle between 1 and 10
- ld [wOptionsBattleStyleCursorX], a
- jp .eraseOldMenuCursor
-.pressedLeftInTextSpeed
- ld a, [wOptionsTextSpeedCursorX] ; text speed cursor X coordinate
- cp 1
- jr z, .updateTextSpeedXCoord
- cp 7
- jr nz, .fromSlowToMedium
- sub 6
- jr .updateTextSpeedXCoord
-.fromSlowToMedium
- sub 7
- jr .updateTextSpeedXCoord
-.pressedRightInTextSpeed
- ld a, [wOptionsTextSpeedCursorX] ; text speed cursor X coordinate
- cp 14
- jr z, .updateTextSpeedXCoord
- cp 7
- jr nz, .fromFastToMedium
- add 7
- jr .updateTextSpeedXCoord
-.fromFastToMedium
- add 6
-.updateTextSpeedXCoord
- ld [wOptionsTextSpeedCursorX], a ; text speed cursor X coordinate
- jp .eraseOldMenuCursor
-
-TextSpeedOptionText:
- db "TEXT SPEED"
- next " FAST MEDIUM SLOW@"
-
-BattleAnimationOptionText:
- db "BATTLE ANIMATION"
- next " ON OFF@"
-
-BattleStyleOptionText:
- db "BATTLE STYLE"
- next " SHIFT SET@"
-
-OptionMenuCancelText:
- db "CANCEL@"
-
-; sets the options variable according to the current placement of the menu cursors in the options menu
-SetOptionsFromCursorPositions:
- ld hl, TextSpeedOptionData
- ld a, [wOptionsTextSpeedCursorX] ; text speed cursor X coordinate
- ld c, a
-.loop
- ld a, [hli]
- cp c
- jr z, .textSpeedMatchFound
- inc hl
- jr .loop
-.textSpeedMatchFound
- ld a, [hl]
- ld d, a
- ld a, [wOptionsBattleAnimCursorX] ; battle animation cursor X coordinate
- dec a
- jr z, .battleAnimationOn
-.battleAnimationOff
- set 7, d
- jr .checkBattleStyle
-.battleAnimationOn
- res 7, d
-.checkBattleStyle
- ld a, [wOptionsBattleStyleCursorX] ; battle style cursor X coordinate
- dec a
- jr z, .battleStyleShift
-.battleStyleSet
- set 6, d
- jr .storeOptions
-.battleStyleShift
- res 6, d
-.storeOptions
- ld a, d
- ld [wOptions], a
- ret
-
-; reads the options variable and places menu cursors in the correct positions within the options menu
-SetCursorPositionsFromOptions:
- ld hl, TextSpeedOptionData + 1
- ld a, [wOptions]
- ld c, a
- and $3f
- push bc
- ld de, 2
- call IsInArray
- pop bc
- dec hl
- ld a, [hl]
- ld [wOptionsTextSpeedCursorX], a ; text speed cursor X coordinate
- coord hl, 0, 3
- call .placeUnfilledRightArrow
- sla c
- ld a, 1 ; On
- jr nc, .storeBattleAnimationCursorX
- ld a, 10 ; Off
-.storeBattleAnimationCursorX
- ld [wOptionsBattleAnimCursorX], a ; battle animation cursor X coordinate
- coord hl, 0, 8
- call .placeUnfilledRightArrow
- sla c
- ld a, 1
- jr nc, .storeBattleStyleCursorX
- ld a, 10
-.storeBattleStyleCursorX
- ld [wOptionsBattleStyleCursorX], a ; battle style cursor X coordinate
- coord hl, 0, 13
- call .placeUnfilledRightArrow
-; cursor in front of Cancel
- coord hl, 0, 16
- ld a, 1
-.placeUnfilledRightArrow
- ld e, a
- ld d, 0
- add hl, de
- ld [hl], $ec ; unfilled right arrow menu cursor
- ret
-
-; table that indicates how the 3 text speed options affect frame delays
-; Format:
-; 00: X coordinate of menu cursor
-; 01: delay after printing a letter (in frames)
-TextSpeedOptionData:
- db 14,5 ; Slow
- db 7,3 ; Medium
- db 1,1 ; Fast
- db 7 ; default X coordinate (Medium)
- db $ff ; terminator
-
-CheckForPlayerNameInSRAM:
-; Check if the player name data in SRAM has a string terminator character
-; (indicating that a name may have been saved there) and return whether it does
-; in carry.
- ld a, SRAM_ENABLE
- ld [MBC1SRamEnable], a
- ld a, $1
- ld [MBC1SRamBankingMode], a
- ld [MBC1SRamBank], a
- ld b, NAME_LENGTH
- ld hl, sPlayerName
-.loop
- ld a, [hli]
- cp "@"
- jr z, .found
- dec b
- jr nz, .loop
-; not found
- xor a
- ld [MBC1SRamEnable], a
- ld [MBC1SRamBankingMode], a
- and a
- ret
-.found
- xor a
- ld [MBC1SRamEnable], a
- ld [MBC1SRamBankingMode], a
- scf
- ret
--- a/engine/menu/naming_screen.asm
+++ /dev/null
@@ -1,494 +1,0 @@
-AskName:
- call SaveScreenTilesToBuffer1
- call GetPredefRegisters
- push hl
- ld a, [wIsInBattle]
- dec a
- coord hl, 0, 0
- ld b, 4
- ld c, 11
- call z, ClearScreenArea ; only if in wild battle
- ld a, [wcf91]
- ld [wd11e], a
- call GetMonName
- ld hl, DoYouWantToNicknameText
- call PrintText
- coord hl, 14, 7
- lb bc, 8, 15
- ld a, TWO_OPTION_MENU
- ld [wTextBoxID], a
- call DisplayTextBoxID
- pop hl
- ld a, [wCurrentMenuItem]
- and a
- jr nz, .declinedNickname
- ld a, [wUpdateSpritesEnabled]
- push af
- xor a
- ld [wUpdateSpritesEnabled], a
- push hl
- ld a, NAME_MON_SCREEN
- ld [wNamingScreenType], a
- call DisplayNamingScreen
- ld a, [wIsInBattle]
- and a
- jr nz, .inBattle
- call ReloadMapSpriteTilePatterns
-.inBattle
- call LoadScreenTilesFromBuffer1
- pop hl
- pop af
- ld [wUpdateSpritesEnabled], a
- ld a, [wcf4b]
- cp "@"
- ret nz
-.declinedNickname
- ld d, h
- ld e, l
- ld hl, wcd6d
- ld bc, NAME_LENGTH
- jp CopyData
-
-DoYouWantToNicknameText:
- TX_FAR _DoYouWantToNicknameText
- db "@"
-
-DisplayNameRaterScreen::
- ld hl, wBuffer
- xor a
- ld [wUpdateSpritesEnabled], a
- ld a, NAME_MON_SCREEN
- ld [wNamingScreenType], a
- call DisplayNamingScreen
- call GBPalWhiteOutWithDelay3
- call RestoreScreenTilesAndReloadTilePatterns
- call LoadGBPal
- ld a, [wcf4b]
- cp "@"
- jr z, .playerCancelled
- ld hl, wPartyMonNicks
- ld bc, NAME_LENGTH
- ld a, [wWhichPokemon]
- call AddNTimes
- ld e, l
- ld d, h
- ld hl, wBuffer
- ld bc, NAME_LENGTH
- call CopyData
- and a
- ret
-.playerCancelled
- scf
- ret
-
-DisplayNamingScreen:
- push hl
- ld hl, wd730
- set 6, [hl]
- call GBPalWhiteOutWithDelay3
- call ClearScreen
- call UpdateSprites
- ld b, SET_PAL_GENERIC
- call RunPaletteCommand
- call LoadHpBarAndStatusTilePatterns
- call LoadEDTile
- callba LoadMonPartySpriteGfx
- coord hl, 0, 4
- ld b, 9
- ld c, 18
- call TextBoxBorder
- call PrintNamingText
- ld a, 3
- ld [wTopMenuItemY], a
- ld a, 1
- ld [wTopMenuItemX], a
- ld [wLastMenuItem], a
- ld [wCurrentMenuItem], a
- ld a, $ff
- ld [wMenuWatchedKeys], a
- ld a, 7
- ld [wMaxMenuItem], a
- ld a, "@"
- ld [wcf4b], a
- xor a
- ld hl, wNamingScreenSubmitName
- ld [hli], a
- ld [hli], a
- ld [wAnimCounter], a
-.selectReturnPoint
- call PrintAlphabet
- call GBPalNormal
-.ABStartReturnPoint
- ld a, [wNamingScreenSubmitName]
- and a
- jr nz, .submitNickname
- call PrintNicknameAndUnderscores
-.dPadReturnPoint
- call PlaceMenuCursor
-.inputLoop
- ld a, [wCurrentMenuItem]
- push af
- callba AnimatePartyMon_ForceSpeed1
- pop af
- ld [wCurrentMenuItem], a
- call JoypadLowSensitivity
- ld a, [hJoyPressed]
- and a
- jr z, .inputLoop
- ld hl, .namingScreenButtonFunctions
-.checkForPressedButton
- sla a
- jr c, .foundPressedButton
- inc hl
- inc hl
- inc hl
- inc hl
- jr .checkForPressedButton
-.foundPressedButton
- ld a, [hli]
- ld e, a
- ld a, [hli]
- ld d, a
- ld a, [hli]
- ld h, [hl]
- ld l, a
- push de
- jp hl
-
-.submitNickname
- pop de
- ld hl, wcf4b
- ld bc, NAME_LENGTH
- call CopyData
- call GBPalWhiteOutWithDelay3
- call ClearScreen
- call ClearSprites
- call RunDefaultPaletteCommand
- call GBPalNormal
- xor a
- ld [wAnimCounter], a
- ld hl, wd730
- res 6, [hl]
- ld a, [wIsInBattle]
- and a
- jp z, LoadTextBoxTilePatterns
- jpab LoadHudTilePatterns
-
-.namingScreenButtonFunctions
- dw .dPadReturnPoint
- dw .pressedDown
- dw .dPadReturnPoint
- dw .pressedUp
- dw .dPadReturnPoint
- dw .pressedLeft
- dw .dPadReturnPoint
- dw .pressedRight
- dw .ABStartReturnPoint
- dw .pressedStart
- dw .selectReturnPoint
- dw .pressedSelect
- dw .ABStartReturnPoint
- dw .pressedB
- dw .ABStartReturnPoint
- dw .pressedA
-
-.pressedA_changedCase
- pop de
- ld de, .selectReturnPoint
- push de
-.pressedSelect
- ld a, [wAlphabetCase]
- xor $1
- ld [wAlphabetCase], a
- ret
-
-.pressedStart
- ld a, 1
- ld [wNamingScreenSubmitName], a
- ret
-
-.pressedA
- ld a, [wCurrentMenuItem]
- cp $5 ; "ED" row
- jr nz, .didNotPressED
- ld a, [wTopMenuItemX]
- cp $11 ; "ED" column
- jr z, .pressedStart
-.didNotPressED
- ld a, [wCurrentMenuItem]
- cp $6 ; case switch row
- jr nz, .didNotPressCaseSwtich
- ld a, [wTopMenuItemX]
- cp $1 ; case switch column
- jr z, .pressedA_changedCase
-.didNotPressCaseSwtich
- ld hl, wMenuCursorLocation
- ld a, [hli]
- ld h, [hl]
- ld l, a
- inc hl
- ld a, [hl]
- ld [wNamingScreenLetter], a
- call CalcStringLength
- ld a, [wNamingScreenLetter]
- cp $e5
- ld de, Dakutens
- jr z, .dakutensAndHandakutens
- cp $e4
- ld de, Handakutens
- jr z, .dakutensAndHandakutens
- ld a, [wNamingScreenType]
- cp NAME_MON_SCREEN
- jr nc, .checkMonNameLength
- ld a, [wNamingScreenNameLength]
- cp $7 ; max length of player/rival names
- jr .checkNameLength
-.checkMonNameLength
- ld a, [wNamingScreenNameLength]
- cp $a ; max length of pokemon nicknames
-.checkNameLength
- jr c, .addLetter
- ret
-
-.dakutensAndHandakutens
- push hl
- call DakutensAndHandakutens
- pop hl
- ret nc
- dec hl
-.addLetter
- ld a, [wNamingScreenLetter]
- ld [hli], a
- ld [hl], "@"
- ld a, SFX_PRESS_AB
- call PlaySound
- ret
-.pressedB
- ld a, [wNamingScreenNameLength]
- and a
- ret z
- call CalcStringLength
- dec hl
- ld [hl], "@"
- ret
-.pressedRight
- ld a, [wCurrentMenuItem]
- cp $6
- ret z ; can't scroll right on bottom row
- ld a, [wTopMenuItemX]
- cp $11 ; max
- jp z, .wrapToFirstColumn
- inc a
- inc a
- jr .done
-.wrapToFirstColumn
- ld a, $1
- jr .done
-.pressedLeft
- ld a, [wCurrentMenuItem]
- cp $6
- ret z ; can't scroll right on bottom row
- ld a, [wTopMenuItemX]
- dec a
- jp z, .wrapToLastColumn
- dec a
- jr .done
-.wrapToLastColumn
- ld a, $11 ; max
- jr .done
-.pressedUp
- ld a, [wCurrentMenuItem]
- dec a
- ld [wCurrentMenuItem], a
- and a
- ret nz
- ld a, $6 ; wrap to bottom row
- ld [wCurrentMenuItem], a
- ld a, $1 ; force left column
- jr .done
-.pressedDown
- ld a, [wCurrentMenuItem]
- inc a
- ld [wCurrentMenuItem], a
- cp $7
- jr nz, .wrapToTopRow
- ld a, $1
- ld [wCurrentMenuItem], a
- jr .done
-.wrapToTopRow
- cp $6
- ret nz
- ld a, $1
-.done
- ld [wTopMenuItemX], a
- jp EraseMenuCursor
-
-LoadEDTile:
- ld de, ED_Tile
- ld hl, vFont + $700
- ld bc, (ED_TileEnd - ED_Tile) / $8
- ; to fix the graphical bug on poor emulators
- ;lb bc, BANK(ED_Tile), (ED_TileEnd - ED_Tile) / $8
- jp CopyVideoDataDouble
-
-ED_Tile:
- INCBIN "gfx/font/ED.1bpp"
-ED_TileEnd:
-
-PrintAlphabet:
- xor a
- ld [H_AUTOBGTRANSFERENABLED], a
- ld a, [wAlphabetCase]
- and a
- ld de, LowerCaseAlphabet
- jr nz, .lowercase
- ld de, UpperCaseAlphabet
-.lowercase
- coord hl, 2, 5
- lb bc, 5, 9 ; 5 rows, 9 columns
-.outerLoop
- push bc
-.innerLoop
- ld a, [de]
- ld [hli], a
- inc hl
- inc de
- dec c
- jr nz, .innerLoop
- ld bc, SCREEN_WIDTH + 2
- add hl, bc
- pop bc
- dec b
- jr nz, .outerLoop
- call PlaceString
- ld a, $1
- ld [H_AUTOBGTRANSFERENABLED], a
- jp Delay3
-
-INCLUDE "text/alphabets.asm"
-
-PrintNicknameAndUnderscores:
- call CalcStringLength
- ld a, c
- ld [wNamingScreenNameLength], a
- coord hl, 10, 2
- lb bc, 1, 10
- call ClearScreenArea
- coord hl, 10, 2
- ld de, wcf4b
- call PlaceString
- coord hl, 10, 3
- ld a, [wNamingScreenType]
- cp NAME_MON_SCREEN
- jr nc, .pokemon1
- ld b, 7 ; player or rival max name length
- jr .playerOrRival1
-.pokemon1
- ld b, 10 ; pokemon max name length
-.playerOrRival1
- ld a, $76 ; underscore tile id
-.placeUnderscoreLoop
- ld [hli], a
- dec b
- jr nz, .placeUnderscoreLoop
- ld a, [wNamingScreenType]
- cp NAME_MON_SCREEN
- ld a, [wNamingScreenNameLength]
- jr nc, .pokemon2
- cp 7 ; player or rival max name length
- jr .playerOrRival2
-.pokemon2
- cp 10 ; pokemon max name length
-.playerOrRival2
- jr nz, .emptySpacesRemaining
- ; when all spaces are filled, force the cursor onto the ED tile
- call EraseMenuCursor
- ld a, $11 ; "ED" x coord
- ld [wTopMenuItemX], a
- ld a, $5 ; "ED" y coord
- ld [wCurrentMenuItem], a
- ld a, [wNamingScreenType]
- cp NAME_MON_SCREEN
- ld a, 9 ; keep the last underscore raised
- jr nc, .pokemon3
- ld a, 6 ; keep the last underscore raised
-.pokemon3
-.emptySpacesRemaining
- ld c, a
- ld b, $0
- coord hl, 10, 3
- add hl, bc
- ld [hl], $77 ; raised underscore tile id
- ret
-
-DakutensAndHandakutens:
- push de
- call CalcStringLength
- dec hl
- ld a, [hl]
- pop hl
- ld de, $2
- call IsInArray
- ret nc
- inc hl
- ld a, [hl]
- ld [wNamingScreenLetter], a
- ret
-
-INCLUDE "text/dakutens.asm"
-
-; calculates the length of the string at wcf4b and stores it in c
-CalcStringLength:
- ld hl, wcf4b
- ld c, $0
-.loop
- ld a, [hl]
- cp "@"
- ret z
- inc hl
- inc c
- jr .loop
-
-PrintNamingText:
- coord hl, 0, 1
- ld a, [wNamingScreenType]
- ld de, YourTextString
- and a
- jr z, .notNickname
- ld de, RivalsTextString
- dec a
- jr z, .notNickname
- ld a, [wcf91]
- ld [wMonPartySpriteSpecies], a
- push af
- callba WriteMonPartySpriteOAMBySpecies
- pop af
- ld [wd11e], a
- call GetMonName
- coord hl, 4, 1
- call PlaceString
- ld hl, $1
- add hl, bc
- ld [hl], $c9
- coord hl, 1, 3
- ld de, NicknameTextString
- jr .placeString
-.notNickname
- call PlaceString
- ld l, c
- ld h, b
- ld de, NameTextString
-.placeString
- jp PlaceString
-
-YourTextString:
- db "YOUR @"
-
-RivalsTextString:
- db "RIVAL's @"
-
-NameTextString:
- db "NAME?@"
-
-NicknameTextString:
- db "NICKNAME?@"
--- a/engine/menu/oaks_pc.asm
+++ /dev/null
@@ -1,28 +1,0 @@
-OpenOaksPC:
- call SaveScreenTilesToBuffer2
- ld hl, AccessedOaksPCText
- call PrintText
- ld hl, GetDexRatedText
- call PrintText
- call YesNoChoice
- ld a, [wCurrentMenuItem]
- and a
- jr nz, .closePC
- predef DisplayDexRating
-.closePC
- ld hl, ClosedOaksPCText
- call PrintText
- jp LoadScreenTilesFromBuffer2
-
-GetDexRatedText:
- TX_FAR _GetDexRatedText
- db "@"
-
-ClosedOaksPCText:
- TX_FAR _ClosedOaksPCText
- TX_WAIT
- db "@"
-
-AccessedOaksPCText:
- TX_FAR _AccessedOaksPCText
- db "@"
--- a/engine/menu/party_menu.asm
+++ /dev/null
@@ -1,325 +1,0 @@
-; [wPartyMenuTypeOrMessageID] = menu type / message ID
-; if less than $F0, it is a menu type
-; menu types:
-; 00: normal pokemon menu (e.g. Start menu)
-; 01: use healing item on pokemon menu
-; 02: in-battle switch pokemon menu
-; 03: learn TM/HM menu
-; 04: swap pokemon positions menu
-; 05: use evolution stone on pokemon menu
-; otherwise, it is a message ID
-; f0: poison healed
-; f1: burn healed
-; f2: freeze healed
-; f3: sleep healed
-; f4: paralysis healed
-; f5: HP healed
-; f6: health returned
-; f7: revitalized
-; f8: leveled up
-DrawPartyMenu_::
- xor a
- ld [H_AUTOBGTRANSFERENABLED], a
- call ClearScreen
- call UpdateSprites
- callba LoadMonPartySpriteGfxWithLCDDisabled ; load pokemon icon graphics
-
-RedrawPartyMenu_::
- ld a, [wPartyMenuTypeOrMessageID]
- cp SWAP_MONS_PARTY_MENU
- jp z, .printMessage
- call ErasePartyMenuCursors
- callba InitPartyMenuBlkPacket
- coord hl, 3, 0
- ld de, wPartySpecies
- xor a
- ld c, a
- ld [hPartyMonIndex], a
- ld [wWhichPartyMenuHPBar], a
-.loop
- ld a, [de]
- cp $FF ; reached the terminator?
- jp z, .afterDrawingMonEntries
- push bc
- push de
- push hl
- ld a, c
- push hl
- ld hl, wPartyMonNicks
- call GetPartyMonName
- pop hl
- call PlaceString ; print the pokemon's name
- callba WriteMonPartySpriteOAMByPartyIndex ; place the appropriate pokemon icon
- ld a, [hPartyMonIndex]
- ld [wWhichPokemon], a
- inc a
- ld [hPartyMonIndex], a
- call LoadMonData
- pop hl
- push hl
- ld a, [wMenuItemToSwap]
- and a ; is the player swapping pokemon positions?
- jr z, .skipUnfilledRightArrow
-; if the player is swapping pokemon positions
- dec a
- ld b, a
- ld a, [wWhichPokemon]
- cp b ; is the player swapping the current pokemon in the list?
- jr nz, .skipUnfilledRightArrow
-; the player is swapping the current pokemon in the list
- dec hl
- dec hl
- dec hl
- ld a, "▷" ; unfilled right arrow menu cursor
- ld [hli], a ; place the cursor
- inc hl
- inc hl
-.skipUnfilledRightArrow
- ld a, [wPartyMenuTypeOrMessageID] ; menu type
- cp TMHM_PARTY_MENU
- jr z, .teachMoveMenu
- cp EVO_STONE_PARTY_MENU
- jr z, .evolutionStoneMenu
- push hl
- ld bc, 14 ; 14 columns to the right
- add hl, bc
- ld de, wLoadedMonStatus
- call PrintStatusCondition
- pop hl
- push hl
- ld bc, SCREEN_WIDTH + 1 ; down 1 row and right 1 column
- ld a, [hFlags_0xFFF6]
- set 0, a
- ld [hFlags_0xFFF6], a
- add hl, bc
- predef DrawHP2 ; draw HP bar and prints current / max HP
- ld a, [hFlags_0xFFF6]
- res 0, a
- ld [hFlags_0xFFF6], a
- call SetPartyMenuHPBarColor ; color the HP bar (on SGB)
- pop hl
- jr .printLevel
-.teachMoveMenu
- push hl
- predef CanLearnTM ; check if the pokemon can learn the move
- pop hl
- ld de, .ableToLearnMoveText
- ld a, c
- and a
- jr nz, .placeMoveLearnabilityString
- ld de, .notAbleToLearnMoveText
-.placeMoveLearnabilityString
- ld bc, 20 + 9 ; down 1 row and right 9 columns
- push hl
- add hl, bc
- call PlaceString
- pop hl
-.printLevel
- ld bc, 10 ; move 10 columns to the right
- add hl, bc
- call PrintLevel
- pop hl
- pop de
- inc de
- ld bc, 2 * 20
- add hl, bc
- pop bc
- inc c
- jp .loop
-.ableToLearnMoveText
- db "ABLE@"
-.notAbleToLearnMoveText
- db "NOT ABLE@"
-.evolutionStoneMenu
- push hl
- ld hl, EvosMovesPointerTable
- ld b, 0
- ld a, [wLoadedMonSpecies]
- dec a
- add a
- rl b
- ld c, a
- add hl, bc
- ld de, wEvosMoves
- ld a, BANK(EvosMovesPointerTable)
- ld bc, 2
- call FarCopyData
- ld hl, wEvosMoves
- ld a, [hli]
- ld h, [hl]
- ld l, a
- ld de, wEvosMoves
- ld a, BANK(EvosMovesPointerTable)
- ld bc, wEvosMoves.end - wEvosMoves
- call FarCopyData
- ld hl, wEvosMoves
- ld de, .notAbleToEvolveText
-; loop through the pokemon's evolution entries
-.checkEvolutionsLoop
- ld a, [hli]
- and a ; reached terminator?
- jr z, .placeEvolutionStoneString ; if so, place the "NOT ABLE" string
- inc hl
- inc hl
- cp EV_ITEM
- jr nz, .checkEvolutionsLoop
-; if it's a stone evolution entry
- dec hl
- dec hl
- ld b, [hl]
- ld a, [wEvoStoneItemID] ; the stone the player used
- inc hl
- inc hl
- inc hl
- cp b ; does the player's stone match this evolution entry's stone?
- jr nz, .checkEvolutionsLoop
-; if it does match
- ld de, .ableToEvolveText
-.placeEvolutionStoneString
- ld bc, 20 + 9 ; down 1 row and right 9 columns
- pop hl
- push hl
- add hl, bc
- call PlaceString
- pop hl
- jr .printLevel
-.ableToEvolveText
- db "ABLE@"
-.notAbleToEvolveText
- db "NOT ABLE@"
-.afterDrawingMonEntries
- ld b, SET_PAL_PARTY_MENU
- call RunPaletteCommand
-.printMessage
- ld hl, wd730
- ld a, [hl]
- push af
- push hl
- set 6, [hl] ; turn off letter printing delay
- ld a, [wPartyMenuTypeOrMessageID] ; message ID
- cp $F0
- jr nc, .printItemUseMessage
- add a
- ld hl, PartyMenuMessagePointers
- ld b, 0
- ld c, a
- add hl, bc
- ld a, [hli]
- ld h, [hl]
- ld l, a
- call PrintText
-.done
- pop hl
- pop af
- ld [hl], a
- ld a, 1
- ld [H_AUTOBGTRANSFERENABLED], a
- call Delay3
- jp GBPalNormal
-.printItemUseMessage
- and $0F
- ld hl, PartyMenuItemUseMessagePointers
- add a
- ld c, a
- ld b, 0
- add hl, bc
- ld a, [hli]
- ld h, [hl]
- ld l, a
- push hl
- ld a, [wUsedItemOnWhichPokemon]
- ld hl, wPartyMonNicks
- call GetPartyMonName
- pop hl
- call PrintText
- jr .done
-
-PartyMenuItemUseMessagePointers:
- dw AntidoteText
- dw BurnHealText
- dw IceHealText
- dw AwakeningText
- dw ParlyzHealText
- dw PotionText
- dw FullHealText
- dw ReviveText
- dw RareCandyText
-
-PartyMenuMessagePointers:
- dw PartyMenuNormalText
- dw PartyMenuItemUseText
- dw PartyMenuBattleText
- dw PartyMenuUseTMText
- dw PartyMenuSwapMonText
- dw PartyMenuItemUseText
-
-PartyMenuNormalText:
- TX_FAR _PartyMenuNormalText
- db "@"
-
-PartyMenuItemUseText:
- TX_FAR _PartyMenuItemUseText
- db "@"
-
-PartyMenuBattleText:
- TX_FAR _PartyMenuBattleText
- db "@"
-
-PartyMenuUseTMText:
- TX_FAR _PartyMenuUseTMText
- db "@"
-
-PartyMenuSwapMonText:
- TX_FAR _PartyMenuSwapMonText
- db "@"
-
-PotionText:
- TX_FAR _PotionText
- db "@"
-
-AntidoteText:
- TX_FAR _AntidoteText
- db "@"
-
-ParlyzHealText:
- TX_FAR _ParlyzHealText
- db "@"
-
-BurnHealText:
- TX_FAR _BurnHealText
- db "@"
-
-IceHealText:
- TX_FAR _IceHealText
- db "@"
-
-AwakeningText:
- TX_FAR _AwakeningText
- db "@"
-
-FullHealText:
- TX_FAR _FullHealText
- db "@"
-
-ReviveText:
- TX_FAR _ReviveText
- db "@"
-
-RareCandyText:
- TX_FAR _RareCandyText
- TX_SFX_ITEM_1 ; probably supposed to play SFX_LEVEL_UP but the wrong music bank is loaded
- TX_BLINK
- db "@"
-
-SetPartyMenuHPBarColor:
- ld hl, wPartyMenuHPBarColors
- ld a, [wWhichPartyMenuHPBar]
- ld c, a
- ld b, 0
- add hl, bc
- call GetHealthBarColor
- ld b, UPDATE_PARTY_MENU_BLK_PACKET
- call RunPaletteCommand
- ld hl, wWhichPartyMenuHPBar
- inc [hl]
- ret
--- a/engine/menu/pc.asm
+++ /dev/null
@@ -1,141 +1,0 @@
-ActivatePC::
- call SaveScreenTilesToBuffer2
- ld a, SFX_TURN_ON_PC
- call PlaySound
- ld hl, TurnedOnPC1Text
- call PrintText
- call WaitForSoundToFinish
- ld hl, wFlags_0xcd60
- set 3, [hl]
- call LoadScreenTilesFromBuffer2
- call Delay3
-PCMainMenu:
- callba DisplayPCMainMenu
- ld hl, wFlags_0xcd60
- set 5, [hl]
- call HandleMenuInput
- bit 1, a ;if player pressed B
- jp nz, LogOff
- ld a, [wMaxMenuItem]
- cp 2
- jr nz, .next ;if not 2 menu items (not counting log off) (2 occurs before you get the pokedex)
- ld a, [wCurrentMenuItem]
- and a
- jp z, BillsPC ;if current menu item id is 0, it's bills pc
- cp 1
- jr z, .playersPC ;if current menu item id is 1, it's players pc
- jp LogOff ;otherwise, it's 2, and you're logging off
-.next
- cp 3
- jr nz, .next2 ;if not 3 menu items (not counting log off) (3 occurs after you get the pokedex, before you beat the pokemon league)
- ld a, [wCurrentMenuItem]
- and a
- jp z, BillsPC ;if current menu item id is 0, it's bills pc
- cp 1
- jr z, .playersPC ;if current menu item id is 1, it's players pc
- cp 2
- jp z, OaksPC ;if current menu item id is 2, it's oaks pc
- jp LogOff ;otherwise, it's 3, and you're logging off
-.next2
- ld a, [wCurrentMenuItem]
- and a
- jp z, BillsPC ;if current menu item id is 0, it's bills pc
- cp 1
- jr z, .playersPC ;if current menu item id is 1, it's players pc
- cp 2
- jp z, OaksPC ;if current menu item id is 2, it's oaks pc
- cp 3
- jp z, PKMNLeague ;if current menu item id is 3, it's pkmnleague
- jp LogOff ;otherwise, it's 4, and you're logging off
-.playersPC
- ld hl, wFlags_0xcd60
- res 5, [hl]
- set 3, [hl]
- ld a, SFX_ENTER_PC
- call PlaySound
- call WaitForSoundToFinish
- ld hl, AccessedMyPCText
- call PrintText
- callba PlayerPC
- jr ReloadMainMenu
-OaksPC:
- ld a, SFX_ENTER_PC
- call PlaySound
- call WaitForSoundToFinish
- callba OpenOaksPC
- jr ReloadMainMenu
-PKMNLeague:
- ld a, SFX_ENTER_PC
- call PlaySound
- call WaitForSoundToFinish
- callba PKMNLeaguePC
- jr ReloadMainMenu
-BillsPC:
- ld a, SFX_ENTER_PC
- call PlaySound
- call WaitForSoundToFinish
- CheckEvent EVENT_MET_BILL
- jr nz, .billsPC ;if you've met bill, use that bill's instead of someone's
- ld hl, AccessedSomeonesPCText
- jr .printText
-.billsPC
- ld hl, AccessedBillsPCText
-.printText
- call PrintText
- callba BillsPC_
-ReloadMainMenu:
- xor a
- ld [wDoNotWaitForButtonPressAfterDisplayingText], a
- call ReloadMapData
- call UpdateSprites
- jp PCMainMenu
-LogOff:
- ld a, SFX_TURN_OFF_PC
- call PlaySound
- call WaitForSoundToFinish
- ld hl, wFlags_0xcd60
- res 3, [hl]
- res 5, [hl]
- ret
-
-TurnedOnPC1Text:
- TX_FAR _TurnedOnPC1Text
- db "@"
-
-AccessedBillsPCText:
- TX_FAR _AccessedBillsPCText
- db "@"
-
-AccessedSomeonesPCText:
- TX_FAR _AccessedSomeonesPCText
- db "@"
-
-AccessedMyPCText:
- TX_FAR _AccessedMyPCText
- db "@"
-
-; removes one of the specified item ID [hItemToRemoveID] from bag (if existent)
-RemoveItemByID::
- ld hl, wBagItems
- ld a, [hItemToRemoveID]
- ld b, a
- xor a
- ld [hItemToRemoveIndex], a
-.loop
- ld a, [hli]
- cp -1 ; reached terminator?
- ret z
- cp b
- jr z, .foundItem
- inc hl
- ld a, [hItemToRemoveIndex]
- inc a
- ld [hItemToRemoveIndex], a
- jr .loop
-.foundItem
- ld a, $1
- ld [wItemQuantity], a
- ld a, [hItemToRemoveIndex]
- ld [wWhichPokemon], a
- ld hl, wNumBagItems
- jp RemoveItemFromInventory
--- a/engine/menu/players_pc.asm
+++ /dev/null
@@ -1,303 +1,0 @@
-PlayerPC::
- ld hl, wd730
- set 6, [hl]
- ld a, ITEM_NAME
- ld [wNameListType], a
- call SaveScreenTilesToBuffer1
- xor a
- ld [wBagSavedMenuItem], a
- ld [wParentMenuItem], a
- ld a, [wFlags_0xcd60]
- bit 3, a ; accessing player's PC through another PC?
- jr nz, PlayerPCMenu
-; accessing it directly
- ld a, SFX_TURN_ON_PC
- call PlaySound
- ld hl, TurnedOnPC2Text
- call PrintText
-
-PlayerPCMenu:
- ld a, [wParentMenuItem]
- ld [wCurrentMenuItem], a
- ld hl, wFlags_0xcd60
- set 5, [hl]
- call LoadScreenTilesFromBuffer2
- coord hl, 0, 0
- ld b, $8
- ld c, $e
- call TextBoxBorder
- call UpdateSprites
- coord hl, 2, 2
- ld de, PlayersPCMenuEntries
- call PlaceString
- ld hl, wTopMenuItemY
- ld a, 2
- ld [hli], a ; wTopMenuItemY
- dec a
- ld [hli], a ; wTopMenuItemX
- inc hl
- inc hl
- ld a, 3
- ld [hli], a ; wMaxMenuItem
- ld a, A_BUTTON | B_BUTTON
- ld [hli], a ; wMenuWatchedKeys
- xor a
- ld [hl], a
- ld hl, wListScrollOffset
- ld [hli], a ; wListScrollOffset
- ld [hl], a ; wMenuWatchMovingOutOfBounds
- ld [wPlayerMonNumber], a
- ld hl, WhatDoYouWantText
- call PrintText
- call HandleMenuInput
- bit 1, a
- jp nz, ExitPlayerPC
- call PlaceUnfilledArrowMenuCursor
- ld a, [wCurrentMenuItem]
- ld [wParentMenuItem], a
- and a
- jp z, PlayerPCWithdraw
- dec a
- jp z, PlayerPCDeposit
- dec a
- jp z, PlayerPCToss
-
-ExitPlayerPC:
- ld a, [wFlags_0xcd60]
- bit 3, a ; accessing player's PC through another PC?
- jr nz, .next
-; accessing it directly
- ld a, SFX_TURN_OFF_PC
- call PlaySound
- call WaitForSoundToFinish
-.next
- ld hl, wFlags_0xcd60
- res 5, [hl]
- call LoadScreenTilesFromBuffer2
- xor a
- ld [wListScrollOffset], a
- ld [wBagSavedMenuItem], a
- ld hl, wd730
- res 6, [hl]
- xor a
- ld [wDoNotWaitForButtonPressAfterDisplayingText], a
- ret
-
-PlayerPCDeposit:
- xor a
- ld [wCurrentMenuItem], a
- ld [wListScrollOffset], a
- ld a, [wNumBagItems]
- and a
- jr nz, .loop
- ld hl, NothingToDepositText
- call PrintText
- jp PlayerPCMenu
-.loop
- ld hl, WhatToDepositText
- call PrintText
- ld hl, wNumBagItems
- ld a, l
- ld [wListPointer], a
- ld a, h
- ld [wListPointer + 1], a
- xor a
- ld [wPrintItemPrices], a
- ld a, ITEMLISTMENU
- ld [wListMenuID], a
- call DisplayListMenuID
- jp c, PlayerPCMenu
- call IsKeyItem
- ld a, 1
- ld [wItemQuantity], a
- ld a, [wIsKeyItem]
- and a
- jr nz, .next
-; if it's not a key item, there can be more than one of the item
- ld hl, DepositHowManyText
- call PrintText
- call DisplayChooseQuantityMenu
- cp $ff
- jp z, .loop
-.next
- ld hl, wNumBoxItems
- call AddItemToInventory
- jr c, .roomAvailable
- ld hl, NoRoomToStoreText
- call PrintText
- jp .loop
-.roomAvailable
- ld hl, wNumBagItems
- call RemoveItemFromInventory
- call WaitForSoundToFinish
- ld a, SFX_WITHDRAW_DEPOSIT
- call PlaySound
- call WaitForSoundToFinish
- ld hl, ItemWasStoredText
- call PrintText
- jp .loop
-
-PlayerPCWithdraw:
- xor a
- ld [wCurrentMenuItem], a
- ld [wListScrollOffset], a
- ld a, [wNumBoxItems]
- and a
- jr nz, .loop
- ld hl, NothingStoredText
- call PrintText
- jp PlayerPCMenu
-.loop
- ld hl, WhatToWithdrawText
- call PrintText
- ld hl, wNumBoxItems
- ld a, l
- ld [wListPointer], a
- ld a, h
- ld [wListPointer + 1], a
- xor a
- ld [wPrintItemPrices], a
- ld a, ITEMLISTMENU
- ld [wListMenuID], a
- call DisplayListMenuID
- jp c, PlayerPCMenu
- call IsKeyItem
- ld a, 1
- ld [wItemQuantity], a
- ld a, [wIsKeyItem]
- and a
- jr nz, .next
-; if it's not a key item, there can be more than one of the item
- ld hl, WithdrawHowManyText
- call PrintText
- call DisplayChooseQuantityMenu
- cp $ff
- jp z, .loop
-.next
- ld hl, wNumBagItems
- call AddItemToInventory
- jr c, .roomAvailable
- ld hl, CantCarryMoreText
- call PrintText
- jp .loop
-.roomAvailable
- ld hl, wNumBoxItems
- call RemoveItemFromInventory
- call WaitForSoundToFinish
- ld a, SFX_WITHDRAW_DEPOSIT
- call PlaySound
- call WaitForSoundToFinish
- ld hl, WithdrewItemText
- call PrintText
- jp .loop
-
-PlayerPCToss:
- xor a
- ld [wCurrentMenuItem], a
- ld [wListScrollOffset], a
- ld a, [wNumBoxItems]
- and a
- jr nz, .loop
- ld hl, NothingStoredText
- call PrintText
- jp PlayerPCMenu
-.loop
- ld hl, WhatToTossText
- call PrintText
- ld hl, wNumBoxItems
- ld a, l
- ld [wListPointer], a
- ld a, h
- ld [wListPointer + 1], a
- xor a
- ld [wPrintItemPrices], a
- ld a, ITEMLISTMENU
- ld [wListMenuID], a
- push hl
- call DisplayListMenuID
- pop hl
- jp c, PlayerPCMenu
- push hl
- call IsKeyItem
- pop hl
- ld a, 1
- ld [wItemQuantity], a
- ld a, [wIsKeyItem]
- and a
- jr nz, .next
- ld a, [wcf91]
- call IsItemHM
- jr c, .next
-; if it's not a key item, there can be more than one of the item
- push hl
- ld hl, TossHowManyText
- call PrintText
- call DisplayChooseQuantityMenu
- pop hl
- cp $ff
- jp z, .loop
-.next
- call TossItem ; disallows tossing key items
- jp .loop
-
-PlayersPCMenuEntries:
- db "WITHDRAW ITEM"
- next "DEPOSIT ITEM"
- next "TOSS ITEM"
- next "LOG OFF@"
-
-TurnedOnPC2Text:
- TX_FAR _TurnedOnPC2Text
- db "@"
-
-WhatDoYouWantText:
- TX_FAR _WhatDoYouWantText
- db "@"
-
-WhatToDepositText:
- TX_FAR _WhatToDepositText
- db "@"
-
-DepositHowManyText:
- TX_FAR _DepositHowManyText
- db "@"
-
-ItemWasStoredText:
- TX_FAR _ItemWasStoredText
- db "@"
-
-NothingToDepositText:
- TX_FAR _NothingToDepositText
- db "@"
-
-NoRoomToStoreText:
- TX_FAR _NoRoomToStoreText
- db "@"
-
-WhatToWithdrawText:
- TX_FAR _WhatToWithdrawText
- db "@"
-
-WithdrawHowManyText:
- TX_FAR _WithdrawHowManyText
- db "@"
-
-WithdrewItemText:
- TX_FAR _WithdrewItemText
- db "@"
-
-NothingStoredText:
- TX_FAR _NothingStoredText
- db "@"
-
-CantCarryMoreText:
- TX_FAR _CantCarryMoreText
- db "@"
-
-WhatToTossText:
- TX_FAR _WhatToTossText
- db "@"
-
-TossHowManyText:
- TX_FAR _TossHowManyText
- db "@"
--- a/engine/menu/pokedex.asm
+++ /dev/null
@@ -1,665 +1,0 @@
-ShowPokedexMenu:
- call GBPalWhiteOut
- call ClearScreen
- call UpdateSprites
- ld a, [wListScrollOffset]
- push af
- xor a
- ld [wCurrentMenuItem], a
- ld [wListScrollOffset], a
- ld [wLastMenuItem], a
- inc a
- ld [wd11e], a
- ld [hJoy7], a
-.setUpGraphics
- ld b, SET_PAL_GENERIC
- call RunPaletteCommand
- callab LoadPokedexTilePatterns
-.doPokemonListMenu
- ld hl, wTopMenuItemY
- ld a, 3
- ld [hli], a ; top menu item Y
- xor a
- ld [hli], a ; top menu item X
- inc a
- ld [wMenuWatchMovingOutOfBounds], a
- inc hl
- inc hl
- ld a, 6
- ld [hli], a ; max menu item ID
- ld [hl], D_LEFT | D_RIGHT | B_BUTTON | A_BUTTON
- call HandlePokedexListMenu
- jr c, .goToSideMenu ; if the player chose a pokemon from the list
-.exitPokedex
- xor a
- ld [wMenuWatchMovingOutOfBounds], a
- ld [wCurrentMenuItem], a
- ld [wLastMenuItem], a
- ld [hJoy7], a
- ld [wWastedByteCD3A], a
- ld [wOverrideSimulatedJoypadStatesMask], a
- pop af
- ld [wListScrollOffset], a
- call GBPalWhiteOutWithDelay3
- call RunDefaultPaletteCommand
- jp ReloadMapData
-.goToSideMenu
- call HandlePokedexSideMenu
- dec b
- jr z, .exitPokedex ; if the player chose Quit
- dec b
- jr z, .doPokemonListMenu ; if pokemon not seen or player pressed B button
- jp .setUpGraphics ; if pokemon data or area was shown
-
-; handles the menu on the lower right in the pokedex screen
-; OUTPUT:
-; b = reason for exiting menu
-; 00: showed pokemon data or area
-; 01: the player chose Quit
-; 02: the pokemon has not been seen yet or the player pressed the B button
-HandlePokedexSideMenu:
- call PlaceUnfilledArrowMenuCursor
- ld a, [wCurrentMenuItem]
- push af
- ld b, a
- ld a, [wLastMenuItem]
- push af
- ld a, [wListScrollOffset]
- push af
- add b
- inc a
- ld [wd11e], a
- ld a, [wd11e]
- push af
- ld a, [wDexMaxSeenMon]
- push af ; this doesn't need to be preserved
- ld hl, wPokedexSeen
- call IsPokemonBitSet
- ld b, 2
- jr z, .exitSideMenu
- call PokedexToIndex
- ld hl, wTopMenuItemY
- ld a, 10
- ld [hli], a ; top menu item Y
- ld a, 15
- ld [hli], a ; top menu item X
- xor a
- ld [hli], a ; current menu item ID
- inc hl
- ld a, 3
- ld [hli], a ; max menu item ID
- ;ld a, A_BUTTON | B_BUTTON
- ld [hli], a ; menu watched keys (A button and B button)
- xor a
- ld [hli], a ; old menu item ID
- ld [wMenuWatchMovingOutOfBounds], a
-.handleMenuInput
- call HandleMenuInput
- bit 1, a ; was the B button pressed?
- ld b, 2
- jr nz, .buttonBPressed
- ld a, [wCurrentMenuItem]
- and a
- jr z, .choseData
- dec a
- jr z, .choseCry
- dec a
- jr z, .choseArea
-.choseQuit
- ld b, 1
-.exitSideMenu
- pop af
- ld [wDexMaxSeenMon], a
- pop af
- ld [wd11e], a
- pop af
- ld [wListScrollOffset], a
- pop af
- ld [wLastMenuItem], a
- pop af
- ld [wCurrentMenuItem], a
- push bc
- coord hl, 0, 3
- ld de, 20
- lb bc, " ", 13
- call DrawTileLine ; cover up the menu cursor in the pokemon list
- pop bc
- ret
-
-.buttonBPressed
- push bc
- coord hl, 15, 10
- ld de, 20
- lb bc, " ", 7
- call DrawTileLine ; cover up the menu cursor in the side menu
- pop bc
- jr .exitSideMenu
-
-.choseData
- call ShowPokedexDataInternal
- ld b, 0
- jr .exitSideMenu
-
-; play pokemon cry
-.choseCry
- ld a, [wd11e]
- call GetCryData
- call PlaySound
- jr .handleMenuInput
-
-.choseArea
- predef LoadTownMap_Nest ; display pokemon areas
- ld b, 0
- jr .exitSideMenu
-
-; handles the list of pokemon on the left of the pokedex screen
-; sets carry flag if player presses A, unsets carry flag if player presses B
-HandlePokedexListMenu:
- xor a
- ld [H_AUTOBGTRANSFERENABLED], a
-; draw the horizontal line separating the seen and owned amounts from the menu
- coord hl, 15, 8
- ld a, "─"
- ld [hli], a
- ld [hli], a
- ld [hli], a
- ld [hli], a
- ld [hli], a
- coord hl, 14, 0
- ld [hl], $71 ; vertical line tile
- coord hl, 14, 1
- call DrawPokedexVerticalLine
- coord hl, 14, 9
- call DrawPokedexVerticalLine
- ld hl, wPokedexSeen
- ld b, wPokedexSeenEnd - wPokedexSeen
- call CountSetBits
- ld de, wNumSetBits
- coord hl, 16, 3
- lb bc, 1, 3
- call PrintNumber ; print number of seen pokemon
- ld hl, wPokedexOwned
- ld b, wPokedexOwnedEnd - wPokedexOwned
- call CountSetBits
- ld de, wNumSetBits
- coord hl, 16, 6
- lb bc, 1, 3
- call PrintNumber ; print number of owned pokemon
- coord hl, 16, 2
- ld de, PokedexSeenText
- call PlaceString
- coord hl, 16, 5
- ld de, PokedexOwnText
- call PlaceString
- coord hl, 1, 1
- ld de, PokedexContentsText
- call PlaceString
- coord hl, 16, 10
- ld de, PokedexMenuItemsText
- call PlaceString
-; find the highest pokedex number among the pokemon the player has seen
- ld hl, wPokedexSeenEnd - 1
- ld b, (wPokedexSeenEnd - wPokedexSeen) * 8 + 1
-.maxSeenPokemonLoop
- ld a, [hld]
- ld c, 8
-.maxSeenPokemonInnerLoop
- dec b
- sla a
- jr c, .storeMaxSeenPokemon
- dec c
- jr nz, .maxSeenPokemonInnerLoop
- jr .maxSeenPokemonLoop
-
-.storeMaxSeenPokemon
- ld a, b
- ld [wDexMaxSeenMon], a
-.loop
- xor a
- ld [H_AUTOBGTRANSFERENABLED], a
- coord hl, 4, 2
- lb bc, 14, 10
- call ClearScreenArea
- coord hl, 1, 3
- ld a, [wListScrollOffset]
- ld [wd11e], a
- ld d, 7
- ld a, [wDexMaxSeenMon]
- cp 7
- jr nc, .printPokemonLoop
- ld d, a
- dec a
- ld [wMaxMenuItem], a
-; loop to print pokemon pokedex numbers and names
-; if the player has owned the pokemon, it puts a pokeball beside the name
-.printPokemonLoop
- ld a, [wd11e]
- inc a
- ld [wd11e], a
- push af
- push de
- push hl
- ld de, -SCREEN_WIDTH
- add hl, de
- ld de, wd11e
- lb bc, LEADING_ZEROES | 1, 3
- call PrintNumber ; print the pokedex number
- ld de, SCREEN_WIDTH
- add hl, de
- dec hl
- push hl
- ld hl, wPokedexOwned
- call IsPokemonBitSet
- pop hl
- ld a, " "
- jr z, .writeTile
- ld a, $72 ; pokeball tile
-.writeTile
- ld [hl], a ; put a pokeball next to pokemon that the player has owned
- push hl
- ld hl, wPokedexSeen
- call IsPokemonBitSet
- jr nz, .getPokemonName ; if the player has seen the pokemon
- ld de, .dashedLine ; print a dashed line in place of the name if the player hasn't seen the pokemon
- jr .skipGettingName
-.dashedLine ; for unseen pokemon in the list
- db "----------@"
-.getPokemonName
- call PokedexToIndex
- call GetMonName
-.skipGettingName
- pop hl
- inc hl
- call PlaceString
- pop hl
- ld bc, 2 * SCREEN_WIDTH
- add hl, bc
- pop de
- pop af
- ld [wd11e], a
- dec d
- jr nz, .printPokemonLoop
- ld a, 01
- ld [H_AUTOBGTRANSFERENABLED], a
- call Delay3
- call GBPalNormal
- call HandleMenuInput
- bit 1, a ; was the B button pressed?
- jp nz, .buttonBPressed
-.checkIfUpPressed
- bit 6, a ; was Up pressed?
- jr z, .checkIfDownPressed
-.upPressed ; scroll up one row
- ld a, [wListScrollOffset]
- and a
- jp z, .loop
- dec a
- ld [wListScrollOffset], a
- jp .loop
-.checkIfDownPressed
- bit 7, a ; was Down pressed?
- jr z, .checkIfRightPressed
-.downPressed ; scroll down one row
- ld a, [wDexMaxSeenMon]
- cp 7
- jp c, .loop ; can't if the list is shorter than 7
- sub 7
- ld b, a
- ld a, [wListScrollOffset]
- cp b
- jp z, .loop
- inc a
- ld [wListScrollOffset], a
- jp .loop
-.checkIfRightPressed
- bit 4, a ; was Right pressed?
- jr z, .checkIfLeftPressed
-.rightPressed ; scroll down 7 rows
- ld a, [wDexMaxSeenMon]
- cp 7
- jp c, .loop ; can't if the list is shorter than 7
- sub 6
- ld b, a
- ld a, [wListScrollOffset]
- add 7
- ld [wListScrollOffset], a
- cp b
- jp c, .loop
- dec b
- ld a, b
- ld [wListScrollOffset], a
- jp .loop
-.checkIfLeftPressed ; scroll up 7 rows
- bit 5, a ; was Left pressed?
- jr z, .buttonAPressed
-.leftPressed
- ld a, [wListScrollOffset]
- sub 7
- ld [wListScrollOffset], a
- jp nc, .loop
- xor a
- ld [wListScrollOffset], a
- jp .loop
-.buttonAPressed
- scf
- ret
-.buttonBPressed
- and a
- ret
-
-DrawPokedexVerticalLine:
- ld c, 9 ; height of line
- ld de, SCREEN_WIDTH
- ld a, $71 ; vertical line tile
-.loop
- ld [hl], a
- add hl, de
- xor 1 ; toggle between vertical line tile and box tile
- dec c
- jr nz, .loop
- ret
-
-PokedexSeenText:
- db "SEEN@"
-
-PokedexOwnText:
- db "OWN@"
-
-PokedexContentsText:
- db "CONTENTS@"
-
-PokedexMenuItemsText:
- db "DATA"
- next "CRY"
- next "AREA"
- next "QUIT@"
-
-; tests if a pokemon's bit is set in the seen or owned pokemon bit fields
-; INPUT:
-; [wd11e] = pokedex number
-; hl = address of bit field
-IsPokemonBitSet:
- ld a, [wd11e]
- dec a
- ld c, a
- ld b, FLAG_TEST
- predef FlagActionPredef
- ld a, c
- and a
- ret
-
-; function to display pokedex data from outside the pokedex
-ShowPokedexData:
- call GBPalWhiteOutWithDelay3
- call ClearScreen
- call UpdateSprites
- callab LoadPokedexTilePatterns ; load pokedex tiles
-
-; function to display pokedex data from inside the pokedex
-ShowPokedexDataInternal:
- ld hl, wd72c
- set 1, [hl]
- ld a, $33 ; 3/7 volume
- ld [rNR50], a
- call GBPalWhiteOut ; zero all palettes
- call ClearScreen
- ld a, [wd11e] ; pokemon ID
- ld [wcf91], a
- push af
- ld b, SET_PAL_POKEDEX
- call RunPaletteCommand
- pop af
- ld [wd11e], a
- ld a, [hTilesetType]
- push af
- xor a
- ld [hTilesetType], a
-
- coord hl, 0, 0
- ld de, 1
- lb bc, $64, SCREEN_WIDTH
- call DrawTileLine ; draw top border
-
- coord hl, 0, 17
- ld b, $6f
- call DrawTileLine ; draw bottom border
-
- coord hl, 0, 1
- ld de, 20
- lb bc, $66, $10
- call DrawTileLine ; draw left border
-
- coord hl, 19, 1
- ld b, $67
- call DrawTileLine ; draw right border
-
- ld a, $63 ; upper left corner tile
- Coorda 0, 0
- ld a, $65 ; upper right corner tile
- Coorda 19, 0
- ld a, $6c ; lower left corner tile
- Coorda 0, 17
- ld a, $6e ; lower right corner tile
- Coorda 19, 17
-
- coord hl, 0, 9
- ld de, PokedexDataDividerLine
- call PlaceString ; draw horizontal divider line
-
- coord hl, 9, 6
- ld de, HeightWeightText
- call PlaceString
-
- call GetMonName
- coord hl, 9, 2
- call PlaceString
-
- ld hl, PokedexEntryPointers
- ld a, [wd11e]
- dec a
- ld e, a
- ld d, 0
- add hl, de
- add hl, de
- ld a, [hli]
- ld e, a
- ld d, [hl] ; de = address of pokedex entry
-
- coord hl, 9, 4
- call PlaceString ; print species name
-
- ld h, b
- ld l, c
- push de
- ld a, [wd11e]
- push af
- call IndexToPokedex
-
- coord hl, 2, 8
- ld a, "№"
- ld [hli], a
- ld a, "⠄"
- ld [hli], a
- ld de, wd11e
- lb bc, LEADING_ZEROES | 1, 3
- call PrintNumber ; print pokedex number
-
- ld hl, wPokedexOwned
- call IsPokemonBitSet
- pop af
- ld [wd11e], a
- ld a, [wcf91]
- ld [wd0b5], a
- pop de
-
- push af
- push bc
- push de
- push hl
-
- call Delay3
- call GBPalNormal
- call GetMonHeader ; load pokemon picture location
- coord hl, 1, 1
- call LoadFlippedFrontSpriteByMonIndex ; draw pokemon picture
- ld a, [wcf91]
- call PlayCry ; play pokemon cry
-
- pop hl
- pop de
- pop bc
- pop af
-
- ld a, c
- and a
- jp z, .waitForButtonPress ; if the pokemon has not been owned, don't print the height, weight, or description
- inc de ; de = address of feet (height)
- ld a, [de] ; reads feet, but a is overwritten without being used
- coord hl, 12, 6
- lb bc, 1, 2
- call PrintNumber ; print feet (height)
- ld a, $60 ; feet symbol tile (one tick)
- ld [hl], a
- inc de
- inc de ; de = address of inches (height)
- coord hl, 15, 6
- lb bc, LEADING_ZEROES | 1, 2
- call PrintNumber ; print inches (height)
- ld a, $61 ; inches symbol tile (two ticks)
- ld [hl], a
-; now print the weight (note that weight is stored in tenths of pounds internally)
- inc de
- inc de
- inc de ; de = address of upper byte of weight
- push de
-; put weight in big-endian order at hDexWeight
- ld hl, hDexWeight
- ld a, [hl] ; save existing value of [hDexWeight]
- push af
- ld a, [de] ; a = upper byte of weight
- ld [hli], a ; store upper byte of weight in [hDexWeight]
- ld a, [hl] ; save existing value of [hDexWeight + 1]
- push af
- dec de
- ld a, [de] ; a = lower byte of weight
- ld [hl], a ; store lower byte of weight in [hDexWeight + 1]
- ld de, hDexWeight
- coord hl, 11, 8
- lb bc, 2, 5 ; 2 bytes, 5 digits
- call PrintNumber ; print weight
- coord hl, 14, 8
- ld a, [hDexWeight + 1]
- sub 10
- ld a, [hDexWeight]
- sbc 0
- jr nc, .next
- ld [hl], "0" ; if the weight is less than 10, put a 0 before the decimal point
-.next
- inc hl
- ld a, [hli]
- ld [hld], a ; make space for the decimal point by moving the last digit forward one tile
- ld [hl], "⠄" ; decimal point tile
- pop af
- ld [hDexWeight + 1], a ; restore original value of [hDexWeight + 1]
- pop af
- ld [hDexWeight], a ; restore original value of [hDexWeight]
- pop hl
- inc hl ; hl = address of pokedex description text
- coord bc, 1, 11
- ld a, 2
- ld [$fff4], a
- call TextCommandProcessor ; print pokedex description text
- xor a
- ld [$fff4], a
-.waitForButtonPress
- call JoypadLowSensitivity
- ld a, [hJoy5]
- and A_BUTTON | B_BUTTON
- jr z, .waitForButtonPress
- pop af
- ld [hTilesetType], a
- call GBPalWhiteOut
- call ClearScreen
- call RunDefaultPaletteCommand
- call LoadTextBoxTilePatterns
- call GBPalNormal
- ld hl, wd72c
- res 1, [hl]
- ld a, $77 ; max volume
- ld [rNR50], a
- ret
-
-HeightWeightText:
- db "HT ?",$60,"??",$61
- next "WT ???lb@"
-
-; XXX does anything point to this?
-PokeText:
- db "#@"
-
-; horizontal line that divides the pokedex text description from the rest of the data
-PokedexDataDividerLine:
- db $68,$69,$6B,$69,$6B
- db $69,$6B,$69,$6B,$6B
- db $6B,$6B,$69,$6B,$69
- db $6B,$69,$6B,$69,$6A
- db "@"
-
-; draws a line of tiles
-; INPUT:
-; b = tile ID
-; c = number of tile ID's to write
-; de = amount to destination address after each tile (1 for horizontal, 20 for vertical)
-; hl = destination address
-DrawTileLine:
- push bc
- push de
-.loop
- ld [hl], b
- add hl, de
- dec c
- jr nz, .loop
- pop de
- pop bc
- ret
-
-INCLUDE "data/pokedex_entries.asm"
-
-PokedexToIndex:
- ; converts the Pokédex number at wd11e to an index
- push bc
- push hl
- ld a, [wd11e]
- ld b, a
- ld c, 0
- ld hl, PokedexOrder
-
-.loop ; go through the list until we find an entry with a matching dex number
- inc c
- ld a, [hli]
- cp b
- jr nz, .loop
-
- ld a, c
- ld [wd11e], a
- pop hl
- pop bc
- ret
-
-IndexToPokedex:
- ; converts the index number at wd11e to a Pokédex number
- push bc
- push hl
- ld a, [wd11e]
- dec a
- ld hl, PokedexOrder
- ld b, 0
- ld c, a
- add hl, bc
- ld a, [hl]
- ld [wd11e], a
- pop hl
- pop bc
- ret
-
-INCLUDE "data/pokedex_order.asm"
--- a/engine/menu/prize_menu.asm
+++ /dev/null
@@ -1,306 +1,0 @@
-CeladonPrizeMenu::
- ld b, COIN_CASE
- call IsItemInBag
- jr nz, .havingCoinCase
- ld hl, RequireCoinCaseTextPtr
- jp PrintText
-.havingCoinCase
- ld hl, wd730
- set 6, [hl] ; disable letter-printing delay
- ld hl, ExchangeCoinsForPrizesTextPtr
- call PrintText
-; the following are the menu settings
- xor a
- ld [wCurrentMenuItem], a
- ld [wLastMenuItem], a
- ld a, A_BUTTON | B_BUTTON
- ld [wMenuWatchedKeys], a
- ld a, $03
- ld [wMaxMenuItem], a
- ld a, $04
- ld [wTopMenuItemY], a
- ld a, $01
- ld [wTopMenuItemX], a
- call PrintPrizePrice
- coord hl, 0, 2
- ld b, 8
- ld c, 16
- call TextBoxBorder
- call GetPrizeMenuId
- call UpdateSprites
- ld hl, WhichPrizeTextPtr
- call PrintText
- call HandleMenuInput ; menu choice handler
- bit 1, a ; keypress = B (Cancel)
- jr nz, .noChoice
- ld a, [wCurrentMenuItem]
- cp 3 ; "NO,THANKS" choice
- jr z, .noChoice
- call HandlePrizeChoice
-.noChoice
- ld hl, wd730
- res 6, [hl]
- ret
-
-RequireCoinCaseTextPtr:
- TX_FAR _RequireCoinCaseText
- TX_WAIT
- db "@"
-
-ExchangeCoinsForPrizesTextPtr:
- TX_FAR _ExchangeCoinsForPrizesText
- db "@"
-
-WhichPrizeTextPtr:
- TX_FAR _WhichPrizeText
- db "@"
-
-GetPrizeMenuId:
-; determine which one among the three
-; prize-texts has been selected
-; using the text ID (stored in [hSpriteIndexOrTextID])
-; load the three prizes at wd13d-wd13f
-; load the three prices at wd141-wd146
-; display the three prizes' names
-; (distinguishing between Pokemon names
-; and Items (specifically TMs) names)
- ld a, [hSpriteIndexOrTextID]
- sub 3 ; prize-texts' id are 3, 4 and 5
- ld [wWhichPrizeWindow], a ; prize-texts' id (relative, i.e. 0, 1 or 2)
- add a
- add a
- ld d, 0
- ld e, a
- ld hl, PrizeDifferentMenuPtrs
- add hl, de
- ld a, [hli]
- ld d, [hl]
- ld e, a
- inc hl
- push hl
- ld hl, wPrize1
- call CopyString
- pop hl
- ld a, [hli]
- ld h, [hl]
- ld l, a
- ld de, wPrize1Price
- ld bc, 6
- call CopyData
- ld a, [wWhichPrizeWindow]
- cp 2 ;is TM_menu?
- jr nz, .putMonName
- ld a, [wPrize1]
- ld [wd11e], a
- call GetItemName
- coord hl, 2, 4
- call PlaceString
- ld a, [wPrize2]
- ld [wd11e], a
- call GetItemName
- coord hl, 2, 6
- call PlaceString
- ld a, [wPrize3]
- ld [wd11e], a
- call GetItemName
- coord hl, 2, 8
- call PlaceString
- jr .putNoThanksText
-.putMonName
- ld a, [wPrize1]
- ld [wd11e], a
- call GetMonName
- coord hl, 2, 4
- call PlaceString
- ld a, [wPrize2]
- ld [wd11e], a
- call GetMonName
- coord hl, 2, 6
- call PlaceString
- ld a, [wPrize3]
- ld [wd11e], a
- call GetMonName
- coord hl, 2, 8
- call PlaceString
-.putNoThanksText
- coord hl, 2, 10
- ld de, NoThanksText
- call PlaceString
-; put prices on the right side of the textbox
- ld de, wPrize1Price
- coord hl, 13, 5
-; reg. c:
-; [low nybble] number of bytes
-; [bit 765 = %100] space-padding (not zero-padding)
- ld c, (1 << 7 | 2)
-; Function $15CD displays BCD value (same routine
-; used by text-command $02)
- call PrintBCDNumber
- ld de, wPrize2Price
- coord hl, 13, 7
- ld c, (1 << 7 | 2)
- call PrintBCDNumber
- ld de, wPrize3Price
- coord hl, 13, 9
- ld c, (1 << 7 | 2)
- jp PrintBCDNumber
-
-INCLUDE "data/prizes.asm"
-
-PrintPrizePrice:
- coord hl, 11, 0
- ld b, 1
- ld c, 7
- call TextBoxBorder
- call UpdateSprites
- coord hl, 12, 0
- ld de, .CoinString
- call PlaceString
- coord hl, 13, 1
- ld de, .SixSpacesString
- call PlaceString
- coord hl, 13, 1
- ld de, wPlayerCoins
- ld c, %10000010
- call PrintBCDNumber
- ret
-
-.CoinString:
- db "COIN@"
-
-.SixSpacesString:
- db " @"
-
-LoadCoinsToSubtract:
- ld a, [wWhichPrize]
- add a
- ld d, 0
- ld e, a
- ld hl, wPrize1Price
- add hl, de ; get selected prize's price
- xor a
- ld [hUnusedCoinsByte], a
- ld a, [hli]
- ld [hCoins], a
- ld a, [hl]
- ld [hCoins + 1], a
- ret
-
-HandlePrizeChoice:
- ld a, [wCurrentMenuItem]
- ld [wWhichPrize], a
- ld d, 0
- ld e, a
- ld hl, wPrize1
- add hl, de
- ld a, [hl]
- ld [wd11e], a
- ld a, [wWhichPrizeWindow]
- cp 2 ; is prize a TM?
- jr nz, .getMonName
- call GetItemName
- jr .givePrize
-.getMonName
- call GetMonName
-.givePrize
- ld hl, SoYouWantPrizeTextPtr
- call PrintText
- call YesNoChoice
- ld a, [wCurrentMenuItem] ; yes/no answer (Y=0, N=1)
- and a
- jr nz, .printOhFineThen
- call LoadCoinsToSubtract
- call HasEnoughCoins
- jr c, .notEnoughCoins
- ld a, [wWhichPrizeWindow]
- cp $02
- jr nz, .giveMon
- ld a, [wd11e]
- ld b, a
- ld a, 1
- ld c, a
- call GiveItem
- jr nc, .bagFull
- jr .subtractCoins
-.giveMon
- ld a, [wd11e]
- ld [wcf91], a
- push af
- call GetPrizeMonLevel
- ld c, a
- pop af
- ld b, a
- call GivePokemon
-
-; If either the party or box was full, wait after displaying message.
- push af
- ld a, [wAddedToParty]
- and a
- call z, WaitForTextScrollButtonPress
- pop af
-
-; If the mon couldn't be given to the player (because both the party and box
-; were full), return without subtracting coins.
- ret nc
-
-.subtractCoins
- call LoadCoinsToSubtract
- ld hl, hCoins + 1
- ld de, wPlayerCoins + 1
- ld c, $02 ; how many bytes
- predef SubBCDPredef
- jp PrintPrizePrice
-.bagFull
- ld hl, PrizeRoomBagIsFullTextPtr
- jp PrintText
-.notEnoughCoins
- ld hl, SorryNeedMoreCoinsText
- jp PrintText
-.printOhFineThen
- ld hl, OhFineThenTextPtr
- jp PrintText
-
-UnknownPrizeData:
-; XXX what's this?
- db $00,$01,$00,$01,$00,$01,$00,$00,$01
-
-HereYouGoTextPtr:
- TX_FAR _HereYouGoText
- TX_WAIT
- db "@"
-
-SoYouWantPrizeTextPtr:
- TX_FAR _SoYouWantPrizeText
- db "@"
-
-SorryNeedMoreCoinsText:
- TX_FAR _SorryNeedMoreCoinsText
- TX_WAIT
- db "@"
-
-PrizeRoomBagIsFullTextPtr:
- TX_FAR _OopsYouDontHaveEnoughRoomText
- TX_WAIT
- db "@"
-
-OhFineThenTextPtr:
- TX_FAR _OhFineThenText
- TX_WAIT
- db "@"
-
-GetPrizeMonLevel:
- ld a, [wcf91]
- ld b, a
- ld hl, PrizeMonLevelDictionary
-.loop
- ld a, [hli]
- cp b
- jr z, .matchFound
- inc hl
- jr .loop
-.matchFound
- ld a, [hl]
- ld [wCurEnemyLVL], a
- ret
-
-INCLUDE "data/prize_mon_levels.asm"
--- a/engine/menu/start_menu.asm
+++ /dev/null
@@ -1,85 +1,0 @@
-DisplayStartMenu::
- ld a, BANK(StartMenu_Pokedex)
- ld [H_LOADEDROMBANK], a
- ld [MBC1RomBank], a
- ld a, [wWalkBikeSurfState] ; walking/biking/surfing
- ld [wWalkBikeSurfStateCopy], a
- ld a, SFX_START_MENU
- call PlaySound
-
-RedisplayStartMenu::
- callba DrawStartMenu
- callba PrintSafariZoneSteps ; print Safari Zone info, if in Safari Zone
- call UpdateSprites
-.loop
- call HandleMenuInput
- ld b, a
-.checkIfUpPressed
- bit 6, a ; was Up pressed?
- jr z, .checkIfDownPressed
- ld a, [wCurrentMenuItem] ; menu selection
- and a
- jr nz, .loop
- ld a, [wLastMenuItem]
- and a
- jr nz, .loop
-; if the player pressed tried to go past the top item, wrap around to the bottom
- CheckEvent EVENT_GOT_POKEDEX
- ld a, 6 ; there are 7 menu items with the pokedex, so the max index is 6
- jr nz, .wrapMenuItemId
- dec a ; there are only 6 menu items without the pokedex
-.wrapMenuItemId
- ld [wCurrentMenuItem], a
- call EraseMenuCursor
- jr .loop
-.checkIfDownPressed
- bit 7, a
- jr z, .buttonPressed
-; if the player pressed tried to go past the bottom item, wrap around to the top
- CheckEvent EVENT_GOT_POKEDEX
- ld a, [wCurrentMenuItem]
- ld c, 7 ; there are 7 menu items with the pokedex
- jr nz, .checkIfPastBottom
- dec c ; there are only 6 menu items without the pokedex
-.checkIfPastBottom
- cp c
- jr nz, .loop
-; the player went past the bottom, so wrap to the top
- xor a
- ld [wCurrentMenuItem], a
- call EraseMenuCursor
- jr .loop
-.buttonPressed ; A, B, or Start button pressed
- call PlaceUnfilledArrowMenuCursor
- ld a, [wCurrentMenuItem]
- ld [wBattleAndStartSavedMenuItem], a ; save current menu selection
- ld a, b
- and %00001010 ; was the Start button or B button pressed?
- jp nz, CloseStartMenu
- call SaveScreenTilesToBuffer2 ; copy background from wTileMap to wTileMapBackup2
- CheckEvent EVENT_GOT_POKEDEX
- ld a, [wCurrentMenuItem]
- jr nz, .displayMenuItem
- inc a ; adjust position to account for missing pokedex menu item
-.displayMenuItem
- cp 0
- jp z, StartMenu_Pokedex
- cp 1
- jp z, StartMenu_Pokemon
- cp 2
- jp z, StartMenu_Item
- cp 3
- jp z, StartMenu_TrainerInfo
- cp 4
- jp z, StartMenu_SaveReset
- cp 5
- jp z, StartMenu_Option
-
-; EXIT falls through to here
-CloseStartMenu::
- call Joypad
- ld a, [hJoyPressed]
- bit 0, a ; was A button newly pressed?
- jr nz, CloseStartMenu
- call LoadTextBoxTilePatterns
- jp CloseTextDisplay
--- a/engine/menu/start_sub_menus.asm
+++ /dev/null
@@ -1,808 +1,0 @@
-StartMenu_Pokedex::
- predef ShowPokedexMenu
- call LoadScreenTilesFromBuffer2 ; restore saved screen
- call Delay3
- call LoadGBPal
- call UpdateSprites
- jp RedisplayStartMenu
-
-StartMenu_Pokemon::
- ld a, [wPartyCount]
- and a
- jp z, RedisplayStartMenu
- xor a
- ld [wMenuItemToSwap], a
- ld [wPartyMenuTypeOrMessageID], a
- ld [wUpdateSpritesEnabled], a
- call DisplayPartyMenu
- jr .checkIfPokemonChosen
-.loop
- xor a
- ld [wMenuItemToSwap], a
- ld [wPartyMenuTypeOrMessageID], a
- call GoBackToPartyMenu
-.checkIfPokemonChosen
- jr nc, .chosePokemon
-.exitMenu
- call GBPalWhiteOutWithDelay3
- call RestoreScreenTilesAndReloadTilePatterns
- call LoadGBPal
- jp RedisplayStartMenu
-.chosePokemon
- call SaveScreenTilesToBuffer1
- ld a, FIELD_MOVE_MON_MENU
- ld [wTextBoxID], a
- call DisplayTextBoxID ; display pokemon menu options
- ld hl, wFieldMoves
- lb bc, 2, 12 ; max menu item ID, top menu item Y
- ld e, 5
-.adjustMenuVariablesLoop
- dec e
- jr z, .storeMenuVariables
- ld a, [hli]
- and a ; end of field moves?
- jr z, .storeMenuVariables
- inc b
- dec c
- dec c
- jr .adjustMenuVariablesLoop
-.storeMenuVariables
- ld hl, wTopMenuItemY
- ld a, c
- ld [hli], a ; top menu item Y
- ld a, [hFieldMoveMonMenuTopMenuItemX]
- ld [hli], a ; top menu item X
- xor a
- ld [hli], a ; current menu item ID
- inc hl
- ld a, b
- ld [hli], a ; max menu item ID
- ld a, A_BUTTON | B_BUTTON
- ld [hli], a ; menu watched keys
- xor a
- ld [hl], a
- call HandleMenuInput
- push af
- call LoadScreenTilesFromBuffer1 ; restore saved screen
- pop af
- bit 1, a ; was the B button pressed?
- jp nz, .loop
-; if the B button wasn't pressed
- ld a, [wMaxMenuItem]
- ld b, a
- ld a, [wCurrentMenuItem] ; menu selection
- cp b
- jp z, .exitMenu ; if the player chose Cancel
- dec b
- cp b
- jr z, .choseSwitch
- dec b
- cp b
- jp z, .choseStats
- ld c, a
- ld b, 0
- ld hl, wFieldMoves
- add hl, bc
- jp .choseOutOfBattleMove
-.choseSwitch
- ld a, [wPartyCount]
- cp 2 ; is there more than one pokemon in the party?
- jp c, StartMenu_Pokemon ; if not, no switching
- call SwitchPartyMon_InitVarOrSwapData ; init [wMenuItemToSwap]
- ld a, SWAP_MONS_PARTY_MENU
- ld [wPartyMenuTypeOrMessageID], a
- call GoBackToPartyMenu
- jp .checkIfPokemonChosen
-.choseStats
- call ClearSprites
- xor a ; PLAYER_PARTY_DATA
- ld [wMonDataLocation], a
- predef StatusScreen
- predef StatusScreen2
- call ReloadMapData
- jp StartMenu_Pokemon
-.choseOutOfBattleMove
- push hl
- ld a, [wWhichPokemon]
- ld hl, wPartyMonNicks
- call GetPartyMonName
- pop hl
- ld a, [hl]
- dec a
- add a
- ld b, 0
- ld c, a
- ld hl, .outOfBattleMovePointers
- add hl, bc
- ld a, [hli]
- ld h, [hl]
- ld l, a
- ld a, [wObtainedBadges] ; badges obtained
- jp hl
-.outOfBattleMovePointers
- dw .cut
- dw .fly
- dw .surf
- dw .surf
- dw .strength
- dw .flash
- dw .dig
- dw .teleport
- dw .softboiled
-.fly
- bit 2, a ; does the player have the Thunder Badge?
- jp z, .newBadgeRequired
- call CheckIfInOutsideMap
- jr z, .canFly
- ld a, [wWhichPokemon]
- ld hl, wPartyMonNicks
- call GetPartyMonName
- ld hl, .cannotFlyHereText
- call PrintText
- jp .loop
-.canFly
- call ChooseFlyDestination
- ld a, [wd732]
- bit 3, a ; did the player decide to fly?
- jp nz, .goBackToMap
- call LoadFontTilePatterns
- ld hl, wd72e
- set 1, [hl]
- jp StartMenu_Pokemon
-.cut
- bit 1, a ; does the player have the Cascade Badge?
- jp z, .newBadgeRequired
- predef UsedCut
- ld a, [wActionResultOrTookBattleTurn]
- and a
- jp z, .loop
- jp CloseTextDisplay
-.surf
- bit 4, a ; does the player have the Soul Badge?
- jp z, .newBadgeRequired
- callba IsSurfingAllowed
- ld hl, wd728
- bit 1, [hl]
- res 1, [hl]
- jp z, .loop
- ld a, SURFBOARD
- ld [wcf91], a
- ld [wPseudoItemID], a
- call UseItem
- ld a, [wActionResultOrTookBattleTurn]
- and a
- jp z, .loop
- call GBPalWhiteOutWithDelay3
- jp .goBackToMap
-.strength
- bit 3, a ; does the player have the Rainbow Badge?
- jp z, .newBadgeRequired
- predef PrintStrengthTxt
- call GBPalWhiteOutWithDelay3
- jp .goBackToMap
-.flash
- bit 0, a ; does the player have the Boulder Badge?
- jp z, .newBadgeRequired
- xor a
- ld [wMapPalOffset], a
- ld hl, .flashLightsAreaText
- call PrintText
- call GBPalWhiteOutWithDelay3
- jp .goBackToMap
-.flashLightsAreaText
- TX_FAR _FlashLightsAreaText
- db "@"
-.dig
- ld a, ESCAPE_ROPE
- ld [wcf91], a
- ld [wPseudoItemID], a
- call UseItem
- ld a, [wActionResultOrTookBattleTurn]
- and a
- jp z, .loop
- call GBPalWhiteOutWithDelay3
- jp .goBackToMap
-.teleport
- call CheckIfInOutsideMap
- jr z, .canTeleport
- ld a, [wWhichPokemon]
- ld hl, wPartyMonNicks
- call GetPartyMonName
- ld hl, .cannotUseTeleportNowText
- call PrintText
- jp .loop
-.canTeleport
- ld hl, .warpToLastPokemonCenterText
- call PrintText
- ld hl, wd732
- set 3, [hl]
- set 6, [hl]
- ld hl, wd72e
- set 1, [hl]
- res 4, [hl]
- ld c, 60
- call DelayFrames
- call GBPalWhiteOutWithDelay3
- jp .goBackToMap
-.warpToLastPokemonCenterText
- TX_FAR _WarpToLastPokemonCenterText
- db "@"
-.cannotUseTeleportNowText
- TX_FAR _CannotUseTeleportNowText
- db "@"
-.cannotFlyHereText
- TX_FAR _CannotFlyHereText
- db "@"
-.softboiled
- ld hl, wPartyMon1MaxHP
- ld a, [wWhichPokemon]
- ld bc, wPartyMon2 - wPartyMon1
- call AddNTimes
- ld a, [hli]
- ld [H_DIVIDEND], a
- ld a, [hl]
- ld [H_DIVIDEND + 1], a
- ld a, 5
- ld [H_DIVISOR], a
- ld b, 2 ; number of bytes
- call Divide
- ld bc, wPartyMon1HP - wPartyMon1MaxHP
- add hl, bc
- ld a, [hld]
- ld b, a
- ld a, [H_QUOTIENT + 3]
- sub b
- ld b, [hl]
- ld a, [H_QUOTIENT + 2]
- sbc b
- jp nc, .notHealthyEnough
- ld a, [wPartyAndBillsPCSavedMenuItem]
- push af
- ld a, POTION
- ld [wcf91], a
- ld [wPseudoItemID], a
- call UseItem
- pop af
- ld [wPartyAndBillsPCSavedMenuItem], a
- jp .loop
-.notHealthyEnough ; if current HP is less than 1/5 of max HP
- ld hl, .notHealthyEnoughText
- call PrintText
- jp .loop
-.notHealthyEnoughText
- TX_FAR _NotHealthyEnoughText
- db "@"
-.goBackToMap
- call RestoreScreenTilesAndReloadTilePatterns
- jp CloseTextDisplay
-.newBadgeRequired
- ld hl, .newBadgeRequiredText
- call PrintText
- jp .loop
-.newBadgeRequiredText
- TX_FAR _NewBadgeRequiredText
- db "@"
-
-; writes a blank tile to all possible menu cursor positions on the party menu
-ErasePartyMenuCursors::
- coord hl, 0, 1
- ld bc, 2 * 20 ; menu cursor positions are 2 rows apart
- ld a, 6 ; 6 menu cursor positions
-.loop
- ld [hl], " "
- add hl, bc
- dec a
- jr nz, .loop
- ret
-
-ItemMenuLoop:
- call LoadScreenTilesFromBuffer2DisableBGTransfer ; restore saved screen
- call RunDefaultPaletteCommand
-
-StartMenu_Item::
- ld a, [wLinkState]
- dec a ; is the player in the Colosseum or Trade Centre?
- jr nz, .notInCableClubRoom
- ld hl, CannotUseItemsHereText
- call PrintText
- jr .exitMenu
-.notInCableClubRoom
- ld bc, wNumBagItems
- ld hl, wListPointer
- ld a, c
- ld [hli], a
- ld [hl], b ; store item bag pointer in wListPointer (for DisplayListMenuID)
- xor a
- ld [wPrintItemPrices], a
- ld a, ITEMLISTMENU
- ld [wListMenuID], a
- ld a, [wBagSavedMenuItem]
- ld [wCurrentMenuItem], a
- call DisplayListMenuID
- ld a, [wCurrentMenuItem]
- ld [wBagSavedMenuItem], a
- jr nc, .choseItem
-.exitMenu
- call LoadScreenTilesFromBuffer2 ; restore saved screen
- call LoadTextBoxTilePatterns
- call UpdateSprites
- jp RedisplayStartMenu
-.choseItem
-; erase menu cursor (blank each tile in front of an item name)
- ld a, " "
- Coorda 5, 4
- Coorda 5, 6
- Coorda 5, 8
- Coorda 5, 10
- call PlaceUnfilledArrowMenuCursor
- xor a
- ld [wMenuItemToSwap], a
- ld a, [wcf91]
- cp BICYCLE
- jp z, .useOrTossItem
-.notBicycle1
- ld a, USE_TOSS_MENU_TEMPLATE
- ld [wTextBoxID], a
- call DisplayTextBoxID
- ld hl, wTopMenuItemY
- ld a, 11
- ld [hli], a ; top menu item Y
- ld a, 14
- ld [hli], a ; top menu item X
- xor a
- ld [hli], a ; current menu item ID
- inc hl
- inc a ; a = 1
- ld [hli], a ; max menu item ID
- ld a, A_BUTTON | B_BUTTON
- ld [hli], a ; menu watched keys
- xor a
- ld [hl], a ; old menu item id
- call HandleMenuInput
- call PlaceUnfilledArrowMenuCursor
- bit 1, a ; was the B button pressed?
- jr z, .useOrTossItem
- jp ItemMenuLoop
-.useOrTossItem ; if the player made the choice to use or toss the item
- ld a, [wcf91]
- ld [wd11e], a
- call GetItemName
- call CopyStringToCF4B ; copy name to wcf4b
- ld a, [wcf91]
- cp BICYCLE
- jr nz, .notBicycle2
- ld a, [wd732]
- bit 5, a
- jr z, .useItem_closeMenu
- ld hl, CannotGetOffHereText
- call PrintText
- jp ItemMenuLoop
-.notBicycle2
- ld a, [wCurrentMenuItem]
- and a
- jr nz, .tossItem
-; use item
- ld [wPseudoItemID], a ; a must be 0 due to above conditional jump
- ld a, [wcf91]
- cp HM_01
- jr nc, .useItem_partyMenu
- ld hl, UsableItems_CloseMenu
- ld de, 1
- call IsInArray
- jr c, .useItem_closeMenu
- ld a, [wcf91]
- ld hl, UsableItems_PartyMenu
- ld de, 1
- call IsInArray
- jr c, .useItem_partyMenu
- call UseItem
- jp ItemMenuLoop
-.useItem_closeMenu
- xor a
- ld [wPseudoItemID], a
- call UseItem
- ld a, [wActionResultOrTookBattleTurn]
- and a
- jp z, ItemMenuLoop
- jp CloseStartMenu
-.useItem_partyMenu
- ld a, [wUpdateSpritesEnabled]
- push af
- call UseItem
- ld a, [wActionResultOrTookBattleTurn]
- cp $02
- jp z, .partyMenuNotDisplayed
- call GBPalWhiteOutWithDelay3
- call RestoreScreenTilesAndReloadTilePatterns
- pop af
- ld [wUpdateSpritesEnabled], a
- jp StartMenu_Item
-.partyMenuNotDisplayed
- pop af
- ld [wUpdateSpritesEnabled], a
- jp ItemMenuLoop
-.tossItem
- call IsKeyItem
- ld a, [wIsKeyItem]
- and a
- jr nz, .skipAskingQuantity
- ld a, [wcf91]
- call IsItemHM
- jr c, .skipAskingQuantity
- call DisplayChooseQuantityMenu
- inc a
- jr z, .tossZeroItems
-.skipAskingQuantity
- ld hl, wNumBagItems
- call TossItem
-.tossZeroItems
- jp ItemMenuLoop
-
-CannotUseItemsHereText:
- TX_FAR _CannotUseItemsHereText
- db "@"
-
-CannotGetOffHereText:
- TX_FAR _CannotGetOffHereText
- db "@"
-
-INCLUDE "data/party_items.asm"
-
-INCLUDE "data/overworld_items.asm"
-
-StartMenu_TrainerInfo::
- call GBPalWhiteOut
- call ClearScreen
- call UpdateSprites
- ld a, [hTilesetType]
- push af
- xor a
- ld [hTilesetType], a
- call DrawTrainerInfo
- predef DrawBadges ; draw badges
- ld b, SET_PAL_TRAINER_CARD
- call RunPaletteCommand
- call GBPalNormal
- call WaitForTextScrollButtonPress ; wait for button press
- call GBPalWhiteOut
- call LoadFontTilePatterns
- call LoadScreenTilesFromBuffer2 ; restore saved screen
- call RunDefaultPaletteCommand
- call ReloadMapData
- call LoadGBPal
- pop af
- ld [hTilesetType], a
- jp RedisplayStartMenu
-
-; loads tile patterns and draws everything except for gym leader faces / badges
-DrawTrainerInfo:
- ld de, RedPicFront
- lb bc, BANK(RedPicFront), $01
- predef DisplayPicCenteredOrUpperRight
- call DisableLCD
- coord hl, 0, 2
- ld a, " "
- call TrainerInfo_DrawVerticalLine
- coord hl, 1, 2
- call TrainerInfo_DrawVerticalLine
- ld hl, vChars2 + $70
- ld de, vChars2
- ld bc, $70 * 4
- call CopyData
- ld hl, TrainerInfoTextBoxTileGraphics ; trainer info text box tile patterns
- ld de, vChars2 + $770
- ld bc, $0080
- push bc
- call TrainerInfo_FarCopyData
- ld hl, BlankLeaderNames
- ld de, vChars2 + $600
- ld bc, $0170
- call TrainerInfo_FarCopyData
- pop bc
- ld hl, BadgeNumbersTileGraphics ; badge number tile patterns
- ld de, vChars1 + $580
- call TrainerInfo_FarCopyData
- ld hl, GymLeaderFaceAndBadgeTileGraphics ; gym leader face and badge tile patterns
- ld de, vChars2 + $200
- ld bc, $0400
- ld a, $03
- call FarCopyData2
- ld hl, TextBoxGraphics
- ld de, $00d0
- add hl, de ; hl = colon tile pattern
- ld de, vChars1 + $560
- ld bc, $0010
- ld a, $04
- push bc
- call FarCopyData2
- pop bc
- ld hl, TrainerInfoTextBoxTileGraphics + $80 ; background tile pattern
- ld de, vChars1 + $570
- call TrainerInfo_FarCopyData
- call EnableLCD
- ld hl, wTrainerInfoTextBoxWidthPlus1
- ld a, 18 + 1
- ld [hli], a
- dec a
- ld [hli], a
- ld [hl], 1
- coord hl, 0, 0
- call TrainerInfo_DrawTextBox
- ld hl, wTrainerInfoTextBoxWidthPlus1
- ld a, 16 + 1
- ld [hli], a
- dec a
- ld [hli], a
- ld [hl], 3
- coord hl, 1, 10
- call TrainerInfo_DrawTextBox
- coord hl, 0, 10
- ld a, $d7
- call TrainerInfo_DrawVerticalLine
- coord hl, 19, 10
- call TrainerInfo_DrawVerticalLine
- coord hl, 6, 9
- ld de, TrainerInfo_BadgesText
- call PlaceString
- coord hl, 2, 2
- ld de, TrainerInfo_NameMoneyTimeText
- call PlaceString
- coord hl, 7, 2
- ld de, wPlayerName
- call PlaceString
- coord hl, 8, 4
- ld de, wPlayerMoney
- ld c, $e3
- call PrintBCDNumber
- coord hl, 9, 6
- ld de, wPlayTimeHours ; hours
- lb bc, LEFT_ALIGN | 1, 3
- call PrintNumber
- ld [hl], $d6 ; colon tile ID
- inc hl
- ld de, wPlayTimeMinutes ; minutes
- lb bc, LEADING_ZEROES | 1, 2
- jp PrintNumber
-
-TrainerInfo_FarCopyData:
- ld a, BANK(TrainerInfoTextBoxTileGraphics)
- jp FarCopyData2
-
-TrainerInfo_NameMoneyTimeText:
- db "NAME/"
- next "MONEY/"
- next "TIME/@"
-
-; $76 is a circle tile
-TrainerInfo_BadgesText:
- db $76,"BADGES",$76,"@"
-
-; draws a text box on the trainer info screen
-; height is always 6
-; INPUT:
-; hl = destination address
-; [wTrainerInfoTextBoxWidthPlus1] = width
-; [wTrainerInfoTextBoxWidth] = width - 1
-; [wTrainerInfoTextBoxNextRowOffset] = distance from the end of a text box row to the start of the next
-TrainerInfo_DrawTextBox:
- ld a, $79 ; upper left corner tile ID
- lb de, $7a, $7b ; top edge and upper right corner tile ID's
- call TrainerInfo_DrawHorizontalEdge ; draw top edge
- call TrainerInfo_NextTextBoxRow
- ld a, [wTrainerInfoTextBoxWidthPlus1]
- ld e, a
- ld d, 0
- ld c, 6 ; height of the text box
-.loop
- ld [hl], $7c ; left edge tile ID
- add hl, de
- ld [hl], $78 ; right edge tile ID
- call TrainerInfo_NextTextBoxRow
- dec c
- jr nz, .loop
- ld a, $7d ; lower left corner tile ID
- lb de, $77, $7e ; bottom edge and lower right corner tile ID's
-
-TrainerInfo_DrawHorizontalEdge:
- ld [hli], a ; place left corner tile
- ld a, [wTrainerInfoTextBoxWidth]
- ld c, a
- ld a, d
-.loop
- ld [hli], a ; place edge tile
- dec c
- jr nz, .loop
- ld a, e
- ld [hl], a ; place right corner tile
- ret
-
-TrainerInfo_NextTextBoxRow:
- ld a, [wTrainerInfoTextBoxNextRowOffset] ; distance to the start of the next row
-.loop
- inc hl
- dec a
- jr nz, .loop
- ret
-
-; draws a vertical line
-; INPUT:
-; hl = address of top tile in the line
-; a = tile ID
-TrainerInfo_DrawVerticalLine:
- ld de, SCREEN_WIDTH
- ld c, 8
-.loop
- ld [hl], a
- add hl, de
- dec c
- jr nz, .loop
- ret
-
-StartMenu_SaveReset::
- ld a, [wd72e]
- bit 6, a ; is the player using the link feature?
- jp nz, Init
- predef SaveSAV ; save the game
- call LoadScreenTilesFromBuffer2 ; restore saved screen
- jp HoldTextDisplayOpen
-
-StartMenu_Option::
- xor a
- ld [H_AUTOBGTRANSFERENABLED], a
- call ClearScreen
- call UpdateSprites
- callab DisplayOptionMenu
- call LoadScreenTilesFromBuffer2 ; restore saved screen
- call LoadTextBoxTilePatterns
- call UpdateSprites
- jp RedisplayStartMenu
-
-SwitchPartyMon::
- call SwitchPartyMon_InitVarOrSwapData ; swap data
- ld a, [wSwappedMenuItem]
- call SwitchPartyMon_ClearGfx
- ld a, [wCurrentMenuItem]
- call SwitchPartyMon_ClearGfx
- jp RedrawPartyMenu_
-
-SwitchPartyMon_ClearGfx:
- push af
- coord hl, 0, 0
- ld bc, SCREEN_WIDTH * 2
- call AddNTimes
- ld c, SCREEN_WIDTH * 2
- ld a, " "
-.clearMonBGLoop ; clear the mon's row in the party menu
- ld [hli], a
- dec c
- jr nz, .clearMonBGLoop
- pop af
- ld hl, wOAMBuffer
- ld bc, $10
- call AddNTimes
- ld de, $4
- ld c, e
-.clearMonOAMLoop
- ld [hl], $a0
- add hl, de
- dec c
- jr nz, .clearMonOAMLoop
- call WaitForSoundToFinish
- ld a, SFX_SWAP
- jp PlaySound
-
-SwitchPartyMon_InitVarOrSwapData:
-; This is used to initialise [wMenuItemToSwap] and to actually swap the data.
- ld a, [wMenuItemToSwap]
- and a ; has [wMenuItemToSwap] been initialised yet?
- jr nz, .pickedMonsToSwap
-; If not, initialise [wMenuItemToSwap] so that it matches the current mon.
- ld a, [wWhichPokemon]
- inc a ; [wMenuItemToSwap] counts from 1
- ld [wMenuItemToSwap], a
- ret
-.pickedMonsToSwap
- xor a
- ld [wPartyMenuTypeOrMessageID], a
- ld a, [wMenuItemToSwap]
- dec a
- ld b, a
- ld a, [wCurrentMenuItem]
- ld [wSwappedMenuItem], a
- cp b ; swapping a mon with itself?
- jr nz, .swappingDifferentMons
-; can't swap a mon with itself
- xor a
- ld [wMenuItemToSwap], a
- ld [wPartyMenuTypeOrMessageID], a
- ret
-.swappingDifferentMons
- ld a, b
- ld [wMenuItemToSwap], a
- push hl
- push de
- ld hl, wPartySpecies
- ld d, h
- ld e, l
- ld a, [wCurrentMenuItem]
- add l
- ld l, a
- jr nc, .noCarry
- inc h
-.noCarry
- ld a, [wMenuItemToSwap]
- add e
- ld e, a
- jr nc, .noCarry2
- inc d
-.noCarry2
- ld a, [hl]
- ld [hSwapTemp], a
- ld a, [de]
- ld [hl], a
- ld a, [hSwapTemp]
- ld [de], a
- ld hl, wPartyMons
- ld bc, wPartyMon2 - wPartyMon1
- ld a, [wCurrentMenuItem]
- call AddNTimes
- push hl
- ld de, wSwitchPartyMonTempBuffer
- ld bc, wPartyMon2 - wPartyMon1
- call CopyData
- ld hl, wPartyMons
- ld bc, wPartyMon2 - wPartyMon1
- ld a, [wMenuItemToSwap]
- call AddNTimes
- pop de
- push hl
- ld bc, wPartyMon2 - wPartyMon1
- call CopyData
- pop de
- ld hl, wSwitchPartyMonTempBuffer
- ld bc, wPartyMon2 - wPartyMon1
- call CopyData
- ld hl, wPartyMonOT
- ld a, [wCurrentMenuItem]
- call SkipFixedLengthTextEntries
- push hl
- ld de, wSwitchPartyMonTempBuffer
- ld bc, NAME_LENGTH
- call CopyData
- ld hl, wPartyMonOT
- ld a, [wMenuItemToSwap]
- call SkipFixedLengthTextEntries
- pop de
- push hl
- ld bc, NAME_LENGTH
- call CopyData
- pop de
- ld hl, wSwitchPartyMonTempBuffer
- ld bc, NAME_LENGTH
- call CopyData
- ld hl, wPartyMonNicks
- ld a, [wCurrentMenuItem]
- call SkipFixedLengthTextEntries
- push hl
- ld de, wSwitchPartyMonTempBuffer
- ld bc, NAME_LENGTH
- call CopyData
- ld hl, wPartyMonNicks
- ld a, [wMenuItemToSwap]
- call SkipFixedLengthTextEntries
- pop de
- push hl
- ld bc, NAME_LENGTH
- call CopyData
- pop de
- ld hl, wSwitchPartyMonTempBuffer
- ld bc, NAME_LENGTH
- call CopyData
- ld a, [wMenuItemToSwap]
- ld [wSwappedMenuItem], a
- xor a
- ld [wMenuItemToSwap], a
- ld [wPartyMenuTypeOrMessageID], a
- pop de
- pop hl
- ret
--- a/engine/menu/status_screen.asm
+++ /dev/null
@@ -1,481 +1,0 @@
-DrawHP:
-; Draws the HP bar in the stats screen
- call GetPredefRegisters
- ld a, $1
- jr DrawHP_
-
-DrawHP2:
-; Draws the HP bar in the party screen
- call GetPredefRegisters
- ld a, $2
-
-DrawHP_:
- ld [wHPBarType], a
- push hl
- ld a, [wLoadedMonHP]
- ld b, a
- ld a, [wLoadedMonHP + 1]
- ld c, a
- or b
- jr nz, .nonzeroHP
- xor a
- ld c, a
- ld e, a
- ld a, $6
- ld d, a
- jp .drawHPBarAndPrintFraction
-.nonzeroHP
- ld a, [wLoadedMonMaxHP]
- ld d, a
- ld a, [wLoadedMonMaxHP + 1]
- ld e, a
- predef HPBarLength
- ld a, $6
- ld d, a
- ld c, a
-.drawHPBarAndPrintFraction
- pop hl
- push de
- push hl
- push hl
- call DrawHPBar
- pop hl
- ld a, [hFlags_0xFFF6]
- bit 0, a
- jr z, .printFractionBelowBar
- ld bc, $9 ; right of bar
- jr .printFraction
-.printFractionBelowBar
- ld bc, SCREEN_WIDTH + 1 ; below bar
-.printFraction
- add hl, bc
- ld de, wLoadedMonHP
- lb bc, 2, 3
- call PrintNumber
- ld a, "/"
- ld [hli], a
- ld de, wLoadedMonMaxHP
- lb bc, 2, 3
- call PrintNumber
- pop hl
- pop de
- ret
-
-
-; Predef 0x37
-StatusScreen:
- call LoadMonData
- ld a, [wMonDataLocation]
- cp BOX_DATA
- jr c, .DontRecalculate
-; mon is in a box or daycare
- ld a, [wLoadedMonBoxLevel]
- ld [wLoadedMonLevel], a
- ld [wCurEnemyLVL], a
- ld hl, wLoadedMonHPExp - 1
- ld de, wLoadedMonStats
- ld b, $1
- call CalcStats ; Recalculate stats
-.DontRecalculate
- ld hl, wd72c
- set 1, [hl]
- ld a, $33
- ld [rNR50], a ; Reduce the volume
- call GBPalWhiteOutWithDelay3
- call ClearScreen
- call UpdateSprites
- call LoadHpBarAndStatusTilePatterns
- ld de, BattleHudTiles1 ; source
- ld hl, vChars2 + $6d0 ; dest
- lb bc, BANK(BattleHudTiles1), $03
- call CopyVideoDataDouble ; ·│ :L and halfarrow line end
- ld de, BattleHudTiles2
- ld hl, vChars2 + $780
- lb bc, BANK(BattleHudTiles2), $01
- call CopyVideoDataDouble ; │
- ld de, BattleHudTiles3
- ld hl, vChars2 + $760
- lb bc, BANK(BattleHudTiles3), $02
- call CopyVideoDataDouble ; ─┘
- ld de, PTile
- ld hl, vChars2 + $720
- lb bc, BANK(PTile), (PTileEnd - PTile) / $8
- call CopyVideoDataDouble ; P (for PP), inline
- ld a, [hTilesetType]
- push af
- xor a
- ld [hTilesetType], a
- coord hl, 19, 1
- lb bc, 6, 10
- call DrawLineBox ; Draws the box around name, HP and status
- ld de, -6
- add hl, de
- ld [hl], "⠄" ; . after No ("." is a different one)
- dec hl
- ld [hl], "№"
- coord hl, 19, 9
- lb bc, 8, 6
- call DrawLineBox ; Draws the box around types, ID No. and OT
- coord hl, 10, 9
- ld de, Type1Text
- call PlaceString ; "TYPE1/"
- coord hl, 11, 3
- predef DrawHP
- ld hl, wStatusScreenHPBarColor
- call GetHealthBarColor
- ld b, SET_PAL_STATUS_SCREEN
- call RunPaletteCommand
- coord hl, 16, 6
- ld de, wLoadedMonStatus
- call PrintStatusCondition
- jr nz, .StatusWritten
- coord hl, 16, 6
- ld de, OKText
- call PlaceString ; "OK"
-.StatusWritten
- coord hl, 9, 6
- ld de, StatusText
- call PlaceString ; "STATUS/"
- coord hl, 14, 2
- call PrintLevel ; Pokémon level
- ld a, [wMonHIndex]
- ld [wd11e], a
- ld [wd0b5], a
- predef IndexToPokedex
- coord hl, 3, 7
- ld de, wd11e
- lb bc, LEADING_ZEROES | 1, 3
- call PrintNumber ; Pokémon no.
- coord hl, 11, 10
- predef PrintMonType
- ld hl, NamePointers2
- call .GetStringPointer
- ld d, h
- ld e, l
- coord hl, 9, 1
- call PlaceString ; Pokémon name
- ld hl, OTPointers
- call .GetStringPointer
- ld d, h
- ld e, l
- coord hl, 12, 16
- call PlaceString ; OT
- coord hl, 12, 14
- ld de, wLoadedMonOTID
- lb bc, LEADING_ZEROES | 2, 5
- call PrintNumber ; ID Number
- ld d, $0
- call PrintStatsBox
- call Delay3
- call GBPalNormal
- coord hl, 1, 0
- call LoadFlippedFrontSpriteByMonIndex ; draw Pokémon picture
- ld a, [wcf91]
- call PlayCry ; play Pokémon cry
- call WaitForTextScrollButtonPress ; wait for button
- pop af
- ld [hTilesetType], a
- ret
-
-.GetStringPointer
- ld a, [wMonDataLocation]
- add a
- ld c, a
- ld b, 0
- add hl, bc
- ld a, [hli]
- ld h, [hl]
- ld l, a
- ld a, [wMonDataLocation]
- cp DAYCARE_DATA
- ret z
- ld a, [wWhichPokemon]
- jp SkipFixedLengthTextEntries
-
-OTPointers:
- dw wPartyMonOT
- dw wEnemyMonOT
- dw wBoxMonOT
- dw wDayCareMonOT
-
-NamePointers2:
- dw wPartyMonNicks
- dw wEnemyMonNicks
- dw wBoxMonNicks
- dw wDayCareMonName
-
-Type1Text:
- db "TYPE1/", $4e
-
-Type2Text:
- db "TYPE2/", $4e
-
-IDNoText:
- db $73, "№/", $4e
-
-OTText:
- db "OT/"
- next "@"
-
-StatusText:
- db "STATUS/@"
-
-OKText:
- db "OK@"
-
-; Draws a line starting from hl high b and wide c
-DrawLineBox:
- ld de, SCREEN_WIDTH ; New line
-.PrintVerticalLine
- ld [hl], $78 ; │
- add hl, de
- dec b
- jr nz, .PrintVerticalLine
- ld [hl], $77 ; ┘
- dec hl
-.PrintHorizLine
- ld [hl], $76 ; ─
- dec hl
- dec c
- jr nz, .PrintHorizLine
- ld [hl], $6f ; ← (halfarrow ending)
- ret
-
-PTile:
- INCBIN "gfx/font/P.1bpp"
-PTileEnd:
-
-PrintStatsBox:
- ld a, d
- and a ; a is 0 from the status screen
- jr nz, .DifferentBox
- coord hl, 0, 8
- ld b, 8
- ld c, 8
- call TextBoxBorder ; Draws the box
- coord hl, 1, 9 ; Start printing stats from here
- ld bc, $0019 ; Number offset
- jr .PrintStats
-.DifferentBox
- coord hl, 9, 2
- ld b, 8
- ld c, 9
- call TextBoxBorder
- coord hl, 11, 3
- ld bc, $0018
-.PrintStats
- push bc
- push hl
- ld de, StatsText
- call PlaceString
- pop hl
- pop bc
- add hl, bc
- ld de, wLoadedMonAttack
- lb bc, 2, 3
- call PrintStat
- ld de, wLoadedMonDefense
- call PrintStat
- ld de, wLoadedMonSpeed
- call PrintStat
- ld de, wLoadedMonSpecial
- jp PrintNumber
-PrintStat:
- push hl
- call PrintNumber
- pop hl
- ld de, SCREEN_WIDTH * 2
- add hl, de
- ret
-
-StatsText:
- db "ATTACK"
- next "DEFENSE"
- next "SPEED"
- next "SPECIAL@"
-
-StatusScreen2:
- ld a, [hTilesetType]
- push af
- xor a
- ld [hTilesetType], a
- ld [H_AUTOBGTRANSFERENABLED], a
- ld bc, NUM_MOVES + 1
- ld hl, wMoves
- call FillMemory
- ld hl, wLoadedMonMoves
- ld de, wMoves
- ld bc, NUM_MOVES
- call CopyData
- callab FormatMovesString
- coord hl, 9, 2
- lb bc, 5, 10
- call ClearScreenArea ; Clear under name
- coord hl, 19, 3
- ld [hl], $78
- coord hl, 0, 8
- ld b, 8
- ld c, 18
- call TextBoxBorder ; Draw move container
- coord hl, 2, 9
- ld de, wMovesString
- call PlaceString ; Print moves
- ld a, [wNumMovesMinusOne]
- inc a
- ld c, a
- ld a, $4
- sub c
- ld b, a ; Number of moves ?
- coord hl, 11, 10
- ld de, SCREEN_WIDTH * 2
- ld a, $72 ; special P tile id
- call StatusScreen_PrintPP ; Print "PP"
- ld a, b
- and a
- jr z, .InitPP
- ld c, a
- ld a, "-"
- call StatusScreen_PrintPP ; Fill the rest with --
-.InitPP
- ld hl, wLoadedMonMoves
- coord de, 14, 10
- ld b, 0
-.PrintPP
- ld a, [hli]
- and a
- jr z, .PPDone
- push bc
- push hl
- push de
- ld hl, wCurrentMenuItem
- ld a, [hl]
- push af
- ld a, b
- ld [hl], a
- push hl
- callab GetMaxPP
- pop hl
- pop af
- ld [hl], a
- pop de
- pop hl
- push hl
- ld bc, wPartyMon1PP - wPartyMon1Moves - 1
- add hl, bc
- ld a, [hl]
- and $3f
- ld [wStatusScreenCurrentPP], a
- ld h, d
- ld l, e
- push hl
- ld de, wStatusScreenCurrentPP
- lb bc, 1, 2
- call PrintNumber
- ld a, "/"
- ld [hli], a
- ld de, wMaxPP
- lb bc, 1, 2
- call PrintNumber
- pop hl
- ld de, SCREEN_WIDTH * 2
- add hl, de
- ld d, h
- ld e, l
- pop hl
- pop bc
- inc b
- ld a, b
- cp $4
- jr nz, .PrintPP
-.PPDone
- coord hl, 9, 3
- ld de, StatusScreenExpText
- call PlaceString
- ld a, [wLoadedMonLevel]
- push af
- cp MAX_LEVEL
- jr z, .Level100
- inc a
- ld [wLoadedMonLevel], a ; Increase temporarily if not 100
-.Level100
- coord hl, 14, 6
- ld [hl], $70 ; 1-tile "to"
- inc hl
- inc hl
- call PrintLevel
- pop af
- ld [wLoadedMonLevel], a
- ld de, wLoadedMonExp
- coord hl, 12, 4
- lb bc, 3, 7
- call PrintNumber ; exp
- call CalcExpToLevelUp
- ld de, wLoadedMonExp
- coord hl, 7, 6
- lb bc, 3, 7
- call PrintNumber ; exp needed to level up
- coord hl, 9, 0
- call StatusScreen_ClearName
- coord hl, 9, 1
- call StatusScreen_ClearName
- ld a, [wMonHIndex]
- ld [wd11e], a
- call GetMonName
- coord hl, 9, 1
- call PlaceString
- ld a, $1
- ld [H_AUTOBGTRANSFERENABLED], a
- call Delay3
- call WaitForTextScrollButtonPress ; wait for button
- pop af
- ld [hTilesetType], a
- ld hl, wd72c
- res 1, [hl]
- ld a, $77
- ld [rNR50], a
- call GBPalWhiteOut
- jp ClearScreen
-
-CalcExpToLevelUp:
- ld a, [wLoadedMonLevel]
- cp MAX_LEVEL
- jr z, .atMaxLevel
- inc a
- ld d, a
- callab CalcExperience
- ld hl, wLoadedMonExp + 2
- ld a, [hExperience + 2]
- sub [hl]
- ld [hld], a
- ld a, [hExperience + 1]
- sbc [hl]
- ld [hld], a
- ld a, [hExperience]
- sbc [hl]
- ld [hld], a
- ret
-.atMaxLevel
- ld hl, wLoadedMonExp
- xor a
- ld [hli], a
- ld [hli], a
- ld [hl], a
- ret
-
-StatusScreenExpText:
- db "EXP POINTS"
- next "LEVEL UP@"
-
-StatusScreen_ClearName:
- ld bc, 10
- ld a, " "
- jp FillMemory
-
-StatusScreen_PrintPP:
-; print PP or -- c times, going down two rows each time
- ld [hli], a
- ld [hld], a
- add hl, de
- dec c
- jr nz, StatusScreen_PrintPP
- ret
--- a/engine/menu/swap_items.asm
+++ /dev/null
@@ -1,149 +1,0 @@
-HandleItemListSwapping::
- ld a, [wListMenuID]
- cp ITEMLISTMENU
- jp nz, DisplayListMenuIDLoop ; only rearrange item list menus
- push hl
- ld hl, wListPointer
- ld a, [hli]
- ld h, [hl]
- ld l, a
- inc hl ; hl = beginning of list entries
- ld a, [wCurrentMenuItem]
- ld b, a
- ld a, [wListScrollOffset]
- add b
- add a
- ld c, a
- ld b, 0
- add hl, bc ; hl = address of currently selected item entry
- ld a, [hl]
- pop hl
- inc a
- jp z, DisplayListMenuIDLoop ; ignore attempts to swap the Cancel menu item
- ld a, [wMenuItemToSwap] ; ID of item chosen for swapping (counts from 1)
- and a ; has the first item to swap already been chosen?
- jr nz, .swapItems
-; if not, set the currently selected item as the first item
- ld a, [wCurrentMenuItem]
- inc a
- ld b, a
- ld a, [wListScrollOffset] ; index of top (visible) menu item within the list
- add b
- ld [wMenuItemToSwap], a ; ID of item chosen for swapping (counts from 1)
- ld c, 20
- call DelayFrames
- jp DisplayListMenuIDLoop
-.swapItems
- ld a, [wCurrentMenuItem]
- inc a
- ld b, a
- ld a, [wListScrollOffset]
- add b
- ld b, a
- ld a, [wMenuItemToSwap] ; ID of item chosen for swapping (counts from 1)
- cp b ; is the currently selected item the same as the first item to swap?
- jp z, DisplayListMenuIDLoop ; ignore attempts to swap an item with itself
- dec a
- ld [wMenuItemToSwap], a ; ID of item chosen for swapping (counts from 1)
- ld c, 20
- call DelayFrames
- push hl
- push de
- ld hl, wListPointer
- ld a, [hli]
- ld h, [hl]
- ld l, a
- inc hl ; hl = beginning of list entries
- ld d, h
- ld e, l ; de = beginning of list entries
- ld a, [wCurrentMenuItem]
- ld b, a
- ld a, [wListScrollOffset]
- add b
- add a
- ld c, a
- ld b, 0
- add hl, bc ; hl = address of currently selected item entry
- ld a, [wMenuItemToSwap] ; ID of item chosen for swapping (counts from 1)
- add a
- add e
- ld e, a
- jr nc, .noCarry
- inc d
-.noCarry ; de = address of first item to swap
- ld a, [de]
- ld b, a
- ld a, [hli]
- cp b
- jr z, .swapSameItemType
-.swapDifferentItems
- ld [$ff95], a ; [$ff95] = second item ID
- ld a, [hld]
- ld [$ff96], a ; [$ff96] = second item quantity
- ld a, [de]
- ld [hli], a ; put first item ID in second item slot
- inc de
- ld a, [de]
- ld [hl], a ; put first item quantity in second item slot
- ld a, [$ff96]
- ld [de], a ; put second item quantity in first item slot
- dec de
- ld a, [$ff95]
- ld [de], a ; put second item ID in first item slot
- xor a
- ld [wMenuItemToSwap], a ; 0 means no item is currently being swapped
- pop de
- pop hl
- jp DisplayListMenuIDLoop
-.swapSameItemType
- inc de
- ld a, [hl]
- ld b, a
- ld a, [de]
- add b ; a = sum of both item quantities
- cp 100 ; is the sum too big for one item slot?
- jr c, .combineItemSlots
-; swap enough items from the first slot to max out the second slot if they can't be combined
- sub 99
- ld [de], a
- ld a, 99
- ld [hl], a
- jr .done
-.combineItemSlots
- ld [hl], a ; put the sum in the second item slot
- ld hl, wListPointer
- ld a, [hli]
- ld h, [hl]
- ld l, a
- dec [hl] ; decrease the number of items
- ld a, [hl]
- ld [wListCount], a ; update number of items variable
- cp 1
- jr nz, .skipSettingMaxMenuItemID
- ld [wMaxMenuItem], a ; if the number of items is only one now, update the max menu item ID
-.skipSettingMaxMenuItemID
- dec de
- ld h, d
- ld l, e
- inc hl
- inc hl ; hl = address of item after first item to swap
-.moveItemsUpLoop ; erase the first item slot and move up all the following item slots to fill the gap
- ld a, [hli]
- ld [de], a
- inc de
- inc a ; reached the $ff terminator?
- jr z, .afterMovingItemsUp
- ld a, [hli]
- ld [de], a
- inc de
- jr .moveItemsUpLoop
-.afterMovingItemsUp
- xor a
- ld [wListScrollOffset], a
- ld [wCurrentMenuItem], a
-.done
- xor a
- ld [wMenuItemToSwap], a ; 0 means no item is currently being swapped
- pop de
- pop hl
- jp DisplayListMenuIDLoop
--- a/engine/menu/text_box.asm
+++ /dev/null
@@ -1,767 +1,0 @@
-; function to draw various text boxes
-DisplayTextBoxID_::
- ld a, [wTextBoxID]
- cp TWO_OPTION_MENU
- jp z, DisplayTwoOptionMenu
- ld c, a
- ld hl, TextBoxFunctionTable
- ld de, 3
- call SearchTextBoxTable
- jr c, .functionTableMatch
- ld hl, TextBoxCoordTable
- ld de, 5
- call SearchTextBoxTable
- jr c, .coordTableMatch
- ld hl, TextBoxTextAndCoordTable
- ld de, 9
- call SearchTextBoxTable
- jr c, .textAndCoordTableMatch
-.done
- ret
-.functionTableMatch
- ld a, [hli]
- ld h, [hl]
- ld l, a ; hl = address of function
- ld de, .done
- push de
- jp hl ; jump to the function
-.coordTableMatch
- call GetTextBoxIDCoords
- call GetAddressOfScreenCoords
- call TextBoxBorder
- ret
-.textAndCoordTableMatch
- call GetTextBoxIDCoords
- push hl
- call GetAddressOfScreenCoords
- call TextBoxBorder
- pop hl
- call GetTextBoxIDText
- ld a, [wd730]
- push af
- ld a, [wd730]
- set 6, a ; no pauses between printing each letter
- ld [wd730], a
- call PlaceString
- pop af
- ld [wd730], a
- call UpdateSprites
- ret
-
-; function to search a table terminated with $ff for a byte matching c in increments of de
-; sets carry flag if a match is found and clears carry flag if not
-SearchTextBoxTable:
- dec de
-.loop
- ld a, [hli]
- cp $ff
- jr z, .notFound
- cp c
- jr z, .found
- add hl, de
- jr .loop
-.found
- scf
-.notFound
- ret
-
-; function to load coordinates from the TextBoxCoordTable or the TextBoxTextAndCoordTable
-; INPUT:
-; hl = address of coordinates
-; OUTPUT:
-; b = height
-; c = width
-; d = row of upper left corner
-; e = column of upper left corner
-GetTextBoxIDCoords:
- ld a, [hli] ; column of upper left corner
- ld e, a
- ld a, [hli] ; row of upper left corner
- ld d, a
- ld a, [hli] ; column of lower right corner
- sub e
- dec a
- ld c, a ; c = width
- ld a, [hli] ; row of lower right corner
- sub d
- dec a
- ld b, a ; b = height
- ret
-
-; function to load a text address and text coordinates from the TextBoxTextAndCoordTable
-GetTextBoxIDText:
- ld a, [hli]
- ld e, a
- ld a, [hli]
- ld d, a ; de = address of text
- push de ; save text address
- ld a, [hli]
- ld e, a ; column of upper left corner of text
- ld a, [hl]
- ld d, a ; row of upper left corner of text
- call GetAddressOfScreenCoords
- pop de ; restore text address
- ret
-
-; function to point hl to the screen coordinates
-; INPUT:
-; d = row
-; e = column
-; OUTPUT:
-; hl = address of upper left corner of text box
-GetAddressOfScreenCoords:
- push bc
- coord hl, 0, 0
- ld bc, 20
-.loop ; loop to add d rows to the base address
- ld a, d
- and a
- jr z, .addedRows
- add hl, bc
- dec d
- jr .loop
-.addedRows
- pop bc
- add hl, de
- ret
-
-; Format:
-; 00: text box ID
-; 01-02: function address
-TextBoxFunctionTable:
- dbw MONEY_BOX, DisplayMoneyBox
- dbw BUY_SELL_QUIT_MENU, DoBuySellQuitMenu
- dbw FIELD_MOVE_MON_MENU, DisplayFieldMoveMonMenu
- db $ff ; terminator
-
-; Format:
-; 00: text box ID
-; 01: column of upper left corner
-; 02: row of upper left corner
-; 03: column of lower right corner
-; 04: row of lower right corner
-TextBoxCoordTable:
- db MESSAGE_BOX, 0, 12, 19, 17
- db $03, 0, 0, 19, 14
- db $07, 0, 0, 11, 6
- db LIST_MENU_BOX, 4, 2, 19, 12
- db $10, 7, 0, 19, 17
- db MON_SPRITE_POPUP, 6, 4, 14, 13
- db $ff ; terminator
-
-; Format:
-; 00: text box ID
-; 01: column of upper left corner
-; 02: row of upper left corner
-; 03: column of lower right corner
-; 04: row of lower right corner
-; 05-06: address of text
-; 07: column of beginning of text
-; 08: row of beginning of text
-; table of window positions and corresponding text [key, start column, start row, end column, end row, text pointer [2 bytes], text column, text row]
-TextBoxTextAndCoordTable:
- db JP_MOCHIMONO_MENU_TEMPLATE
- db 0,0,14,17 ; text box coordinates
- dw JapaneseMochimonoText
- db 3,0 ; text coordinates
-
- db USE_TOSS_MENU_TEMPLATE
- db 13,10,19,14 ; text box coordinates
- dw UseTossText
- db 15,11 ; text coordinates
-
- db JP_SAVE_MESSAGE_MENU_TEMPLATE
- db 0,0,7,5 ; text box coordinates
- dw JapaneseSaveMessageText
- db 2,2 ; text coordinates
-
- db JP_SPEED_OPTIONS_MENU_TEMPLATE
- db 0,6,5,10 ; text box coordinates
- dw JapaneseSpeedOptionsText
- db 2,7 ; text coordinates
-
- db BATTLE_MENU_TEMPLATE
- db 8,12,19,17 ; text box coordinates
- dw BattleMenuText
- db 10,14 ; text coordinates
-
- db SAFARI_BATTLE_MENU_TEMPLATE
- db 0,12,19,17 ; text box coordinates
- dw SafariZoneBattleMenuText
- db 2,14 ; text coordinates
-
- db SWITCH_STATS_CANCEL_MENU_TEMPLATE
- db 11,11,19,17 ; text box coordinates
- dw SwitchStatsCancelText
- db 13,12 ; text coordinates
-
- db BUY_SELL_QUIT_MENU_TEMPLATE
- db 0,0,10,6 ; text box coordinates
- dw BuySellQuitText
- db 2,1 ; text coordinates
-
- db MONEY_BOX_TEMPLATE
- db 11,0,19,2 ; text box coordinates
- dw MoneyText
- db 13,0 ; text coordinates
-
- db JP_AH_MENU_TEMPLATE
- db 7,6,11,10 ; text box coordinates
- dw JapaneseAhText
- db 8,8 ; text coordinates
-
- db JP_POKEDEX_MENU_TEMPLATE
- db 11,8,19,17 ; text box coordinates
- dw JapanesePokedexMenu
- db 12,10 ; text coordinates
-
-; note that there is no terminator
-
-BuySellQuitText:
- db "BUY"
- next "SELL"
- next "QUIT@@"
-
-UseTossText:
- db "USE"
- next "TOSS@"
-
-JapaneseSaveMessageText:
- db "きろく"
- next "メッセージ@"
-
-JapaneseSpeedOptionsText:
- db "はやい"
- next "おそい@"
-
-MoneyText:
- db "MONEY@"
-
-JapaneseMochimonoText:
- db "もちもの@"
-
-JapaneseMainMenuText:
- db "つづきから"
- next "さいしょから@"
-
-BattleMenuText:
- db "FIGHT ",$E1,$E2
- next "ITEM RUN@"
-
-SafariZoneBattleMenuText:
- db "BALL× BAIT"
- next "THROW ROCK RUN@"
-
-SwitchStatsCancelText:
- db "SWITCH"
- next "STATS"
- next "CANCEL@"
-
-JapaneseAhText:
- db "アッ!@"
-
-JapanesePokedexMenu:
- db "データをみる"
- next "なきごえ"
- next "ぶんぷをみる"
- next "キャンセル@"
-
-DisplayMoneyBox:
- ld hl, wd730
- set 6, [hl]
- ld a, MONEY_BOX_TEMPLATE
- ld [wTextBoxID], a
- call DisplayTextBoxID
- coord hl, 13, 1
- ld b, 1
- ld c, 6
- call ClearScreenArea
- coord hl, 12, 1
- ld de, wPlayerMoney
- ld c, $a3
- call PrintBCDNumber
- ld hl, wd730
- res 6, [hl]
- ret
-
-CurrencyString:
- db " ¥@"
-
-DoBuySellQuitMenu:
- ld a, [wd730]
- set 6, a ; no printing delay
- ld [wd730], a
- xor a
- ld [wChosenMenuItem], a
- ld a, BUY_SELL_QUIT_MENU_TEMPLATE
- ld [wTextBoxID], a
- call DisplayTextBoxID
- ld a, A_BUTTON | B_BUTTON
- ld [wMenuWatchedKeys], a
- ld a, $2
- ld [wMaxMenuItem], a
- ld a, $1
- ld [wTopMenuItemY], a
- ld a, $1
- ld [wTopMenuItemX], a
- xor a
- ld [wCurrentMenuItem], a
- ld [wLastMenuItem], a
- ld [wMenuWatchMovingOutOfBounds], a
- ld a, [wd730]
- res 6, a ; turn on the printing delay
- ld [wd730], a
- call HandleMenuInput
- call PlaceUnfilledArrowMenuCursor
- bit 0, a ; was A pressed?
- jr nz, .pressedA
- bit 1, a ; was B pressed? (always true since only A/B are watched)
- jr z, .pressedA
- ld a, CANCELLED_MENU
- ld [wMenuExitMethod], a
- jr .quit
-.pressedA
- ld a, CHOSE_MENU_ITEM
- ld [wMenuExitMethod], a
- ld a, [wCurrentMenuItem]
- ld [wChosenMenuItem], a
- ld b, a
- ld a, [wMaxMenuItem]
- cp b
- jr z, .quit
- ret
-.quit
- ld a, CANCELLED_MENU
- ld [wMenuExitMethod], a
- ld a, [wCurrentMenuItem]
- ld [wChosenMenuItem], a
- scf
- ret
-
-; displays a menu with two options to choose from
-; b = Y of upper left corner of text region
-; c = X of upper left corner of text region
-; hl = address where the text box border should be drawn
-DisplayTwoOptionMenu:
- push hl
- ld a, [wd730]
- set 6, a ; no printing delay
- ld [wd730], a
-
-; pointless because both values are overwritten before they are read
- xor a
- ld [wChosenMenuItem], a
- ld [wMenuExitMethod], a
-
- ld a, A_BUTTON | B_BUTTON
- ld [wMenuWatchedKeys], a
- ld a, $1
- ld [wMaxMenuItem], a
- ld a, b
- ld [wTopMenuItemY], a
- ld a, c
- ld [wTopMenuItemX], a
- xor a
- ld [wLastMenuItem], a
- ld [wMenuWatchMovingOutOfBounds], a
- push hl
- ld hl, wTwoOptionMenuID
- bit 7, [hl] ; select second menu item by default?
- res 7, [hl]
- jr z, .storeCurrentMenuItem
- inc a
-.storeCurrentMenuItem
- ld [wCurrentMenuItem], a
- pop hl
- push hl
- push hl
- call TwoOptionMenu_SaveScreenTiles
- ld a, [wTwoOptionMenuID]
- ld hl, TwoOptionMenuStrings
- ld e, a
- ld d, $0
- ld a, $5
-.menuStringLoop
- add hl, de
- dec a
- jr nz, .menuStringLoop
- ld a, [hli]
- ld c, a
- ld a, [hli]
- ld b, a
- ld e, l
- ld d, h
- pop hl
- push de
- ld a, [wTwoOptionMenuID]
- cp TRADE_CANCEL_MENU
- jr nz, .notTradeCancelMenu
- call CableClub_TextBoxBorder
- jr .afterTextBoxBorder
-.notTradeCancelMenu
- call TextBoxBorder
-.afterTextBoxBorder
- call UpdateSprites
- pop hl
- ld a, [hli]
- and a ; put blank line before first menu item?
- ld bc, 20 + 2
- jr z, .noBlankLine
- ld bc, 2 * 20 + 2
-.noBlankLine
- ld a, [hli]
- ld e, a
- ld a, [hli]
- ld d, a
- pop hl
- add hl, bc
- call PlaceString
- ld hl, wd730
- res 6, [hl] ; turn on the printing delay
- ld a, [wTwoOptionMenuID]
- cp NO_YES_MENU
- jr nz, .notNoYesMenu
-; No/Yes menu
-; this menu type ignores the B button
-; it only seems to be used when confirming the deletion of a save file
- xor a
- ld [wTwoOptionMenuID], a
- ld a, [wFlags_0xcd60]
- push af
- push hl
- ld hl, wFlags_0xcd60
- bit 5, [hl]
- set 5, [hl] ; don't play sound when A or B is pressed in menu
- pop hl
-.noYesMenuInputLoop
- call HandleMenuInput
- bit 1, a ; A button pressed?
- jr nz, .noYesMenuInputLoop ; try again if A was not pressed
- pop af
- pop hl
- ld [wFlags_0xcd60], a
- ld a, SFX_PRESS_AB
- call PlaySound
- jr .pressedAButton
-.notNoYesMenu
- xor a
- ld [wTwoOptionMenuID], a
- call HandleMenuInput
- pop hl
- bit 1, a ; A button pressed?
- jr nz, .choseSecondMenuItem ; automatically choose the second option if B is pressed
-.pressedAButton
- ld a, [wCurrentMenuItem]
- ld [wChosenMenuItem], a
- and a
- jr nz, .choseSecondMenuItem
-; chose first menu item
- ld a, CHOSE_FIRST_ITEM
- ld [wMenuExitMethod], a
- ld c, 15
- call DelayFrames
- call TwoOptionMenu_RestoreScreenTiles
- and a
- ret
-.choseSecondMenuItem
- ld a, 1
- ld [wCurrentMenuItem], a
- ld [wChosenMenuItem], a
- ld a, CHOSE_SECOND_ITEM
- ld [wMenuExitMethod], a
- ld c, 15
- call DelayFrames
- call TwoOptionMenu_RestoreScreenTiles
- scf
- ret
-
-; Some of the wider/taller two option menus will not have the screen areas
-; they cover be fully saved/restored by the two functions below.
-; The bottom and right edges of the menu may remain after the function returns.
-
-TwoOptionMenu_SaveScreenTiles:
- ld de, wBuffer
- lb bc, 5, 6
-.loop
- ld a, [hli]
- ld [de], a
- inc de
- dec c
- jr nz, .loop
- push bc
- ld bc, SCREEN_WIDTH - 6
- add hl, bc
- pop bc
- ld c, $6
- dec b
- jr nz, .loop
- ret
-
-TwoOptionMenu_RestoreScreenTiles:
- ld de, wBuffer
- lb bc, 5, 6
-.loop
- ld a, [de]
- inc de
- ld [hli], a
- dec c
- jr nz, .loop
- push bc
- ld bc, SCREEN_WIDTH - 6
- add hl, bc
- pop bc
- ld c, 6
- dec b
- jr nz, .loop
- call UpdateSprites
- ret
-
-; Format:
-; 00: byte width
-; 01: byte height
-; 02: byte put blank line before first menu item
-; 03: word text pointer
-TwoOptionMenuStrings:
- db 4,3,0
- dw .YesNoMenu
- db 6,3,0
- dw .NorthWestMenu
- db 6,3,0
- dw .SouthEastMenu
- db 6,3,0
- dw .YesNoMenu
- db 6,3,0
- dw .NorthEastMenu
- db 7,3,0
- dw .TradeCancelMenu
- db 7,4,1
- dw .HealCancelMenu
- db 4,3,0
- dw .NoYesMenu
-
-.NoYesMenu
- db "NO"
- next "YES@"
-.YesNoMenu
- db "YES"
- next "NO@"
-.NorthWestMenu
- db "NORTH"
- next "WEST@"
-.SouthEastMenu
- db "SOUTH"
- next "EAST@"
-.NorthEastMenu
- db "NORTH"
- next "EAST@"
-.TradeCancelMenu
- db "TRADE"
- next "CANCEL@"
-.HealCancelMenu
- db "HEAL"
- next "CANCEL@"
-
-DisplayFieldMoveMonMenu:
- xor a
- ld hl, wFieldMoves
- ld [hli], a ; wFieldMoves
- ld [hli], a ; wFieldMoves + 1
- ld [hli], a ; wFieldMoves + 2
- ld [hli], a ; wFieldMoves + 3
- ld [hli], a ; wNumFieldMoves
- ld [hl], 12 ; wFieldMovesLeftmostXCoord
- call GetMonFieldMoves
- ld a, [wNumFieldMoves]
- and a
- jr nz, .fieldMovesExist
-
-; no field moves
- coord hl, 11, 11
- ld b, 5
- ld c, 7
- call TextBoxBorder
- call UpdateSprites
- ld a, 12
- ld [hFieldMoveMonMenuTopMenuItemX], a
- coord hl, 13, 12
- ld de, PokemonMenuEntries
- jp PlaceString
-
-.fieldMovesExist
- push af
-
-; Calculate the text box position and dimensions based on the leftmost X coord
-; of the field move names before adjusting for the number of field moves.
- coord hl, 0, 11
- ld a, [wFieldMovesLeftmostXCoord]
- dec a
- ld e, a
- ld d, 0
- add hl, de
- ld b, 5
- ld a, 18
- sub e
- ld c, a
- pop af
-
-; For each field move, move the top of the text box up 2 rows while the leaving
-; the bottom of the text box at the bottom of the screen.
- ld de, -SCREEN_WIDTH * 2
-.textBoxHeightLoop
- add hl, de
- inc b
- inc b
- dec a
- jr nz, .textBoxHeightLoop
-
-; Make space for an extra blank row above the top field move.
- ld de, -SCREEN_WIDTH
- add hl, de
- inc b
-
- call TextBoxBorder
- call UpdateSprites
-
-; Calculate the position of the first field move name to print.
- coord hl, 0, 12
- ld a, [wFieldMovesLeftmostXCoord]
- inc a
- ld e, a
- ld d, 0
- add hl, de
- ld de, -SCREEN_WIDTH * 2
- ld a, [wNumFieldMoves]
-.calcFirstFieldMoveYLoop
- add hl, de
- dec a
- jr nz, .calcFirstFieldMoveYLoop
-
- xor a
- ld [wNumFieldMoves], a
- ld de, wFieldMoves
-.printNamesLoop
- push hl
- ld hl, FieldMoveNames
- ld a, [de]
- and a
- jr z, .donePrintingNames
- inc de
- ld b, a ; index of name
-.skipNamesLoop ; skip past names before the name we want
- dec b
- jr z, .reachedName
-.skipNameLoop ; skip past current name
- ld a, [hli]
- cp "@"
- jr nz, .skipNameLoop
- jr .skipNamesLoop
-.reachedName
- ld b, h
- ld c, l
- pop hl
- push de
- ld d, b
- ld e, c
- call PlaceString
- ld bc, SCREEN_WIDTH * 2
- add hl, bc
- pop de
- jr .printNamesLoop
-
-.donePrintingNames
- pop hl
- ld a, [wFieldMovesLeftmostXCoord]
- ld [hFieldMoveMonMenuTopMenuItemX], a
- coord hl, 0, 12
- ld a, [wFieldMovesLeftmostXCoord]
- inc a
- ld e, a
- ld d, 0
- add hl, de
- ld de, PokemonMenuEntries
- jp PlaceString
-
-FieldMoveNames:
- db "CUT@"
- db "FLY@"
- db "@"
- db "SURF@"
- db "STRENGTH@"
- db "FLASH@"
- db "DIG@"
- db "TELEPORT@"
- db "SOFTBOILED@"
-
-PokemonMenuEntries:
- db "STATS"
- next "SWITCH"
- next "CANCEL@"
-
-GetMonFieldMoves:
- ld a, [wWhichPokemon]
- ld hl, wPartyMon1Moves
- ld bc, wPartyMon2 - wPartyMon1
- call AddNTimes
- ld d, h
- ld e, l
- ld c, NUM_MOVES + 1
- ld hl, wFieldMoves
-.loop
- push hl
-.nextMove
- dec c
- jr z, .done
- ld a, [de] ; move ID
- and a
- jr z, .done
- ld b, a
- inc de
- ld hl, FieldMoveDisplayData
-.fieldMoveLoop
- ld a, [hli]
- cp $ff
- jr z, .nextMove ; if the move is not a field move
- cp b
- jr z, .foundFieldMove
- inc hl
- inc hl
- jr .fieldMoveLoop
-.foundFieldMove
- ld a, b
- ld [wLastFieldMoveID], a
- ld a, [hli] ; field move name index
- ld b, [hl] ; field move leftmost X coordinate
- pop hl
- ld [hli], a ; store name index in wFieldMoves
- ld a, [wNumFieldMoves]
- inc a
- ld [wNumFieldMoves], a
- ld a, [wFieldMovesLeftmostXCoord]
- cp b
- jr c, .skipUpdatingLeftmostXCoord
- ld a, b
- ld [wFieldMovesLeftmostXCoord], a
-.skipUpdatingLeftmostXCoord
- ld a, [wLastFieldMoveID]
- ld b, a
- jr .loop
-.done
- pop hl
- ret
-
-; Format: [Move id], [name index], [leftmost tile]
-; Move id = id of move
-; Name index = index of name in FieldMoveNames
-; Leftmost tile = -1 + tile column in which the first letter of the move's name should be displayed
-; "SOFTBOILED" is $08 because it has 4 more letters than "SURF", for example, whose value is $0C
-FieldMoveDisplayData:
- db CUT, $01, $0C
- db FLY, $02, $0C
- db $B4, $03, $0C ; unused field move
- db SURF, $04, $0C
- db STRENGTH, $05, $0A
- db FLASH, $06, $0C
- db DIG, $07, $0C
- db TELEPORT, $08, $0A
- db SOFTBOILED, $09, $08
- db $ff ; list terminator
--- a/engine/menu/vending_machine.asm
+++ /dev/null
@@ -1,133 +1,0 @@
-VendingMachineMenu::
- ld hl, VendingMachineText1
- call PrintText
- ld a, MONEY_BOX
- ld [wTextBoxID], a
- call DisplayTextBoxID
- xor a
- ld [wCurrentMenuItem], a
- ld [wLastMenuItem], a
- ld a, A_BUTTON | B_BUTTON
- ld [wMenuWatchedKeys], a
- ld a, 3
- ld [wMaxMenuItem], a
- ld a, 5
- ld [wTopMenuItemY], a
- ld a, 1
- ld [wTopMenuItemX], a
- ld hl, wd730
- set 6, [hl]
- coord hl, 0, 3
- ld b, 8
- ld c, 12
- call TextBoxBorder
- call UpdateSprites
- coord hl, 2, 5
- ld de, DrinkText
- call PlaceString
- coord hl, 9, 6
- ld de, DrinkPriceText
- call PlaceString
- ld hl, wd730
- res 6, [hl]
- call HandleMenuInput
- bit 1, a ; pressed B?
- jr nz, .notThirsty
- ld a, [wCurrentMenuItem]
- cp 3 ; chose Cancel?
- jr z, .notThirsty
- xor a
- ld [hMoney], a
- ld [hMoney + 2], a
- ld a, $2
- ld [hMoney + 1], a
- call HasEnoughMoney
- jr nc, .enoughMoney
- ld hl, VendingMachineText4
- jp PrintText
-.enoughMoney
- call LoadVendingMachineItem
- ld a, [hVendingMachineItem]
- ld b, a
- ld c, 1
- call GiveItem
- jr nc, .BagFull
-
- ld b, 60 ; number of times to play the "brrrrr" sound
-.playDeliverySound
- ld c, 2
- call DelayFrames
- push bc
- ld a, SFX_PUSH_BOULDER
- call PlaySound
- pop bc
- dec b
- jr nz, .playDeliverySound
-
- ld hl, VendingMachineText5
- call PrintText
- ld hl, hVendingMachinePrice + 2
- ld de, wPlayerMoney + 2
- ld c, $3
- predef SubBCDPredef
- ld a, MONEY_BOX
- ld [wTextBoxID], a
- jp DisplayTextBoxID
-.BagFull
- ld hl, VendingMachineText6
- jp PrintText
-.notThirsty
- ld hl, VendingMachineText7
- jp PrintText
-
-VendingMachineText1:
- TX_FAR _VendingMachineText1
- db "@"
-
-DrinkText:
- db "FRESH WATER"
- next "SODA POP"
- next "LEMONADE"
- next "CANCEL@"
-
-DrinkPriceText:
- db "¥200"
- next "¥300"
- next "¥350"
- next "@"
-
-VendingMachineText4:
- TX_FAR _VendingMachineText4
- db "@"
-
-VendingMachineText5:
- TX_FAR _VendingMachineText5
- db "@"
-
-VendingMachineText6:
- TX_FAR _VendingMachineText6
- db "@"
-
-VendingMachineText7:
- TX_FAR _VendingMachineText7
- db "@"
-
-LoadVendingMachineItem:
- ld hl, VendingPrices
- ld a, [wCurrentMenuItem]
- add a
- add a
- ld d, 0
- ld e, a
- add hl, de
- ld a, [hli]
- ld [hVendingMachineItem], a
- ld a, [hli]
- ld [hVendingMachinePrice], a
- ld a, [hli]
- ld [hVendingMachinePrice + 1], a
- ld a, [hl]
- ld [hVendingMachinePrice + 2], a
- ret
-
-INCLUDE "data/vending_prices.asm"
--- /dev/null
+++ b/engine/menus/display_text_id_init.asm
@@ -1,0 +1,78 @@
+; function that performs initialization for DisplayTextID
+DisplayTextIDInit::
+ xor a
+ ld [wListMenuID], a
+ ld a, [wAutoTextBoxDrawingControl]
+ bit 0, a
+ jr nz, .skipDrawingTextBoxBorder
+ ld a, [hSpriteIndexOrTextID] ; text ID (or sprite ID)
+ and a
+ jr nz, .notStartMenu
+; if text ID is 0 (i.e. the start menu)
+; Note that the start menu text border is also drawn in the function directly
+; below this, so this seems unnecessary.
+ CheckEvent EVENT_GOT_POKEDEX
+; start menu with pokedex
+ coord hl, 10, 0
+ ld b, $0e
+ ld c, $08
+ jr nz, .drawTextBoxBorder
+; start menu without pokedex
+ coord hl, 10, 0
+ ld b, $0c
+ ld c, $08
+ jr .drawTextBoxBorder
+; if text ID is not 0 (i.e. not the start menu) then do a standard dialogue text box
+.notStartMenu
+ coord hl, 0, 12
+ ld b, $04
+ ld c, $12
+.drawTextBoxBorder
+ call TextBoxBorder
+.skipDrawingTextBoxBorder
+ ld hl, wFontLoaded
+ set 0, [hl]
+ ld hl, wFlags_0xcd60
+ bit 4, [hl]
+ res 4, [hl]
+ jr nz, .skipMovingSprites
+ call UpdateSprites
+.skipMovingSprites
+; loop to copy C1X9 (direction the sprite is facing) to C2X9 for each sprite
+; this is done because when you talk to an NPC, they turn to look your way
+; the original direction they were facing must be restored after the dialogue is over
+ ld hl, wSpriteStateData1 + $19
+ ld c, $0f
+ ld de, $0010
+.spriteFacingDirectionCopyLoop
+ ld a, [hl]
+ inc h
+ ld [hl], a
+ dec h
+ add hl, de
+ dec c
+ jr nz, .spriteFacingDirectionCopyLoop
+; loop to force all the sprites in the middle of animation to stand still
+; (so that they don't like they're frozen mid-step during the dialogue)
+ ld hl, wSpriteStateData1 + 2
+ ld de, $0010
+ ld c, e
+.spriteStandStillLoop
+ ld a, [hl]
+ cp $ff ; is the sprite visible?
+ jr z, .nextSprite
+; if it is visible
+ and $fc
+ ld [hl], a
+.nextSprite
+ add hl, de
+ dec c
+ jr nz, .spriteStandStillLoop
+ ld b, $9c ; window background address
+ call CopyScreenTileBufferToVRAM ; transfer background in WRAM to VRAM
+ xor a
+ ld [hWY], a ; put the window on the screen
+ call LoadFontTilePatterns
+ ld a, $01
+ ld [H_AUTOBGTRANSFERENABLED], a ; enable continuous WRAM to VRAM transfer each V-blank
+ ret
--- /dev/null
+++ b/engine/menus/draw_badges.asm
@@ -1,0 +1,120 @@
+DrawBadges:
+; Draw 4x2 gym leader faces, with the faces replaced by
+; badges if they are owned. Used in the player status screen.
+
+; In Japanese versions, names are displayed above faces.
+; Instead of removing relevant code, the name graphics were erased.
+
+; Tile ids for face/badge graphics.
+ ld de, wBadgeOrFaceTiles
+ ld hl, .FaceBadgeTiles
+ ld bc, 8
+ call CopyData
+
+; Booleans for each badge.
+ ld hl, wTempObtainedBadgesBooleans
+ ld bc, 8
+ xor a
+ call FillMemory
+
+; Alter these based on owned badges.
+ ld de, wTempObtainedBadgesBooleans
+ ld hl, wBadgeOrFaceTiles
+ ld a, [wObtainedBadges]
+ ld b, a
+ ld c, 8
+.CheckBadge
+ srl b
+ jr nc, .NextBadge
+ ld a, [hl]
+ add 4 ; Badge graphics are after each face
+ ld [hl], a
+ ld a, 1
+ ld [de], a
+.NextBadge
+ inc hl
+ inc de
+ dec c
+ jr nz, .CheckBadge
+
+; Draw two rows of badges.
+ ld hl, wBadgeNumberTile
+ ld a, $d8 ; [1]
+ ld [hli], a
+ ld [hl], $60 ; First name
+
+ coord hl, 2, 11
+ ld de, wTempObtainedBadgesBooleans
+ call .DrawBadgeRow
+
+ coord hl, 2, 14
+ ld de, wTempObtainedBadgesBooleans + 4
+; call .DrawBadgeRow
+; ret
+
+.DrawBadgeRow
+; Draw 4 badges.
+
+ ld c, 4
+.DrawBadge
+ push de
+ push hl
+
+; Badge no.
+ ld a, [wBadgeNumberTile]
+ ld [hli], a
+ inc a
+ ld [wBadgeNumberTile], a
+
+; Names aren't printed if the badge is owned.
+ ld a, [de]
+ and a
+ ld a, [wBadgeNameTile]
+ jr nz, .SkipName
+ call .PlaceTiles
+ jr .PlaceBadge
+
+.SkipName
+ inc a
+ inc a
+ inc hl
+
+.PlaceBadge
+ ld [wBadgeNameTile], a
+ ld de, SCREEN_WIDTH - 1
+ add hl, de
+ ld a, [wBadgeOrFaceTiles]
+ call .PlaceTiles
+ add hl, de
+ call .PlaceTiles
+
+; Shift badge array back one byte.
+ push bc
+ ld hl, wBadgeOrFaceTiles + 1
+ ld de, wBadgeOrFaceTiles
+ ld bc, 8
+ call CopyData
+ pop bc
+
+ pop hl
+ ld de, 4
+ add hl, de
+
+ pop de
+ inc de
+ dec c
+ jr nz, .DrawBadge
+ ret
+
+.PlaceTiles
+ ld [hli], a
+ inc a
+ ld [hl], a
+ inc a
+ ret
+
+.FaceBadgeTiles
+ db $20, $28, $30, $38, $40, $48, $50, $58
+
+GymLeaderFaceAndBadgeTileGraphics:
+ INCBIN "gfx/trainer_card/badges.2bpp"
--- /dev/null
+++ b/engine/menus/draw_start_menu.asm
@@ -1,0 +1,89 @@
+; function that displays the start menu
+DrawStartMenu::
+ CheckEvent EVENT_GOT_POKEDEX
+; menu with pokedex
+ coord hl, 10, 0
+ ld b, $0e
+ ld c, $08
+ jr nz, .drawTextBoxBorder
+; shorter menu if the player doesn't have the pokedex
+ coord hl, 10, 0
+ ld b, $0c
+ ld c, $08
+.drawTextBoxBorder
+ call TextBoxBorder
+ ld a, D_DOWN | D_UP | START | B_BUTTON | A_BUTTON
+ ld [wMenuWatchedKeys], a
+ ld a, $02
+ ld [wTopMenuItemY], a ; Y position of first menu choice
+ ld a, $0b
+ ld [wTopMenuItemX], a ; X position of first menu choice
+ ld a, [wBattleAndStartSavedMenuItem] ; remembered menu selection from last time
+ ld [wCurrentMenuItem], a
+ ld [wLastMenuItem], a
+ xor a
+ ld [wMenuWatchMovingOutOfBounds], a
+ ld hl, wd730
+ set 6, [hl] ; no pauses between printing each letter
+ coord hl, 12, 2
+ CheckEvent EVENT_GOT_POKEDEX
+; case for not having pokedex
+ ld a, $06
+ jr z, .storeMenuItemCount
+; case for having pokedex
+ ld de, StartMenuPokedexText
+ call PrintStartMenuItem
+ ld a, $07
+.storeMenuItemCount
+ ld [wMaxMenuItem], a ; number of menu items
+ ld de, StartMenuPokemonText
+ call PrintStartMenuItem
+ ld de, StartMenuItemText
+ call PrintStartMenuItem
+ ld de, wPlayerName ; player's name
+ call PrintStartMenuItem
+ ld a, [wd72e]
+ bit 6, a ; is the player using the link feature?
+; case for not using link feature
+ ld de, StartMenuSaveText
+ jr z, .printSaveOrResetText
+; case for using link feature
+ ld de, StartMenuResetText
+.printSaveOrResetText
+ call PrintStartMenuItem
+ ld de, StartMenuOptionText
+ call PrintStartMenuItem
+ ld de, StartMenuExitText
+ call PlaceString
+ ld hl, wd730
+ res 6, [hl] ; turn pauses between printing letters back on
+ ret
+
+StartMenuPokedexText:
+ db "POKéDEX@"
+
+StartMenuPokemonText:
+ db "POKéMON@"
+
+StartMenuItemText:
+ db "ITEM@"
+
+StartMenuSaveText:
+ db "SAVE@"
+
+StartMenuResetText:
+ db "RESET@"
+
+StartMenuExitText:
+ db "EXIT@"
+
+StartMenuOptionText:
+ db "OPTION@"
+
+PrintStartMenuItem:
+ push hl
+ call PlaceString
+ pop hl
+ ld de, SCREEN_WIDTH * 2
+ add hl, de
+ ret
--- /dev/null
+++ b/engine/menus/league_pc.asm
@@ -1,0 +1,120 @@
+PKMNLeaguePC:
+ ld hl, AccessedHoFPCText
+ call PrintText
+ ld hl, wd730
+ set 6, [hl]
+ push hl
+ ld a, [wUpdateSpritesEnabled]
+ push af
+ ld a, [hTilesetType]
+ push af
+ xor a
+ ld [hTilesetType], a
+ ld [wSpriteFlipped], a
+ ld [wUpdateSpritesEnabled], a
+ ld [wHoFTeamIndex2], a
+ ld [wHoFTeamNo], a
+ ld a, [wNumHoFTeams]
+ ld b, a
+ cp HOF_TEAM_CAPACITY + 1
+ jr c, .loop
+; If the total number of hall of fame teams is greater than the storage
+; capacity, then calculate the number of the first team that is still recorded.
+ ld b, HOF_TEAM_CAPACITY
+ sub b
+ ld [wHoFTeamNo], a
+.loop
+ ld hl, wHoFTeamNo
+ inc [hl]
+ push bc
+ ld a, [wHoFTeamIndex2]
+ ld [wHoFTeamIndex], a
+ callba LoadHallOfFameTeams
+ call LeaguePCShowTeam
+ pop bc
+ jr c, .doneShowingTeams
+ ld hl, wHoFTeamIndex2
+ inc [hl]
+ ld a, [hl]
+ cp b
+ jr nz, .loop
+.doneShowingTeams
+ pop af
+ ld [hTilesetType], a
+ pop af
+ ld [wUpdateSpritesEnabled], a
+ pop hl
+ res 6, [hl]
+ call GBPalWhiteOutWithDelay3
+ call ClearScreen
+ call RunDefaultPaletteCommand
+ jp GBPalNormal
+
+LeaguePCShowTeam:
+ ld c, PARTY_LENGTH
+.loop
+ push bc
+ call LeaguePCShowMon
+ call WaitForTextScrollButtonPress
+ ld a, [hJoyHeld]
+ bit 1, a
+ jr nz, .exit
+ ld hl, wHallOfFame + HOF_MON
+ ld de, wHallOfFame
+ ld bc, HOF_TEAM - HOF_MON
+ call CopyData
+ pop bc
+ ld a, [wHallOfFame + 0]
+ cp $ff
+ jr z, .done
+ dec c
+ jr nz, .loop
+.done
+ and a
+ ret
+.exit
+ pop bc
+ scf
+ ret
+
+LeaguePCShowMon:
+ call GBPalWhiteOutWithDelay3
+ call ClearScreen
+ ld hl, wHallOfFame
+ ld a, [hli]
+ ld [wHoFMonSpecies], a
+ ld [wcf91], a
+ ld [wd0b5], a
+ ld [wBattleMonSpecies2], a
+ ld [wWholeScreenPaletteMonSpecies], a
+ ld a, [hli]
+ ld [wHoFMonLevel], a
+ ld de, wcd6d
+ ld bc, NAME_LENGTH
+ call CopyData
+ ld b, SET_PAL_POKEMON_WHOLE_SCREEN
+ ld c, 0
+ call RunPaletteCommand
+ coord hl, 12, 5
+ call GetMonHeader
+ call LoadFrontSpriteByMonIndex
+ call GBPalNormal
+ coord hl, 0, 13
+ ld b, 2
+ ld c, $12
+ call TextBoxBorder
+ coord hl, 1, 15
+ ld de, HallOfFameNoText
+ call PlaceString
+ coord hl, 16, 15
+ ld de, wHoFTeamNo
+ lb bc, 1, 3
+ call PrintNumber
+ jpba HoFDisplayMonInfo
+
+HallOfFameNoText:
+ db "HALL OF FAME No @"
+
+AccessedHoFPCText:
+ TX_FAR _AccessedHoFPCText
+ db "@"
--- /dev/null
+++ b/engine/menus/main_menu.asm
@@ -1,0 +1,712 @@
+MainMenu:
+; Check save file
+ call InitOptions
+ xor a
+ ld [wOptionsInitialized], a
+ inc a
+ ld [wSaveFileStatus], a
+ call CheckForPlayerNameInSRAM
+ jr nc, .mainMenuLoop
+
+ predef LoadSAV
+
+.mainMenuLoop
+ ld c, 20
+ call DelayFrames
+ xor a ; LINK_STATE_NONE
+ ld [wLinkState], a
+ ld hl, wPartyAndBillsPCSavedMenuItem
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+ ld [wDefaultMap], a
+ ld hl, wd72e
+ res 6, [hl]
+ call ClearScreen
+ call RunDefaultPaletteCommand
+ call LoadTextBoxTilePatterns
+ call LoadFontTilePatterns
+ ld hl, wd730
+ set 6, [hl]
+ ld a, [wSaveFileStatus]
+ cp 1
+ jr z, .noSaveFile
+; there's a save file
+ coord hl, 0, 0
+ ld b, 6
+ ld c, 13
+ call TextBoxBorder
+ coord hl, 2, 2
+ ld de, ContinueText
+ call PlaceString
+ jr .next2
+.noSaveFile
+ coord hl, 0, 0
+ ld b, 4
+ ld c, 13
+ call TextBoxBorder
+ coord hl, 2, 2
+ ld de, NewGameText
+ call PlaceString
+.next2
+ ld hl, wd730
+ res 6, [hl]
+ call UpdateSprites
+ xor a
+ ld [wCurrentMenuItem], a
+ ld [wLastMenuItem], a
+ ld [wMenuJoypadPollCount], a
+ inc a
+ ld [wTopMenuItemX], a
+ inc a
+ ld [wTopMenuItemY], a
+ ld a, A_BUTTON | B_BUTTON | START
+ ld [wMenuWatchedKeys], a
+ ld a, [wSaveFileStatus]
+ ld [wMaxMenuItem], a
+ call HandleMenuInput
+ bit 1, a ; pressed B?
+ jp nz, DisplayTitleScreen ; if so, go back to the title screen
+ ld c, 20
+ call DelayFrames
+ ld a, [wCurrentMenuItem]
+ ld b, a
+ ld a, [wSaveFileStatus]
+ cp 2
+ jp z, .skipInc
+; If there's no save file, increment the current menu item so that the numbers
+; are the same whether or not there's a save file.
+ inc b
+.skipInc
+ ld a, b
+ and a
+ jr z, .choseContinue
+ cp 1
+ jp z, StartNewGame
+ call DisplayOptionMenu
+ ld a, 1
+ ld [wOptionsInitialized], a
+ jp .mainMenuLoop
+.choseContinue
+ call DisplayContinueGameInfo
+ ld hl, wCurrentMapScriptFlags
+ set 5, [hl]
+.inputLoop
+ xor a
+ ld [hJoyPressed], a
+ ld [hJoyReleased], a
+ ld [hJoyHeld], a
+ call Joypad
+ ld a, [hJoyHeld]
+ bit 0, a
+ jr nz, .pressedA
+ bit 1, a
+ jp nz, .mainMenuLoop ; pressed B
+ jr .inputLoop
+.pressedA
+ call GBPalWhiteOutWithDelay3
+ call ClearScreen
+ ld a, PLAYER_DIR_DOWN
+ ld [wPlayerDirection], a
+ ld c, 10
+ call DelayFrames
+ ld a, [wNumHoFTeams]
+ and a
+ jp z, SpecialEnterMap
+ ld a, [wCurMap] ; map ID
+ cp HALL_OF_FAME
+ jp nz, SpecialEnterMap
+ xor a
+ ld [wDestinationMap], a
+ ld hl, wd732
+ set 2, [hl] ; fly warp or dungeon warp
+ call SpecialWarpIn
+ jp SpecialEnterMap
+
+InitOptions:
+ ld a, 1 ; no delay
+ ld [wLetterPrintingDelayFlags], a
+ ld a, 3 ; medium speed
+ ld [wOptions], a
+ ret
+
+LinkMenu:
+ xor a
+ ld [wLetterPrintingDelayFlags], a
+ ld hl, wd72e
+ set 6, [hl]
+ ld hl, TextTerminator_6b20
+ call PrintText
+ call SaveScreenTilesToBuffer1
+ ld hl, WhereWouldYouLikeText
+ call PrintText
+ coord hl, 5, 5
+ ld b, $6
+ ld c, $d
+ call TextBoxBorder
+ call UpdateSprites
+ coord hl, 7, 7
+ ld de, CableClubOptionsText
+ call PlaceString
+ xor a
+ ld [wUnusedCD37], a
+ ld [wd72d], a
+ ld hl, wTopMenuItemY
+ ld a, $7
+ ld [hli], a
+ ld a, $6
+ ld [hli], a
+ xor a
+ ld [hli], a
+ inc hl
+ ld a, $2
+ ld [hli], a
+ inc a
+ ; ld a, A_BUTTON | B_BUTTON
+ ld [hli], a ; wMenuWatchedKeys
+ xor a
+ ld [hl], a
+.waitForInputLoop
+ call HandleMenuInput
+ and A_BUTTON | B_BUTTON
+ add a
+ add a
+ ld b, a
+ ld a, [wCurrentMenuItem]
+ add b
+ add $d0
+ ld [wLinkMenuSelectionSendBuffer], a
+ ld [wLinkMenuSelectionSendBuffer + 1], a
+.exchangeMenuSelectionLoop
+ call Serial_ExchangeLinkMenuSelection
+ ld a, [wLinkMenuSelectionReceiveBuffer]
+ ld b, a
+ and $f0
+ cp $d0
+ jr z, .asm_5c7d
+ ld a, [wLinkMenuSelectionReceiveBuffer + 1]
+ ld b, a
+ and $f0
+ cp $d0
+ jr nz, .exchangeMenuSelectionLoop
+.asm_5c7d
+ ld a, b
+ and $c ; did the enemy press A or B?
+ jr nz, .enemyPressedAOrB
+; the enemy didn't press A or B
+ ld a, [wLinkMenuSelectionSendBuffer]
+ and $c ; did the player press A or B?
+ jr z, .waitForInputLoop ; if neither the player nor the enemy pressed A or B, try again
+ jr .doneChoosingMenuSelection ; if the player pressed A or B but the enemy didn't, use the player's selection
+.enemyPressedAOrB
+ ld a, [wLinkMenuSelectionSendBuffer]
+ and $c ; did the player press A or B?
+ jr z, .useEnemyMenuSelection ; if the enemy pressed A or B but the player didn't, use the enemy's selection
+; the enemy and the player both pressed A or B
+; The gameboy that is clocking the connection wins.
+ ld a, [hSerialConnectionStatus]
+ cp USING_INTERNAL_CLOCK
+ jr z, .doneChoosingMenuSelection
+.useEnemyMenuSelection
+ ld a, b
+ ld [wLinkMenuSelectionSendBuffer], a
+ and $3
+ ld [wCurrentMenuItem], a
+.doneChoosingMenuSelection
+ ld a, [hSerialConnectionStatus]
+ cp USING_INTERNAL_CLOCK
+ jr nz, .skipStartingTransfer
+ call DelayFrame
+ call DelayFrame
+ ld a, START_TRANSFER_INTERNAL_CLOCK
+ ld [rSC], a
+.skipStartingTransfer
+ ld b, $7f
+ ld c, $7f
+ ld d, $ec
+ ld a, [wLinkMenuSelectionSendBuffer]
+ and (B_BUTTON << 2) ; was B button pressed?
+ jr nz, .updateCursorPosition
+; A button was pressed
+ ld a, [wCurrentMenuItem]
+ cp $2
+ jr z, .updateCursorPosition
+ ld c, d
+ ld d, b
+ dec a
+ jr z, .updateCursorPosition
+ ld b, c
+ ld c, d
+.updateCursorPosition
+ ld a, b
+ Coorda 6, 7
+ ld a, c
+ Coorda 6, 9
+ ld a, d
+ Coorda 6, 11
+ ld c, 40
+ call DelayFrames
+ call LoadScreenTilesFromBuffer1
+ ld a, [wLinkMenuSelectionSendBuffer]
+ and (B_BUTTON << 2) ; was B button pressed?
+ jr nz, .choseCancel ; cancel if B pressed
+ ld a, [wCurrentMenuItem]
+ cp $2
+ jr z, .choseCancel
+ xor a
+ ld [wWalkBikeSurfState], a ; start walking
+ ld a, [wCurrentMenuItem]
+ and a
+ ld a, COLOSSEUM
+ jr nz, .next
+ ld a, TRADE_CENTER
+.next
+ ld [wd72d], a
+ ld hl, PleaseWaitText
+ call PrintText
+ ld c, 50
+ call DelayFrames
+ ld hl, wd732
+ res 1, [hl]
+ ld a, [wDefaultMap]
+ ld [wDestinationMap], a
+ call SpecialWarpIn
+ ld c, 20
+ call DelayFrames
+ xor a
+ ld [wMenuJoypadPollCount], a
+ ld [wSerialExchangeNybbleSendData], a
+ inc a ; LINK_STATE_IN_CABLE_CLUB
+ ld [wLinkState], a
+ ld [wEnteringCableClub], a
+ jr SpecialEnterMap
+.choseCancel
+ xor a
+ ld [wMenuJoypadPollCount], a
+ call Delay3
+ call CloseLinkConnection
+ ld hl, LinkCanceledText
+ call PrintText
+ ld hl, wd72e
+ res 6, [hl]
+ ret
+
+WhereWouldYouLikeText:
+ TX_FAR _WhereWouldYouLikeText
+ db "@"
+
+PleaseWaitText:
+ TX_FAR _PleaseWaitText
+ db "@"
+
+LinkCanceledText:
+ TX_FAR _LinkCanceledText
+ db "@"
+
+StartNewGame:
+ ld hl, wd732
+ res 1, [hl]
+ call OakSpeech
+ ld c, 20
+ call DelayFrames
+
+; enter map after using a special warp or loading the game from the main menu
+SpecialEnterMap::
+ xor a
+ ld [hJoyPressed], a
+ ld [hJoyHeld], a
+ ld [hJoy5], a
+ ld [wd72d], a
+ ld hl, wd732
+ set 0, [hl] ; count play time
+ call ResetPlayerSpriteData
+ ld c, 20
+ call DelayFrames
+ ld a, [wEnteringCableClub]
+ and a
+ ret nz
+ jp EnterMap
+
+ContinueText:
+ db "CONTINUE", $4e
+
+NewGameText:
+ db "NEW GAME"
+ next "OPTION@"
+
+CableClubOptionsText:
+ db "TRADE CENTER"
+ next "COLOSSEUM"
+ next "CANCEL@"
+
+DisplayContinueGameInfo:
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ coord hl, 4, 7
+ ld b, 8
+ ld c, 14
+ call TextBoxBorder
+ coord hl, 5, 9
+ ld de, SaveScreenInfoText
+ call PlaceString
+ coord hl, 12, 9
+ ld de, wPlayerName
+ call PlaceString
+ coord hl, 17, 11
+ call PrintNumBadges
+ coord hl, 16, 13
+ call PrintNumOwnedMons
+ coord hl, 13, 15
+ call PrintPlayTime
+ ld a, 1
+ ld [H_AUTOBGTRANSFERENABLED], a
+ ld c, 30
+ jp DelayFrames
+
+PrintSaveScreenText:
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ coord hl, 4, 0
+ ld b, $8
+ ld c, $e
+ call TextBoxBorder
+ call LoadTextBoxTilePatterns
+ call UpdateSprites
+ coord hl, 5, 2
+ ld de, SaveScreenInfoText
+ call PlaceString
+ coord hl, 12, 2
+ ld de, wPlayerName
+ call PlaceString
+ coord hl, 17, 4
+ call PrintNumBadges
+ coord hl, 16, 6
+ call PrintNumOwnedMons
+ coord hl, 13, 8
+ call PrintPlayTime
+ ld a, $1
+ ld [H_AUTOBGTRANSFERENABLED], a
+ ld c, 30
+ jp DelayFrames
+
+PrintNumBadges:
+ push hl
+ ld hl, wObtainedBadges
+ ld b, $1
+ call CountSetBits
+ pop hl
+ ld de, wNumSetBits
+ lb bc, 1, 2
+ jp PrintNumber
+
+PrintNumOwnedMons:
+ push hl
+ ld hl, wPokedexOwned
+ ld b, wPokedexOwnedEnd - wPokedexOwned
+ call CountSetBits
+ pop hl
+ ld de, wNumSetBits
+ lb bc, 1, 3
+ jp PrintNumber
+
+PrintPlayTime:
+ ld de, wPlayTimeHours
+ lb bc, 1, 3
+ call PrintNumber
+ ld [hl], $6d
+ inc hl
+ ld de, wPlayTimeMinutes
+ lb bc, LEADING_ZEROES | 1, 2
+ jp PrintNumber
+
+SaveScreenInfoText:
+ db "PLAYER"
+ next "BADGES "
+ next "#DEX "
+ next "TIME@"
+
+DisplayOptionMenu:
+ coord hl, 0, 0
+ ld b, 3
+ ld c, 18
+ call TextBoxBorder
+ coord hl, 0, 5
+ ld b, 3
+ ld c, 18
+ call TextBoxBorder
+ coord hl, 0, 10
+ ld b, 3
+ ld c, 18
+ call TextBoxBorder
+ coord hl, 1, 1
+ ld de, TextSpeedOptionText
+ call PlaceString
+ coord hl, 1, 6
+ ld de, BattleAnimationOptionText
+ call PlaceString
+ coord hl, 1, 11
+ ld de, BattleStyleOptionText
+ call PlaceString
+ coord hl, 2, 16
+ ld de, OptionMenuCancelText
+ call PlaceString
+ xor a
+ ld [wCurrentMenuItem], a
+ ld [wLastMenuItem], a
+ inc a
+ ld [wLetterPrintingDelayFlags], a
+ ld [wOptionsCancelCursorX], a
+ ld a, 3 ; text speed cursor Y coordinate
+ ld [wTopMenuItemY], a
+ call SetCursorPositionsFromOptions
+ ld a, [wOptionsTextSpeedCursorX] ; text speed cursor X coordinate
+ ld [wTopMenuItemX], a
+ ld a, $01
+ ld [H_AUTOBGTRANSFERENABLED], a ; enable auto background transfer
+ call Delay3
+.loop
+ call PlaceMenuCursor
+ call SetOptionsFromCursorPositions
+.getJoypadStateLoop
+ call JoypadLowSensitivity
+ ld a, [hJoy5]
+ ld b, a
+ and A_BUTTON | B_BUTTON | START | D_RIGHT | D_LEFT | D_UP | D_DOWN ; any key besides select pressed?
+ jr z, .getJoypadStateLoop
+ bit 1, b ; B button pressed?
+ jr nz, .exitMenu
+ bit 3, b ; Start button pressed?
+ jr nz, .exitMenu
+ bit 0, b ; A button pressed?
+ jr z, .checkDirectionKeys
+ ld a, [wTopMenuItemY]
+ cp 16 ; is the cursor on Cancel?
+ jr nz, .loop
+.exitMenu
+ ld a, SFX_PRESS_AB
+ call PlaySound
+ ret
+.eraseOldMenuCursor
+ ld [wTopMenuItemX], a
+ call EraseMenuCursor
+ jp .loop
+.checkDirectionKeys
+ ld a, [wTopMenuItemY]
+ bit 7, b ; Down pressed?
+ jr nz, .downPressed
+ bit 6, b ; Up pressed?
+ jr nz, .upPressed
+ cp 8 ; cursor in Battle Animation section?
+ jr z, .cursorInBattleAnimation
+ cp 13 ; cursor in Battle Style section?
+ jr z, .cursorInBattleStyle
+ cp 16 ; cursor on Cancel?
+ jr z, .loop
+.cursorInTextSpeed
+ bit 5, b ; Left pressed?
+ jp nz, .pressedLeftInTextSpeed
+ jp .pressedRightInTextSpeed
+.downPressed
+ cp 16
+ ld b, -13
+ ld hl, wOptionsTextSpeedCursorX
+ jr z, .updateMenuVariables
+ ld b, 5
+ cp 3
+ inc hl
+ jr z, .updateMenuVariables
+ cp 8
+ inc hl
+ jr z, .updateMenuVariables
+ ld b, 3
+ inc hl
+ jr .updateMenuVariables
+.upPressed
+ cp 8
+ ld b, -5
+ ld hl, wOptionsTextSpeedCursorX
+ jr z, .updateMenuVariables
+ cp 13
+ inc hl
+ jr z, .updateMenuVariables
+ cp 16
+ ld b, -3
+ inc hl
+ jr z, .updateMenuVariables
+ ld b, 13
+ inc hl
+.updateMenuVariables
+ add b
+ ld [wTopMenuItemY], a
+ ld a, [hl]
+ ld [wTopMenuItemX], a
+ call PlaceUnfilledArrowMenuCursor
+ jp .loop
+.cursorInBattleAnimation
+ ld a, [wOptionsBattleAnimCursorX] ; battle animation cursor X coordinate
+ xor $0b ; toggle between 1 and 10
+ ld [wOptionsBattleAnimCursorX], a
+ jp .eraseOldMenuCursor
+.cursorInBattleStyle
+ ld a, [wOptionsBattleStyleCursorX] ; battle style cursor X coordinate
+ xor $0b ; toggle between 1 and 10
+ ld [wOptionsBattleStyleCursorX], a
+ jp .eraseOldMenuCursor
+.pressedLeftInTextSpeed
+ ld a, [wOptionsTextSpeedCursorX] ; text speed cursor X coordinate
+ cp 1
+ jr z, .updateTextSpeedXCoord
+ cp 7
+ jr nz, .fromSlowToMedium
+ sub 6
+ jr .updateTextSpeedXCoord
+.fromSlowToMedium
+ sub 7
+ jr .updateTextSpeedXCoord
+.pressedRightInTextSpeed
+ ld a, [wOptionsTextSpeedCursorX] ; text speed cursor X coordinate
+ cp 14
+ jr z, .updateTextSpeedXCoord
+ cp 7
+ jr nz, .fromFastToMedium
+ add 7
+ jr .updateTextSpeedXCoord
+.fromFastToMedium
+ add 6
+.updateTextSpeedXCoord
+ ld [wOptionsTextSpeedCursorX], a ; text speed cursor X coordinate
+ jp .eraseOldMenuCursor
+
+TextSpeedOptionText:
+ db "TEXT SPEED"
+ next " FAST MEDIUM SLOW@"
+
+BattleAnimationOptionText:
+ db "BATTLE ANIMATION"
+ next " ON OFF@"
+
+BattleStyleOptionText:
+ db "BATTLE STYLE"
+ next " SHIFT SET@"
+
+OptionMenuCancelText:
+ db "CANCEL@"
+
+; sets the options variable according to the current placement of the menu cursors in the options menu
+SetOptionsFromCursorPositions:
+ ld hl, TextSpeedOptionData
+ ld a, [wOptionsTextSpeedCursorX] ; text speed cursor X coordinate
+ ld c, a
+.loop
+ ld a, [hli]
+ cp c
+ jr z, .textSpeedMatchFound
+ inc hl
+ jr .loop
+.textSpeedMatchFound
+ ld a, [hl]
+ ld d, a
+ ld a, [wOptionsBattleAnimCursorX] ; battle animation cursor X coordinate
+ dec a
+ jr z, .battleAnimationOn
+.battleAnimationOff
+ set 7, d
+ jr .checkBattleStyle
+.battleAnimationOn
+ res 7, d
+.checkBattleStyle
+ ld a, [wOptionsBattleStyleCursorX] ; battle style cursor X coordinate
+ dec a
+ jr z, .battleStyleShift
+.battleStyleSet
+ set 6, d
+ jr .storeOptions
+.battleStyleShift
+ res 6, d
+.storeOptions
+ ld a, d
+ ld [wOptions], a
+ ret
+
+; reads the options variable and places menu cursors in the correct positions within the options menu
+SetCursorPositionsFromOptions:
+ ld hl, TextSpeedOptionData + 1
+ ld a, [wOptions]
+ ld c, a
+ and $3f
+ push bc
+ ld de, 2
+ call IsInArray
+ pop bc
+ dec hl
+ ld a, [hl]
+ ld [wOptionsTextSpeedCursorX], a ; text speed cursor X coordinate
+ coord hl, 0, 3
+ call .placeUnfilledRightArrow
+ sla c
+ ld a, 1 ; On
+ jr nc, .storeBattleAnimationCursorX
+ ld a, 10 ; Off
+.storeBattleAnimationCursorX
+ ld [wOptionsBattleAnimCursorX], a ; battle animation cursor X coordinate
+ coord hl, 0, 8
+ call .placeUnfilledRightArrow
+ sla c
+ ld a, 1
+ jr nc, .storeBattleStyleCursorX
+ ld a, 10
+.storeBattleStyleCursorX
+ ld [wOptionsBattleStyleCursorX], a ; battle style cursor X coordinate
+ coord hl, 0, 13
+ call .placeUnfilledRightArrow
+; cursor in front of Cancel
+ coord hl, 0, 16
+ ld a, 1
+.placeUnfilledRightArrow
+ ld e, a
+ ld d, 0
+ add hl, de
+ ld [hl], $ec ; unfilled right arrow menu cursor
+ ret
+
+; table that indicates how the 3 text speed options affect frame delays
+; Format:
+; 00: X coordinate of menu cursor
+; 01: delay after printing a letter (in frames)
+TextSpeedOptionData:
+ db 14,5 ; Slow
+ db 7,3 ; Medium
+ db 1,1 ; Fast
+ db 7 ; default X coordinate (Medium)
+ db $ff ; terminator
+
+CheckForPlayerNameInSRAM:
+; Check if the player name data in SRAM has a string terminator character
+; (indicating that a name may have been saved there) and return whether it does
+; in carry.
+ ld a, SRAM_ENABLE
+ ld [MBC1SRamEnable], a
+ ld a, $1
+ ld [MBC1SRamBankingMode], a
+ ld [MBC1SRamBank], a
+ ld b, NAME_LENGTH
+ ld hl, sPlayerName
+.loop
+ ld a, [hli]
+ cp "@"
+ jr z, .found
+ dec b
+ jr nz, .loop
+; not found
+ xor a
+ ld [MBC1SRamEnable], a
+ ld [MBC1SRamBankingMode], a
+ and a
+ ret
+.found
+ xor a
+ ld [MBC1SRamEnable], a
+ ld [MBC1SRamBankingMode], a
+ scf
+ ret
--- /dev/null
+++ b/engine/menus/naming_screen.asm
@@ -1,0 +1,494 @@
+AskName:
+ call SaveScreenTilesToBuffer1
+ call GetPredefRegisters
+ push hl
+ ld a, [wIsInBattle]
+ dec a
+ coord hl, 0, 0
+ ld b, 4
+ ld c, 11
+ call z, ClearScreenArea ; only if in wild battle
+ ld a, [wcf91]
+ ld [wd11e], a
+ call GetMonName
+ ld hl, DoYouWantToNicknameText
+ call PrintText
+ coord hl, 14, 7
+ lb bc, 8, 15
+ ld a, TWO_OPTION_MENU
+ ld [wTextBoxID], a
+ call DisplayTextBoxID
+ pop hl
+ ld a, [wCurrentMenuItem]
+ and a
+ jr nz, .declinedNickname
+ ld a, [wUpdateSpritesEnabled]
+ push af
+ xor a
+ ld [wUpdateSpritesEnabled], a
+ push hl
+ ld a, NAME_MON_SCREEN
+ ld [wNamingScreenType], a
+ call DisplayNamingScreen
+ ld a, [wIsInBattle]
+ and a
+ jr nz, .inBattle
+ call ReloadMapSpriteTilePatterns
+.inBattle
+ call LoadScreenTilesFromBuffer1
+ pop hl
+ pop af
+ ld [wUpdateSpritesEnabled], a
+ ld a, [wcf4b]
+ cp "@"
+ ret nz
+.declinedNickname
+ ld d, h
+ ld e, l
+ ld hl, wcd6d
+ ld bc, NAME_LENGTH
+ jp CopyData
+
+DoYouWantToNicknameText:
+ TX_FAR _DoYouWantToNicknameText
+ db "@"
+
+DisplayNameRaterScreen::
+ ld hl, wBuffer
+ xor a
+ ld [wUpdateSpritesEnabled], a
+ ld a, NAME_MON_SCREEN
+ ld [wNamingScreenType], a
+ call DisplayNamingScreen
+ call GBPalWhiteOutWithDelay3
+ call RestoreScreenTilesAndReloadTilePatterns
+ call LoadGBPal
+ ld a, [wcf4b]
+ cp "@"
+ jr z, .playerCancelled
+ ld hl, wPartyMonNicks
+ ld bc, NAME_LENGTH
+ ld a, [wWhichPokemon]
+ call AddNTimes
+ ld e, l
+ ld d, h
+ ld hl, wBuffer
+ ld bc, NAME_LENGTH
+ call CopyData
+ and a
+ ret
+.playerCancelled
+ scf
+ ret
+
+DisplayNamingScreen:
+ push hl
+ ld hl, wd730
+ set 6, [hl]
+ call GBPalWhiteOutWithDelay3
+ call ClearScreen
+ call UpdateSprites
+ ld b, SET_PAL_GENERIC
+ call RunPaletteCommand
+ call LoadHpBarAndStatusTilePatterns
+ call LoadEDTile
+ callba LoadMonPartySpriteGfx
+ coord hl, 0, 4
+ ld b, 9
+ ld c, 18
+ call TextBoxBorder
+ call PrintNamingText
+ ld a, 3
+ ld [wTopMenuItemY], a
+ ld a, 1
+ ld [wTopMenuItemX], a
+ ld [wLastMenuItem], a
+ ld [wCurrentMenuItem], a
+ ld a, $ff
+ ld [wMenuWatchedKeys], a
+ ld a, 7
+ ld [wMaxMenuItem], a
+ ld a, "@"
+ ld [wcf4b], a
+ xor a
+ ld hl, wNamingScreenSubmitName
+ ld [hli], a
+ ld [hli], a
+ ld [wAnimCounter], a
+.selectReturnPoint
+ call PrintAlphabet
+ call GBPalNormal
+.ABStartReturnPoint
+ ld a, [wNamingScreenSubmitName]
+ and a
+ jr nz, .submitNickname
+ call PrintNicknameAndUnderscores
+.dPadReturnPoint
+ call PlaceMenuCursor
+.inputLoop
+ ld a, [wCurrentMenuItem]
+ push af
+ callba AnimatePartyMon_ForceSpeed1
+ pop af
+ ld [wCurrentMenuItem], a
+ call JoypadLowSensitivity
+ ld a, [hJoyPressed]
+ and a
+ jr z, .inputLoop
+ ld hl, .namingScreenButtonFunctions
+.checkForPressedButton
+ sla a
+ jr c, .foundPressedButton
+ inc hl
+ inc hl
+ inc hl
+ inc hl
+ jr .checkForPressedButton
+.foundPressedButton
+ ld a, [hli]
+ ld e, a
+ ld a, [hli]
+ ld d, a
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ push de
+ jp hl
+
+.submitNickname
+ pop de
+ ld hl, wcf4b
+ ld bc, NAME_LENGTH
+ call CopyData
+ call GBPalWhiteOutWithDelay3
+ call ClearScreen
+ call ClearSprites
+ call RunDefaultPaletteCommand
+ call GBPalNormal
+ xor a
+ ld [wAnimCounter], a
+ ld hl, wd730
+ res 6, [hl]
+ ld a, [wIsInBattle]
+ and a
+ jp z, LoadTextBoxTilePatterns
+ jpab LoadHudTilePatterns
+
+.namingScreenButtonFunctions
+ dw .dPadReturnPoint
+ dw .pressedDown
+ dw .dPadReturnPoint
+ dw .pressedUp
+ dw .dPadReturnPoint
+ dw .pressedLeft
+ dw .dPadReturnPoint
+ dw .pressedRight
+ dw .ABStartReturnPoint
+ dw .pressedStart
+ dw .selectReturnPoint
+ dw .pressedSelect
+ dw .ABStartReturnPoint
+ dw .pressedB
+ dw .ABStartReturnPoint
+ dw .pressedA
+
+.pressedA_changedCase
+ pop de
+ ld de, .selectReturnPoint
+ push de
+.pressedSelect
+ ld a, [wAlphabetCase]
+ xor $1
+ ld [wAlphabetCase], a
+ ret
+
+.pressedStart
+ ld a, 1
+ ld [wNamingScreenSubmitName], a
+ ret
+
+.pressedA
+ ld a, [wCurrentMenuItem]
+ cp $5 ; "ED" row
+ jr nz, .didNotPressED
+ ld a, [wTopMenuItemX]
+ cp $11 ; "ED" column
+ jr z, .pressedStart
+.didNotPressED
+ ld a, [wCurrentMenuItem]
+ cp $6 ; case switch row
+ jr nz, .didNotPressCaseSwtich
+ ld a, [wTopMenuItemX]
+ cp $1 ; case switch column
+ jr z, .pressedA_changedCase
+.didNotPressCaseSwtich
+ ld hl, wMenuCursorLocation
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ inc hl
+ ld a, [hl]
+ ld [wNamingScreenLetter], a
+ call CalcStringLength
+ ld a, [wNamingScreenLetter]
+ cp $e5
+ ld de, Dakutens
+ jr z, .dakutensAndHandakutens
+ cp $e4
+ ld de, Handakutens
+ jr z, .dakutensAndHandakutens
+ ld a, [wNamingScreenType]
+ cp NAME_MON_SCREEN
+ jr nc, .checkMonNameLength
+ ld a, [wNamingScreenNameLength]
+ cp $7 ; max length of player/rival names
+ jr .checkNameLength
+.checkMonNameLength
+ ld a, [wNamingScreenNameLength]
+ cp $a ; max length of pokemon nicknames
+.checkNameLength
+ jr c, .addLetter
+ ret
+
+.dakutensAndHandakutens
+ push hl
+ call DakutensAndHandakutens
+ pop hl
+ ret nc
+ dec hl
+.addLetter
+ ld a, [wNamingScreenLetter]
+ ld [hli], a
+ ld [hl], "@"
+ ld a, SFX_PRESS_AB
+ call PlaySound
+ ret
+.pressedB
+ ld a, [wNamingScreenNameLength]
+ and a
+ ret z
+ call CalcStringLength
+ dec hl
+ ld [hl], "@"
+ ret
+.pressedRight
+ ld a, [wCurrentMenuItem]
+ cp $6
+ ret z ; can't scroll right on bottom row
+ ld a, [wTopMenuItemX]
+ cp $11 ; max
+ jp z, .wrapToFirstColumn
+ inc a
+ inc a
+ jr .done
+.wrapToFirstColumn
+ ld a, $1
+ jr .done
+.pressedLeft
+ ld a, [wCurrentMenuItem]
+ cp $6
+ ret z ; can't scroll right on bottom row
+ ld a, [wTopMenuItemX]
+ dec a
+ jp z, .wrapToLastColumn
+ dec a
+ jr .done
+.wrapToLastColumn
+ ld a, $11 ; max
+ jr .done
+.pressedUp
+ ld a, [wCurrentMenuItem]
+ dec a
+ ld [wCurrentMenuItem], a
+ and a
+ ret nz
+ ld a, $6 ; wrap to bottom row
+ ld [wCurrentMenuItem], a
+ ld a, $1 ; force left column
+ jr .done
+.pressedDown
+ ld a, [wCurrentMenuItem]
+ inc a
+ ld [wCurrentMenuItem], a
+ cp $7
+ jr nz, .wrapToTopRow
+ ld a, $1
+ ld [wCurrentMenuItem], a
+ jr .done
+.wrapToTopRow
+ cp $6
+ ret nz
+ ld a, $1
+.done
+ ld [wTopMenuItemX], a
+ jp EraseMenuCursor
+
+LoadEDTile:
+ ld de, ED_Tile
+ ld hl, vFont + $700
+ ld bc, (ED_TileEnd - ED_Tile) / $8
+ ; to fix the graphical bug on poor emulators
+ ;lb bc, BANK(ED_Tile), (ED_TileEnd - ED_Tile) / $8
+ jp CopyVideoDataDouble
+
+ED_Tile:
+ INCBIN "gfx/font/ED.1bpp"
+ED_TileEnd:
+
+PrintAlphabet:
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ ld a, [wAlphabetCase]
+ and a
+ ld de, LowerCaseAlphabet
+ jr nz, .lowercase
+ ld de, UpperCaseAlphabet
+.lowercase
+ coord hl, 2, 5
+ lb bc, 5, 9 ; 5 rows, 9 columns
+.outerLoop
+ push bc
+.innerLoop
+ ld a, [de]
+ ld [hli], a
+ inc hl
+ inc de
+ dec c
+ jr nz, .innerLoop
+ ld bc, SCREEN_WIDTH + 2
+ add hl, bc
+ pop bc
+ dec b
+ jr nz, .outerLoop
+ call PlaceString
+ ld a, $1
+ ld [H_AUTOBGTRANSFERENABLED], a
+ jp Delay3
+
+INCLUDE "text/alphabets.asm"
+
+PrintNicknameAndUnderscores:
+ call CalcStringLength
+ ld a, c
+ ld [wNamingScreenNameLength], a
+ coord hl, 10, 2
+ lb bc, 1, 10
+ call ClearScreenArea
+ coord hl, 10, 2
+ ld de, wcf4b
+ call PlaceString
+ coord hl, 10, 3
+ ld a, [wNamingScreenType]
+ cp NAME_MON_SCREEN
+ jr nc, .pokemon1
+ ld b, 7 ; player or rival max name length
+ jr .playerOrRival1
+.pokemon1
+ ld b, 10 ; pokemon max name length
+.playerOrRival1
+ ld a, $76 ; underscore tile id
+.placeUnderscoreLoop
+ ld [hli], a
+ dec b
+ jr nz, .placeUnderscoreLoop
+ ld a, [wNamingScreenType]
+ cp NAME_MON_SCREEN
+ ld a, [wNamingScreenNameLength]
+ jr nc, .pokemon2
+ cp 7 ; player or rival max name length
+ jr .playerOrRival2
+.pokemon2
+ cp 10 ; pokemon max name length
+.playerOrRival2
+ jr nz, .emptySpacesRemaining
+ ; when all spaces are filled, force the cursor onto the ED tile
+ call EraseMenuCursor
+ ld a, $11 ; "ED" x coord
+ ld [wTopMenuItemX], a
+ ld a, $5 ; "ED" y coord
+ ld [wCurrentMenuItem], a
+ ld a, [wNamingScreenType]
+ cp NAME_MON_SCREEN
+ ld a, 9 ; keep the last underscore raised
+ jr nc, .pokemon3
+ ld a, 6 ; keep the last underscore raised
+.pokemon3
+.emptySpacesRemaining
+ ld c, a
+ ld b, $0
+ coord hl, 10, 3
+ add hl, bc
+ ld [hl], $77 ; raised underscore tile id
+ ret
+
+DakutensAndHandakutens:
+ push de
+ call CalcStringLength
+ dec hl
+ ld a, [hl]
+ pop hl
+ ld de, $2
+ call IsInArray
+ ret nc
+ inc hl
+ ld a, [hl]
+ ld [wNamingScreenLetter], a
+ ret
+
+INCLUDE "text/dakutens.asm"
+
+; calculates the length of the string at wcf4b and stores it in c
+CalcStringLength:
+ ld hl, wcf4b
+ ld c, $0
+.loop
+ ld a, [hl]
+ cp "@"
+ ret z
+ inc hl
+ inc c
+ jr .loop
+
+PrintNamingText:
+ coord hl, 0, 1
+ ld a, [wNamingScreenType]
+ ld de, YourTextString
+ and a
+ jr z, .notNickname
+ ld de, RivalsTextString
+ dec a
+ jr z, .notNickname
+ ld a, [wcf91]
+ ld [wMonPartySpriteSpecies], a
+ push af
+ callba WriteMonPartySpriteOAMBySpecies
+ pop af
+ ld [wd11e], a
+ call GetMonName
+ coord hl, 4, 1
+ call PlaceString
+ ld hl, $1
+ add hl, bc
+ ld [hl], $c9
+ coord hl, 1, 3
+ ld de, NicknameTextString
+ jr .placeString
+.notNickname
+ call PlaceString
+ ld l, c
+ ld h, b
+ ld de, NameTextString
+.placeString
+ jp PlaceString
+
+YourTextString:
+ db "YOUR @"
+
+RivalsTextString:
+ db "RIVAL's @"
+
+NameTextString:
+ db "NAME?@"
+
+NicknameTextString:
+ db "NICKNAME?@"
--- /dev/null
+++ b/engine/menus/oaks_pc.asm
@@ -1,0 +1,28 @@
+OpenOaksPC:
+ call SaveScreenTilesToBuffer2
+ ld hl, AccessedOaksPCText
+ call PrintText
+ ld hl, GetDexRatedText
+ call PrintText
+ call YesNoChoice
+ ld a, [wCurrentMenuItem]
+ and a
+ jr nz, .closePC
+ predef DisplayDexRating
+.closePC
+ ld hl, ClosedOaksPCText
+ call PrintText
+ jp LoadScreenTilesFromBuffer2
+
+GetDexRatedText:
+ TX_FAR _GetDexRatedText
+ db "@"
+
+ClosedOaksPCText:
+ TX_FAR _ClosedOaksPCText
+ TX_WAIT
+ db "@"
+
+AccessedOaksPCText:
+ TX_FAR _AccessedOaksPCText
+ db "@"
--- /dev/null
+++ b/engine/menus/party_menu.asm
@@ -1,0 +1,325 @@
+; [wPartyMenuTypeOrMessageID] = menu type / message ID
+; if less than $F0, it is a menu type
+; menu types:
+; 00: normal pokemon menu (e.g. Start menu)
+; 01: use healing item on pokemon menu
+; 02: in-battle switch pokemon menu
+; 03: learn TM/HM menu
+; 04: swap pokemon positions menu
+; 05: use evolution stone on pokemon menu
+; otherwise, it is a message ID
+; f0: poison healed
+; f1: burn healed
+; f2: freeze healed
+; f3: sleep healed
+; f4: paralysis healed
+; f5: HP healed
+; f6: health returned
+; f7: revitalized
+; f8: leveled up
+DrawPartyMenu_::
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call ClearScreen
+ call UpdateSprites
+ callba LoadMonPartySpriteGfxWithLCDDisabled ; load pokemon icon graphics
+
+RedrawPartyMenu_::
+ ld a, [wPartyMenuTypeOrMessageID]
+ cp SWAP_MONS_PARTY_MENU
+ jp z, .printMessage
+ call ErasePartyMenuCursors
+ callba InitPartyMenuBlkPacket
+ coord hl, 3, 0
+ ld de, wPartySpecies
+ xor a
+ ld c, a
+ ld [hPartyMonIndex], a
+ ld [wWhichPartyMenuHPBar], a
+.loop
+ ld a, [de]
+ cp $FF ; reached the terminator?
+ jp z, .afterDrawingMonEntries
+ push bc
+ push de
+ push hl
+ ld a, c
+ push hl
+ ld hl, wPartyMonNicks
+ call GetPartyMonName
+ pop hl
+ call PlaceString ; print the pokemon's name
+ callba WriteMonPartySpriteOAMByPartyIndex ; place the appropriate pokemon icon
+ ld a, [hPartyMonIndex]
+ ld [wWhichPokemon], a
+ inc a
+ ld [hPartyMonIndex], a
+ call LoadMonData
+ pop hl
+ push hl
+ ld a, [wMenuItemToSwap]
+ and a ; is the player swapping pokemon positions?
+ jr z, .skipUnfilledRightArrow
+; if the player is swapping pokemon positions
+ dec a
+ ld b, a
+ ld a, [wWhichPokemon]
+ cp b ; is the player swapping the current pokemon in the list?
+ jr nz, .skipUnfilledRightArrow
+; the player is swapping the current pokemon in the list
+ dec hl
+ dec hl
+ dec hl
+ ld a, "▷" ; unfilled right arrow menu cursor
+ ld [hli], a ; place the cursor
+ inc hl
+ inc hl
+.skipUnfilledRightArrow
+ ld a, [wPartyMenuTypeOrMessageID] ; menu type
+ cp TMHM_PARTY_MENU
+ jr z, .teachMoveMenu
+ cp EVO_STONE_PARTY_MENU
+ jr z, .evolutionStoneMenu
+ push hl
+ ld bc, 14 ; 14 columns to the right
+ add hl, bc
+ ld de, wLoadedMonStatus
+ call PrintStatusCondition
+ pop hl
+ push hl
+ ld bc, SCREEN_WIDTH + 1 ; down 1 row and right 1 column
+ ld a, [hFlags_0xFFF6]
+ set 0, a
+ ld [hFlags_0xFFF6], a
+ add hl, bc
+ predef DrawHP2 ; draw HP bar and prints current / max HP
+ ld a, [hFlags_0xFFF6]
+ res 0, a
+ ld [hFlags_0xFFF6], a
+ call SetPartyMenuHPBarColor ; color the HP bar (on SGB)
+ pop hl
+ jr .printLevel
+.teachMoveMenu
+ push hl
+ predef CanLearnTM ; check if the pokemon can learn the move
+ pop hl
+ ld de, .ableToLearnMoveText
+ ld a, c
+ and a
+ jr nz, .placeMoveLearnabilityString
+ ld de, .notAbleToLearnMoveText
+.placeMoveLearnabilityString
+ ld bc, 20 + 9 ; down 1 row and right 9 columns
+ push hl
+ add hl, bc
+ call PlaceString
+ pop hl
+.printLevel
+ ld bc, 10 ; move 10 columns to the right
+ add hl, bc
+ call PrintLevel
+ pop hl
+ pop de
+ inc de
+ ld bc, 2 * 20
+ add hl, bc
+ pop bc
+ inc c
+ jp .loop
+.ableToLearnMoveText
+ db "ABLE@"
+.notAbleToLearnMoveText
+ db "NOT ABLE@"
+.evolutionStoneMenu
+ push hl
+ ld hl, EvosMovesPointerTable
+ ld b, 0
+ ld a, [wLoadedMonSpecies]
+ dec a
+ add a
+ rl b
+ ld c, a
+ add hl, bc
+ ld de, wEvosMoves
+ ld a, BANK(EvosMovesPointerTable)
+ ld bc, 2
+ call FarCopyData
+ ld hl, wEvosMoves
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, wEvosMoves
+ ld a, BANK(EvosMovesPointerTable)
+ ld bc, wEvosMoves.end - wEvosMoves
+ call FarCopyData
+ ld hl, wEvosMoves
+ ld de, .notAbleToEvolveText
+; loop through the pokemon's evolution entries
+.checkEvolutionsLoop
+ ld a, [hli]
+ and a ; reached terminator?
+ jr z, .placeEvolutionStoneString ; if so, place the "NOT ABLE" string
+ inc hl
+ inc hl
+ cp EV_ITEM
+ jr nz, .checkEvolutionsLoop
+; if it's a stone evolution entry
+ dec hl
+ dec hl
+ ld b, [hl]
+ ld a, [wEvoStoneItemID] ; the stone the player used
+ inc hl
+ inc hl
+ inc hl
+ cp b ; does the player's stone match this evolution entry's stone?
+ jr nz, .checkEvolutionsLoop
+; if it does match
+ ld de, .ableToEvolveText
+.placeEvolutionStoneString
+ ld bc, 20 + 9 ; down 1 row and right 9 columns
+ pop hl
+ push hl
+ add hl, bc
+ call PlaceString
+ pop hl
+ jr .printLevel
+.ableToEvolveText
+ db "ABLE@"
+.notAbleToEvolveText
+ db "NOT ABLE@"
+.afterDrawingMonEntries
+ ld b, SET_PAL_PARTY_MENU
+ call RunPaletteCommand
+.printMessage
+ ld hl, wd730
+ ld a, [hl]
+ push af
+ push hl
+ set 6, [hl] ; turn off letter printing delay
+ ld a, [wPartyMenuTypeOrMessageID] ; message ID
+ cp $F0
+ jr nc, .printItemUseMessage
+ add a
+ ld hl, PartyMenuMessagePointers
+ ld b, 0
+ ld c, a
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call PrintText
+.done
+ pop hl
+ pop af
+ ld [hl], a
+ ld a, 1
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call Delay3
+ jp GBPalNormal
+.printItemUseMessage
+ and $0F
+ ld hl, PartyMenuItemUseMessagePointers
+ add a
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ push hl
+ ld a, [wUsedItemOnWhichPokemon]
+ ld hl, wPartyMonNicks
+ call GetPartyMonName
+ pop hl
+ call PrintText
+ jr .done
+
+PartyMenuItemUseMessagePointers:
+ dw AntidoteText
+ dw BurnHealText
+ dw IceHealText
+ dw AwakeningText
+ dw ParlyzHealText
+ dw PotionText
+ dw FullHealText
+ dw ReviveText
+ dw RareCandyText
+
+PartyMenuMessagePointers:
+ dw PartyMenuNormalText
+ dw PartyMenuItemUseText
+ dw PartyMenuBattleText
+ dw PartyMenuUseTMText
+ dw PartyMenuSwapMonText
+ dw PartyMenuItemUseText
+
+PartyMenuNormalText:
+ TX_FAR _PartyMenuNormalText
+ db "@"
+
+PartyMenuItemUseText:
+ TX_FAR _PartyMenuItemUseText
+ db "@"
+
+PartyMenuBattleText:
+ TX_FAR _PartyMenuBattleText
+ db "@"
+
+PartyMenuUseTMText:
+ TX_FAR _PartyMenuUseTMText
+ db "@"
+
+PartyMenuSwapMonText:
+ TX_FAR _PartyMenuSwapMonText
+ db "@"
+
+PotionText:
+ TX_FAR _PotionText
+ db "@"
+
+AntidoteText:
+ TX_FAR _AntidoteText
+ db "@"
+
+ParlyzHealText:
+ TX_FAR _ParlyzHealText
+ db "@"
+
+BurnHealText:
+ TX_FAR _BurnHealText
+ db "@"
+
+IceHealText:
+ TX_FAR _IceHealText
+ db "@"
+
+AwakeningText:
+ TX_FAR _AwakeningText
+ db "@"
+
+FullHealText:
+ TX_FAR _FullHealText
+ db "@"
+
+ReviveText:
+ TX_FAR _ReviveText
+ db "@"
+
+RareCandyText:
+ TX_FAR _RareCandyText
+ TX_SFX_ITEM_1 ; probably supposed to play SFX_LEVEL_UP but the wrong music bank is loaded
+ TX_BLINK
+ db "@"
+
+SetPartyMenuHPBarColor:
+ ld hl, wPartyMenuHPBarColors
+ ld a, [wWhichPartyMenuHPBar]
+ ld c, a
+ ld b, 0
+ add hl, bc
+ call GetHealthBarColor
+ ld b, UPDATE_PARTY_MENU_BLK_PACKET
+ call RunPaletteCommand
+ ld hl, wWhichPartyMenuHPBar
+ inc [hl]
+ ret
--- /dev/null
+++ b/engine/menus/pc.asm
@@ -1,0 +1,141 @@
+ActivatePC::
+ call SaveScreenTilesToBuffer2
+ ld a, SFX_TURN_ON_PC
+ call PlaySound
+ ld hl, TurnedOnPC1Text
+ call PrintText
+ call WaitForSoundToFinish
+ ld hl, wFlags_0xcd60
+ set 3, [hl]
+ call LoadScreenTilesFromBuffer2
+ call Delay3
+PCMainMenu:
+ callba DisplayPCMainMenu
+ ld hl, wFlags_0xcd60
+ set 5, [hl]
+ call HandleMenuInput
+ bit 1, a ;if player pressed B
+ jp nz, LogOff
+ ld a, [wMaxMenuItem]
+ cp 2
+ jr nz, .next ;if not 2 menu items (not counting log off) (2 occurs before you get the pokedex)
+ ld a, [wCurrentMenuItem]
+ and a
+ jp z, BillsPC ;if current menu item id is 0, it's bills pc
+ cp 1
+ jr z, .playersPC ;if current menu item id is 1, it's players pc
+ jp LogOff ;otherwise, it's 2, and you're logging off
+.next
+ cp 3
+ jr nz, .next2 ;if not 3 menu items (not counting log off) (3 occurs after you get the pokedex, before you beat the pokemon league)
+ ld a, [wCurrentMenuItem]
+ and a
+ jp z, BillsPC ;if current menu item id is 0, it's bills pc
+ cp 1
+ jr z, .playersPC ;if current menu item id is 1, it's players pc
+ cp 2
+ jp z, OaksPC ;if current menu item id is 2, it's oaks pc
+ jp LogOff ;otherwise, it's 3, and you're logging off
+.next2
+ ld a, [wCurrentMenuItem]
+ and a
+ jp z, BillsPC ;if current menu item id is 0, it's bills pc
+ cp 1
+ jr z, .playersPC ;if current menu item id is 1, it's players pc
+ cp 2
+ jp z, OaksPC ;if current menu item id is 2, it's oaks pc
+ cp 3
+ jp z, PKMNLeague ;if current menu item id is 3, it's pkmnleague
+ jp LogOff ;otherwise, it's 4, and you're logging off
+.playersPC
+ ld hl, wFlags_0xcd60
+ res 5, [hl]
+ set 3, [hl]
+ ld a, SFX_ENTER_PC
+ call PlaySound
+ call WaitForSoundToFinish
+ ld hl, AccessedMyPCText
+ call PrintText
+ callba PlayerPC
+ jr ReloadMainMenu
+OaksPC:
+ ld a, SFX_ENTER_PC
+ call PlaySound
+ call WaitForSoundToFinish
+ callba OpenOaksPC
+ jr ReloadMainMenu
+PKMNLeague:
+ ld a, SFX_ENTER_PC
+ call PlaySound
+ call WaitForSoundToFinish
+ callba PKMNLeaguePC
+ jr ReloadMainMenu
+BillsPC:
+ ld a, SFX_ENTER_PC
+ call PlaySound
+ call WaitForSoundToFinish
+ CheckEvent EVENT_MET_BILL
+ jr nz, .billsPC ;if you've met bill, use that bill's instead of someone's
+ ld hl, AccessedSomeonesPCText
+ jr .printText
+.billsPC
+ ld hl, AccessedBillsPCText
+.printText
+ call PrintText
+ callba BillsPC_
+ReloadMainMenu:
+ xor a
+ ld [wDoNotWaitForButtonPressAfterDisplayingText], a
+ call ReloadMapData
+ call UpdateSprites
+ jp PCMainMenu
+LogOff:
+ ld a, SFX_TURN_OFF_PC
+ call PlaySound
+ call WaitForSoundToFinish
+ ld hl, wFlags_0xcd60
+ res 3, [hl]
+ res 5, [hl]
+ ret
+
+TurnedOnPC1Text:
+ TX_FAR _TurnedOnPC1Text
+ db "@"
+
+AccessedBillsPCText:
+ TX_FAR _AccessedBillsPCText
+ db "@"
+
+AccessedSomeonesPCText:
+ TX_FAR _AccessedSomeonesPCText
+ db "@"
+
+AccessedMyPCText:
+ TX_FAR _AccessedMyPCText
+ db "@"
+
+; removes one of the specified item ID [hItemToRemoveID] from bag (if existent)
+RemoveItemByID::
+ ld hl, wBagItems
+ ld a, [hItemToRemoveID]
+ ld b, a
+ xor a
+ ld [hItemToRemoveIndex], a
+.loop
+ ld a, [hli]
+ cp -1 ; reached terminator?
+ ret z
+ cp b
+ jr z, .foundItem
+ inc hl
+ ld a, [hItemToRemoveIndex]
+ inc a
+ ld [hItemToRemoveIndex], a
+ jr .loop
+.foundItem
+ ld a, $1
+ ld [wItemQuantity], a
+ ld a, [hItemToRemoveIndex]
+ ld [wWhichPokemon], a
+ ld hl, wNumBagItems
+ jp RemoveItemFromInventory
--- /dev/null
+++ b/engine/menus/players_pc.asm
@@ -1,0 +1,303 @@
+PlayerPC::
+ ld hl, wd730
+ set 6, [hl]
+ ld a, ITEM_NAME
+ ld [wNameListType], a
+ call SaveScreenTilesToBuffer1
+ xor a
+ ld [wBagSavedMenuItem], a
+ ld [wParentMenuItem], a
+ ld a, [wFlags_0xcd60]
+ bit 3, a ; accessing player's PC through another PC?
+ jr nz, PlayerPCMenu
+; accessing it directly
+ ld a, SFX_TURN_ON_PC
+ call PlaySound
+ ld hl, TurnedOnPC2Text
+ call PrintText
+
+PlayerPCMenu:
+ ld a, [wParentMenuItem]
+ ld [wCurrentMenuItem], a
+ ld hl, wFlags_0xcd60
+ set 5, [hl]
+ call LoadScreenTilesFromBuffer2
+ coord hl, 0, 0
+ ld b, $8
+ ld c, $e
+ call TextBoxBorder
+ call UpdateSprites
+ coord hl, 2, 2
+ ld de, PlayersPCMenuEntries
+ call PlaceString
+ ld hl, wTopMenuItemY
+ ld a, 2
+ ld [hli], a ; wTopMenuItemY
+ dec a
+ ld [hli], a ; wTopMenuItemX
+ inc hl
+ inc hl
+ ld a, 3
+ ld [hli], a ; wMaxMenuItem
+ ld a, A_BUTTON | B_BUTTON
+ ld [hli], a ; wMenuWatchedKeys
+ xor a
+ ld [hl], a
+ ld hl, wListScrollOffset
+ ld [hli], a ; wListScrollOffset
+ ld [hl], a ; wMenuWatchMovingOutOfBounds
+ ld [wPlayerMonNumber], a
+ ld hl, WhatDoYouWantText
+ call PrintText
+ call HandleMenuInput
+ bit 1, a
+ jp nz, ExitPlayerPC
+ call PlaceUnfilledArrowMenuCursor
+ ld a, [wCurrentMenuItem]
+ ld [wParentMenuItem], a
+ and a
+ jp z, PlayerPCWithdraw
+ dec a
+ jp z, PlayerPCDeposit
+ dec a
+ jp z, PlayerPCToss
+
+ExitPlayerPC:
+ ld a, [wFlags_0xcd60]
+ bit 3, a ; accessing player's PC through another PC?
+ jr nz, .next
+; accessing it directly
+ ld a, SFX_TURN_OFF_PC
+ call PlaySound
+ call WaitForSoundToFinish
+.next
+ ld hl, wFlags_0xcd60
+ res 5, [hl]
+ call LoadScreenTilesFromBuffer2
+ xor a
+ ld [wListScrollOffset], a
+ ld [wBagSavedMenuItem], a
+ ld hl, wd730
+ res 6, [hl]
+ xor a
+ ld [wDoNotWaitForButtonPressAfterDisplayingText], a
+ ret
+
+PlayerPCDeposit:
+ xor a
+ ld [wCurrentMenuItem], a
+ ld [wListScrollOffset], a
+ ld a, [wNumBagItems]
+ and a
+ jr nz, .loop
+ ld hl, NothingToDepositText
+ call PrintText
+ jp PlayerPCMenu
+.loop
+ ld hl, WhatToDepositText
+ call PrintText
+ ld hl, wNumBagItems
+ ld a, l
+ ld [wListPointer], a
+ ld a, h
+ ld [wListPointer + 1], a
+ xor a
+ ld [wPrintItemPrices], a
+ ld a, ITEMLISTMENU
+ ld [wListMenuID], a
+ call DisplayListMenuID
+ jp c, PlayerPCMenu
+ call IsKeyItem
+ ld a, 1
+ ld [wItemQuantity], a
+ ld a, [wIsKeyItem]
+ and a
+ jr nz, .next
+; if it's not a key item, there can be more than one of the item
+ ld hl, DepositHowManyText
+ call PrintText
+ call DisplayChooseQuantityMenu
+ cp $ff
+ jp z, .loop
+.next
+ ld hl, wNumBoxItems
+ call AddItemToInventory
+ jr c, .roomAvailable
+ ld hl, NoRoomToStoreText
+ call PrintText
+ jp .loop
+.roomAvailable
+ ld hl, wNumBagItems
+ call RemoveItemFromInventory
+ call WaitForSoundToFinish
+ ld a, SFX_WITHDRAW_DEPOSIT
+ call PlaySound
+ call WaitForSoundToFinish
+ ld hl, ItemWasStoredText
+ call PrintText
+ jp .loop
+
+PlayerPCWithdraw:
+ xor a
+ ld [wCurrentMenuItem], a
+ ld [wListScrollOffset], a
+ ld a, [wNumBoxItems]
+ and a
+ jr nz, .loop
+ ld hl, NothingStoredText
+ call PrintText
+ jp PlayerPCMenu
+.loop
+ ld hl, WhatToWithdrawText
+ call PrintText
+ ld hl, wNumBoxItems
+ ld a, l
+ ld [wListPointer], a
+ ld a, h
+ ld [wListPointer + 1], a
+ xor a
+ ld [wPrintItemPrices], a
+ ld a, ITEMLISTMENU
+ ld [wListMenuID], a
+ call DisplayListMenuID
+ jp c, PlayerPCMenu
+ call IsKeyItem
+ ld a, 1
+ ld [wItemQuantity], a
+ ld a, [wIsKeyItem]
+ and a
+ jr nz, .next
+; if it's not a key item, there can be more than one of the item
+ ld hl, WithdrawHowManyText
+ call PrintText
+ call DisplayChooseQuantityMenu
+ cp $ff
+ jp z, .loop
+.next
+ ld hl, wNumBagItems
+ call AddItemToInventory
+ jr c, .roomAvailable
+ ld hl, CantCarryMoreText
+ call PrintText
+ jp .loop
+.roomAvailable
+ ld hl, wNumBoxItems
+ call RemoveItemFromInventory
+ call WaitForSoundToFinish
+ ld a, SFX_WITHDRAW_DEPOSIT
+ call PlaySound
+ call WaitForSoundToFinish
+ ld hl, WithdrewItemText
+ call PrintText
+ jp .loop
+
+PlayerPCToss:
+ xor a
+ ld [wCurrentMenuItem], a
+ ld [wListScrollOffset], a
+ ld a, [wNumBoxItems]
+ and a
+ jr nz, .loop
+ ld hl, NothingStoredText
+ call PrintText
+ jp PlayerPCMenu
+.loop
+ ld hl, WhatToTossText
+ call PrintText
+ ld hl, wNumBoxItems
+ ld a, l
+ ld [wListPointer], a
+ ld a, h
+ ld [wListPointer + 1], a
+ xor a
+ ld [wPrintItemPrices], a
+ ld a, ITEMLISTMENU
+ ld [wListMenuID], a
+ push hl
+ call DisplayListMenuID
+ pop hl
+ jp c, PlayerPCMenu
+ push hl
+ call IsKeyItem
+ pop hl
+ ld a, 1
+ ld [wItemQuantity], a
+ ld a, [wIsKeyItem]
+ and a
+ jr nz, .next
+ ld a, [wcf91]
+ call IsItemHM
+ jr c, .next
+; if it's not a key item, there can be more than one of the item
+ push hl
+ ld hl, TossHowManyText
+ call PrintText
+ call DisplayChooseQuantityMenu
+ pop hl
+ cp $ff
+ jp z, .loop
+.next
+ call TossItem ; disallows tossing key items
+ jp .loop
+
+PlayersPCMenuEntries:
+ db "WITHDRAW ITEM"
+ next "DEPOSIT ITEM"
+ next "TOSS ITEM"
+ next "LOG OFF@"
+
+TurnedOnPC2Text:
+ TX_FAR _TurnedOnPC2Text
+ db "@"
+
+WhatDoYouWantText:
+ TX_FAR _WhatDoYouWantText
+ db "@"
+
+WhatToDepositText:
+ TX_FAR _WhatToDepositText
+ db "@"
+
+DepositHowManyText:
+ TX_FAR _DepositHowManyText
+ db "@"
+
+ItemWasStoredText:
+ TX_FAR _ItemWasStoredText
+ db "@"
+
+NothingToDepositText:
+ TX_FAR _NothingToDepositText
+ db "@"
+
+NoRoomToStoreText:
+ TX_FAR _NoRoomToStoreText
+ db "@"
+
+WhatToWithdrawText:
+ TX_FAR _WhatToWithdrawText
+ db "@"
+
+WithdrawHowManyText:
+ TX_FAR _WithdrawHowManyText
+ db "@"
+
+WithdrewItemText:
+ TX_FAR _WithdrewItemText
+ db "@"
+
+NothingStoredText:
+ TX_FAR _NothingStoredText
+ db "@"
+
+CantCarryMoreText:
+ TX_FAR _CantCarryMoreText
+ db "@"
+
+WhatToTossText:
+ TX_FAR _WhatToTossText
+ db "@"
+
+TossHowManyText:
+ TX_FAR _TossHowManyText
+ db "@"
--- /dev/null
+++ b/engine/menus/pokedex.asm
@@ -1,0 +1,665 @@
+ShowPokedexMenu:
+ call GBPalWhiteOut
+ call ClearScreen
+ call UpdateSprites
+ ld a, [wListScrollOffset]
+ push af
+ xor a
+ ld [wCurrentMenuItem], a
+ ld [wListScrollOffset], a
+ ld [wLastMenuItem], a
+ inc a
+ ld [wd11e], a
+ ld [hJoy7], a
+.setUpGraphics
+ ld b, SET_PAL_GENERIC
+ call RunPaletteCommand
+ callab LoadPokedexTilePatterns
+.doPokemonListMenu
+ ld hl, wTopMenuItemY
+ ld a, 3
+ ld [hli], a ; top menu item Y
+ xor a
+ ld [hli], a ; top menu item X
+ inc a
+ ld [wMenuWatchMovingOutOfBounds], a
+ inc hl
+ inc hl
+ ld a, 6
+ ld [hli], a ; max menu item ID
+ ld [hl], D_LEFT | D_RIGHT | B_BUTTON | A_BUTTON
+ call HandlePokedexListMenu
+ jr c, .goToSideMenu ; if the player chose a pokemon from the list
+.exitPokedex
+ xor a
+ ld [wMenuWatchMovingOutOfBounds], a
+ ld [wCurrentMenuItem], a
+ ld [wLastMenuItem], a
+ ld [hJoy7], a
+ ld [wWastedByteCD3A], a
+ ld [wOverrideSimulatedJoypadStatesMask], a
+ pop af
+ ld [wListScrollOffset], a
+ call GBPalWhiteOutWithDelay3
+ call RunDefaultPaletteCommand
+ jp ReloadMapData
+.goToSideMenu
+ call HandlePokedexSideMenu
+ dec b
+ jr z, .exitPokedex ; if the player chose Quit
+ dec b
+ jr z, .doPokemonListMenu ; if pokemon not seen or player pressed B button
+ jp .setUpGraphics ; if pokemon data or area was shown
+
+; handles the menu on the lower right in the pokedex screen
+; OUTPUT:
+; b = reason for exiting menu
+; 00: showed pokemon data or area
+; 01: the player chose Quit
+; 02: the pokemon has not been seen yet or the player pressed the B button
+HandlePokedexSideMenu:
+ call PlaceUnfilledArrowMenuCursor
+ ld a, [wCurrentMenuItem]
+ push af
+ ld b, a
+ ld a, [wLastMenuItem]
+ push af
+ ld a, [wListScrollOffset]
+ push af
+ add b
+ inc a
+ ld [wd11e], a
+ ld a, [wd11e]
+ push af
+ ld a, [wDexMaxSeenMon]
+ push af ; this doesn't need to be preserved
+ ld hl, wPokedexSeen
+ call IsPokemonBitSet
+ ld b, 2
+ jr z, .exitSideMenu
+ call PokedexToIndex
+ ld hl, wTopMenuItemY
+ ld a, 10
+ ld [hli], a ; top menu item Y
+ ld a, 15
+ ld [hli], a ; top menu item X
+ xor a
+ ld [hli], a ; current menu item ID
+ inc hl
+ ld a, 3
+ ld [hli], a ; max menu item ID
+ ;ld a, A_BUTTON | B_BUTTON
+ ld [hli], a ; menu watched keys (A button and B button)
+ xor a
+ ld [hli], a ; old menu item ID
+ ld [wMenuWatchMovingOutOfBounds], a
+.handleMenuInput
+ call HandleMenuInput
+ bit 1, a ; was the B button pressed?
+ ld b, 2
+ jr nz, .buttonBPressed
+ ld a, [wCurrentMenuItem]
+ and a
+ jr z, .choseData
+ dec a
+ jr z, .choseCry
+ dec a
+ jr z, .choseArea
+.choseQuit
+ ld b, 1
+.exitSideMenu
+ pop af
+ ld [wDexMaxSeenMon], a
+ pop af
+ ld [wd11e], a
+ pop af
+ ld [wListScrollOffset], a
+ pop af
+ ld [wLastMenuItem], a
+ pop af
+ ld [wCurrentMenuItem], a
+ push bc
+ coord hl, 0, 3
+ ld de, 20
+ lb bc, " ", 13
+ call DrawTileLine ; cover up the menu cursor in the pokemon list
+ pop bc
+ ret
+
+.buttonBPressed
+ push bc
+ coord hl, 15, 10
+ ld de, 20
+ lb bc, " ", 7
+ call DrawTileLine ; cover up the menu cursor in the side menu
+ pop bc
+ jr .exitSideMenu
+
+.choseData
+ call ShowPokedexDataInternal
+ ld b, 0
+ jr .exitSideMenu
+
+; play pokemon cry
+.choseCry
+ ld a, [wd11e]
+ call GetCryData
+ call PlaySound
+ jr .handleMenuInput
+
+.choseArea
+ predef LoadTownMap_Nest ; display pokemon areas
+ ld b, 0
+ jr .exitSideMenu
+
+; handles the list of pokemon on the left of the pokedex screen
+; sets carry flag if player presses A, unsets carry flag if player presses B
+HandlePokedexListMenu:
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a
+; draw the horizontal line separating the seen and owned amounts from the menu
+ coord hl, 15, 8
+ ld a, "─"
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ coord hl, 14, 0
+ ld [hl], $71 ; vertical line tile
+ coord hl, 14, 1
+ call DrawPokedexVerticalLine
+ coord hl, 14, 9
+ call DrawPokedexVerticalLine
+ ld hl, wPokedexSeen
+ ld b, wPokedexSeenEnd - wPokedexSeen
+ call CountSetBits
+ ld de, wNumSetBits
+ coord hl, 16, 3
+ lb bc, 1, 3
+ call PrintNumber ; print number of seen pokemon
+ ld hl, wPokedexOwned
+ ld b, wPokedexOwnedEnd - wPokedexOwned
+ call CountSetBits
+ ld de, wNumSetBits
+ coord hl, 16, 6
+ lb bc, 1, 3
+ call PrintNumber ; print number of owned pokemon
+ coord hl, 16, 2
+ ld de, PokedexSeenText
+ call PlaceString
+ coord hl, 16, 5
+ ld de, PokedexOwnText
+ call PlaceString
+ coord hl, 1, 1
+ ld de, PokedexContentsText
+ call PlaceString
+ coord hl, 16, 10
+ ld de, PokedexMenuItemsText
+ call PlaceString
+; find the highest pokedex number among the pokemon the player has seen
+ ld hl, wPokedexSeenEnd - 1
+ ld b, (wPokedexSeenEnd - wPokedexSeen) * 8 + 1
+.maxSeenPokemonLoop
+ ld a, [hld]
+ ld c, 8
+.maxSeenPokemonInnerLoop
+ dec b
+ sla a
+ jr c, .storeMaxSeenPokemon
+ dec c
+ jr nz, .maxSeenPokemonInnerLoop
+ jr .maxSeenPokemonLoop
+
+.storeMaxSeenPokemon
+ ld a, b
+ ld [wDexMaxSeenMon], a
+.loop
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ coord hl, 4, 2
+ lb bc, 14, 10
+ call ClearScreenArea
+ coord hl, 1, 3
+ ld a, [wListScrollOffset]
+ ld [wd11e], a
+ ld d, 7
+ ld a, [wDexMaxSeenMon]
+ cp 7
+ jr nc, .printPokemonLoop
+ ld d, a
+ dec a
+ ld [wMaxMenuItem], a
+; loop to print pokemon pokedex numbers and names
+; if the player has owned the pokemon, it puts a pokeball beside the name
+.printPokemonLoop
+ ld a, [wd11e]
+ inc a
+ ld [wd11e], a
+ push af
+ push de
+ push hl
+ ld de, -SCREEN_WIDTH
+ add hl, de
+ ld de, wd11e
+ lb bc, LEADING_ZEROES | 1, 3
+ call PrintNumber ; print the pokedex number
+ ld de, SCREEN_WIDTH
+ add hl, de
+ dec hl
+ push hl
+ ld hl, wPokedexOwned
+ call IsPokemonBitSet
+ pop hl
+ ld a, " "
+ jr z, .writeTile
+ ld a, $72 ; pokeball tile
+.writeTile
+ ld [hl], a ; put a pokeball next to pokemon that the player has owned
+ push hl
+ ld hl, wPokedexSeen
+ call IsPokemonBitSet
+ jr nz, .getPokemonName ; if the player has seen the pokemon
+ ld de, .dashedLine ; print a dashed line in place of the name if the player hasn't seen the pokemon
+ jr .skipGettingName
+.dashedLine ; for unseen pokemon in the list
+ db "----------@"
+.getPokemonName
+ call PokedexToIndex
+ call GetMonName
+.skipGettingName
+ pop hl
+ inc hl
+ call PlaceString
+ pop hl
+ ld bc, 2 * SCREEN_WIDTH
+ add hl, bc
+ pop de
+ pop af
+ ld [wd11e], a
+ dec d
+ jr nz, .printPokemonLoop
+ ld a, 01
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call Delay3
+ call GBPalNormal
+ call HandleMenuInput
+ bit 1, a ; was the B button pressed?
+ jp nz, .buttonBPressed
+.checkIfUpPressed
+ bit 6, a ; was Up pressed?
+ jr z, .checkIfDownPressed
+.upPressed ; scroll up one row
+ ld a, [wListScrollOffset]
+ and a
+ jp z, .loop
+ dec a
+ ld [wListScrollOffset], a
+ jp .loop
+.checkIfDownPressed
+ bit 7, a ; was Down pressed?
+ jr z, .checkIfRightPressed
+.downPressed ; scroll down one row
+ ld a, [wDexMaxSeenMon]
+ cp 7
+ jp c, .loop ; can't if the list is shorter than 7
+ sub 7
+ ld b, a
+ ld a, [wListScrollOffset]
+ cp b
+ jp z, .loop
+ inc a
+ ld [wListScrollOffset], a
+ jp .loop
+.checkIfRightPressed
+ bit 4, a ; was Right pressed?
+ jr z, .checkIfLeftPressed
+.rightPressed ; scroll down 7 rows
+ ld a, [wDexMaxSeenMon]
+ cp 7
+ jp c, .loop ; can't if the list is shorter than 7
+ sub 6
+ ld b, a
+ ld a, [wListScrollOffset]
+ add 7
+ ld [wListScrollOffset], a
+ cp b
+ jp c, .loop
+ dec b
+ ld a, b
+ ld [wListScrollOffset], a
+ jp .loop
+.checkIfLeftPressed ; scroll up 7 rows
+ bit 5, a ; was Left pressed?
+ jr z, .buttonAPressed
+.leftPressed
+ ld a, [wListScrollOffset]
+ sub 7
+ ld [wListScrollOffset], a
+ jp nc, .loop
+ xor a
+ ld [wListScrollOffset], a
+ jp .loop
+.buttonAPressed
+ scf
+ ret
+.buttonBPressed
+ and a
+ ret
+
+DrawPokedexVerticalLine:
+ ld c, 9 ; height of line
+ ld de, SCREEN_WIDTH
+ ld a, $71 ; vertical line tile
+.loop
+ ld [hl], a
+ add hl, de
+ xor 1 ; toggle between vertical line tile and box tile
+ dec c
+ jr nz, .loop
+ ret
+
+PokedexSeenText:
+ db "SEEN@"
+
+PokedexOwnText:
+ db "OWN@"
+
+PokedexContentsText:
+ db "CONTENTS@"
+
+PokedexMenuItemsText:
+ db "DATA"
+ next "CRY"
+ next "AREA"
+ next "QUIT@"
+
+; tests if a pokemon's bit is set in the seen or owned pokemon bit fields
+; INPUT:
+; [wd11e] = pokedex number
+; hl = address of bit field
+IsPokemonBitSet:
+ ld a, [wd11e]
+ dec a
+ ld c, a
+ ld b, FLAG_TEST
+ predef FlagActionPredef
+ ld a, c
+ and a
+ ret
+
+; function to display pokedex data from outside the pokedex
+ShowPokedexData:
+ call GBPalWhiteOutWithDelay3
+ call ClearScreen
+ call UpdateSprites
+ callab LoadPokedexTilePatterns ; load pokedex tiles
+
+; function to display pokedex data from inside the pokedex
+ShowPokedexDataInternal:
+ ld hl, wd72c
+ set 1, [hl]
+ ld a, $33 ; 3/7 volume
+ ld [rNR50], a
+ call GBPalWhiteOut ; zero all palettes
+ call ClearScreen
+ ld a, [wd11e] ; pokemon ID
+ ld [wcf91], a
+ push af
+ ld b, SET_PAL_POKEDEX
+ call RunPaletteCommand
+ pop af
+ ld [wd11e], a
+ ld a, [hTilesetType]
+ push af
+ xor a
+ ld [hTilesetType], a
+
+ coord hl, 0, 0
+ ld de, 1
+ lb bc, $64, SCREEN_WIDTH
+ call DrawTileLine ; draw top border
+
+ coord hl, 0, 17
+ ld b, $6f
+ call DrawTileLine ; draw bottom border
+
+ coord hl, 0, 1
+ ld de, 20
+ lb bc, $66, $10
+ call DrawTileLine ; draw left border
+
+ coord hl, 19, 1
+ ld b, $67
+ call DrawTileLine ; draw right border
+
+ ld a, $63 ; upper left corner tile
+ Coorda 0, 0
+ ld a, $65 ; upper right corner tile
+ Coorda 19, 0
+ ld a, $6c ; lower left corner tile
+ Coorda 0, 17
+ ld a, $6e ; lower right corner tile
+ Coorda 19, 17
+
+ coord hl, 0, 9
+ ld de, PokedexDataDividerLine
+ call PlaceString ; draw horizontal divider line
+
+ coord hl, 9, 6
+ ld de, HeightWeightText
+ call PlaceString
+
+ call GetMonName
+ coord hl, 9, 2
+ call PlaceString
+
+ ld hl, PokedexEntryPointers
+ ld a, [wd11e]
+ dec a
+ ld e, a
+ ld d, 0
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld e, a
+ ld d, [hl] ; de = address of pokedex entry
+
+ coord hl, 9, 4
+ call PlaceString ; print species name
+
+ ld h, b
+ ld l, c
+ push de
+ ld a, [wd11e]
+ push af
+ call IndexToPokedex
+
+ coord hl, 2, 8
+ ld a, "№"
+ ld [hli], a
+ ld a, "⠄"
+ ld [hli], a
+ ld de, wd11e
+ lb bc, LEADING_ZEROES | 1, 3
+ call PrintNumber ; print pokedex number
+
+ ld hl, wPokedexOwned
+ call IsPokemonBitSet
+ pop af
+ ld [wd11e], a
+ ld a, [wcf91]
+ ld [wd0b5], a
+ pop de
+
+ push af
+ push bc
+ push de
+ push hl
+
+ call Delay3
+ call GBPalNormal
+ call GetMonHeader ; load pokemon picture location
+ coord hl, 1, 1
+ call LoadFlippedFrontSpriteByMonIndex ; draw pokemon picture
+ ld a, [wcf91]
+ call PlayCry ; play pokemon cry
+
+ pop hl
+ pop de
+ pop bc
+ pop af
+
+ ld a, c
+ and a
+ jp z, .waitForButtonPress ; if the pokemon has not been owned, don't print the height, weight, or description
+ inc de ; de = address of feet (height)
+ ld a, [de] ; reads feet, but a is overwritten without being used
+ coord hl, 12, 6
+ lb bc, 1, 2
+ call PrintNumber ; print feet (height)
+ ld a, $60 ; feet symbol tile (one tick)
+ ld [hl], a
+ inc de
+ inc de ; de = address of inches (height)
+ coord hl, 15, 6
+ lb bc, LEADING_ZEROES | 1, 2
+ call PrintNumber ; print inches (height)
+ ld a, $61 ; inches symbol tile (two ticks)
+ ld [hl], a
+; now print the weight (note that weight is stored in tenths of pounds internally)
+ inc de
+ inc de
+ inc de ; de = address of upper byte of weight
+ push de
+; put weight in big-endian order at hDexWeight
+ ld hl, hDexWeight
+ ld a, [hl] ; save existing value of [hDexWeight]
+ push af
+ ld a, [de] ; a = upper byte of weight
+ ld [hli], a ; store upper byte of weight in [hDexWeight]
+ ld a, [hl] ; save existing value of [hDexWeight + 1]
+ push af
+ dec de
+ ld a, [de] ; a = lower byte of weight
+ ld [hl], a ; store lower byte of weight in [hDexWeight + 1]
+ ld de, hDexWeight
+ coord hl, 11, 8
+ lb bc, 2, 5 ; 2 bytes, 5 digits
+ call PrintNumber ; print weight
+ coord hl, 14, 8
+ ld a, [hDexWeight + 1]
+ sub 10
+ ld a, [hDexWeight]
+ sbc 0
+ jr nc, .next
+ ld [hl], "0" ; if the weight is less than 10, put a 0 before the decimal point
+.next
+ inc hl
+ ld a, [hli]
+ ld [hld], a ; make space for the decimal point by moving the last digit forward one tile
+ ld [hl], "⠄" ; decimal point tile
+ pop af
+ ld [hDexWeight + 1], a ; restore original value of [hDexWeight + 1]
+ pop af
+ ld [hDexWeight], a ; restore original value of [hDexWeight]
+ pop hl
+ inc hl ; hl = address of pokedex description text
+ coord bc, 1, 11
+ ld a, 2
+ ld [$fff4], a
+ call TextCommandProcessor ; print pokedex description text
+ xor a
+ ld [$fff4], a
+.waitForButtonPress
+ call JoypadLowSensitivity
+ ld a, [hJoy5]
+ and A_BUTTON | B_BUTTON
+ jr z, .waitForButtonPress
+ pop af
+ ld [hTilesetType], a
+ call GBPalWhiteOut
+ call ClearScreen
+ call RunDefaultPaletteCommand
+ call LoadTextBoxTilePatterns
+ call GBPalNormal
+ ld hl, wd72c
+ res 1, [hl]
+ ld a, $77 ; max volume
+ ld [rNR50], a
+ ret
+
+HeightWeightText:
+ db "HT ?",$60,"??",$61
+ next "WT ???lb@"
+
+; XXX does anything point to this?
+PokeText:
+ db "#@"
+
+; horizontal line that divides the pokedex text description from the rest of the data
+PokedexDataDividerLine:
+ db $68,$69,$6B,$69,$6B
+ db $69,$6B,$69,$6B,$6B
+ db $6B,$6B,$69,$6B,$69
+ db $6B,$69,$6B,$69,$6A
+ db "@"
+
+; draws a line of tiles
+; INPUT:
+; b = tile ID
+; c = number of tile ID's to write
+; de = amount to destination address after each tile (1 for horizontal, 20 for vertical)
+; hl = destination address
+DrawTileLine:
+ push bc
+ push de
+.loop
+ ld [hl], b
+ add hl, de
+ dec c
+ jr nz, .loop
+ pop de
+ pop bc
+ ret
+
+INCLUDE "data/pokedex_entries.asm"
+
+PokedexToIndex:
+ ; converts the Pokédex number at wd11e to an index
+ push bc
+ push hl
+ ld a, [wd11e]
+ ld b, a
+ ld c, 0
+ ld hl, PokedexOrder
+
+.loop ; go through the list until we find an entry with a matching dex number
+ inc c
+ ld a, [hli]
+ cp b
+ jr nz, .loop
+
+ ld a, c
+ ld [wd11e], a
+ pop hl
+ pop bc
+ ret
+
+IndexToPokedex:
+ ; converts the index number at wd11e to a Pokédex number
+ push bc
+ push hl
+ ld a, [wd11e]
+ dec a
+ ld hl, PokedexOrder
+ ld b, 0
+ ld c, a
+ add hl, bc
+ ld a, [hl]
+ ld [wd11e], a
+ pop hl
+ pop bc
+ ret
+
+INCLUDE "data/pokedex_order.asm"
--- /dev/null
+++ b/engine/menus/save.asm
@@ -1,0 +1,708 @@
+LoadSAV:
+;(if carry -> write
+;"the file data is destroyed")
+ call ClearScreen
+ call LoadFontTilePatterns
+ call LoadTextBoxTilePatterns
+ call LoadSAV0
+ jr c, .badsum
+ call LoadSAV1
+ jr c, .badsum
+ call LoadSAV2
+ jr c, .badsum
+ ld a, $2 ; good checksum
+ jr .goodsum
+.badsum
+ ld hl, wd730
+ push hl
+ set 6, [hl]
+ ld hl, FileDataDestroyedText
+ call PrintText
+ ld c, 100
+ call DelayFrames
+ pop hl
+ res 6, [hl]
+ ld a, $1 ; bad checksum
+.goodsum
+ ld [wSaveFileStatus], a
+ ret
+
+FileDataDestroyedText:
+ TX_FAR _FileDataDestroyedText
+ db "@"
+
+LoadSAV0:
+ ld a, SRAM_ENABLE
+ ld [MBC1SRamEnable], a
+ ld a, $1
+ ld [MBC1SRamBankingMode], a
+ ld [MBC1SRamBank], a
+ ld hl, sPlayerName ; hero name located in SRAM
+ ld bc, sMainDataCheckSum - sPlayerName ; but here checks the full SAV
+ call SAVCheckSum
+ ld c, a
+ ld a, [sMainDataCheckSum] ; SAV's checksum
+ cp c
+ jp z, .checkSumsMatched
+
+; If the computed checksum didn't match the saved on, try again.
+ ld hl, sPlayerName
+ ld bc, sMainDataCheckSum - sPlayerName
+ call SAVCheckSum
+ ld c, a
+ ld a, [sMainDataCheckSum] ; SAV's checksum
+ cp c
+ jp nz, SAVBadCheckSum
+
+.checkSumsMatched
+ ld hl, sPlayerName
+ ld de, wPlayerName
+ ld bc, NAME_LENGTH
+ call CopyData
+ ld hl, sMainData
+ ld de, wMainDataStart
+ ld bc, wMainDataEnd - wMainDataStart
+ call CopyData
+ ld hl, wCurMapTileset
+ set 7, [hl]
+ ld hl, sSpriteData
+ ld de, wSpriteDataStart
+ ld bc, wSpriteDataEnd - wSpriteDataStart
+ call CopyData
+ ld a, [sTilesetType]
+ ld [hTilesetType], a
+ ld hl, sCurBoxData
+ ld de, wBoxDataStart
+ ld bc, wBoxDataEnd - wBoxDataStart
+ call CopyData
+ and a
+ jp SAVGoodChecksum
+
+LoadSAV1:
+ ld a, SRAM_ENABLE
+ ld [MBC1SRamEnable], a
+ ld a, $1
+ ld [MBC1SRamBankingMode], a
+ ld [MBC1SRamBank], a
+ ld hl, sPlayerName ; hero name located in SRAM
+ ld bc, sMainDataCheckSum - sPlayerName ; but here checks the full SAV
+ call SAVCheckSum
+ ld c, a
+ ld a, [sMainDataCheckSum] ; SAV's checksum
+ cp c
+ jr nz, SAVBadCheckSum
+ ld hl, sCurBoxData
+ ld de, wBoxDataStart
+ ld bc, wBoxDataEnd - wBoxDataStart
+ call CopyData
+ and a
+ jp SAVGoodChecksum
+
+LoadSAV2:
+ ld a, SRAM_ENABLE
+ ld [MBC1SRamEnable], a
+ ld a, $1
+ ld [MBC1SRamBankingMode], a
+ ld [MBC1SRamBank], a
+ ld hl, sPlayerName ; hero name located in SRAM
+ ld bc, sMainDataCheckSum - sPlayerName ; but here checks the full SAV
+ call SAVCheckSum
+ ld c, a
+ ld a, [sMainDataCheckSum] ; SAV's checksum
+ cp c
+ jp nz, SAVBadCheckSum
+ ld hl, sPartyData
+ ld de, wPartyDataStart
+ ld bc, wPartyDataEnd - wPartyDataStart
+ call CopyData
+ ld hl, sMainData
+ ld de, wPokedexOwned
+ ld bc, wPokedexSeenEnd - wPokedexOwned
+ call CopyData
+ and a
+ jp SAVGoodChecksum
+
+SAVBadCheckSum:
+ scf
+
+SAVGoodChecksum:
+ ld a, $0
+ ld [MBC1SRamBankingMode], a
+ ld [MBC1SRamEnable], a
+ ret
+
+LoadSAVIgnoreBadCheckSum:
+; unused function that loads save data and ignores bad checksums
+ call LoadSAV0
+ call LoadSAV1
+ jp LoadSAV2
+
+SaveSAV:
+ callba PrintSaveScreenText
+ ld hl, WouldYouLikeToSaveText
+ call SaveSAVConfirm
+ and a ;|0 = Yes|1 = No|
+ ret nz
+ ld a, [wSaveFileStatus]
+ dec a
+ jr z, .save
+ call SAVCheckRandomID
+ jr z, .save
+ ld hl, OlderFileWillBeErasedText
+ call SaveSAVConfirm
+ and a
+ ret nz
+.save
+ call SaveSAVtoSRAM
+ coord hl, 1, 13
+ lb bc, 4, 18
+ call ClearScreenArea
+ coord hl, 1, 14
+ ld de, NowSavingString
+ call PlaceString
+ ld c, 120
+ call DelayFrames
+ ld hl, GameSavedText
+ call PrintText
+ ld a, SFX_SAVE
+ call PlaySoundWaitForCurrent
+ call WaitForSoundToFinish
+ ld c, 30
+ jp DelayFrames
+
+NowSavingString:
+ db "Now saving...@"
+
+SaveSAVConfirm:
+ call PrintText
+ coord hl, 0, 7
+ lb bc, 8, 1
+ ld a, TWO_OPTION_MENU
+ ld [wTextBoxID], a
+ call DisplayTextBoxID ; yes/no menu
+ ld a, [wCurrentMenuItem]
+ ret
+
+WouldYouLikeToSaveText:
+ TX_FAR _WouldYouLikeToSaveText
+ db "@"
+
+GameSavedText:
+ TX_FAR _GameSavedText
+ db "@"
+
+OlderFileWillBeErasedText:
+ TX_FAR _OlderFileWillBeErasedText
+ db "@"
+
+SaveSAVtoSRAM0:
+ ld a, SRAM_ENABLE
+ ld [MBC1SRamEnable], a
+ ld a, $1
+ ld [MBC1SRamBankingMode], a
+ ld [MBC1SRamBank], a
+ ld hl, wPlayerName
+ ld de, sPlayerName
+ ld bc, NAME_LENGTH
+ call CopyData
+ ld hl, wMainDataStart
+ ld de, sMainData
+ ld bc, wMainDataEnd - wMainDataStart
+ call CopyData
+ ld hl, wSpriteDataStart
+ ld de, sSpriteData
+ ld bc, wSpriteDataEnd - wSpriteDataStart
+ call CopyData
+ ld hl, wBoxDataStart
+ ld de, sCurBoxData
+ ld bc, wBoxDataEnd - wBoxDataStart
+ call CopyData
+ ld a, [hTilesetType]
+ ld [sTilesetType], a
+ ld hl, sPlayerName
+ ld bc, sMainDataCheckSum - sPlayerName
+ call SAVCheckSum
+ ld [sMainDataCheckSum], a
+ xor a
+ ld [MBC1SRamBankingMode], a
+ ld [MBC1SRamEnable], a
+ ret
+
+SaveSAVtoSRAM1:
+; stored pokémon
+ ld a, SRAM_ENABLE
+ ld [MBC1SRamEnable], a
+ ld a, $1
+ ld [MBC1SRamBankingMode], a
+ ld [MBC1SRamBank], a
+ ld hl, wBoxDataStart
+ ld de, sCurBoxData
+ ld bc, wBoxDataEnd - wBoxDataStart
+ call CopyData
+ ld hl, sPlayerName
+ ld bc, sMainDataCheckSum - sPlayerName
+ call SAVCheckSum
+ ld [sMainDataCheckSum], a
+ xor a
+ ld [MBC1SRamBankingMode], a
+ ld [MBC1SRamEnable], a
+ ret
+
+SaveSAVtoSRAM2:
+ ld a, SRAM_ENABLE
+ ld [MBC1SRamEnable], a
+ ld a, $1
+ ld [MBC1SRamBankingMode], a
+ ld [MBC1SRamBank], a
+ ld hl, wPartyDataStart
+ ld de, sPartyData
+ ld bc, wPartyDataEnd - wPartyDataStart
+ call CopyData
+ ld hl, wPokedexOwned ; pokédex only
+ ld de, sMainData
+ ld bc, wPokedexSeenEnd - wPokedexOwned
+ call CopyData
+ ld hl, sPlayerName
+ ld bc, sMainDataCheckSum - sPlayerName
+ call SAVCheckSum
+ ld [sMainDataCheckSum], a
+ xor a
+ ld [MBC1SRamBankingMode], a
+ ld [MBC1SRamEnable], a
+ ret
+
+SaveSAVtoSRAM::
+ ld a, $2
+ ld [wSaveFileStatus], a
+ call SaveSAVtoSRAM0
+ call SaveSAVtoSRAM1
+ jp SaveSAVtoSRAM2
+
+SAVCheckSum:
+;Check Sum (result[1 byte] is complemented)
+ ld d, 0
+.loop
+ ld a, [hli]
+ add d
+ ld d, a
+ dec bc
+ ld a, b
+ or c
+ jr nz, .loop
+ ld a, d
+ cpl
+ ret
+
+CalcIndividualBoxCheckSums:
+ ld hl, sBox1 ; sBox7
+ ld de, sBank2IndividualBoxChecksums ; sBank3IndividualBoxChecksums
+ ld b, NUM_BOXES / 2
+.loop
+ push bc
+ push de
+ ld bc, wBoxDataEnd - wBoxDataStart
+ call SAVCheckSum
+ pop de
+ ld [de], a
+ inc de
+ pop bc
+ dec b
+ jr nz, .loop
+ ret
+
+GetBoxSRAMLocation:
+; in: a = box num
+; out: b = box SRAM bank, hl = pointer to start of box
+ ld hl, BoxSRAMPointerTable
+ ld a, [wCurrentBoxNum]
+ and $7f
+ cp NUM_BOXES / 2
+ ld b, 2
+ jr c, .next
+ inc b
+ sub NUM_BOXES / 2
+.next
+ ld e, a
+ ld d, 0
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ret
+
+BoxSRAMPointerTable:
+ dw sBox1 ; sBox7
+ dw sBox2 ; sBox8
+ dw sBox3 ; sBox9
+ dw sBox4 ; sBox10
+ dw sBox5 ; sBox11
+ dw sBox6 ; sBox12
+
+ChangeBox::
+ ld hl, WhenYouChangeBoxText
+ call PrintText
+ call YesNoChoice
+ ld a, [wCurrentMenuItem]
+ and a
+ ret nz ; return if No was chosen
+ ld hl, wCurrentBoxNum
+ bit 7, [hl] ; is it the first time player is changing the box?
+ call z, EmptyAllSRAMBoxes ; if so, empty all boxes in SRAM
+ call DisplayChangeBoxMenu
+ call UpdateSprites
+ ld hl, hFlags_0xFFF6
+ set 1, [hl]
+ call HandleMenuInput
+ ld hl, hFlags_0xFFF6
+ res 1, [hl]
+ bit 1, a ; pressed b
+ ret nz
+ call GetBoxSRAMLocation
+ ld e, l
+ ld d, h
+ ld hl, wBoxDataStart
+ call CopyBoxToOrFromSRAM ; copy old box from WRAM to SRAM
+ ld a, [wCurrentMenuItem]
+ set 7, a
+ ld [wCurrentBoxNum], a
+ call GetBoxSRAMLocation
+ ld de, wBoxDataStart
+ call CopyBoxToOrFromSRAM ; copy new box from SRAM to WRAM
+ ld hl, wMapTextPtr
+ ld de, wChangeBoxSavedMapTextPointer
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hl]
+ ld [de], a
+ call RestoreMapTextPointer
+ call SaveSAVtoSRAM
+ ld hl, wChangeBoxSavedMapTextPointer
+ call SetMapTextPointer
+ ld a, SFX_SAVE
+ call PlaySoundWaitForCurrent
+ call WaitForSoundToFinish
+ ret
+
+WhenYouChangeBoxText:
+ TX_FAR _WhenYouChangeBoxText
+ db "@"
+
+CopyBoxToOrFromSRAM:
+; copy an entire box from hl to de with b as the SRAM bank
+ push hl
+ ld a, SRAM_ENABLE
+ ld [MBC1SRamEnable], a
+ ld a, $1
+ ld [MBC1SRamBankingMode], a
+ ld a, b
+ ld [MBC1SRamBank], a
+ ld bc, wBoxDataEnd - wBoxDataStart
+ call CopyData
+ pop hl
+
+; mark the memory that the box was copied from as am empty box
+ xor a
+ ld [hli], a
+ dec a
+ ld [hl], a
+
+ ld hl, sBox1 ; sBox7
+ ld bc, sBank2AllBoxesChecksum - sBox1
+ call SAVCheckSum
+ ld [sBank2AllBoxesChecksum], a ; sBank3AllBoxesChecksum
+ call CalcIndividualBoxCheckSums
+ xor a
+ ld [MBC1SRamBankingMode], a
+ ld [MBC1SRamEnable], a
+ ret
+
+DisplayChangeBoxMenu:
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ ld a, A_BUTTON | B_BUTTON
+ ld [wMenuWatchedKeys], a
+ ld a, 11
+ ld [wMaxMenuItem], a
+ ld a, 1
+ ld [wTopMenuItemY], a
+ ld a, 12
+ ld [wTopMenuItemX], a
+ xor a
+ ld [wMenuWatchMovingOutOfBounds], a
+ ld a, [wCurrentBoxNum]
+ and $7f
+ ld [wCurrentMenuItem], a
+ ld [wLastMenuItem], a
+ coord hl, 0, 0
+ ld b, 2
+ ld c, 9
+ call TextBoxBorder
+ ld hl, ChooseABoxText
+ call PrintText
+ coord hl, 11, 0
+ ld b, 12
+ ld c, 7
+ call TextBoxBorder
+ ld hl, hFlags_0xFFF6
+ set 2, [hl]
+ ld de, BoxNames
+ coord hl, 13, 1
+ call PlaceString
+ ld hl, hFlags_0xFFF6
+ res 2, [hl]
+ ld a, [wCurrentBoxNum]
+ and $7f
+ cp 9
+ jr c, .singleDigitBoxNum
+ sub 9
+ coord hl, 8, 2
+ ld [hl], "1"
+ add "0"
+ jr .next
+.singleDigitBoxNum
+ add "1"
+.next
+ Coorda 9, 2
+ coord hl, 1, 2
+ ld de, BoxNoText
+ call PlaceString
+ call GetMonCountsForAllBoxes
+ coord hl, 18, 1
+ ld de, wBoxMonCounts
+ ld bc, SCREEN_WIDTH
+ ld a, $c
+.loop
+ push af
+ ld a, [de]
+ and a ; is the box empty?
+ jr z, .skipPlacingPokeball
+ ld [hl], $78 ; place pokeball tile next to box name if box not empty
+.skipPlacingPokeball
+ add hl, bc
+ inc de
+ pop af
+ dec a
+ jr nz, .loop
+ ld a, 1
+ ld [H_AUTOBGTRANSFERENABLED], a
+ ret
+
+ChooseABoxText:
+ TX_FAR _ChooseABoxText
+ db "@"
+
+BoxNames:
+ db "BOX 1"
+ next "BOX 2"
+ next "BOX 3"
+ next "BOX 4"
+ next "BOX 5"
+ next "BOX 6"
+ next "BOX 7"
+ next "BOX 8"
+ next "BOX 9"
+ next "BOX10"
+ next "BOX11"
+ next "BOX12@"
+
+BoxNoText:
+ db "BOX No.@"
+
+EmptyAllSRAMBoxes:
+; marks all boxes in SRAM as empty (initialisation for the first time the
+; player changes the box)
+ ld a, SRAM_ENABLE
+ ld [MBC1SRamEnable], a
+ ld a, $1
+ ld [MBC1SRamBankingMode], a
+ ld a, 2
+ ld [MBC1SRamBank], a
+ call EmptySRAMBoxesInBank
+ ld a, 3
+ ld [MBC1SRamBank], a
+ call EmptySRAMBoxesInBank
+ xor a
+ ld [MBC1SRamBankingMode], a
+ ld [MBC1SRamEnable], a
+ ret
+
+EmptySRAMBoxesInBank:
+; marks every box in the current SRAM bank as empty
+ ld hl, sBox1 ; sBox7
+ call EmptySRAMBox
+ ld hl, sBox2 ; sBox8
+ call EmptySRAMBox
+ ld hl, sBox3 ; sBox9
+ call EmptySRAMBox
+ ld hl, sBox4 ; sBox10
+ call EmptySRAMBox
+ ld hl, sBox5 ; sBox11
+ call EmptySRAMBox
+ ld hl, sBox6 ; sBox12
+ call EmptySRAMBox
+ ld hl, sBox1 ; sBox7
+ ld bc, sBank2AllBoxesChecksum - sBox1
+ call SAVCheckSum
+ ld [sBank2AllBoxesChecksum], a ; sBank3AllBoxesChecksum
+ call CalcIndividualBoxCheckSums
+ ret
+
+EmptySRAMBox:
+ xor a
+ ld [hli], a
+ dec a
+ ld [hl], a
+ ret
+
+GetMonCountsForAllBoxes:
+ ld hl, wBoxMonCounts
+ push hl
+ ld a, SRAM_ENABLE
+ ld [MBC1SRamEnable], a
+ ld a, $1
+ ld [MBC1SRamBankingMode], a
+ ld a, $2
+ ld [MBC1SRamBank], a
+ call GetMonCountsForBoxesInBank
+ ld a, $3
+ ld [MBC1SRamBank], a
+ call GetMonCountsForBoxesInBank
+ xor a
+ ld [MBC1SRamBankingMode], a
+ ld [MBC1SRamEnable], a
+ pop hl
+
+; copy the count for the current box from WRAM
+ ld a, [wCurrentBoxNum]
+ and $7f
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [wNumInBox]
+ ld [hl], a
+
+ ret
+
+GetMonCountsForBoxesInBank:
+ ld a, [sBox1] ; sBox7
+ ld [hli], a
+ ld a, [sBox2] ; sBox8
+ ld [hli], a
+ ld a, [sBox3] ; sBox9
+ ld [hli], a
+ ld a, [sBox4] ; sBox10
+ ld [hli], a
+ ld a, [sBox5] ; sBox11
+ ld [hli], a
+ ld a, [sBox6] ; sBox12
+ ld [hli], a
+ ret
+
+SAVCheckRandomID:
+;checks if Sav file is the same by checking player's name 1st letter ($a598)
+; and the two random numbers generated at game beginning
+;(which are stored at wPlayerID)s
+ ld a, $0a
+ ld [MBC1SRamEnable], a
+ ld a, $01
+ ld [MBC1SRamBankingMode], a
+ ld [MBC1SRamBank], a
+ ld a, [sPlayerName]
+ and a
+ jr z, .next
+ ld hl, sPlayerName
+ ld bc, sMainDataCheckSum - sPlayerName
+ call SAVCheckSum
+ ld c, a
+ ld a, [sMainDataCheckSum]
+ cp c
+ jr nz, .next
+ ld hl, sMainData + (wPlayerID - wMainDataStart) ; player ID
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [wPlayerID]
+ cp l
+ jr nz, .next
+ ld a, [wPlayerID + 1]
+ cp h
+.next
+ ld a, $00
+ ld [MBC1SRamBankingMode], a
+ ld [MBC1SRamEnable], a
+ ret
+
+SaveHallOfFameTeams:
+ ld a, [wNumHoFTeams]
+ dec a
+ cp HOF_TEAM_CAPACITY
+ jr nc, .shiftHOFTeams
+ ld hl, sHallOfFame
+ ld bc, HOF_TEAM
+ call AddNTimes
+ ld e, l
+ ld d, h
+ ld hl, wHallOfFame
+ ld bc, HOF_TEAM
+ jr HallOfFame_Copy
+
+.shiftHOFTeams
+; if the space designated for HOF teams is full, then shift all HOF teams to the next slot, making space for the new HOF team
+; this deletes the last HOF team though
+ ld hl, sHallOfFame + HOF_TEAM
+ ld de, sHallOfFame
+ ld bc, HOF_TEAM * (HOF_TEAM_CAPACITY - 1)
+ call HallOfFame_Copy
+ ld hl, wHallOfFame
+ ld de, sHallOfFame + HOF_TEAM * (HOF_TEAM_CAPACITY - 1)
+ ld bc, HOF_TEAM
+ jr HallOfFame_Copy
+
+LoadHallOfFameTeams:
+ ld hl, sHallOfFame
+ ld bc, HOF_TEAM
+ ld a, [wHoFTeamIndex]
+ call AddNTimes
+ ld de, wHallOfFame
+ ld bc, HOF_TEAM
+ ; fallthrough
+
+HallOfFame_Copy:
+ ld a, SRAM_ENABLE
+ ld [MBC1SRamEnable], a
+ ld a, $1
+ ld [MBC1SRamBankingMode], a
+ xor a
+ ld [MBC1SRamBank], a
+ call CopyData
+ xor a
+ ld [MBC1SRamBankingMode], a
+ ld [MBC1SRamEnable], a
+ ret
+
+ClearSAV:
+ ld a, SRAM_ENABLE
+ ld [MBC1SRamEnable], a
+ ld a, $1
+ ld [MBC1SRamBankingMode], a
+ xor a
+ call PadSRAM_FF
+ ld a, $1
+ call PadSRAM_FF
+ ld a, $2
+ call PadSRAM_FF
+ ld a, $3
+ call PadSRAM_FF
+ xor a
+ ld [MBC1SRamBankingMode], a
+ ld [MBC1SRamEnable], a
+ ret
+
+PadSRAM_FF:
+ ld [MBC1SRamBank], a
+ ld hl, $a000
+ ld bc, $2000
+ ld a, $ff
+ jp FillMemory
--- /dev/null
+++ b/engine/menus/start_sub_menus.asm
@@ -1,0 +1,808 @@
+StartMenu_Pokedex::
+ predef ShowPokedexMenu
+ call LoadScreenTilesFromBuffer2 ; restore saved screen
+ call Delay3
+ call LoadGBPal
+ call UpdateSprites
+ jp RedisplayStartMenu
+
+StartMenu_Pokemon::
+ ld a, [wPartyCount]
+ and a
+ jp z, RedisplayStartMenu
+ xor a
+ ld [wMenuItemToSwap], a
+ ld [wPartyMenuTypeOrMessageID], a
+ ld [wUpdateSpritesEnabled], a
+ call DisplayPartyMenu
+ jr .checkIfPokemonChosen
+.loop
+ xor a
+ ld [wMenuItemToSwap], a
+ ld [wPartyMenuTypeOrMessageID], a
+ call GoBackToPartyMenu
+.checkIfPokemonChosen
+ jr nc, .chosePokemon
+.exitMenu
+ call GBPalWhiteOutWithDelay3
+ call RestoreScreenTilesAndReloadTilePatterns
+ call LoadGBPal
+ jp RedisplayStartMenu
+.chosePokemon
+ call SaveScreenTilesToBuffer1
+ ld a, FIELD_MOVE_MON_MENU
+ ld [wTextBoxID], a
+ call DisplayTextBoxID ; display pokemon menu options
+ ld hl, wFieldMoves
+ lb bc, 2, 12 ; max menu item ID, top menu item Y
+ ld e, 5
+.adjustMenuVariablesLoop
+ dec e
+ jr z, .storeMenuVariables
+ ld a, [hli]
+ and a ; end of field moves?
+ jr z, .storeMenuVariables
+ inc b
+ dec c
+ dec c
+ jr .adjustMenuVariablesLoop
+.storeMenuVariables
+ ld hl, wTopMenuItemY
+ ld a, c
+ ld [hli], a ; top menu item Y
+ ld a, [hFieldMoveMonMenuTopMenuItemX]
+ ld [hli], a ; top menu item X
+ xor a
+ ld [hli], a ; current menu item ID
+ inc hl
+ ld a, b
+ ld [hli], a ; max menu item ID
+ ld a, A_BUTTON | B_BUTTON
+ ld [hli], a ; menu watched keys
+ xor a
+ ld [hl], a
+ call HandleMenuInput
+ push af
+ call LoadScreenTilesFromBuffer1 ; restore saved screen
+ pop af
+ bit 1, a ; was the B button pressed?
+ jp nz, .loop
+; if the B button wasn't pressed
+ ld a, [wMaxMenuItem]
+ ld b, a
+ ld a, [wCurrentMenuItem] ; menu selection
+ cp b
+ jp z, .exitMenu ; if the player chose Cancel
+ dec b
+ cp b
+ jr z, .choseSwitch
+ dec b
+ cp b
+ jp z, .choseStats
+ ld c, a
+ ld b, 0
+ ld hl, wFieldMoves
+ add hl, bc
+ jp .choseOutOfBattleMove
+.choseSwitch
+ ld a, [wPartyCount]
+ cp 2 ; is there more than one pokemon in the party?
+ jp c, StartMenu_Pokemon ; if not, no switching
+ call SwitchPartyMon_InitVarOrSwapData ; init [wMenuItemToSwap]
+ ld a, SWAP_MONS_PARTY_MENU
+ ld [wPartyMenuTypeOrMessageID], a
+ call GoBackToPartyMenu
+ jp .checkIfPokemonChosen
+.choseStats
+ call ClearSprites
+ xor a ; PLAYER_PARTY_DATA
+ ld [wMonDataLocation], a
+ predef StatusScreen
+ predef StatusScreen2
+ call ReloadMapData
+ jp StartMenu_Pokemon
+.choseOutOfBattleMove
+ push hl
+ ld a, [wWhichPokemon]
+ ld hl, wPartyMonNicks
+ call GetPartyMonName
+ pop hl
+ ld a, [hl]
+ dec a
+ add a
+ ld b, 0
+ ld c, a
+ ld hl, .outOfBattleMovePointers
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [wObtainedBadges] ; badges obtained
+ jp hl
+.outOfBattleMovePointers
+ dw .cut
+ dw .fly
+ dw .surf
+ dw .surf
+ dw .strength
+ dw .flash
+ dw .dig
+ dw .teleport
+ dw .softboiled
+.fly
+ bit 2, a ; does the player have the Thunder Badge?
+ jp z, .newBadgeRequired
+ call CheckIfInOutsideMap
+ jr z, .canFly
+ ld a, [wWhichPokemon]
+ ld hl, wPartyMonNicks
+ call GetPartyMonName
+ ld hl, .cannotFlyHereText
+ call PrintText
+ jp .loop
+.canFly
+ call ChooseFlyDestination
+ ld a, [wd732]
+ bit 3, a ; did the player decide to fly?
+ jp nz, .goBackToMap
+ call LoadFontTilePatterns
+ ld hl, wd72e
+ set 1, [hl]
+ jp StartMenu_Pokemon
+.cut
+ bit 1, a ; does the player have the Cascade Badge?
+ jp z, .newBadgeRequired
+ predef UsedCut
+ ld a, [wActionResultOrTookBattleTurn]
+ and a
+ jp z, .loop
+ jp CloseTextDisplay
+.surf
+ bit 4, a ; does the player have the Soul Badge?
+ jp z, .newBadgeRequired
+ callba IsSurfingAllowed
+ ld hl, wd728
+ bit 1, [hl]
+ res 1, [hl]
+ jp z, .loop
+ ld a, SURFBOARD
+ ld [wcf91], a
+ ld [wPseudoItemID], a
+ call UseItem
+ ld a, [wActionResultOrTookBattleTurn]
+ and a
+ jp z, .loop
+ call GBPalWhiteOutWithDelay3
+ jp .goBackToMap
+.strength
+ bit 3, a ; does the player have the Rainbow Badge?
+ jp z, .newBadgeRequired
+ predef PrintStrengthTxt
+ call GBPalWhiteOutWithDelay3
+ jp .goBackToMap
+.flash
+ bit 0, a ; does the player have the Boulder Badge?
+ jp z, .newBadgeRequired
+ xor a
+ ld [wMapPalOffset], a
+ ld hl, .flashLightsAreaText
+ call PrintText
+ call GBPalWhiteOutWithDelay3
+ jp .goBackToMap
+.flashLightsAreaText
+ TX_FAR _FlashLightsAreaText
+ db "@"
+.dig
+ ld a, ESCAPE_ROPE
+ ld [wcf91], a
+ ld [wPseudoItemID], a
+ call UseItem
+ ld a, [wActionResultOrTookBattleTurn]
+ and a
+ jp z, .loop
+ call GBPalWhiteOutWithDelay3
+ jp .goBackToMap
+.teleport
+ call CheckIfInOutsideMap
+ jr z, .canTeleport
+ ld a, [wWhichPokemon]
+ ld hl, wPartyMonNicks
+ call GetPartyMonName
+ ld hl, .cannotUseTeleportNowText
+ call PrintText
+ jp .loop
+.canTeleport
+ ld hl, .warpToLastPokemonCenterText
+ call PrintText
+ ld hl, wd732
+ set 3, [hl]
+ set 6, [hl]
+ ld hl, wd72e
+ set 1, [hl]
+ res 4, [hl]
+ ld c, 60
+ call DelayFrames
+ call GBPalWhiteOutWithDelay3
+ jp .goBackToMap
+.warpToLastPokemonCenterText
+ TX_FAR _WarpToLastPokemonCenterText
+ db "@"
+.cannotUseTeleportNowText
+ TX_FAR _CannotUseTeleportNowText
+ db "@"
+.cannotFlyHereText
+ TX_FAR _CannotFlyHereText
+ db "@"
+.softboiled
+ ld hl, wPartyMon1MaxHP
+ ld a, [wWhichPokemon]
+ ld bc, wPartyMon2 - wPartyMon1
+ call AddNTimes
+ ld a, [hli]
+ ld [H_DIVIDEND], a
+ ld a, [hl]
+ ld [H_DIVIDEND + 1], a
+ ld a, 5
+ ld [H_DIVISOR], a
+ ld b, 2 ; number of bytes
+ call Divide
+ ld bc, wPartyMon1HP - wPartyMon1MaxHP
+ add hl, bc
+ ld a, [hld]
+ ld b, a
+ ld a, [H_QUOTIENT + 3]
+ sub b
+ ld b, [hl]
+ ld a, [H_QUOTIENT + 2]
+ sbc b
+ jp nc, .notHealthyEnough
+ ld a, [wPartyAndBillsPCSavedMenuItem]
+ push af
+ ld a, POTION
+ ld [wcf91], a
+ ld [wPseudoItemID], a
+ call UseItem
+ pop af
+ ld [wPartyAndBillsPCSavedMenuItem], a
+ jp .loop
+.notHealthyEnough ; if current HP is less than 1/5 of max HP
+ ld hl, .notHealthyEnoughText
+ call PrintText
+ jp .loop
+.notHealthyEnoughText
+ TX_FAR _NotHealthyEnoughText
+ db "@"
+.goBackToMap
+ call RestoreScreenTilesAndReloadTilePatterns
+ jp CloseTextDisplay
+.newBadgeRequired
+ ld hl, .newBadgeRequiredText
+ call PrintText
+ jp .loop
+.newBadgeRequiredText
+ TX_FAR _NewBadgeRequiredText
+ db "@"
+
+; writes a blank tile to all possible menu cursor positions on the party menu
+ErasePartyMenuCursors::
+ coord hl, 0, 1
+ ld bc, 2 * 20 ; menu cursor positions are 2 rows apart
+ ld a, 6 ; 6 menu cursor positions
+.loop
+ ld [hl], " "
+ add hl, bc
+ dec a
+ jr nz, .loop
+ ret
+
+ItemMenuLoop:
+ call LoadScreenTilesFromBuffer2DisableBGTransfer ; restore saved screen
+ call RunDefaultPaletteCommand
+
+StartMenu_Item::
+ ld a, [wLinkState]
+ dec a ; is the player in the Colosseum or Trade Centre?
+ jr nz, .notInCableClubRoom
+ ld hl, CannotUseItemsHereText
+ call PrintText
+ jr .exitMenu
+.notInCableClubRoom
+ ld bc, wNumBagItems
+ ld hl, wListPointer
+ ld a, c
+ ld [hli], a
+ ld [hl], b ; store item bag pointer in wListPointer (for DisplayListMenuID)
+ xor a
+ ld [wPrintItemPrices], a
+ ld a, ITEMLISTMENU
+ ld [wListMenuID], a
+ ld a, [wBagSavedMenuItem]
+ ld [wCurrentMenuItem], a
+ call DisplayListMenuID
+ ld a, [wCurrentMenuItem]
+ ld [wBagSavedMenuItem], a
+ jr nc, .choseItem
+.exitMenu
+ call LoadScreenTilesFromBuffer2 ; restore saved screen
+ call LoadTextBoxTilePatterns
+ call UpdateSprites
+ jp RedisplayStartMenu
+.choseItem
+; erase menu cursor (blank each tile in front of an item name)
+ ld a, " "
+ Coorda 5, 4
+ Coorda 5, 6
+ Coorda 5, 8
+ Coorda 5, 10
+ call PlaceUnfilledArrowMenuCursor
+ xor a
+ ld [wMenuItemToSwap], a
+ ld a, [wcf91]
+ cp BICYCLE
+ jp z, .useOrTossItem
+.notBicycle1
+ ld a, USE_TOSS_MENU_TEMPLATE
+ ld [wTextBoxID], a
+ call DisplayTextBoxID
+ ld hl, wTopMenuItemY
+ ld a, 11
+ ld [hli], a ; top menu item Y
+ ld a, 14
+ ld [hli], a ; top menu item X
+ xor a
+ ld [hli], a ; current menu item ID
+ inc hl
+ inc a ; a = 1
+ ld [hli], a ; max menu item ID
+ ld a, A_BUTTON | B_BUTTON
+ ld [hli], a ; menu watched keys
+ xor a
+ ld [hl], a ; old menu item id
+ call HandleMenuInput
+ call PlaceUnfilledArrowMenuCursor
+ bit 1, a ; was the B button pressed?
+ jr z, .useOrTossItem
+ jp ItemMenuLoop
+.useOrTossItem ; if the player made the choice to use or toss the item
+ ld a, [wcf91]
+ ld [wd11e], a
+ call GetItemName
+ call CopyStringToCF4B ; copy name to wcf4b
+ ld a, [wcf91]
+ cp BICYCLE
+ jr nz, .notBicycle2
+ ld a, [wd732]
+ bit 5, a
+ jr z, .useItem_closeMenu
+ ld hl, CannotGetOffHereText
+ call PrintText
+ jp ItemMenuLoop
+.notBicycle2
+ ld a, [wCurrentMenuItem]
+ and a
+ jr nz, .tossItem
+; use item
+ ld [wPseudoItemID], a ; a must be 0 due to above conditional jump
+ ld a, [wcf91]
+ cp HM_01
+ jr nc, .useItem_partyMenu
+ ld hl, UsableItems_CloseMenu
+ ld de, 1
+ call IsInArray
+ jr c, .useItem_closeMenu
+ ld a, [wcf91]
+ ld hl, UsableItems_PartyMenu
+ ld de, 1
+ call IsInArray
+ jr c, .useItem_partyMenu
+ call UseItem
+ jp ItemMenuLoop
+.useItem_closeMenu
+ xor a
+ ld [wPseudoItemID], a
+ call UseItem
+ ld a, [wActionResultOrTookBattleTurn]
+ and a
+ jp z, ItemMenuLoop
+ jp CloseStartMenu
+.useItem_partyMenu
+ ld a, [wUpdateSpritesEnabled]
+ push af
+ call UseItem
+ ld a, [wActionResultOrTookBattleTurn]
+ cp $02
+ jp z, .partyMenuNotDisplayed
+ call GBPalWhiteOutWithDelay3
+ call RestoreScreenTilesAndReloadTilePatterns
+ pop af
+ ld [wUpdateSpritesEnabled], a
+ jp StartMenu_Item
+.partyMenuNotDisplayed
+ pop af
+ ld [wUpdateSpritesEnabled], a
+ jp ItemMenuLoop
+.tossItem
+ call IsKeyItem
+ ld a, [wIsKeyItem]
+ and a
+ jr nz, .skipAskingQuantity
+ ld a, [wcf91]
+ call IsItemHM
+ jr c, .skipAskingQuantity
+ call DisplayChooseQuantityMenu
+ inc a
+ jr z, .tossZeroItems
+.skipAskingQuantity
+ ld hl, wNumBagItems
+ call TossItem
+.tossZeroItems
+ jp ItemMenuLoop
+
+CannotUseItemsHereText:
+ TX_FAR _CannotUseItemsHereText
+ db "@"
+
+CannotGetOffHereText:
+ TX_FAR _CannotGetOffHereText
+ db "@"
+
+INCLUDE "data/party_items.asm"
+
+INCLUDE "data/overworld_items.asm"
+
+StartMenu_TrainerInfo::
+ call GBPalWhiteOut
+ call ClearScreen
+ call UpdateSprites
+ ld a, [hTilesetType]
+ push af
+ xor a
+ ld [hTilesetType], a
+ call DrawTrainerInfo
+ predef DrawBadges ; draw badges
+ ld b, SET_PAL_TRAINER_CARD
+ call RunPaletteCommand
+ call GBPalNormal
+ call WaitForTextScrollButtonPress ; wait for button press
+ call GBPalWhiteOut
+ call LoadFontTilePatterns
+ call LoadScreenTilesFromBuffer2 ; restore saved screen
+ call RunDefaultPaletteCommand
+ call ReloadMapData
+ call LoadGBPal
+ pop af
+ ld [hTilesetType], a
+ jp RedisplayStartMenu
+
+; loads tile patterns and draws everything except for gym leader faces / badges
+DrawTrainerInfo:
+ ld de, RedPicFront
+ lb bc, BANK(RedPicFront), $01
+ predef DisplayPicCenteredOrUpperRight
+ call DisableLCD
+ coord hl, 0, 2
+ ld a, " "
+ call TrainerInfo_DrawVerticalLine
+ coord hl, 1, 2
+ call TrainerInfo_DrawVerticalLine
+ ld hl, vChars2 + $70
+ ld de, vChars2
+ ld bc, $70 * 4
+ call CopyData
+ ld hl, TrainerInfoTextBoxTileGraphics ; trainer info text box tile patterns
+ ld de, vChars2 + $770
+ ld bc, $0080
+ push bc
+ call TrainerInfo_FarCopyData
+ ld hl, BlankLeaderNames
+ ld de, vChars2 + $600
+ ld bc, $0170
+ call TrainerInfo_FarCopyData
+ pop bc
+ ld hl, BadgeNumbersTileGraphics ; badge number tile patterns
+ ld de, vChars1 + $580
+ call TrainerInfo_FarCopyData
+ ld hl, GymLeaderFaceAndBadgeTileGraphics ; gym leader face and badge tile patterns
+ ld de, vChars2 + $200
+ ld bc, $0400
+ ld a, $03
+ call FarCopyData2
+ ld hl, TextBoxGraphics
+ ld de, $00d0
+ add hl, de ; hl = colon tile pattern
+ ld de, vChars1 + $560
+ ld bc, $0010
+ ld a, $04
+ push bc
+ call FarCopyData2
+ pop bc
+ ld hl, TrainerInfoTextBoxTileGraphics + $80 ; background tile pattern
+ ld de, vChars1 + $570
+ call TrainerInfo_FarCopyData
+ call EnableLCD
+ ld hl, wTrainerInfoTextBoxWidthPlus1
+ ld a, 18 + 1
+ ld [hli], a
+ dec a
+ ld [hli], a
+ ld [hl], 1
+ coord hl, 0, 0
+ call TrainerInfo_DrawTextBox
+ ld hl, wTrainerInfoTextBoxWidthPlus1
+ ld a, 16 + 1
+ ld [hli], a
+ dec a
+ ld [hli], a
+ ld [hl], 3
+ coord hl, 1, 10
+ call TrainerInfo_DrawTextBox
+ coord hl, 0, 10
+ ld a, $d7
+ call TrainerInfo_DrawVerticalLine
+ coord hl, 19, 10
+ call TrainerInfo_DrawVerticalLine
+ coord hl, 6, 9
+ ld de, TrainerInfo_BadgesText
+ call PlaceString
+ coord hl, 2, 2
+ ld de, TrainerInfo_NameMoneyTimeText
+ call PlaceString
+ coord hl, 7, 2
+ ld de, wPlayerName
+ call PlaceString
+ coord hl, 8, 4
+ ld de, wPlayerMoney
+ ld c, $e3
+ call PrintBCDNumber
+ coord hl, 9, 6
+ ld de, wPlayTimeHours ; hours
+ lb bc, LEFT_ALIGN | 1, 3
+ call PrintNumber
+ ld [hl], $d6 ; colon tile ID
+ inc hl
+ ld de, wPlayTimeMinutes ; minutes
+ lb bc, LEADING_ZEROES | 1, 2
+ jp PrintNumber
+
+TrainerInfo_FarCopyData:
+ ld a, BANK(TrainerInfoTextBoxTileGraphics)
+ jp FarCopyData2
+
+TrainerInfo_NameMoneyTimeText:
+ db "NAME/"
+ next "MONEY/"
+ next "TIME/@"
+
+; $76 is a circle tile
+TrainerInfo_BadgesText:
+ db $76,"BADGES",$76,"@"
+
+; draws a text box on the trainer info screen
+; height is always 6
+; INPUT:
+; hl = destination address
+; [wTrainerInfoTextBoxWidthPlus1] = width
+; [wTrainerInfoTextBoxWidth] = width - 1
+; [wTrainerInfoTextBoxNextRowOffset] = distance from the end of a text box row to the start of the next
+TrainerInfo_DrawTextBox:
+ ld a, $79 ; upper left corner tile ID
+ lb de, $7a, $7b ; top edge and upper right corner tile ID's
+ call TrainerInfo_DrawHorizontalEdge ; draw top edge
+ call TrainerInfo_NextTextBoxRow
+ ld a, [wTrainerInfoTextBoxWidthPlus1]
+ ld e, a
+ ld d, 0
+ ld c, 6 ; height of the text box
+.loop
+ ld [hl], $7c ; left edge tile ID
+ add hl, de
+ ld [hl], $78 ; right edge tile ID
+ call TrainerInfo_NextTextBoxRow
+ dec c
+ jr nz, .loop
+ ld a, $7d ; lower left corner tile ID
+ lb de, $77, $7e ; bottom edge and lower right corner tile ID's
+
+TrainerInfo_DrawHorizontalEdge:
+ ld [hli], a ; place left corner tile
+ ld a, [wTrainerInfoTextBoxWidth]
+ ld c, a
+ ld a, d
+.loop
+ ld [hli], a ; place edge tile
+ dec c
+ jr nz, .loop
+ ld a, e
+ ld [hl], a ; place right corner tile
+ ret
+
+TrainerInfo_NextTextBoxRow:
+ ld a, [wTrainerInfoTextBoxNextRowOffset] ; distance to the start of the next row
+.loop
+ inc hl
+ dec a
+ jr nz, .loop
+ ret
+
+; draws a vertical line
+; INPUT:
+; hl = address of top tile in the line
+; a = tile ID
+TrainerInfo_DrawVerticalLine:
+ ld de, SCREEN_WIDTH
+ ld c, 8
+.loop
+ ld [hl], a
+ add hl, de
+ dec c
+ jr nz, .loop
+ ret
+
+StartMenu_SaveReset::
+ ld a, [wd72e]
+ bit 6, a ; is the player using the link feature?
+ jp nz, Init
+ predef SaveSAV ; save the game
+ call LoadScreenTilesFromBuffer2 ; restore saved screen
+ jp HoldTextDisplayOpen
+
+StartMenu_Option::
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call ClearScreen
+ call UpdateSprites
+ callab DisplayOptionMenu
+ call LoadScreenTilesFromBuffer2 ; restore saved screen
+ call LoadTextBoxTilePatterns
+ call UpdateSprites
+ jp RedisplayStartMenu
+
+SwitchPartyMon::
+ call SwitchPartyMon_InitVarOrSwapData ; swap data
+ ld a, [wSwappedMenuItem]
+ call SwitchPartyMon_ClearGfx
+ ld a, [wCurrentMenuItem]
+ call SwitchPartyMon_ClearGfx
+ jp RedrawPartyMenu_
+
+SwitchPartyMon_ClearGfx:
+ push af
+ coord hl, 0, 0
+ ld bc, SCREEN_WIDTH * 2
+ call AddNTimes
+ ld c, SCREEN_WIDTH * 2
+ ld a, " "
+.clearMonBGLoop ; clear the mon's row in the party menu
+ ld [hli], a
+ dec c
+ jr nz, .clearMonBGLoop
+ pop af
+ ld hl, wOAMBuffer
+ ld bc, $10
+ call AddNTimes
+ ld de, $4
+ ld c, e
+.clearMonOAMLoop
+ ld [hl], $a0
+ add hl, de
+ dec c
+ jr nz, .clearMonOAMLoop
+ call WaitForSoundToFinish
+ ld a, SFX_SWAP
+ jp PlaySound
+
+SwitchPartyMon_InitVarOrSwapData:
+; This is used to initialise [wMenuItemToSwap] and to actually swap the data.
+ ld a, [wMenuItemToSwap]
+ and a ; has [wMenuItemToSwap] been initialised yet?
+ jr nz, .pickedMonsToSwap
+; If not, initialise [wMenuItemToSwap] so that it matches the current mon.
+ ld a, [wWhichPokemon]
+ inc a ; [wMenuItemToSwap] counts from 1
+ ld [wMenuItemToSwap], a
+ ret
+.pickedMonsToSwap
+ xor a
+ ld [wPartyMenuTypeOrMessageID], a
+ ld a, [wMenuItemToSwap]
+ dec a
+ ld b, a
+ ld a, [wCurrentMenuItem]
+ ld [wSwappedMenuItem], a
+ cp b ; swapping a mon with itself?
+ jr nz, .swappingDifferentMons
+; can't swap a mon with itself
+ xor a
+ ld [wMenuItemToSwap], a
+ ld [wPartyMenuTypeOrMessageID], a
+ ret
+.swappingDifferentMons
+ ld a, b
+ ld [wMenuItemToSwap], a
+ push hl
+ push de
+ ld hl, wPartySpecies
+ ld d, h
+ ld e, l
+ ld a, [wCurrentMenuItem]
+ add l
+ ld l, a
+ jr nc, .noCarry
+ inc h
+.noCarry
+ ld a, [wMenuItemToSwap]
+ add e
+ ld e, a
+ jr nc, .noCarry2
+ inc d
+.noCarry2
+ ld a, [hl]
+ ld [hSwapTemp], a
+ ld a, [de]
+ ld [hl], a
+ ld a, [hSwapTemp]
+ ld [de], a
+ ld hl, wPartyMons
+ ld bc, wPartyMon2 - wPartyMon1
+ ld a, [wCurrentMenuItem]
+ call AddNTimes
+ push hl
+ ld de, wSwitchPartyMonTempBuffer
+ ld bc, wPartyMon2 - wPartyMon1
+ call CopyData
+ ld hl, wPartyMons
+ ld bc, wPartyMon2 - wPartyMon1
+ ld a, [wMenuItemToSwap]
+ call AddNTimes
+ pop de
+ push hl
+ ld bc, wPartyMon2 - wPartyMon1
+ call CopyData
+ pop de
+ ld hl, wSwitchPartyMonTempBuffer
+ ld bc, wPartyMon2 - wPartyMon1
+ call CopyData
+ ld hl, wPartyMonOT
+ ld a, [wCurrentMenuItem]
+ call SkipFixedLengthTextEntries
+ push hl
+ ld de, wSwitchPartyMonTempBuffer
+ ld bc, NAME_LENGTH
+ call CopyData
+ ld hl, wPartyMonOT
+ ld a, [wMenuItemToSwap]
+ call SkipFixedLengthTextEntries
+ pop de
+ push hl
+ ld bc, NAME_LENGTH
+ call CopyData
+ pop de
+ ld hl, wSwitchPartyMonTempBuffer
+ ld bc, NAME_LENGTH
+ call CopyData
+ ld hl, wPartyMonNicks
+ ld a, [wCurrentMenuItem]
+ call SkipFixedLengthTextEntries
+ push hl
+ ld de, wSwitchPartyMonTempBuffer
+ ld bc, NAME_LENGTH
+ call CopyData
+ ld hl, wPartyMonNicks
+ ld a, [wMenuItemToSwap]
+ call SkipFixedLengthTextEntries
+ pop de
+ push hl
+ ld bc, NAME_LENGTH
+ call CopyData
+ pop de
+ ld hl, wSwitchPartyMonTempBuffer
+ ld bc, NAME_LENGTH
+ call CopyData
+ ld a, [wMenuItemToSwap]
+ ld [wSwappedMenuItem], a
+ xor a
+ ld [wMenuItemToSwap], a
+ ld [wPartyMenuTypeOrMessageID], a
+ pop de
+ pop hl
+ ret
--- /dev/null
+++ b/engine/menus/swap_items.asm
@@ -1,0 +1,149 @@
+HandleItemListSwapping::
+ ld a, [wListMenuID]
+ cp ITEMLISTMENU
+ jp nz, DisplayListMenuIDLoop ; only rearrange item list menus
+ push hl
+ ld hl, wListPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ inc hl ; hl = beginning of list entries
+ ld a, [wCurrentMenuItem]
+ ld b, a
+ ld a, [wListScrollOffset]
+ add b
+ add a
+ ld c, a
+ ld b, 0
+ add hl, bc ; hl = address of currently selected item entry
+ ld a, [hl]
+ pop hl
+ inc a
+ jp z, DisplayListMenuIDLoop ; ignore attempts to swap the Cancel menu item
+ ld a, [wMenuItemToSwap] ; ID of item chosen for swapping (counts from 1)
+ and a ; has the first item to swap already been chosen?
+ jr nz, .swapItems
+; if not, set the currently selected item as the first item
+ ld a, [wCurrentMenuItem]
+ inc a
+ ld b, a
+ ld a, [wListScrollOffset] ; index of top (visible) menu item within the list
+ add b
+ ld [wMenuItemToSwap], a ; ID of item chosen for swapping (counts from 1)
+ ld c, 20
+ call DelayFrames
+ jp DisplayListMenuIDLoop
+.swapItems
+ ld a, [wCurrentMenuItem]
+ inc a
+ ld b, a
+ ld a, [wListScrollOffset]
+ add b
+ ld b, a
+ ld a, [wMenuItemToSwap] ; ID of item chosen for swapping (counts from 1)
+ cp b ; is the currently selected item the same as the first item to swap?
+ jp z, DisplayListMenuIDLoop ; ignore attempts to swap an item with itself
+ dec a
+ ld [wMenuItemToSwap], a ; ID of item chosen for swapping (counts from 1)
+ ld c, 20
+ call DelayFrames
+ push hl
+ push de
+ ld hl, wListPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ inc hl ; hl = beginning of list entries
+ ld d, h
+ ld e, l ; de = beginning of list entries
+ ld a, [wCurrentMenuItem]
+ ld b, a
+ ld a, [wListScrollOffset]
+ add b
+ add a
+ ld c, a
+ ld b, 0
+ add hl, bc ; hl = address of currently selected item entry
+ ld a, [wMenuItemToSwap] ; ID of item chosen for swapping (counts from 1)
+ add a
+ add e
+ ld e, a
+ jr nc, .noCarry
+ inc d
+.noCarry ; de = address of first item to swap
+ ld a, [de]
+ ld b, a
+ ld a, [hli]
+ cp b
+ jr z, .swapSameItemType
+.swapDifferentItems
+ ld [$ff95], a ; [$ff95] = second item ID
+ ld a, [hld]
+ ld [$ff96], a ; [$ff96] = second item quantity
+ ld a, [de]
+ ld [hli], a ; put first item ID in second item slot
+ inc de
+ ld a, [de]
+ ld [hl], a ; put first item quantity in second item slot
+ ld a, [$ff96]
+ ld [de], a ; put second item quantity in first item slot
+ dec de
+ ld a, [$ff95]
+ ld [de], a ; put second item ID in first item slot
+ xor a
+ ld [wMenuItemToSwap], a ; 0 means no item is currently being swapped
+ pop de
+ pop hl
+ jp DisplayListMenuIDLoop
+.swapSameItemType
+ inc de
+ ld a, [hl]
+ ld b, a
+ ld a, [de]
+ add b ; a = sum of both item quantities
+ cp 100 ; is the sum too big for one item slot?
+ jr c, .combineItemSlots
+; swap enough items from the first slot to max out the second slot if they can't be combined
+ sub 99
+ ld [de], a
+ ld a, 99
+ ld [hl], a
+ jr .done
+.combineItemSlots
+ ld [hl], a ; put the sum in the second item slot
+ ld hl, wListPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ dec [hl] ; decrease the number of items
+ ld a, [hl]
+ ld [wListCount], a ; update number of items variable
+ cp 1
+ jr nz, .skipSettingMaxMenuItemID
+ ld [wMaxMenuItem], a ; if the number of items is only one now, update the max menu item ID
+.skipSettingMaxMenuItemID
+ dec de
+ ld h, d
+ ld l, e
+ inc hl
+ inc hl ; hl = address of item after first item to swap
+.moveItemsUpLoop ; erase the first item slot and move up all the following item slots to fill the gap
+ ld a, [hli]
+ ld [de], a
+ inc de
+ inc a ; reached the $ff terminator?
+ jr z, .afterMovingItemsUp
+ ld a, [hli]
+ ld [de], a
+ inc de
+ jr .moveItemsUpLoop
+.afterMovingItemsUp
+ xor a
+ ld [wListScrollOffset], a
+ ld [wCurrentMenuItem], a
+.done
+ xor a
+ ld [wMenuItemToSwap], a ; 0 means no item is currently being swapped
+ pop de
+ pop hl
+ jp DisplayListMenuIDLoop
--- /dev/null
+++ b/engine/menus/text_box.asm
@@ -1,0 +1,767 @@
+; function to draw various text boxes
+DisplayTextBoxID_::
+ ld a, [wTextBoxID]
+ cp TWO_OPTION_MENU
+ jp z, DisplayTwoOptionMenu
+ ld c, a
+ ld hl, TextBoxFunctionTable
+ ld de, 3
+ call SearchTextBoxTable
+ jr c, .functionTableMatch
+ ld hl, TextBoxCoordTable
+ ld de, 5
+ call SearchTextBoxTable
+ jr c, .coordTableMatch
+ ld hl, TextBoxTextAndCoordTable
+ ld de, 9
+ call SearchTextBoxTable
+ jr c, .textAndCoordTableMatch
+.done
+ ret
+.functionTableMatch
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a ; hl = address of function
+ ld de, .done
+ push de
+ jp hl ; jump to the function
+.coordTableMatch
+ call GetTextBoxIDCoords
+ call GetAddressOfScreenCoords
+ call TextBoxBorder
+ ret
+.textAndCoordTableMatch
+ call GetTextBoxIDCoords
+ push hl
+ call GetAddressOfScreenCoords
+ call TextBoxBorder
+ pop hl
+ call GetTextBoxIDText
+ ld a, [wd730]
+ push af
+ ld a, [wd730]
+ set 6, a ; no pauses between printing each letter
+ ld [wd730], a
+ call PlaceString
+ pop af
+ ld [wd730], a
+ call UpdateSprites
+ ret
+
+; function to search a table terminated with $ff for a byte matching c in increments of de
+; sets carry flag if a match is found and clears carry flag if not
+SearchTextBoxTable:
+ dec de
+.loop
+ ld a, [hli]
+ cp $ff
+ jr z, .notFound
+ cp c
+ jr z, .found
+ add hl, de
+ jr .loop
+.found
+ scf
+.notFound
+ ret
+
+; function to load coordinates from the TextBoxCoordTable or the TextBoxTextAndCoordTable
+; INPUT:
+; hl = address of coordinates
+; OUTPUT:
+; b = height
+; c = width
+; d = row of upper left corner
+; e = column of upper left corner
+GetTextBoxIDCoords:
+ ld a, [hli] ; column of upper left corner
+ ld e, a
+ ld a, [hli] ; row of upper left corner
+ ld d, a
+ ld a, [hli] ; column of lower right corner
+ sub e
+ dec a
+ ld c, a ; c = width
+ ld a, [hli] ; row of lower right corner
+ sub d
+ dec a
+ ld b, a ; b = height
+ ret
+
+; function to load a text address and text coordinates from the TextBoxTextAndCoordTable
+GetTextBoxIDText:
+ ld a, [hli]
+ ld e, a
+ ld a, [hli]
+ ld d, a ; de = address of text
+ push de ; save text address
+ ld a, [hli]
+ ld e, a ; column of upper left corner of text
+ ld a, [hl]
+ ld d, a ; row of upper left corner of text
+ call GetAddressOfScreenCoords
+ pop de ; restore text address
+ ret
+
+; function to point hl to the screen coordinates
+; INPUT:
+; d = row
+; e = column
+; OUTPUT:
+; hl = address of upper left corner of text box
+GetAddressOfScreenCoords:
+ push bc
+ coord hl, 0, 0
+ ld bc, 20
+.loop ; loop to add d rows to the base address
+ ld a, d
+ and a
+ jr z, .addedRows
+ add hl, bc
+ dec d
+ jr .loop
+.addedRows
+ pop bc
+ add hl, de
+ ret
+
+; Format:
+; 00: text box ID
+; 01-02: function address
+TextBoxFunctionTable:
+ dbw MONEY_BOX, DisplayMoneyBox
+ dbw BUY_SELL_QUIT_MENU, DoBuySellQuitMenu
+ dbw FIELD_MOVE_MON_MENU, DisplayFieldMoveMonMenu
+ db $ff ; terminator
+
+; Format:
+; 00: text box ID
+; 01: column of upper left corner
+; 02: row of upper left corner
+; 03: column of lower right corner
+; 04: row of lower right corner
+TextBoxCoordTable:
+ db MESSAGE_BOX, 0, 12, 19, 17
+ db $03, 0, 0, 19, 14
+ db $07, 0, 0, 11, 6
+ db LIST_MENU_BOX, 4, 2, 19, 12
+ db $10, 7, 0, 19, 17
+ db MON_SPRITE_POPUP, 6, 4, 14, 13
+ db $ff ; terminator
+
+; Format:
+; 00: text box ID
+; 01: column of upper left corner
+; 02: row of upper left corner
+; 03: column of lower right corner
+; 04: row of lower right corner
+; 05-06: address of text
+; 07: column of beginning of text
+; 08: row of beginning of text
+; table of window positions and corresponding text [key, start column, start row, end column, end row, text pointer [2 bytes], text column, text row]
+TextBoxTextAndCoordTable:
+ db JP_MOCHIMONO_MENU_TEMPLATE
+ db 0,0,14,17 ; text box coordinates
+ dw JapaneseMochimonoText
+ db 3,0 ; text coordinates
+
+ db USE_TOSS_MENU_TEMPLATE
+ db 13,10,19,14 ; text box coordinates
+ dw UseTossText
+ db 15,11 ; text coordinates
+
+ db JP_SAVE_MESSAGE_MENU_TEMPLATE
+ db 0,0,7,5 ; text box coordinates
+ dw JapaneseSaveMessageText
+ db 2,2 ; text coordinates
+
+ db JP_SPEED_OPTIONS_MENU_TEMPLATE
+ db 0,6,5,10 ; text box coordinates
+ dw JapaneseSpeedOptionsText
+ db 2,7 ; text coordinates
+
+ db BATTLE_MENU_TEMPLATE
+ db 8,12,19,17 ; text box coordinates
+ dw BattleMenuText
+ db 10,14 ; text coordinates
+
+ db SAFARI_BATTLE_MENU_TEMPLATE
+ db 0,12,19,17 ; text box coordinates
+ dw SafariZoneBattleMenuText
+ db 2,14 ; text coordinates
+
+ db SWITCH_STATS_CANCEL_MENU_TEMPLATE
+ db 11,11,19,17 ; text box coordinates
+ dw SwitchStatsCancelText
+ db 13,12 ; text coordinates
+
+ db BUY_SELL_QUIT_MENU_TEMPLATE
+ db 0,0,10,6 ; text box coordinates
+ dw BuySellQuitText
+ db 2,1 ; text coordinates
+
+ db MONEY_BOX_TEMPLATE
+ db 11,0,19,2 ; text box coordinates
+ dw MoneyText
+ db 13,0 ; text coordinates
+
+ db JP_AH_MENU_TEMPLATE
+ db 7,6,11,10 ; text box coordinates
+ dw JapaneseAhText
+ db 8,8 ; text coordinates
+
+ db JP_POKEDEX_MENU_TEMPLATE
+ db 11,8,19,17 ; text box coordinates
+ dw JapanesePokedexMenu
+ db 12,10 ; text coordinates
+
+; note that there is no terminator
+
+BuySellQuitText:
+ db "BUY"
+ next "SELL"
+ next "QUIT@@"
+
+UseTossText:
+ db "USE"
+ next "TOSS@"
+
+JapaneseSaveMessageText:
+ db "きろく"
+ next "メッセージ@"
+
+JapaneseSpeedOptionsText:
+ db "はやい"
+ next "おそい@"
+
+MoneyText:
+ db "MONEY@"
+
+JapaneseMochimonoText:
+ db "もちもの@"
+
+JapaneseMainMenuText:
+ db "つづきから"
+ next "さいしょから@"
+
+BattleMenuText:
+ db "FIGHT ",$E1,$E2
+ next "ITEM RUN@"
+
+SafariZoneBattleMenuText:
+ db "BALL× BAIT"
+ next "THROW ROCK RUN@"
+
+SwitchStatsCancelText:
+ db "SWITCH"
+ next "STATS"
+ next "CANCEL@"
+
+JapaneseAhText:
+ db "アッ!@"
+
+JapanesePokedexMenu:
+ db "データをみる"
+ next "なきごえ"
+ next "ぶんぷをみる"
+ next "キャンセル@"
+
+DisplayMoneyBox:
+ ld hl, wd730
+ set 6, [hl]
+ ld a, MONEY_BOX_TEMPLATE
+ ld [wTextBoxID], a
+ call DisplayTextBoxID
+ coord hl, 13, 1
+ ld b, 1
+ ld c, 6
+ call ClearScreenArea
+ coord hl, 12, 1
+ ld de, wPlayerMoney
+ ld c, $a3
+ call PrintBCDNumber
+ ld hl, wd730
+ res 6, [hl]
+ ret
+
+CurrencyString:
+ db " ¥@"
+
+DoBuySellQuitMenu:
+ ld a, [wd730]
+ set 6, a ; no printing delay
+ ld [wd730], a
+ xor a
+ ld [wChosenMenuItem], a
+ ld a, BUY_SELL_QUIT_MENU_TEMPLATE
+ ld [wTextBoxID], a
+ call DisplayTextBoxID
+ ld a, A_BUTTON | B_BUTTON
+ ld [wMenuWatchedKeys], a
+ ld a, $2
+ ld [wMaxMenuItem], a
+ ld a, $1
+ ld [wTopMenuItemY], a
+ ld a, $1
+ ld [wTopMenuItemX], a
+ xor a
+ ld [wCurrentMenuItem], a
+ ld [wLastMenuItem], a
+ ld [wMenuWatchMovingOutOfBounds], a
+ ld a, [wd730]
+ res 6, a ; turn on the printing delay
+ ld [wd730], a
+ call HandleMenuInput
+ call PlaceUnfilledArrowMenuCursor
+ bit 0, a ; was A pressed?
+ jr nz, .pressedA
+ bit 1, a ; was B pressed? (always true since only A/B are watched)
+ jr z, .pressedA
+ ld a, CANCELLED_MENU
+ ld [wMenuExitMethod], a
+ jr .quit
+.pressedA
+ ld a, CHOSE_MENU_ITEM
+ ld [wMenuExitMethod], a
+ ld a, [wCurrentMenuItem]
+ ld [wChosenMenuItem], a
+ ld b, a
+ ld a, [wMaxMenuItem]
+ cp b
+ jr z, .quit
+ ret
+.quit
+ ld a, CANCELLED_MENU
+ ld [wMenuExitMethod], a
+ ld a, [wCurrentMenuItem]
+ ld [wChosenMenuItem], a
+ scf
+ ret
+
+; displays a menu with two options to choose from
+; b = Y of upper left corner of text region
+; c = X of upper left corner of text region
+; hl = address where the text box border should be drawn
+DisplayTwoOptionMenu:
+ push hl
+ ld a, [wd730]
+ set 6, a ; no printing delay
+ ld [wd730], a
+
+; pointless because both values are overwritten before they are read
+ xor a
+ ld [wChosenMenuItem], a
+ ld [wMenuExitMethod], a
+
+ ld a, A_BUTTON | B_BUTTON
+ ld [wMenuWatchedKeys], a
+ ld a, $1
+ ld [wMaxMenuItem], a
+ ld a, b
+ ld [wTopMenuItemY], a
+ ld a, c
+ ld [wTopMenuItemX], a
+ xor a
+ ld [wLastMenuItem], a
+ ld [wMenuWatchMovingOutOfBounds], a
+ push hl
+ ld hl, wTwoOptionMenuID
+ bit 7, [hl] ; select second menu item by default?
+ res 7, [hl]
+ jr z, .storeCurrentMenuItem
+ inc a
+.storeCurrentMenuItem
+ ld [wCurrentMenuItem], a
+ pop hl
+ push hl
+ push hl
+ call TwoOptionMenu_SaveScreenTiles
+ ld a, [wTwoOptionMenuID]
+ ld hl, TwoOptionMenuStrings
+ ld e, a
+ ld d, $0
+ ld a, $5
+.menuStringLoop
+ add hl, de
+ dec a
+ jr nz, .menuStringLoop
+ ld a, [hli]
+ ld c, a
+ ld a, [hli]
+ ld b, a
+ ld e, l
+ ld d, h
+ pop hl
+ push de
+ ld a, [wTwoOptionMenuID]
+ cp TRADE_CANCEL_MENU
+ jr nz, .notTradeCancelMenu
+ call CableClub_TextBoxBorder
+ jr .afterTextBoxBorder
+.notTradeCancelMenu
+ call TextBoxBorder
+.afterTextBoxBorder
+ call UpdateSprites
+ pop hl
+ ld a, [hli]
+ and a ; put blank line before first menu item?
+ ld bc, 20 + 2
+ jr z, .noBlankLine
+ ld bc, 2 * 20 + 2
+.noBlankLine
+ ld a, [hli]
+ ld e, a
+ ld a, [hli]
+ ld d, a
+ pop hl
+ add hl, bc
+ call PlaceString
+ ld hl, wd730
+ res 6, [hl] ; turn on the printing delay
+ ld a, [wTwoOptionMenuID]
+ cp NO_YES_MENU
+ jr nz, .notNoYesMenu
+; No/Yes menu
+; this menu type ignores the B button
+; it only seems to be used when confirming the deletion of a save file
+ xor a
+ ld [wTwoOptionMenuID], a
+ ld a, [wFlags_0xcd60]
+ push af
+ push hl
+ ld hl, wFlags_0xcd60
+ bit 5, [hl]
+ set 5, [hl] ; don't play sound when A or B is pressed in menu
+ pop hl
+.noYesMenuInputLoop
+ call HandleMenuInput
+ bit 1, a ; A button pressed?
+ jr nz, .noYesMenuInputLoop ; try again if A was not pressed
+ pop af
+ pop hl
+ ld [wFlags_0xcd60], a
+ ld a, SFX_PRESS_AB
+ call PlaySound
+ jr .pressedAButton
+.notNoYesMenu
+ xor a
+ ld [wTwoOptionMenuID], a
+ call HandleMenuInput
+ pop hl
+ bit 1, a ; A button pressed?
+ jr nz, .choseSecondMenuItem ; automatically choose the second option if B is pressed
+.pressedAButton
+ ld a, [wCurrentMenuItem]
+ ld [wChosenMenuItem], a
+ and a
+ jr nz, .choseSecondMenuItem
+; chose first menu item
+ ld a, CHOSE_FIRST_ITEM
+ ld [wMenuExitMethod], a
+ ld c, 15
+ call DelayFrames
+ call TwoOptionMenu_RestoreScreenTiles
+ and a
+ ret
+.choseSecondMenuItem
+ ld a, 1
+ ld [wCurrentMenuItem], a
+ ld [wChosenMenuItem], a
+ ld a, CHOSE_SECOND_ITEM
+ ld [wMenuExitMethod], a
+ ld c, 15
+ call DelayFrames
+ call TwoOptionMenu_RestoreScreenTiles
+ scf
+ ret
+
+; Some of the wider/taller two option menus will not have the screen areas
+; they cover be fully saved/restored by the two functions below.
+; The bottom and right edges of the menu may remain after the function returns.
+
+TwoOptionMenu_SaveScreenTiles:
+ ld de, wBuffer
+ lb bc, 5, 6
+.loop
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .loop
+ push bc
+ ld bc, SCREEN_WIDTH - 6
+ add hl, bc
+ pop bc
+ ld c, $6
+ dec b
+ jr nz, .loop
+ ret
+
+TwoOptionMenu_RestoreScreenTiles:
+ ld de, wBuffer
+ lb bc, 5, 6
+.loop
+ ld a, [de]
+ inc de
+ ld [hli], a
+ dec c
+ jr nz, .loop
+ push bc
+ ld bc, SCREEN_WIDTH - 6
+ add hl, bc
+ pop bc
+ ld c, 6
+ dec b
+ jr nz, .loop
+ call UpdateSprites
+ ret
+
+; Format:
+; 00: byte width
+; 01: byte height
+; 02: byte put blank line before first menu item
+; 03: word text pointer
+TwoOptionMenuStrings:
+ db 4,3,0
+ dw .YesNoMenu
+ db 6,3,0
+ dw .NorthWestMenu
+ db 6,3,0
+ dw .SouthEastMenu
+ db 6,3,0
+ dw .YesNoMenu
+ db 6,3,0
+ dw .NorthEastMenu
+ db 7,3,0
+ dw .TradeCancelMenu
+ db 7,4,1
+ dw .HealCancelMenu
+ db 4,3,0
+ dw .NoYesMenu
+
+.NoYesMenu
+ db "NO"
+ next "YES@"
+.YesNoMenu
+ db "YES"
+ next "NO@"
+.NorthWestMenu
+ db "NORTH"
+ next "WEST@"
+.SouthEastMenu
+ db "SOUTH"
+ next "EAST@"
+.NorthEastMenu
+ db "NORTH"
+ next "EAST@"
+.TradeCancelMenu
+ db "TRADE"
+ next "CANCEL@"
+.HealCancelMenu
+ db "HEAL"
+ next "CANCEL@"
+
+DisplayFieldMoveMonMenu:
+ xor a
+ ld hl, wFieldMoves
+ ld [hli], a ; wFieldMoves
+ ld [hli], a ; wFieldMoves + 1
+ ld [hli], a ; wFieldMoves + 2
+ ld [hli], a ; wFieldMoves + 3
+ ld [hli], a ; wNumFieldMoves
+ ld [hl], 12 ; wFieldMovesLeftmostXCoord
+ call GetMonFieldMoves
+ ld a, [wNumFieldMoves]
+ and a
+ jr nz, .fieldMovesExist
+
+; no field moves
+ coord hl, 11, 11
+ ld b, 5
+ ld c, 7
+ call TextBoxBorder
+ call UpdateSprites
+ ld a, 12
+ ld [hFieldMoveMonMenuTopMenuItemX], a
+ coord hl, 13, 12
+ ld de, PokemonMenuEntries
+ jp PlaceString
+
+.fieldMovesExist
+ push af
+
+; Calculate the text box position and dimensions based on the leftmost X coord
+; of the field move names before adjusting for the number of field moves.
+ coord hl, 0, 11
+ ld a, [wFieldMovesLeftmostXCoord]
+ dec a
+ ld e, a
+ ld d, 0
+ add hl, de
+ ld b, 5
+ ld a, 18
+ sub e
+ ld c, a
+ pop af
+
+; For each field move, move the top of the text box up 2 rows while the leaving
+; the bottom of the text box at the bottom of the screen.
+ ld de, -SCREEN_WIDTH * 2
+.textBoxHeightLoop
+ add hl, de
+ inc b
+ inc b
+ dec a
+ jr nz, .textBoxHeightLoop
+
+; Make space for an extra blank row above the top field move.
+ ld de, -SCREEN_WIDTH
+ add hl, de
+ inc b
+
+ call TextBoxBorder
+ call UpdateSprites
+
+; Calculate the position of the first field move name to print.
+ coord hl, 0, 12
+ ld a, [wFieldMovesLeftmostXCoord]
+ inc a
+ ld e, a
+ ld d, 0
+ add hl, de
+ ld de, -SCREEN_WIDTH * 2
+ ld a, [wNumFieldMoves]
+.calcFirstFieldMoveYLoop
+ add hl, de
+ dec a
+ jr nz, .calcFirstFieldMoveYLoop
+
+ xor a
+ ld [wNumFieldMoves], a
+ ld de, wFieldMoves
+.printNamesLoop
+ push hl
+ ld hl, FieldMoveNames
+ ld a, [de]
+ and a
+ jr z, .donePrintingNames
+ inc de
+ ld b, a ; index of name
+.skipNamesLoop ; skip past names before the name we want
+ dec b
+ jr z, .reachedName
+.skipNameLoop ; skip past current name
+ ld a, [hli]
+ cp "@"
+ jr nz, .skipNameLoop
+ jr .skipNamesLoop
+.reachedName
+ ld b, h
+ ld c, l
+ pop hl
+ push de
+ ld d, b
+ ld e, c
+ call PlaceString
+ ld bc, SCREEN_WIDTH * 2
+ add hl, bc
+ pop de
+ jr .printNamesLoop
+
+.donePrintingNames
+ pop hl
+ ld a, [wFieldMovesLeftmostXCoord]
+ ld [hFieldMoveMonMenuTopMenuItemX], a
+ coord hl, 0, 12
+ ld a, [wFieldMovesLeftmostXCoord]
+ inc a
+ ld e, a
+ ld d, 0
+ add hl, de
+ ld de, PokemonMenuEntries
+ jp PlaceString
+
+FieldMoveNames:
+ db "CUT@"
+ db "FLY@"
+ db "@"
+ db "SURF@"
+ db "STRENGTH@"
+ db "FLASH@"
+ db "DIG@"
+ db "TELEPORT@"
+ db "SOFTBOILED@"
+
+PokemonMenuEntries:
+ db "STATS"
+ next "SWITCH"
+ next "CANCEL@"
+
+GetMonFieldMoves:
+ ld a, [wWhichPokemon]
+ ld hl, wPartyMon1Moves
+ ld bc, wPartyMon2 - wPartyMon1
+ call AddNTimes
+ ld d, h
+ ld e, l
+ ld c, NUM_MOVES + 1
+ ld hl, wFieldMoves
+.loop
+ push hl
+.nextMove
+ dec c
+ jr z, .done
+ ld a, [de] ; move ID
+ and a
+ jr z, .done
+ ld b, a
+ inc de
+ ld hl, FieldMoveDisplayData
+.fieldMoveLoop
+ ld a, [hli]
+ cp $ff
+ jr z, .nextMove ; if the move is not a field move
+ cp b
+ jr z, .foundFieldMove
+ inc hl
+ inc hl
+ jr .fieldMoveLoop
+.foundFieldMove
+ ld a, b
+ ld [wLastFieldMoveID], a
+ ld a, [hli] ; field move name index
+ ld b, [hl] ; field move leftmost X coordinate
+ pop hl
+ ld [hli], a ; store name index in wFieldMoves
+ ld a, [wNumFieldMoves]
+ inc a
+ ld [wNumFieldMoves], a
+ ld a, [wFieldMovesLeftmostXCoord]
+ cp b
+ jr c, .skipUpdatingLeftmostXCoord
+ ld a, b
+ ld [wFieldMovesLeftmostXCoord], a
+.skipUpdatingLeftmostXCoord
+ ld a, [wLastFieldMoveID]
+ ld b, a
+ jr .loop
+.done
+ pop hl
+ ret
+
+; Format: [Move id], [name index], [leftmost tile]
+; Move id = id of move
+; Name index = index of name in FieldMoveNames
+; Leftmost tile = -1 + tile column in which the first letter of the move's name should be displayed
+; "SOFTBOILED" is $08 because it has 4 more letters than "SURF", for example, whose value is $0C
+FieldMoveDisplayData:
+ db CUT, $01, $0C
+ db FLY, $02, $0C
+ db $B4, $03, $0C ; unused field move
+ db SURF, $04, $0C
+ db STRENGTH, $05, $0A
+ db FLASH, $06, $0C
+ db DIG, $07, $0C
+ db TELEPORT, $08, $0A
+ db SOFTBOILED, $09, $08
+ db $ff ; list terminator
--- a/engine/mon_party_sprites.asm
+++ /dev/null
@@ -1,295 +1,0 @@
-AnimatePartyMon_ForceSpeed1:
- xor a
- ld [wCurrentMenuItem], a
- ld b, a
- inc a
- jr GetAnimationSpeed
-
-; wPartyMenuHPBarColors contains the party mon's health bar colors
-; 0: green
-; 1: yellow
-; 2: red
-AnimatePartyMon::
- ld hl, wPartyMenuHPBarColors
- ld a, [wCurrentMenuItem]
- ld c, a
- ld b, 0
- add hl, bc
- ld a, [hl]
-
-GetAnimationSpeed:
- ld c, a
- ld hl, PartyMonSpeeds
- add hl, bc
- ld a, [wOnSGB]
- xor $1
- add [hl]
- ld c, a
- add a
- ld b, a
- ld a, [wAnimCounter]
- and a
- jr z, .resetSprites
- cp c
- jr z, .animateSprite
-.incTimer
- inc a
- cp b
- jr nz, .skipResetTimer
- xor a ; reset timer
-.skipResetTimer
- ld [wAnimCounter], a
- jp DelayFrame
-.resetSprites
- push bc
- ld hl, wMonPartySpritesSavedOAM
- ld de, wOAMBuffer
- ld bc, $60
- call CopyData
- pop bc
- xor a
- jr .incTimer
-.animateSprite
- push bc
- ld hl, wOAMBuffer + $02 ; OAM tile id
- ld bc, $10
- ld a, [wCurrentMenuItem]
- call AddNTimes
- ld c, $40 ; amount to increase the tile id by
- ld a, [hl]
- cp $4 ; tile ID for ICON_BALL
- jr z, .editCoords
- cp $8 ; tile ID for ICON_HELIX
- jr nz, .editTileIDS
-; ICON_BALL and ICON_HELIX only shake up and down
-.editCoords
- dec hl
- dec hl ; dec hl to the OAM y coord
- ld c, $1 ; amount to increase the y coord by
-; otherwise, load a second sprite frame
-.editTileIDS
- ld b, $4
- ld de, $4
-.loop
- ld a, [hl]
- add c
- ld [hl], a
- add hl, de
- dec b
- jr nz, .loop
- pop bc
- ld a, c
- jr .incTimer
-
-; Party mon animations cycle between 2 frames.
-; The members of the PartyMonSpeeds array specify the number of V-blanks
-; that each frame lasts for green HP, yellow HP, and red HP in order.
-; On the naming screen, the yellow HP speed is always used.
-PartyMonSpeeds:
- db 5, 16, 32
-
-LoadMonPartySpriteGfx:
-; Load mon party sprite tile patterns into VRAM during V-blank.
- ld hl, MonPartySpritePointers
- ld a, $1c
-
-LoadAnimSpriteGfx:
-; Load animated sprite tile patterns into VRAM during V-blank. hl is the address
-; of an array of structures that contain arguments for CopyVideoData and a is
-; the number of structures in the array.
- ld bc, $0
-.loop
- push af
- push bc
- push hl
- add hl, bc
- ld a, [hli]
- ld e, a
- ld a, [hli]
- ld d, a
- ld a, [hli]
- ld c, a
- ld a, [hli]
- ld b, a
- ld a, [hli]
- ld h, [hl]
- ld l, a
- call CopyVideoData
- pop hl
- pop bc
- ld a, $6
- add c
- ld c, a
- pop af
- dec a
- jr nz, .loop
- ret
-
-LoadMonPartySpriteGfxWithLCDDisabled:
-; Load mon party sprite tile patterns into VRAM immediately by disabling the
-; LCD.
- call DisableLCD
- ld hl, MonPartySpritePointers
- ld a, $1c
- ld bc, $0
-.loop
- push af
- push bc
- push hl
- add hl, bc
- ld a, [hli]
- ld e, a
- ld a, [hli]
- ld d, a
- push de
- ld a, [hli]
- ld c, a
- swap c
- ld b, $0
- ld a, [hli]
- ld e, [hl]
- inc hl
- ld d, [hl]
- pop hl
- call FarCopyData2
- pop hl
- pop bc
- ld a, $6
- add c
- ld c, a
- pop af
- dec a
- jr nz, .loop
- jp EnableLCD
-
-INCLUDE "data/mon_party_sprite_pointers.asm"
-
-WriteMonPartySpriteOAMByPartyIndex:
-; Write OAM blocks for the party mon in [hPartyMonIndex].
- push hl
- push de
- push bc
- ld a, [hPartyMonIndex]
- ld hl, wPartySpecies
- ld e, a
- ld d, 0
- add hl, de
- ld a, [hl]
- call GetPartyMonSpriteID
- ld [wOAMBaseTile], a
- call WriteMonPartySpriteOAM
- pop bc
- pop de
- pop hl
- ret
-
-WriteMonPartySpriteOAMBySpecies:
-; Write OAM blocks for the party sprite of the species in
-; [wMonPartySpriteSpecies].
- xor a
- ld [hPartyMonIndex], a
- ld a, [wMonPartySpriteSpecies]
- call GetPartyMonSpriteID
- ld [wOAMBaseTile], a
- jr WriteMonPartySpriteOAM
-
-UnusedPartyMonSpriteFunction:
-; This function is unused and doesn't appear to do anything useful. It looks
-; like it may have been intended to load the tile patterns and OAM data for
-; the mon party sprite associated with the species in [wcf91].
-; However, its calculations are off and it loads garbage data.
- ld a, [wcf91]
- call GetPartyMonSpriteID
- push af
- ld hl, vSprites
- call .LoadTilePatterns
- pop af
- add $54
- ld hl, vSprites + $40
- call .LoadTilePatterns
- xor a
- ld [wMonPartySpriteSpecies], a
- jr WriteMonPartySpriteOAMBySpecies
-
-.LoadTilePatterns
- push hl
- add a
- ld c, a
- ld b, 0
- ld hl, MonPartySpritePointers
- add hl, bc
- add hl, bc
- add hl, bc
- ld a, [hli]
- ld e, a
- ld a, [hli]
- ld d, a
- ld a, [hli]
- ld c, a
- ld a, [hli]
- ld b, a
- pop hl
- jp CopyVideoData
-
-WriteMonPartySpriteOAM:
-; Write the OAM blocks for the first animation frame into the OAM buffer and
-; make a copy at wMonPartySpritesSavedOAM.
- push af
- ld c, $10
- ld h, wOAMBuffer / $100
- ld a, [hPartyMonIndex]
- swap a
- ld l, a
- add $10
- ld b, a
- pop af
- cp ICON_HELIX << 2
- jr z, .helix
- call WriteSymmetricMonPartySpriteOAM
- jr .makeCopy
-.helix
- call WriteAsymmetricMonPartySpriteOAM
-; Make a copy of the OAM buffer with the first animation frame written so that
-; we can flip back to it from the second frame by copying it back.
-.makeCopy
- ld hl, wOAMBuffer
- ld de, wMonPartySpritesSavedOAM
- ld bc, $60
- jp CopyData
-
-GetPartyMonSpriteID:
- ld [wd11e], a
- predef IndexToPokedex
- ld a, [wd11e]
- ld c, a
- dec a
- srl a
- ld hl, MonPartyData
- ld e, a
- ld d, 0
- add hl, de
- ld a, [hl]
- bit 0, c
- jr nz, .skipSwap
- swap a ; use lower nybble if pokedex num is even
-.skipSwap
- and $f0
- srl a
- srl a
- ret
-
-INCLUDE "data/mon_party_sprites.asm"
-
-INC_FRAME_1 EQUS "0, $20"
-INC_FRAME_2 EQUS "$20, $20"
-
-BugIconFrame1: INCBIN "gfx/icons/bug.2bpp", INC_FRAME_1
-PlantIconFrame1: INCBIN "gfx/icons/plant.2bpp", INC_FRAME_1
-BugIconFrame2: INCBIN "gfx/icons/bug.2bpp", INC_FRAME_2
-PlantIconFrame2: INCBIN "gfx/icons/plant.2bpp", INC_FRAME_2
-SnakeIconFrame1: INCBIN "gfx/icons/snake.2bpp", INC_FRAME_1
-QuadrupedIconFrame1: INCBIN "gfx/icons/quadruped.2bpp", INC_FRAME_1
-SnakeIconFrame2: INCBIN "gfx/icons/snake.2bpp", INC_FRAME_2
-QuadrupedIconFrame2: INCBIN "gfx/icons/quadruped.2bpp", INC_FRAME_2
-
-TradeBubbleIconGFX: INCBIN "gfx/trade/bubble.2bpp"
--- /dev/null
+++ b/engine/movie/credits.asm
@@ -1,0 +1,270 @@
+HallOfFamePC:
+ callba AnimateHallOfFame
+ call ClearScreen
+ ld c, 100
+ call DelayFrames
+ call DisableLCD
+ ld hl, vFont
+ ld bc, $800 / 2
+ call ZeroMemory
+ ld hl, vChars2 + $600
+ ld bc, $200 / 2
+ call ZeroMemory
+ ld hl, vChars2 + $7e0
+ ld bc, $10
+ ld a, $ff
+ call FillMemory
+ coord hl, 0, 0
+ call FillFourRowsWithBlack
+ coord hl, 0, 14
+ call FillFourRowsWithBlack
+ ld a, %11000000
+ ld [rBGP], a
+ call EnableLCD
+ ld a, $ff
+ call PlaySoundWaitForCurrent
+ ld c, BANK(Music_Credits)
+ ld a, MUSIC_CREDITS
+ call PlayMusic
+ ld c, 128
+ call DelayFrames
+ xor a
+ ld [wUnusedCD3D], a ; not read
+ ld [wNumCreditsMonsDisplayed], a
+ jp Credits
+
+FadeInCreditsText:
+ ld hl, HoFGBPalettes
+ ld b, 4
+.loop
+ ld a, [hli]
+ ld [rBGP], a
+ ld c, 5
+ call DelayFrames
+ dec b
+ jr nz, .loop
+ ret
+
+DisplayCreditsMon:
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call SaveScreenTilesToBuffer1
+ call FillMiddleOfScreenWithWhite
+
+ ; display the next monster from CreditsMons
+ ld hl, wNumCreditsMonsDisplayed
+ ld c, [hl] ; how many monsters have we displayed so far?
+ inc [hl]
+ ld b, 0
+ ld hl, CreditsMons
+ add hl, bc ; go that far in the list of monsters and get the next one
+ ld a, [hl]
+ ld [wcf91], a
+ ld [wd0b5], a
+ coord hl, 8, 6
+ call GetMonHeader
+ call LoadFrontSpriteByMonIndex
+ ld hl, vBGMap0 + $c
+ call CreditsCopyTileMapToVRAM
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call LoadScreenTilesFromBuffer1
+ ld hl, vBGMap0
+ call CreditsCopyTileMapToVRAM
+ ld a, $A7
+ ld [rWX], a
+ ld hl, vBGMap1
+ call CreditsCopyTileMapToVRAM
+ call FillMiddleOfScreenWithWhite
+ ld a, %11111100 ; make the mon a black silhouette
+ ld [rBGP], a
+
+; scroll the mon left by one tile 7 times
+ ld bc, 7
+.scrollLoop1
+ call ScrollCreditsMonLeft
+ dec c
+ jr nz, .scrollLoop1
+
+; scroll the mon left by one tile 20 times
+; This time, we have to move the window left too in order to hide the text that
+; is wrapping around to the right side of the screen.
+ ld c, 20
+.scrollLoop2
+ call ScrollCreditsMonLeft
+ ld a, [rWX]
+ sub 8
+ ld [rWX], a
+ dec c
+ jr nz, .scrollLoop2
+
+ xor a
+ ld [hWY], a
+ ld a, %11000000
+ ld [rBGP], a
+ ret
+
+INCLUDE "data/credit_mons.asm"
+
+ScrollCreditsMonLeft:
+ ld h, b
+ ld l, $20
+ call ScrollCreditsMonLeft_SetSCX
+ ld h, $0
+ ld l, $70
+ call ScrollCreditsMonLeft_SetSCX
+ ld a, b
+ add $8
+ ld b, a
+ ret
+
+ScrollCreditsMonLeft_SetSCX:
+ ld a, [rLY]
+ cp l
+ jr nz, ScrollCreditsMonLeft_SetSCX
+ ld a, h
+ ld [rSCX], a
+.loop
+ ld a, [rLY]
+ cp h
+ jr z, .loop
+ ret
+
+HoFGBPalettes:
+ db %11000000
+ db %11010000
+ db %11100000
+ db %11110000
+
+CreditsCopyTileMapToVRAM:
+ ld a, l
+ ld [H_AUTOBGTRANSFERDEST], a
+ ld a, h
+ ld [H_AUTOBGTRANSFERDEST + 1], a
+ ld a, 1
+ ld [H_AUTOBGTRANSFERENABLED], a
+ jp Delay3
+
+ZeroMemory:
+; zero bc bytes at hl
+ ld [hl], 0
+ inc hl
+ inc hl
+ dec bc
+ ld a, b
+ or c
+ jr nz, ZeroMemory
+ ret
+
+FillFourRowsWithBlack:
+ ld bc, SCREEN_WIDTH * 4
+ ld a, $7e
+ jp FillMemory
+
+FillMiddleOfScreenWithWhite:
+ coord hl, 0, 4
+ ld bc, SCREEN_WIDTH * 10
+ ld a, " "
+ jp FillMemory
+
+Credits:
+ ld de, CreditsOrder
+ push de
+.nextCreditsScreen
+ pop de
+ coord hl, 9, 6
+ push hl
+ call FillMiddleOfScreenWithWhite
+ pop hl
+.nextCreditsCommand
+ ld a, [de]
+ inc de
+ push de
+ cp $ff
+ jr z, .fadeInTextAndShowMon
+ cp $fe
+ jr z, .showTextAndShowMon
+ cp $fd
+ jr z, .fadeInText
+ cp $fc
+ jr z, .showText
+ cp $fb
+ jr z, .showCopyrightText
+ cp $fa
+ jr z, .showTheEnd
+ push hl
+ push hl
+ ld hl, CreditsTextPointers
+ add a
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ ld a, [de]
+ inc de
+ ld c, a
+ ld b, $ff
+ pop hl
+ add hl, bc
+ call PlaceString
+ pop hl
+ ld bc, SCREEN_WIDTH * 2
+ add hl, bc
+ pop de
+ jr .nextCreditsCommand
+.fadeInTextAndShowMon
+ call FadeInCreditsText
+ ld c, 90
+ jr .next1
+.showTextAndShowMon
+ ld c, 110
+.next1
+ call DelayFrames
+ call DisplayCreditsMon
+ jr .nextCreditsScreen
+.fadeInText
+ call FadeInCreditsText
+ ld c, 120
+ jr .next2
+.showText
+ ld c, 140
+.next2
+ call DelayFrames
+ jr .nextCreditsScreen
+.showCopyrightText
+ push de
+ callba LoadCopyrightTiles
+ pop de
+ pop de
+ jr .nextCreditsCommand
+.showTheEnd
+ ld c, 16
+ call DelayFrames
+ call FillMiddleOfScreenWithWhite
+ pop de
+ ld de, TheEndGfx
+ ld hl, vChars2 + $600
+ lb bc, BANK(TheEndGfx), (TheEndGfxEnd - TheEndGfx) / $10
+ call CopyVideoData
+ coord hl, 4, 8
+ ld de, TheEndTextString
+ call PlaceString
+ coord hl, 4, 9
+ inc de
+ call PlaceString
+ jp FadeInCreditsText
+
+TheEndTextString:
+; "T H E E N D"
+ db $60," ",$62," ",$64," ",$64," ",$66," ",$68,"@"
+ db $61," ",$63," ",$65," ",$65," ",$67," ",$69,"@"
+
+INCLUDE "data/credits_order.asm"
+
+INCLUDE "text/credits_text.asm"
+
+TheEndGfx:
+ INCBIN "gfx/intro_credits/the_end.2bpp"
+TheEndGfxEnd:
--- /dev/null
+++ b/engine/movie/evolution.asm
@@ -1,0 +1,160 @@
+EvolveMon:
+ push hl
+ push de
+ push bc
+ ld a, [wcf91]
+ push af
+ ld a, [wd0b5]
+ push af
+ xor a
+ ld [wLowHealthAlarm], a
+ ld [wChannelSoundIDs + Ch5], a
+ dec a
+ ld [wNewSoundID], a
+ call PlaySound
+ ld a, $1
+ ld [H_AUTOBGTRANSFERENABLED], a
+ ld a, SFX_TINK
+ call PlaySound
+ call Delay3
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ ld [hTilesetType], a
+ ld a, [wEvoOldSpecies]
+ ld [wWholeScreenPaletteMonSpecies], a
+ ld c, 0
+ call EvolutionSetWholeScreenPalette
+ ld a, [wEvoNewSpecies]
+ ld [wcf91], a
+ ld [wd0b5], a
+ call Evolution_LoadPic
+ ld de, vFrontPic
+ ld hl, vBackPic
+ ld bc, 7 * 7
+ call CopyVideoData
+ ld a, [wEvoOldSpecies]
+ ld [wcf91], a
+ ld [wd0b5], a
+ call Evolution_LoadPic
+ ld a, $1
+ ld [H_AUTOBGTRANSFERENABLED], a
+ ld a, [wEvoOldSpecies]
+ call PlayCry
+ call WaitForSoundToFinish
+ ld c, BANK(Music_SafariZone)
+ ld a, MUSIC_SAFARI_ZONE
+ call PlayMusic
+ ld c, 80
+ call DelayFrames
+ ld c, 1 ; set PAL_BLACK instead of mon palette
+ call EvolutionSetWholeScreenPalette
+ lb bc, $1, $10
+.animLoop
+ push bc
+ call Evolution_CheckForCancel
+ jr c, .evolutionCancelled
+ call Evolution_BackAndForthAnim
+ pop bc
+ inc b
+ dec c
+ dec c
+ jr nz, .animLoop
+ xor a
+ ld [wEvoCancelled], a
+ ld a, $31
+ ld [wEvoMonTileOffset], a
+ call Evolution_ChangeMonPic ; show the new species pic
+ ld a, [wEvoNewSpecies]
+.done
+ ld [wWholeScreenPaletteMonSpecies], a
+ ld a, $ff
+ ld [wNewSoundID], a
+ call PlaySound
+ ld a, [wWholeScreenPaletteMonSpecies]
+ call PlayCry
+ ld c, 0
+ call EvolutionSetWholeScreenPalette
+ pop af
+ ld [wd0b5], a
+ pop af
+ ld [wcf91], a
+ pop bc
+ pop de
+ pop hl
+ ld a, [wEvoCancelled]
+ and a
+ ret z
+ scf
+ ret
+.evolutionCancelled
+ pop bc
+ ld a, 1
+ ld [wEvoCancelled], a
+ ld a, [wEvoOldSpecies]
+ jr .done
+
+EvolutionSetWholeScreenPalette:
+ ld b, SET_PAL_POKEMON_WHOLE_SCREEN
+ jp RunPaletteCommand
+
+Evolution_LoadPic:
+ call GetMonHeader
+ coord hl, 7, 2
+ jp LoadFlippedFrontSpriteByMonIndex
+
+Evolution_BackAndForthAnim:
+; show the mon change back and forth between the new and old species b times
+ ld a, $31
+ ld [wEvoMonTileOffset], a
+ call Evolution_ChangeMonPic
+ ld a, -$31
+ ld [wEvoMonTileOffset], a
+ call Evolution_ChangeMonPic
+ dec b
+ jr nz, Evolution_BackAndForthAnim
+ ret
+
+Evolution_ChangeMonPic:
+ push bc
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ coord hl, 7, 2
+ lb bc, 7, 7
+ ld de, SCREEN_WIDTH - 7
+.loop
+ push bc
+.innerLoop
+ ld a, [wEvoMonTileOffset]
+ add [hl]
+ ld [hli], a
+ dec c
+ jr nz, .innerLoop
+ pop bc
+ add hl, de
+ dec b
+ jr nz, .loop
+ ld a, 1
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call Delay3
+ pop bc
+ ret
+
+Evolution_CheckForCancel:
+ call DelayFrame
+ push bc
+ call JoypadLowSensitivity
+ ld a, [hJoy5]
+ pop bc
+ and B_BUTTON
+ jr nz, .pressedB
+.notAllowedToCancel
+ dec c
+ jr nz, Evolution_CheckForCancel
+ and a
+ ret
+.pressedB
+ ld a, [wForceEvolution]
+ and a
+ jr nz, .notAllowedToCancel
+ scf
+ ret
--- /dev/null
+++ b/engine/movie/gamefreak.asm
@@ -1,0 +1,243 @@
+LoadShootingStarGraphics:
+ ld a, $f9
+ ld [rOBP0], a
+ ld a, $a4
+ ld [rOBP1], a
+ ld de, AnimationTileset2 + $30 ; star tile (top left quadrant)
+ ld hl, vChars1 + $200
+ lb bc, BANK(AnimationTileset2), $01
+ call CopyVideoData
+ ld de, AnimationTileset2 + $130 ; star tile (bottom left quadrant)
+ ld hl, vChars1 + $210
+ lb bc, BANK(AnimationTileset2), $01
+ call CopyVideoData
+ ld de, FallingStar
+ ld hl, vChars1 + $220
+ lb bc, BANK(FallingStar), (FallingStarEnd - FallingStar) / $10
+ call CopyVideoData
+ ld hl, GameFreakLogoOAMData
+ ld de, wOAMBuffer + $60
+ ld bc, GameFreakLogoOAMDataEnd - GameFreakLogoOAMData
+ call CopyData
+ ld hl, GameFreakShootingStarOAMData
+ ld de, wOAMBuffer
+ ld bc, GameFreakShootingStarOAMDataEnd - GameFreakShootingStarOAMData
+ jp CopyData
+
+AnimateShootingStar:
+ call LoadShootingStarGraphics
+ ld a, SFX_SHOOTING_STAR
+ call PlaySound
+
+; Move the big star down and left across the screen.
+ ld hl, wOAMBuffer
+ lb bc, $a0, $4
+.bigStarLoop
+ push hl
+ push bc
+.bigStarInnerLoop
+ ld a, [hl] ; Y
+ add 4
+ ld [hli], a
+ ld a, [hl] ; X
+ add -4
+ ld [hli], a
+ inc hl
+ inc hl
+ dec c
+ jr nz, .bigStarInnerLoop
+ ld c, 1
+ call CheckForUserInterruption
+ pop bc
+ pop hl
+ ret c
+ ld a, [hl]
+ cp 80
+ jr nz, .next
+ jr .bigStarLoop
+.next
+ cp b
+ jr nz, .bigStarLoop
+
+; Clear big star OAM.
+ ld hl, wOAMBuffer
+ ld c, 4
+ ld de, 4
+.clearOAMLoop
+ ld [hl], 160
+ add hl, de
+ dec c
+ jr nz, .clearOAMLoop
+
+; Make Gamefreak logo flash.
+ ld b, 3
+.flashLogoLoop
+ ld hl, rOBP0
+ rrc [hl]
+ rrc [hl]
+ ld c, 10
+ call CheckForUserInterruption
+ ret c
+ dec b
+ jr nz, .flashLogoLoop
+
+; Copy 24 instances of the small stars OAM data.
+; Note that their coordinates put them off-screen.
+ ld de, wOAMBuffer
+ ld a, 24
+.initSmallStarsOAMLoop
+ push af
+ ld hl, SmallStarsOAM
+ ld bc, SmallStarsOAMEnd - SmallStarsOAM
+ call CopyData
+ pop af
+ dec a
+ jr nz, .initSmallStarsOAMLoop
+
+; Animate the small stars falling from the Gamefreak logo.
+ xor a
+ ld [wMoveDownSmallStarsOAMCount], a
+ ld hl, SmallStarsWaveCoordsPointerTable
+ ld c, 6
+.smallStarsLoop
+ ld a, [hli]
+ ld e, a
+ ld a, [hli]
+ ld d, a
+ push bc
+ push hl
+ ld hl, wOAMBuffer + $50
+ ld c, 4
+.smallStarsInnerLoop ; introduce new wave of 4 small stars OAM entries
+ ld a, [de]
+ cp $ff
+ jr z, .next2
+ ld [hli], a ; Y
+ inc de
+ ld a, [de]
+ ld [hli], a ; X
+ inc de
+ inc hl
+ inc hl
+ dec c
+ jr nz, .smallStarsInnerLoop
+ ld a, [wMoveDownSmallStarsOAMCount]
+ cp 24
+ jr z, .next2
+ add 6 ; should be 4, but the extra 2 aren't visible on screen
+ ld [wMoveDownSmallStarsOAMCount], a
+.next2
+ call MoveDownSmallStars
+ push af
+
+; shift the existing OAM entries down to make room for the next wave
+ ld hl, wOAMBuffer + $10
+ ld de, wOAMBuffer
+ ld bc, $50
+ call CopyData
+
+ pop af
+ pop hl
+ pop bc
+ ret c
+ dec c
+ jr nz, .smallStarsLoop
+ and a
+ ret
+
+SmallStarsOAM:
+ db $00,$00,$A2,$90
+SmallStarsOAMEnd:
+
+SmallStarsWaveCoordsPointerTable:
+ dw SmallStarsWave1Coords
+ dw SmallStarsWave2Coords
+ dw SmallStarsWave3Coords
+ dw SmallStarsWave4Coords
+ dw SmallStarsEmptyWave
+ dw SmallStarsEmptyWave
+
+; The stars that fall from the Gamefreak logo come in 4 waves of 4 OAM entries.
+; These arrays contain the Y and X coordinates of each OAM entry.
+
+SmallStarsWave1Coords:
+ db $68,$30
+ db $68,$40
+ db $68,$58
+ db $68,$78
+
+SmallStarsWave2Coords:
+ db $68,$38
+ db $68,$48
+ db $68,$60
+ db $68,$70
+
+SmallStarsWave3Coords:
+ db $68,$34
+ db $68,$4C
+ db $68,$54
+ db $68,$64
+
+SmallStarsWave4Coords:
+ db $68,$3C
+ db $68,$5C
+ db $68,$6C
+ db $68,$74
+
+SmallStarsEmptyWave:
+ db $FF
+
+MoveDownSmallStars:
+ ld b, 8
+.loop
+ ld hl, wOAMBuffer + $5c
+ ld a, [wMoveDownSmallStarsOAMCount]
+ ld de, -4
+ ld c, a
+.innerLoop
+ inc [hl] ; Y
+ add hl, de
+ dec c
+ jr nz, .innerLoop
+; Toggle the palette so that the lower star in the small stars tile blinks in
+; and out.
+ ld a, [rOBP1]
+ xor %10100000
+ ld [rOBP1], a
+
+ ld c, 3
+ call CheckForUserInterruption
+ ret c
+ dec b
+ jr nz, .loop
+ ret
+
+GameFreakLogoOAMData:
+ db $48,$50,$8D,$00
+ db $48,$58,$8E,$00
+ db $50,$50,$8F,$00
+ db $50,$58,$90,$00
+ db $58,$50,$91,$00
+ db $58,$58,$92,$00
+ db $60,$30,$80,$00
+ db $60,$38,$81,$00
+ db $60,$40,$82,$00
+ db $60,$48,$83,$00
+ db $60,$50,$93,$00
+ db $60,$58,$84,$00
+ db $60,$60,$85,$00
+ db $60,$68,$83,$00
+ db $60,$70,$81,$00
+ db $60,$78,$86,$00
+GameFreakLogoOAMDataEnd:
+
+GameFreakShootingStarOAMData:
+ db $00,$A0,$A0,$10
+ db $00,$A8,$A0,$30
+ db $08,$A0,$A1,$10
+ db $08,$A8,$A1,$30
+GameFreakShootingStarOAMDataEnd:
+
+FallingStar:
+ INCBIN "gfx/intro_credits/falling_star.2bpp"
+FallingStarEnd:
--- /dev/null
+++ b/engine/movie/hall_of_fame.asm
@@ -1,0 +1,288 @@
+AnimateHallOfFame:
+ call HoFFadeOutScreenAndMusic
+ call ClearScreen
+ ld c, 100
+ call DelayFrames
+ call LoadFontTilePatterns
+ call LoadTextBoxTilePatterns
+ call DisableLCD
+ ld hl, vBGMap0
+ ld bc, $800
+ ld a, " "
+ call FillMemory
+ call EnableLCD
+ ld hl, rLCDC
+ set 3, [hl]
+ xor a
+ ld hl, wHallOfFame
+ ld bc, HOF_TEAM
+ call FillMemory
+ xor a
+ ld [wUpdateSpritesEnabled], a
+ ld [hTilesetType], a
+ ld [wSpriteFlipped], a
+ ld [wLetterPrintingDelayFlags], a ; no delay
+ ld [wHoFMonOrPlayer], a ; mon
+ inc a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ ld hl, wNumHoFTeams
+ ld a, [hl]
+ inc a
+ jr z, .skipInc ; don't wrap around to 0
+ inc [hl]
+.skipInc
+ ld a, $90
+ ld [hWY], a
+ ld c, BANK(Music_HallOfFame)
+ ld a, MUSIC_HALL_OF_FAME
+ call PlayMusic
+ ld hl, wPartySpecies
+ ld c, $ff
+.partyMonLoop
+ ld a, [hli]
+ cp $ff
+ jr z, .doneShowingParty
+ inc c
+ push hl
+ push bc
+ ld [wHoFMonSpecies], a
+ ld a, c
+ ld [wHoFPartyMonIndex], a
+ ld hl, wPartyMon1Level
+ ld bc, wPartyMon2 - wPartyMon1
+ call AddNTimes
+ ld a, [hl]
+ ld [wHoFMonLevel], a
+ call HoFShowMonOrPlayer
+ call HoFDisplayAndRecordMonInfo
+ ld c, 80
+ call DelayFrames
+ coord hl, 2, 13
+ ld b, 3
+ ld c, 14
+ call TextBoxBorder
+ coord hl, 4, 15
+ ld de, HallOfFameText
+ call PlaceString
+ ld c, 180
+ call DelayFrames
+ call GBFadeOutToWhite
+ pop bc
+ pop hl
+ jr .partyMonLoop
+.doneShowingParty
+ ld a, c
+ inc a
+ ld hl, wHallOfFame
+ ld bc, HOF_MON
+ call AddNTimes
+ ld [hl], $ff
+ call SaveHallOfFameTeams
+ xor a
+ ld [wHoFMonSpecies], a
+ inc a
+ ld [wHoFMonOrPlayer], a ; player
+ call HoFShowMonOrPlayer
+ call HoFDisplayPlayerStats
+ call HoFFadeOutScreenAndMusic
+ xor a
+ ld [hWY], a
+ ld hl, rLCDC
+ res 3, [hl]
+ ret
+
+HallOfFameText:
+ db "HALL OF FAME@"
+
+HoFShowMonOrPlayer:
+ call ClearScreen
+ ld a, $d0
+ ld [hSCY], a
+ ld a, $c0
+ ld [hSCX], a
+ ld a, [wHoFMonSpecies]
+ ld [wcf91], a
+ ld [wd0b5], a
+ ld [wBattleMonSpecies2], a
+ ld [wWholeScreenPaletteMonSpecies], a
+ ld a, [wHoFMonOrPlayer]
+ and a
+ jr z, .showMon
+; show player
+ call HoFLoadPlayerPics
+ jr .next1
+.showMon
+ coord hl, 12, 5
+ call GetMonHeader
+ call LoadFrontSpriteByMonIndex
+ predef LoadMonBackPic
+.next1
+ ld b, SET_PAL_POKEMON_WHOLE_SCREEN
+ ld c, 0
+ call RunPaletteCommand
+ ld a, %11100100
+ ld [rBGP], a
+ ld c, $31 ; back pic
+ call HoFLoadMonPlayerPicTileIDs
+ ld d, $a0
+ ld e, 4
+ ld a, [wOnSGB]
+ and a
+ jr z, .next2
+ sla e ; scroll more slowly on SGB
+.next2
+ call .ScrollPic ; scroll back pic left
+ xor a
+ ld [hSCY], a
+ ld c, a ; front pic
+ call HoFLoadMonPlayerPicTileIDs
+ ld d, 0
+ ld e, -4
+; scroll front pic right
+
+.ScrollPic
+ call DelayFrame
+ ld a, [hSCX]
+ add e
+ ld [hSCX], a
+ cp d
+ jr nz, .ScrollPic
+ ret
+
+HoFDisplayAndRecordMonInfo:
+ ld a, [wHoFPartyMonIndex]
+ ld hl, wPartyMonNicks
+ call GetPartyMonName
+ call HoFDisplayMonInfo
+ jp HoFRecordMonInfo
+
+HoFDisplayMonInfo:
+ coord hl, 0, 2
+ ld b, 9
+ ld c, 10
+ call TextBoxBorder
+ coord hl, 2, 6
+ ld de, HoFMonInfoText
+ call PlaceString
+ coord hl, 1, 4
+ ld de, wcd6d
+ call PlaceString
+ ld a, [wHoFMonLevel]
+ coord hl, 8, 7
+ call PrintLevelCommon
+ ld a, [wHoFMonSpecies]
+ ld [wd0b5], a
+ coord hl, 3, 9
+ predef PrintMonType
+ ld a, [wHoFMonSpecies]
+ jp PlayCry
+
+HoFMonInfoText:
+ db "LEVEL/"
+ next "TYPE1/"
+ next "TYPE2/@"
+
+HoFLoadPlayerPics:
+ ld de, RedPicFront
+ ld a, BANK(RedPicFront)
+ call UncompressSpriteFromDE
+ ld hl, sSpriteBuffer1
+ ld de, sSpriteBuffer0
+ ld bc, $310
+ call CopyData
+ ld de, vFrontPic
+ call InterlaceMergeSpriteBuffers
+ ld de, RedPicBack
+ ld a, BANK(RedPicBack)
+ call UncompressSpriteFromDE
+ predef ScaleSpriteByTwo
+ ld de, vBackPic
+ call InterlaceMergeSpriteBuffers
+ ld c, $1
+
+HoFLoadMonPlayerPicTileIDs:
+; c = base tile ID
+ ld b, 0
+ coord hl, 12, 5
+ predef_jump CopyTileIDsFromList
+
+HoFDisplayPlayerStats:
+ SetEvent EVENT_HALL_OF_FAME_DEX_RATING
+ predef DisplayDexRating
+ coord hl, 0, 4
+ ld b, 6
+ ld c, 10
+ call TextBoxBorder
+ coord hl, 5, 0
+ ld b, 2
+ ld c, 9
+ call TextBoxBorder
+ coord hl, 7, 2
+ ld de, wPlayerName
+ call PlaceString
+ coord hl, 1, 6
+ ld de, HoFPlayTimeText
+ call PlaceString
+ coord hl, 5, 7
+ ld de, wPlayTimeHours
+ lb bc, 1, 3
+ call PrintNumber
+ ld [hl], $6d
+ inc hl
+ ld de, wPlayTimeMinutes
+ lb bc, LEADING_ZEROES | 1, 2
+ call PrintNumber
+ coord hl, 1, 9
+ ld de, HoFMoneyText
+ call PlaceString
+ coord hl, 4, 10
+ ld de, wPlayerMoney
+ ld c, $a3
+ call PrintBCDNumber
+ ld hl, DexSeenOwnedText
+ call HoFPrintTextAndDelay
+ ld hl, DexRatingText
+ call HoFPrintTextAndDelay
+ ld hl, wDexRatingText
+
+HoFPrintTextAndDelay:
+ call PrintText
+ ld c, 120
+ jp DelayFrames
+
+HoFPlayTimeText:
+ db "PLAY TIME@"
+
+HoFMoneyText:
+ db "MONEY@"
+
+DexSeenOwnedText:
+ TX_FAR _DexSeenOwnedText
+ db "@"
+
+DexRatingText:
+ TX_FAR _DexRatingText
+ db "@"
+
+HoFRecordMonInfo:
+ ld hl, wHallOfFame
+ ld bc, HOF_MON
+ ld a, [wHoFPartyMonIndex]
+ call AddNTimes
+ ld a, [wHoFMonSpecies]
+ ld [hli], a
+ ld a, [wHoFMonLevel]
+ ld [hli], a
+ ld e, l
+ ld d, h
+ ld hl, wcd6d
+ ld bc, NAME_LENGTH
+ jp CopyData
+
+HoFFadeOutScreenAndMusic:
+ ld a, 10
+ ld [wAudioFadeOutCounterReloadValue], a
+ ld [wAudioFadeOutCounter], a
+ ld a, $ff
+ ld [wAudioFadeOutControl], a
+ jp GBFadeOutToWhite
--- /dev/null
+++ b/engine/movie/intro.asm
@@ -1,0 +1,470 @@
+const_value = -1
+ const MOVE_NIDORINO_RIGHT
+ const MOVE_GENGAR_RIGHT
+ const MOVE_GENGAR_LEFT
+
+ANIMATION_END EQU 80
+
+const_value = 3
+ const GENGAR_INTRO_TILES1
+ const GENGAR_INTRO_TILES2
+ const GENGAR_INTRO_TILES3
+
+PlayIntro:
+ xor a
+ ld [hJoyHeld], a
+ inc a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call PlayShootingStar
+ call PlayIntroScene
+ call GBFadeOutToWhite
+ xor a
+ ld [hSCX], a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call ClearSprites
+ call DelayFrame
+ ret
+
+PlayIntroScene:
+ ld b, SET_PAL_NIDORINO_INTRO
+ call RunPaletteCommand
+ ldPal a, BLACK, DARK_GRAY, LIGHT_GRAY, WHITE
+ ld [rBGP], a
+ ld [rOBP0], a
+ ld [rOBP1], a
+ xor a
+ ld [hSCX], a
+ ld b, GENGAR_INTRO_TILES1
+ call IntroCopyTiles
+ ld a, 0
+ ld [wBaseCoordX], a
+ ld a, 80
+ ld [wBaseCoordY], a
+ lb bc, 6, 6
+ call InitIntroNidorinoOAM
+ lb de, 80 / 2, MOVE_NIDORINO_RIGHT
+ call IntroMoveMon
+ ret c
+
+; hip
+ ld a, SFX_INTRO_HIP
+ call PlaySound
+ xor a
+ ld [wIntroNidorinoBaseTile], a
+ ld de, IntroNidorinoAnimation1
+ call AnimateIntroNidorino
+; hop
+ ld a, SFX_INTRO_HOP
+ call PlaySound
+ ld de, IntroNidorinoAnimation2
+ call AnimateIntroNidorino
+ ld c, 10
+ call CheckForUserInterruption
+ ret c
+
+; hip
+ ld a, SFX_INTRO_HIP
+ call PlaySound
+ ld de, IntroNidorinoAnimation1
+ call AnimateIntroNidorino
+; hop
+ ld a, SFX_INTRO_HOP
+ call PlaySound
+ ld de, IntroNidorinoAnimation2
+ call AnimateIntroNidorino
+ ld c, 30
+ call CheckForUserInterruption
+ ret c
+
+; raise
+ ld b, GENGAR_INTRO_TILES2
+ call IntroCopyTiles
+ ld a, SFX_INTRO_RAISE
+ call PlaySound
+ lb de, 8 / 2, MOVE_GENGAR_LEFT
+ call IntroMoveMon
+ ld c, 30
+ call CheckForUserInterruption
+ ret c
+
+; slash
+ ld b, GENGAR_INTRO_TILES3
+ call IntroCopyTiles
+ ld a, SFX_INTRO_CRASH
+ call PlaySound
+ lb de, 16 / 2, MOVE_GENGAR_RIGHT
+ call IntroMoveMon
+; hip
+ ld a, SFX_INTRO_HIP
+ call PlaySound
+ ld a, (FightIntroFrontMon2 - FightIntroFrontMon) / BYTES_PER_TILE
+ ld [wIntroNidorinoBaseTile], a
+ ld de, IntroNidorinoAnimation3
+ call AnimateIntroNidorino
+ ld c, 30
+ call CheckForUserInterruption
+ ret c
+
+ lb de, 8 / 2, MOVE_GENGAR_LEFT
+ call IntroMoveMon
+ ld b, GENGAR_INTRO_TILES1
+ call IntroCopyTiles
+ ld c, 60
+ call CheckForUserInterruption
+ ret c
+
+; hip
+ ld a, SFX_INTRO_HIP
+ call PlaySound
+ xor a
+ ld [wIntroNidorinoBaseTile], a
+ ld de, IntroNidorinoAnimation4
+ call AnimateIntroNidorino
+; hop
+ ld a, SFX_INTRO_HOP
+ call PlaySound
+ ld de, IntroNidorinoAnimation5
+ call AnimateIntroNidorino
+ ld c, 20
+ call CheckForUserInterruption
+ ret c
+
+ ld a, (FightIntroFrontMon2 - FightIntroFrontMon) / BYTES_PER_TILE
+ ld [wIntroNidorinoBaseTile], a
+ ld de, IntroNidorinoAnimation6
+ call AnimateIntroNidorino
+ ld c, 30
+ call CheckForUserInterruption
+ ret c
+
+; lunge
+ ld a, SFX_INTRO_LUNGE
+ call PlaySound
+ ld a, (FightIntroFrontMon3 - FightIntroFrontMon) / BYTES_PER_TILE
+ ld [wIntroNidorinoBaseTile], a
+ ld de, IntroNidorinoAnimation7
+ jp AnimateIntroNidorino
+
+AnimateIntroNidorino:
+ ld a, [de]
+ cp ANIMATION_END
+ ret z
+ ld [wBaseCoordY], a
+ inc de
+ ld a, [de]
+ ld [wBaseCoordX], a
+ push de
+ ld c, 6 * 6
+ call UpdateIntroNidorinoOAM
+ ld c, 5
+ call DelayFrames
+ pop de
+ inc de
+ jr AnimateIntroNidorino
+
+UpdateIntroNidorinoOAM:
+ ld hl, wOAMBuffer
+ ld a, [wIntroNidorinoBaseTile]
+ ld d, a
+.loop
+ ld a, [wBaseCoordY]
+ add [hl]
+ ld [hli], a ; Y
+ ld a, [wBaseCoordX]
+ add [hl]
+ ld [hli], a ; X
+ ld a, d
+ ld [hli], a ; tile
+ inc hl
+ inc d
+ dec c
+ jr nz, .loop
+ ret
+
+InitIntroNidorinoOAM:
+ ld hl, wOAMBuffer
+ ld d, 0
+.loop
+ push bc
+ ld a, [wBaseCoordY]
+ ld e, a
+.innerLoop
+ ld a, e
+ add 8
+ ld e, a
+ ld [hli], a ; Y
+ ld a, [wBaseCoordX]
+ ld [hli], a ; X
+ ld a, d
+ ld [hli], a ; tile
+ ld a, OAM_BEHIND_BG
+ ld [hli], a ; attributes
+ inc d
+ dec c
+ jr nz, .innerLoop
+ ld a, [wBaseCoordX]
+ add 8
+ ld [wBaseCoordX], a
+ pop bc
+ dec b
+ jr nz, .loop
+ ret
+
+IntroClearScreen:
+ ld hl, vBGMap1
+ ld bc, BG_MAP_WIDTH * SCREEN_HEIGHT
+ jr IntroClearCommon
+
+IntroClearMiddleOfScreen:
+; clear the area of the tile map between the black bars on the top and bottom
+ coord hl, 0, 4
+ ld bc, SCREEN_WIDTH * 10
+
+IntroClearCommon:
+ ld [hl], 0
+ inc hl
+ dec bc
+ ld a, b
+ or c
+ jr nz, IntroClearCommon
+ ret
+
+IntroPlaceBlackTiles:
+ ld a, 1
+.loop
+ ld [hli], a
+ dec c
+ jr nz, .loop
+ ret
+
+IntroMoveMon:
+; d = number of times to move the mon (2 pixels each time)
+ ld a, e
+ cp MOVE_NIDORINO_RIGHT
+ jr z, .moveNidorinoRight
+ cp MOVE_GENGAR_LEFT
+ jr z, .moveGengarLeft
+; move Gengar right
+ ld a, [hSCX]
+ dec a
+ dec a
+ jr .next
+.moveNidorinoRight
+ push de
+ ld a, 2
+ ld [wBaseCoordX], a
+ xor a
+ ld [wBaseCoordY], a
+ ld c, 6 * 6
+ call UpdateIntroNidorinoOAM
+ pop de
+.moveGengarLeft
+ ld a, [hSCX]
+ inc a
+ inc a
+.next
+ ld [hSCX], a
+ push de
+ ld c, 2
+ call CheckForUserInterruption
+ pop de
+ ret c
+ dec d
+ jr nz, IntroMoveMon
+ ret
+
+IntroCopyTiles:
+ coord hl, 13, 7
+
+CopyTileIDsFromList_ZeroBaseTileID:
+ ld c, 0
+ predef_jump CopyTileIDsFromList
+
+PlayMoveSoundB:
+; unused
+ predef GetMoveSoundB
+ ld a, b
+ jp PlaySound
+
+LoadIntroGraphics:
+ ld hl, FightIntroBackMon
+ ld de, vChars2
+ ld bc, FightIntroBackMonEnd - FightIntroBackMon
+ ld a, BANK(FightIntroBackMon)
+ call FarCopyData2
+ ld hl, GameFreakIntro
+ ld de, vChars2 + (FightIntroBackMonEnd - FightIntroBackMon)
+ ld bc, GameFreakIntroEnd - GameFreakIntro
+ ld a, BANK(GameFreakIntro)
+ call FarCopyData2
+ ld hl, GameFreakIntro
+ ld de, vChars1
+ ld bc, GameFreakIntroEnd - GameFreakIntro
+ ld a, BANK(GameFreakIntro)
+ call FarCopyData2
+ ld hl, FightIntroFrontMon
+ ld de, vChars0
+ ld bc, FightIntroFrontMonEnd - FightIntroFrontMon
+ ld a, BANK(FightIntroFrontMon)
+ jp FarCopyData2
+
+PlayShootingStar:
+ ld b, SET_PAL_GAME_FREAK_INTRO
+ call RunPaletteCommand
+ callba LoadCopyrightAndTextBoxTiles
+ ldPal a, BLACK, DARK_GRAY, LIGHT_GRAY, WHITE
+ ld [rBGP], a
+ ld c, 180
+ call DelayFrames
+ call ClearScreen
+ call DisableLCD
+ xor a
+ ld [wCurOpponent], a
+ call IntroDrawBlackBars
+ call LoadIntroGraphics
+ call EnableLCD
+ ld hl, rLCDC
+ res 5, [hl]
+ set 3, [hl]
+ ld c, 64
+ call DelayFrames
+ callba AnimateShootingStar
+ push af
+ pop af
+ jr c, .next ; skip the delay if the user interrupted the animation
+ ld c, 40
+ call DelayFrames
+.next
+ ld a, BANK(Music_IntroBattle)
+ ld [wAudioROMBank], a
+ ld [wAudioSavedROMBank], a
+ ld a, MUSIC_INTRO_BATTLE
+ ld [wNewSoundID], a
+ call PlaySound
+ call IntroClearMiddleOfScreen
+ call ClearSprites
+ jp Delay3
+
+IntroDrawBlackBars:
+; clear the screen and draw black bars on the top and bottom
+ call IntroClearScreen
+ coord hl, 0, 0
+ ld c, SCREEN_WIDTH * 4
+ call IntroPlaceBlackTiles
+ coord hl, 0, 14
+ ld c, SCREEN_WIDTH * 4
+ call IntroPlaceBlackTiles
+ ld hl, vBGMap1
+ ld c, BG_MAP_WIDTH * 4
+ call IntroPlaceBlackTiles
+ ld hl, vBGMap1 + BG_MAP_WIDTH * 14
+ ld c, BG_MAP_WIDTH * 4
+ jp IntroPlaceBlackTiles
+
+EmptyFunc4:
+ ret
+
+IntroNidorinoAnimation0:
+ db 0, 0
+ db ANIMATION_END
+
+IntroNidorinoAnimation1:
+; This is a sequence of pixel movements for part of the Nidorino animation. This
+; list describes how Nidorino should hop.
+; First byte is y movement, second byte is x movement
+ db 0, 0
+ db -2, 2
+ db -1, 2
+ db 1, 2
+ db 2, 2
+ db ANIMATION_END
+
+IntroNidorinoAnimation2:
+; This is a sequence of pixel movements for part of the Nidorino animation.
+; First byte is y movement, second byte is x movement
+ db 0, 0
+ db -2, -2
+ db -1, -2
+ db 1, -2
+ db 2, -2
+ db ANIMATION_END
+
+IntroNidorinoAnimation3:
+; This is a sequence of pixel movements for part of the Nidorino animation.
+; First byte is y movement, second byte is x movement
+ db 0, 0
+ db -12, 6
+ db -8, 6
+ db 8, 6
+ db 12, 6
+ db ANIMATION_END
+
+IntroNidorinoAnimation4:
+; This is a sequence of pixel movements for part of the Nidorino animation.
+; First byte is y movement, second byte is x movement
+ db 0, 0
+ db -8, -4
+ db -4, -4
+ db 4, -4
+ db 8, -4
+ db ANIMATION_END
+
+IntroNidorinoAnimation5:
+; This is a sequence of pixel movements for part of the Nidorino animation.
+; First byte is y movement, second byte is x movement
+ db 0, 0
+ db -8, 4
+ db -4, 4
+ db 4, 4
+ db 8, 4
+ db ANIMATION_END
+
+IntroNidorinoAnimation6:
+; This is a sequence of pixel movements for part of the Nidorino animation.
+; First byte is y movement, second byte is x movement
+ db 0, 0
+ db 2, 0
+ db 2, 0
+ db 0, 0
+ db ANIMATION_END
+
+IntroNidorinoAnimation7:
+; This is a sequence of pixel movements for part of the Nidorino animation.
+; First byte is y movement, second byte is x movement
+ db -8, -16
+ db -7, -14
+ db -6, -12
+ db -4, -10
+ db ANIMATION_END
+
+GameFreakIntro:
+ INCBIN "gfx/intro_credits/gamefreak_presents.2bpp"
+ INCBIN "gfx/intro_credits/gamefreak_logo.2bpp"
+ ds 16, $00 ; blank tile
+GameFreakIntroEnd:
+
+FightIntroBackMon:
+ INCBIN "gfx/intro_credits/gengar.2bpp"
+FightIntroBackMonEnd:
+
+FightIntroFrontMon:
+
+IF DEF(_RED)
+ INCBIN "gfx/intro_credits/red_nidorino_1.2bpp"
+FightIntroFrontMon2:
+ INCBIN "gfx/intro_credits/red_nidorino_2.2bpp"
+FightIntroFrontMon3:
+ INCBIN "gfx/intro_credits/red_nidorino_3.2bpp"
+ENDC
+
+IF DEF(_BLUE)
+ INCBIN "gfx/intro_credits/blue_jigglypuff_1.2bpp"
+FightIntroFrontMon2:
+ INCBIN "gfx/intro_credits/blue_jigglypuff_2.2bpp"
+FightIntroFrontMon3:
+ INCBIN "gfx/intro_credits/blue_jigglypuff_3.2bpp"
+ENDC
+
+FightIntroFrontMonEnd:
+
+ ds 16, $00 ; blank tile
--- /dev/null
+++ b/engine/movie/oak_speech/clear_save.asm
@@ -1,0 +1,23 @@
+DoClearSaveDialogue:
+ call ClearScreen
+ call RunDefaultPaletteCommand
+ call LoadFontTilePatterns
+ call LoadTextBoxTilePatterns
+ ld hl, ClearSaveDataText
+ call PrintText
+ coord hl, 14, 7
+ lb bc, 8, 15
+ ld a, NO_YES_MENU
+ ld [wTwoOptionMenuID], a
+ ld a, TWO_OPTION_MENU
+ ld [wTextBoxID], a
+ call DisplayTextBoxID
+ ld a, [wCurrentMenuItem]
+ and a
+ jp z, Init
+ callba ClearSAV
+ jp Init
+
+ClearSaveDataText:
+ TX_FAR _ClearSaveDataText
+ db "@"
--- /dev/null
+++ b/engine/movie/oak_speech/init_player_data.asm
@@ -1,0 +1,55 @@
+InitPlayerData:
+InitPlayerData2:
+
+ call Random
+ ld a, [hRandomSub]
+ ld [wPlayerID], a
+
+ call Random
+ ld a, [hRandomAdd]
+ ld [wPlayerID + 1], a
+
+ ld a, $ff
+ ld [wUnusedD71B], a
+
+ ld hl, wPartyCount
+ call InitializeEmptyList
+ ld hl, wNumInBox
+ call InitializeEmptyList
+ ld hl, wNumBagItems
+ call InitializeEmptyList
+ ld hl, wNumBoxItems
+ call InitializeEmptyList
+
+START_MONEY EQU $3000
+ ld hl, wPlayerMoney + 1
+ ld a, START_MONEY / $100
+ ld [hld], a
+ xor a
+ ld [hli], a
+ inc hl
+ ld [hl], a
+
+ ld [wMonDataLocation], a
+
+ ld hl, wObtainedBadges
+ ld [hli], a
+
+ ld [hl], a
+
+ ld hl, wPlayerCoins
+ ld [hli], a
+ ld [hl], a
+
+ ld hl, wGameProgressFlags
+ ld bc, wGameProgressFlagsEnd - wGameProgressFlags
+ call FillMemory ; clear all game progress flags
+
+ jp InitializeMissableObjectsFlags
+
+InitializeEmptyList:
+ xor a ; count
+ ld [hli], a
+ dec a ; terminator
+ ld [hl], a
+ ret
--- /dev/null
+++ b/engine/movie/oak_speech/oak_speech.asm
@@ -1,0 +1,233 @@
+SetDefaultNames:
+ ld a, [wLetterPrintingDelayFlags]
+ push af
+ ld a, [wOptions]
+ push af
+ ld a, [wd732]
+ push af
+ ld hl, wPlayerName
+ ld bc, wBoxDataEnd - wPlayerName
+ xor a
+ call FillMemory
+ ld hl, wSpriteStateData1
+ ld bc, $200
+ xor a
+ call FillMemory
+ pop af
+ ld [wd732], a
+ pop af
+ ld [wOptions], a
+ pop af
+ ld [wLetterPrintingDelayFlags], a
+ ld a, [wOptionsInitialized]
+ and a
+ call z, InitOptions
+ ld hl, NintenText
+ ld de, wPlayerName
+ ld bc, NAME_LENGTH
+ call CopyData
+ ld hl, SonyText
+ ld de, wRivalName
+ ld bc, NAME_LENGTH
+ jp CopyData
+
+OakSpeech:
+ ld a, $FF
+ call PlaySound ; stop music
+ ld a, BANK(Music_Routes2)
+ ld c, a
+ ld a, MUSIC_ROUTES2
+ call PlayMusic
+ call ClearScreen
+ call LoadTextBoxTilePatterns
+ call SetDefaultNames
+ predef InitPlayerData2
+ ld hl, wNumBoxItems
+ ld a, POTION
+ ld [wcf91], a
+ ld a, 1
+ ld [wItemQuantity], a
+ call AddItemToInventory ; give one potion
+ ld a, [wDefaultMap]
+ ld [wDestinationMap], a
+ call SpecialWarpIn
+ xor a
+ ld [hTilesetType], a
+ ld a, [wd732]
+ bit 1, a ; possibly a debug mode bit
+ jp nz, .skipChoosingNames
+ ld de, ProfOakPic
+ lb bc, Bank(ProfOakPic), $00
+ call IntroDisplayPicCenteredOrUpperRight
+ call FadeInIntroPic
+ ld hl, OakSpeechText1
+ call PrintText
+ call GBFadeOutToWhite
+ call ClearScreen
+ ld a, NIDORINO
+ ld [wd0b5], a
+ ld [wcf91], a
+ call GetMonHeader
+ coord hl, 6, 4
+ call LoadFlippedFrontSpriteByMonIndex
+ call MovePicLeft
+ ld hl, OakSpeechText2
+ call PrintText
+ call GBFadeOutToWhite
+ call ClearScreen
+ ld de, RedPicFront
+ lb bc, Bank(RedPicFront), $00
+ call IntroDisplayPicCenteredOrUpperRight
+ call MovePicLeft
+ ld hl, IntroducePlayerText
+ call PrintText
+ call ChoosePlayerName
+ call GBFadeOutToWhite
+ call ClearScreen
+ ld de, Rival1Pic
+ lb bc, Bank(Rival1Pic), $00
+ call IntroDisplayPicCenteredOrUpperRight
+ call FadeInIntroPic
+ ld hl, IntroduceRivalText
+ call PrintText
+ call ChooseRivalName
+.skipChoosingNames
+ call GBFadeOutToWhite
+ call ClearScreen
+ ld de, RedPicFront
+ lb bc, Bank(RedPicFront), $00
+ call IntroDisplayPicCenteredOrUpperRight
+ call GBFadeInFromWhite
+ ld a, [wd72d]
+ and a
+ jr nz, .next
+ ld hl, OakSpeechText3
+ call PrintText
+.next
+ ld a, [H_LOADEDROMBANK]
+ push af
+ ld a, SFX_SHRINK
+ call PlaySound
+ pop af
+ ld [H_LOADEDROMBANK], a
+ ld [MBC1RomBank], a
+ ld c, 4
+ call DelayFrames
+ ld de, RedSprite
+ ld hl, vSprites
+ lb bc, BANK(RedSprite), $0C
+ call CopyVideoData
+ ld de, ShrinkPic1
+ lb bc, BANK(ShrinkPic1), $00
+ call IntroDisplayPicCenteredOrUpperRight
+ ld c, 4
+ call DelayFrames
+ ld de, ShrinkPic2
+ lb bc, BANK(ShrinkPic2), $00
+ call IntroDisplayPicCenteredOrUpperRight
+ call ResetPlayerSpriteData
+ ld a, [H_LOADEDROMBANK]
+ push af
+ ld a, BANK(Music_PalletTown)
+ ld [wAudioROMBank], a
+ ld [wAudioSavedROMBank], a
+ ld a, 10
+ ld [wAudioFadeOutControl], a
+ ld a, $FF
+ ld [wNewSoundID], a
+ call PlaySound ; stop music
+ pop af
+ ld [H_LOADEDROMBANK], a
+ ld [MBC1RomBank], a
+ ld c, 20
+ call DelayFrames
+ coord hl, 6, 5
+ ld b, 7
+ ld c, 7
+ call ClearScreenArea
+ call LoadTextBoxTilePatterns
+ ld a, 1
+ ld [wUpdateSpritesEnabled], a
+ ld c, 50
+ call DelayFrames
+ call GBFadeOutToWhite
+ jp ClearScreen
+OakSpeechText1:
+ TX_FAR _OakSpeechText1
+ db "@"
+OakSpeechText2:
+ TX_FAR _OakSpeechText2A
+ TX_CRY_NIDORINA
+ TX_FAR _OakSpeechText2B
+ db "@"
+IntroducePlayerText:
+ TX_FAR _IntroducePlayerText
+ db "@"
+IntroduceRivalText:
+ TX_FAR _IntroduceRivalText
+ db "@"
+OakSpeechText3:
+ TX_FAR _OakSpeechText3
+ db "@"
+
+FadeInIntroPic:
+ ld hl, IntroFadePalettes
+ ld b, 6
+.next
+ ld a, [hli]
+ ld [rBGP], a
+ ld c, 10
+ call DelayFrames
+ dec b
+ jr nz, .next
+ ret
+
+IntroFadePalettes:
+ db %01010100
+ db %10101000
+ db %11111100
+ db %11111000
+ db %11110100
+ db %11100100
+
+MovePicLeft:
+ ld a, 119
+ ld [rWX], a
+ call DelayFrame
+
+ ld a, %11100100
+ ld [rBGP], a
+.next
+ call DelayFrame
+ ld a, [rWX]
+ sub 8
+ cp $FF
+ ret z
+ ld [rWX], a
+ jr .next
+
+DisplayPicCenteredOrUpperRight:
+ call GetPredefRegisters
+IntroDisplayPicCenteredOrUpperRight:
+; b = bank
+; de = address of compressed pic
+; c: 0 = centred, non-zero = upper-right
+ push bc
+ ld a, b
+ call UncompressSpriteFromDE
+ ld hl, sSpriteBuffer1
+ ld de, sSpriteBuffer0
+ ld bc, $310
+ call CopyData
+ ld de, vFrontPic
+ call InterlaceMergeSpriteBuffers
+ pop bc
+ ld a, c
+ and a
+ coord hl, 15, 1
+ jr nz, .next
+ coord hl, 6, 4
+.next
+ xor a
+ ld [hStartTileID], a
+ predef_jump CopyUncompressedPicToTilemap
--- /dev/null
+++ b/engine/movie/oak_speech/oak_speech2.asm
@@ -1,0 +1,219 @@
+ChoosePlayerName:
+ call OakSpeechSlidePicRight
+ ld de, DefaultNamesPlayer
+ call DisplayIntroNameTextBox
+ ld a, [wCurrentMenuItem]
+ and a
+ jr z, .customName
+ ld hl, DefaultNamesPlayerList
+ call GetDefaultName
+ ld de, wPlayerName
+ call OakSpeechSlidePicLeft
+ jr .done
+.customName
+ ld hl, wPlayerName
+ xor a ; NAME_PLAYER_SCREEN
+ ld [wNamingScreenType], a
+ call DisplayNamingScreen
+ ld a, [wcf4b]
+ cp "@"
+ jr z, .customName
+ call ClearScreen
+ call Delay3
+ ld de, RedPicFront
+ ld b, BANK(RedPicFront)
+ call IntroDisplayPicCenteredOrUpperRight
+.done
+ ld hl, YourNameIsText
+ jp PrintText
+
+YourNameIsText:
+ TX_FAR _YourNameIsText
+ db "@"
+
+ChooseRivalName:
+ call OakSpeechSlidePicRight
+ ld de, DefaultNamesRival
+ call DisplayIntroNameTextBox
+ ld a, [wCurrentMenuItem]
+ and a
+ jr z, .customName
+ ld hl, DefaultNamesRivalList
+ call GetDefaultName
+ ld de, wRivalName
+ call OakSpeechSlidePicLeft
+ jr .done
+.customName
+ ld hl, wRivalName
+ ld a, NAME_RIVAL_SCREEN
+ ld [wNamingScreenType], a
+ call DisplayNamingScreen
+ ld a, [wcf4b]
+ cp "@"
+ jr z, .customName
+ call ClearScreen
+ call Delay3
+ ld de, Rival1Pic
+ ld b, $13
+ call IntroDisplayPicCenteredOrUpperRight
+.done
+ ld hl, HisNameIsText
+ jp PrintText
+
+HisNameIsText:
+ TX_FAR _HisNameIsText
+ db "@"
+
+OakSpeechSlidePicLeft:
+ push de
+ coord hl, 0, 0
+ lb bc, 12, 11
+ call ClearScreenArea ; clear the name list text box
+ ld c, 10
+ call DelayFrames
+ pop de
+ ld hl, wcd6d
+ ld bc, NAME_LENGTH
+ call CopyData
+ call Delay3
+ coord hl, 12, 4
+ lb de, 6, 6 * SCREEN_WIDTH + 5
+ ld a, $ff
+ jr OakSpeechSlidePicCommon
+
+OakSpeechSlidePicRight:
+ coord hl, 5, 4
+ lb de, 6, 6 * SCREEN_WIDTH + 5
+ xor a
+
+OakSpeechSlidePicCommon:
+ push hl
+ push de
+ push bc
+ ld [hSlideDirection], a
+ ld a, d
+ ld [hSlideAmount], a
+ ld a, e
+ ld [hSlidingRegionSize], a
+ ld c, a
+ ld a, [hSlideDirection]
+ and a
+ jr nz, .next
+; If sliding right, point hl to the end of the pic's tiles.
+ ld d, 0
+ add hl, de
+.next
+ ld d, h
+ ld e, l
+.loop
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ ld a, [hSlideDirection]
+ and a
+ jr nz, .slideLeft
+; sliding right
+ ld a, [hli]
+ ld [hld], a
+ dec hl
+ jr .next2
+.slideLeft
+ ld a, [hld]
+ ld [hli], a
+ inc hl
+.next2
+ dec c
+ jr nz, .loop
+ ld a, [hSlideDirection]
+ and a
+ jr z, .next3
+; If sliding left, we need to zero the last tile in the pic (there is no need
+; to take a corresponding action when sliding right because hl initially points
+; to a 0 tile in that case).
+ xor a
+ dec hl
+ ld [hl], a
+.next3
+ ld a, 1
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call Delay3
+ ld a, [hSlidingRegionSize]
+ ld c, a
+ ld h, d
+ ld l, e
+ ld a, [hSlideDirection]
+ and a
+ jr nz, .slideLeft2
+ inc hl
+ jr .next4
+.slideLeft2
+ dec hl
+.next4
+ ld d, h
+ ld e, l
+ ld a, [hSlideAmount]
+ dec a
+ ld [hSlideAmount], a
+ jr nz, .loop
+ pop bc
+ pop de
+ pop hl
+ ret
+
+DisplayIntroNameTextBox:
+ push de
+ coord hl, 0, 0
+ ld b, $a
+ ld c, $9
+ call TextBoxBorder
+ coord hl, 3, 0
+ ld de, .namestring
+ call PlaceString
+ pop de
+ coord hl, 2, 2
+ call PlaceString
+ call UpdateSprites
+ xor a
+ ld [wCurrentMenuItem], a
+ ld [wLastMenuItem], a
+ inc a
+ ld [wTopMenuItemX], a
+ ld [wMenuWatchedKeys], a ; A_BUTTON
+ inc a
+ ld [wTopMenuItemY], a
+ inc a
+ ld [wMaxMenuItem], a
+ jp HandleMenuInput
+
+.namestring
+ db "NAME@"
+
+INCLUDE "text/player_names.asm"
+
+GetDefaultName:
+; a = name index
+; hl = name list
+ ld b, a
+ ld c, 0
+.loop
+ ld d, h
+ ld e, l
+.innerLoop
+ ld a, [hli]
+ cp "@"
+ jr nz, .innerLoop
+ ld a, b
+ cp c
+ jr z, .foundName
+ inc c
+ jr .loop
+.foundName
+ ld h, d
+ ld l, e
+ ld de, wcd6d
+ ld bc, $14
+ jp CopyData
+
+INCLUDE "text/player_names_list.asm"
+
+TextTerminator_6b20:
+ db "@"
--- /dev/null
+++ b/engine/movie/titlescreen.asm
@@ -1,0 +1,403 @@
+; copy text of fixed length NAME_LENGTH (like player name, rival name, mon names, ...)
+CopyFixedLengthText:
+ ld bc, NAME_LENGTH
+ jp CopyData
+
+SetDefaultNamesBeforeTitlescreen::
+ ld hl, NintenText
+ ld de, wPlayerName
+ call CopyFixedLengthText
+ ld hl, SonyText
+ ld de, wRivalName
+ call CopyFixedLengthText
+ xor a
+ ld [hWY], a
+ ld [wLetterPrintingDelayFlags], a
+ ld hl, wd732
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+ ld a, BANK(Music_TitleScreen)
+ ld [wAudioROMBank], a
+ ld [wAudioSavedROMBank], a
+
+DisplayTitleScreen:
+ call GBPalWhiteOut
+ ld a, $1
+ ld [H_AUTOBGTRANSFERENABLED], a
+ xor a
+ ld [hTilesetType], a
+ ld [hSCX], a
+ ld a, $40
+ ld [hSCY], a
+ ld a, $90
+ ld [hWY], a
+ call ClearScreen
+ call DisableLCD
+ call LoadFontTilePatterns
+ ld hl, NintendoCopyrightLogoGraphics
+ ld de, vTitleLogo2 + $100
+ ld bc, $50
+ ld a, BANK(NintendoCopyrightLogoGraphics)
+ call FarCopyData2
+ ld hl, GamefreakLogoGraphics
+ ld de, vTitleLogo2 + $100 + $50
+ ld bc, $90
+ ld a, BANK(GamefreakLogoGraphics)
+ call FarCopyData2
+ ld hl, PokemonLogoGraphics
+ ld de, vTitleLogo
+ ld bc, $600
+ ld a, BANK(PokemonLogoGraphics)
+ call FarCopyData2 ; first chunk
+ ld hl, PokemonLogoGraphics+$600
+ ld de, vTitleLogo2
+ ld bc, $100
+ ld a, BANK(PokemonLogoGraphics)
+ call FarCopyData2 ; second chunk
+ ld hl, Version_GFX
+ ld de, vChars2 + $600 - (Version_GFXEnd - Version_GFX - $50)
+ ld bc, Version_GFXEnd - Version_GFX
+ ld a, BANK(Version_GFX)
+ call FarCopyDataDouble
+ call ClearBothBGMaps
+
+; place tiles for pokemon logo (except for the last row)
+ coord hl, 2, 1
+ ld a, $80
+ ld de, SCREEN_WIDTH
+ ld c, 6
+.pokemonLogoTileLoop
+ ld b, $10
+ push hl
+.pokemonLogoTileRowLoop ; place tiles for one row
+ ld [hli], a
+ inc a
+ dec b
+ jr nz, .pokemonLogoTileRowLoop
+ pop hl
+ add hl, de
+ dec c
+ jr nz, .pokemonLogoTileLoop
+
+; place tiles for the last row of the pokemon logo
+ coord hl, 2, 7
+ ld a, $31
+ ld b, $10
+.pokemonLogoLastTileRowLoop
+ ld [hli], a
+ inc a
+ dec b
+ jr nz, .pokemonLogoLastTileRowLoop
+
+ call DrawPlayerCharacter
+
+; put a pokeball in the player's hand
+ ld hl, wOAMBuffer + $28
+ ld a, $74
+ ld [hl], a
+
+; place tiles for title screen copyright
+ coord hl, 2, 17
+ ld de, .tileScreenCopyrightTiles
+ ld b, $10
+.tileScreenCopyrightTilesLoop
+ ld a, [de]
+ ld [hli], a
+ inc de
+ dec b
+ jr nz, .tileScreenCopyrightTilesLoop
+
+ jr .next
+
+.tileScreenCopyrightTiles
+ db $41,$42,$43,$42,$44,$42,$45,$46,$47,$48,$49,$4A,$4B,$4C,$4D,$4E ; ©'95.'96.'98 GAME FREAK inc.
+
+.next
+ call SaveScreenTilesToBuffer2
+ call LoadScreenTilesFromBuffer2
+ call EnableLCD
+IF DEF(_RED)
+ ld a, CHARMANDER ; which Pokemon to show first on the title screen
+ENDC
+IF DEF(_BLUE)
+ ld a, SQUIRTLE ; which Pokemon to show first on the title screen
+ENDC
+
+ ld [wTitleMonSpecies], a
+ call LoadTitleMonSprite
+ ld a, (vBGMap0 + $300) / $100
+ call TitleScreenCopyTileMapToVRAM
+ call SaveScreenTilesToBuffer1
+ ld a, $40
+ ld [hWY], a
+ call LoadScreenTilesFromBuffer2
+ ld a, vBGMap0 / $100
+ call TitleScreenCopyTileMapToVRAM
+ ld b, SET_PAL_TITLE_SCREEN
+ call RunPaletteCommand
+ call GBPalNormal
+ ld a, %11100100
+ ld [rOBP0], a
+
+; make pokemon logo bounce up and down
+ ld bc, hSCY ; background scroll Y
+ ld hl, .TitleScreenPokemonLogoYScrolls
+.bouncePokemonLogoLoop
+ ld a, [hli]
+ and a
+ jr z, .finishedBouncingPokemonLogo
+ ld d, a
+ cp -3
+ jr nz, .skipPlayingSound
+ ld a, SFX_INTRO_CRASH
+ call PlaySound
+.skipPlayingSound
+ ld a, [hli]
+ ld e, a
+ call .ScrollTitleScreenPokemonLogo
+ jr .bouncePokemonLogoLoop
+
+.TitleScreenPokemonLogoYScrolls:
+; Controls the bouncing effect of the Pokemon logo on the title screen
+ db -4,16 ; y scroll amount, number of times to scroll
+ db 3,4
+ db -3,4
+ db 2,2
+ db -2,2
+ db 1,2
+ db -1,2
+ db 0 ; terminate list with 0
+
+.ScrollTitleScreenPokemonLogo:
+; Scrolls the Pokemon logo on the title screen to create the bouncing effect
+; Scrolls d pixels e times
+ call DelayFrame
+ ld a, [bc] ; background scroll Y
+ add d
+ ld [bc], a
+ dec e
+ jr nz, .ScrollTitleScreenPokemonLogo
+ ret
+
+.finishedBouncingPokemonLogo
+ call LoadScreenTilesFromBuffer1
+ ld c, 36
+ call DelayFrames
+ ld a, SFX_INTRO_WHOOSH
+ call PlaySound
+
+; scroll game version in from the right
+ call PrintGameVersionOnTitleScreen
+ ld a, SCREEN_HEIGHT_PIXELS
+ ld [hWY], a
+ ld d, 144
+.scrollTitleScreenGameVersionLoop
+ ld h, d
+ ld l, 64
+ call ScrollTitleScreenGameVersion
+ ld h, 0
+ ld l, 80
+ call ScrollTitleScreenGameVersion
+ ld a, d
+ add 4
+ ld d, a
+ and a
+ jr nz, .scrollTitleScreenGameVersionLoop
+
+ ld a, vBGMap1 / $100
+ call TitleScreenCopyTileMapToVRAM
+ call LoadScreenTilesFromBuffer2
+ call PrintGameVersionOnTitleScreen
+ call Delay3
+ call WaitForSoundToFinish
+ ld a, MUSIC_TITLE_SCREEN
+ ld [wNewSoundID], a
+ call PlaySound
+ xor a
+ ld [wUnusedCC5B], a
+
+; Keep scrolling in new mons indefinitely until the user performs input.
+.awaitUserInterruptionLoop
+ ld c, 200
+ call CheckForUserInterruption
+ jr c, .finishedWaiting
+ call TitleScreenScrollInMon
+ ld c, 1
+ call CheckForUserInterruption
+ jr c, .finishedWaiting
+ callba TitleScreenAnimateBallIfStarterOut
+ call TitleScreenPickNewMon
+ jr .awaitUserInterruptionLoop
+
+.finishedWaiting
+ ld a, [wTitleMonSpecies]
+ call PlayCry
+ call WaitForSoundToFinish
+ call GBPalWhiteOutWithDelay3
+ call ClearSprites
+ xor a
+ ld [hWY], a
+ inc a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call ClearScreen
+ ld a, vBGMap0 / $100
+ call TitleScreenCopyTileMapToVRAM
+ ld a, vBGMap1 / $100
+ call TitleScreenCopyTileMapToVRAM
+ call Delay3
+ call LoadGBPal
+ ld a, [hJoyHeld]
+ ld b, a
+ and D_UP | SELECT | B_BUTTON
+ cp D_UP | SELECT | B_BUTTON
+ jp z, .doClearSaveDialogue
+ jp MainMenu
+
+.doClearSaveDialogue
+ jpba DoClearSaveDialogue
+
+TitleScreenPickNewMon:
+ ld a, vBGMap0 / $100
+ call TitleScreenCopyTileMapToVRAM
+
+.loop
+; Keep looping until a mon different from the current one is picked.
+ call Random
+ and $f
+ ld c, a
+ ld b, 0
+ ld hl, TitleMons
+ add hl, bc
+ ld a, [hl]
+ ld hl, wTitleMonSpecies
+
+; Can't be the same as before.
+ cp [hl]
+ jr z, .loop
+
+ ld [hl], a
+ call LoadTitleMonSprite
+
+ ld a, $90
+ ld [hWY], a
+ ld d, 1 ; scroll out
+ callba TitleScroll
+ ret
+
+TitleScreenScrollInMon:
+ ld d, 0 ; scroll in
+ callba TitleScroll
+ xor a
+ ld [hWY], a
+ ret
+
+ScrollTitleScreenGameVersion:
+.wait
+ ld a, [rLY]
+ cp l
+ jr nz, .wait
+
+ ld a, h
+ ld [rSCX], a
+
+.wait2
+ ld a, [rLY]
+ cp h
+ jr z, .wait2
+ ret
+
+DrawPlayerCharacter:
+ ld hl, PlayerCharacterTitleGraphics
+ ld de, vSprites
+ ld bc, PlayerCharacterTitleGraphicsEnd - PlayerCharacterTitleGraphics
+ ld a, BANK(PlayerCharacterTitleGraphics)
+ call FarCopyData2
+ call ClearSprites
+ xor a
+ ld [wPlayerCharacterOAMTile], a
+ ld hl, wOAMBuffer
+ ld de, $605a
+ ld b, 7
+.loop
+ push de
+ ld c, 5
+.innerLoop
+ ld a, d
+ ld [hli], a ; Y
+ ld a, e
+ ld [hli], a ; X
+ add 8
+ ld e, a
+ ld a, [wPlayerCharacterOAMTile]
+ ld [hli], a ; tile
+ inc a
+ ld [wPlayerCharacterOAMTile], a
+ inc hl
+ dec c
+ jr nz, .innerLoop
+ pop de
+ ld a, 8
+ add d
+ ld d, a
+ dec b
+ jr nz, .loop
+ ret
+
+ClearBothBGMaps:
+ ld hl, vBGMap0
+ ld bc, $400 * 2
+ ld a, " "
+ jp FillMemory
+
+LoadTitleMonSprite:
+ ld [wcf91], a
+ ld [wd0b5], a
+ coord hl, 5, 10
+ call GetMonHeader
+ jp LoadFrontSpriteByMonIndex
+
+TitleScreenCopyTileMapToVRAM:
+ ld [H_AUTOBGTRANSFERDEST + 1], a
+ jp Delay3
+
+LoadCopyrightAndTextBoxTiles:
+ xor a
+ ld [hWY], a
+ call ClearScreen
+ call LoadTextBoxTilePatterns
+
+LoadCopyrightTiles:
+ ld de, NintendoCopyrightLogoGraphics
+ ld hl, vChars2 + $600
+ lb bc, BANK(NintendoCopyrightLogoGraphics), (GamefreakLogoGraphicsEnd - NintendoCopyrightLogoGraphics) / $10
+ call CopyVideoData
+ coord hl, 2, 7
+ ld de, CopyrightTextString
+ jp PlaceString
+
+CopyrightTextString:
+ db $60,$61,$62,$61,$63,$61,$64,$7F,$65,$66,$67,$68,$69,$6A ; ©'95.'96.'98 Nintendo
+ next $60,$61,$62,$61,$63,$61,$64,$7F,$6B,$6C,$6D,$6E,$6F,$70,$71,$72 ; ©'95.'96.'98 Creatures inc.
+ next $60,$61,$62,$61,$63,$61,$64,$7F,$73,$74,$75,$76,$77,$78,$79,$7A,$7B ; ©'95.'96.'98 GAME FREAK inc.
+ db "@"
+
+INCLUDE "data/title_mons.asm"
+
+; prints version text (red, blue)
+PrintGameVersionOnTitleScreen:
+ coord hl, 7, 8
+ ld de, VersionOnTitleScreenText
+ jp PlaceString
+
+; these point to special tiles specifically loaded for that purpose and are not usual text
+VersionOnTitleScreenText:
+IF DEF(_RED)
+ db $60,$61,$7F,$65,$66,$67,$68,$69,"@" ; "Red Version"
+ENDC
+IF DEF(_BLUE)
+ db $61,$62,$63,$64,$65,$66,$67,$68,"@" ; "Blue Version"
+ENDC
+
+NintenText: db "NINTEN@"
+SonyText: db "SONY@"
--- /dev/null
+++ b/engine/movie/titlescreen2.asm
@@ -1,0 +1,120 @@
+TitleScroll_WaitBall:
+; Wait around for the TitleBall animation to play out.
+; hi: speed
+; lo: duration
+ db $05, $05, 0
+
+TitleScroll_In:
+; Scroll a TitleMon in from the right.
+; hi: speed
+; lo: duration
+ db $a2, $94, $84, $63, $52, $31, $11, 0
+
+TitleScroll_Out:
+; Scroll a TitleMon out to the left.
+; hi: speed
+; lo: duration
+ db $12, $22, $32, $42, $52, $62, $83, $93, 0
+
+TitleScroll:
+ ld a, d
+
+ ld bc, TitleScroll_In
+ ld d, $88
+ ld e, 0 ; don't animate titleball
+
+ and a
+ jr nz, .ok
+
+ ld bc, TitleScroll_Out
+ ld d, $00
+ ld e, 0 ; don't animate titleball
+.ok
+
+_TitleScroll:
+ ld a, [bc]
+ and a
+ ret z
+
+ inc bc
+ push bc
+
+ ld b, a
+ and $f
+ ld c, a
+ ld a, b
+ and $f0
+ swap a
+ ld b, a
+
+.loop
+ ld h, d
+ ld l, $48
+ call .ScrollBetween
+
+ ld h, $00
+ ld l, $88
+ call .ScrollBetween
+
+ ld a, d
+ add b
+ ld d, a
+
+ call GetTitleBallY
+ dec c
+ jr nz, .loop
+
+ pop bc
+ jr _TitleScroll
+
+.ScrollBetween:
+.wait
+ ld a, [rLY] ; rLY
+ cp l
+ jr nz, .wait
+
+ ld a, h
+ ld [rSCX], a
+
+.wait2
+ ld a, [rLY] ; rLY
+ cp h
+ jr z, .wait2
+ ret
+
+TitleBallYTable:
+; OBJ y-positions for the Poke Ball held by Red in the title screen.
+; This is really two 0-terminated lists. Initiated with an index of 1.
+ db 0, $71, $6f, $6e, $6d, $6c, $6d, $6e, $6f, $71, $74, 0
+
+TitleScreenAnimateBallIfStarterOut:
+; Animate the TitleBall if a starter just got scrolled out.
+ ld a, [wTitleMonSpecies]
+ cp STARTER1
+ jr z, .ok
+ cp STARTER2
+ jr z, .ok
+ cp STARTER3
+ ret nz
+.ok
+ ld e, 1 ; animate titleball
+ ld bc, TitleScroll_WaitBall
+ ld d, 0
+ jp _TitleScroll
+
+GetTitleBallY:
+; Get position e from TitleBallYTable
+ push de
+ push hl
+ xor a
+ ld d, a
+ ld hl, TitleBallYTable
+ add hl, de
+ ld a, [hl]
+ pop hl
+ pop de
+ and a
+ ret z
+ ld [wOAMBuffer + $28], a
+ inc e
+ ret
--- /dev/null
+++ b/engine/movie/trade.asm
@@ -1,0 +1,853 @@
+InternalClockTradeAnim:
+; Do the trading animation with the player's gameboy on the left.
+; In-game trades and internally clocked link cable trades use this.
+ ld a, [wTradedPlayerMonSpecies]
+ ld [wLeftGBMonSpecies], a
+ ld a, [wTradedEnemyMonSpecies]
+ ld [wRightGBMonSpecies], a
+ ld de, InternalClockTradeFuncSequence
+ jr TradeAnimCommon
+
+ExternalClockTradeAnim:
+; Do the trading animation with the player's gameboy on the right.
+; Externally clocked link cable trades use this.
+ ld a, [wTradedEnemyMonSpecies]
+ ld [wLeftGBMonSpecies], a
+ ld a, [wTradedPlayerMonSpecies]
+ ld [wRightGBMonSpecies], a
+ ld de, ExternalClockTradeFuncSequence
+
+TradeAnimCommon:
+ ld a, [wOptions]
+ push af
+ ld a, [hSCY]
+ push af
+ ld a, [hSCX]
+ push af
+ xor a
+ ld [wOptions], a
+ ld [hSCY], a
+ ld [hSCX], a
+ push de
+.loop
+ pop de
+ ld a, [de]
+ cp $ff
+ jr z, .done
+ inc de
+ push de
+ ld hl, TradeFuncPointerTable
+ add a
+ ld c, a
+ ld b, $0
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, .loop
+ push de
+ jp hl ; call trade func, which will return to the top of the loop
+.done
+ pop af
+ ld [hSCX], a
+ pop af
+ ld [hSCY], a
+ pop af
+ ld [wOptions], a
+ ret
+
+addtradefunc: MACRO
+\1TradeFunc::
+ dw \1
+ ENDM
+
+tradefunc: MACRO
+ db (\1TradeFunc - TradeFuncPointerTable) / 2
+ ENDM
+
+; The functions in the sequences below are executed in order by TradeFuncCommon.
+; They are from opposite perspectives. The external clock one makes use of
+; Trade_SwapNames to swap the player and enemy names for some functions.
+
+InternalClockTradeFuncSequence:
+ tradefunc LoadTradingGFXAndMonNames
+ tradefunc Trade_ShowPlayerMon
+ tradefunc Trade_DrawOpenEndOfLinkCable
+ tradefunc Trade_AnimateBallEnteringLinkCable
+ tradefunc Trade_AnimLeftToRight
+ tradefunc Trade_Delay100
+ tradefunc Trade_ShowClearedWindow
+ tradefunc PrintTradeWentToText
+ tradefunc PrintTradeForSendsText
+ tradefunc PrintTradeFarewellText
+ tradefunc Trade_AnimRightToLeft
+ tradefunc Trade_ShowClearedWindow
+ tradefunc Trade_DrawOpenEndOfLinkCable
+ tradefunc Trade_ShowEnemyMon
+ tradefunc Trade_Delay100
+ tradefunc Trade_Cleanup
+ db $FF
+
+ExternalClockTradeFuncSequence:
+ tradefunc LoadTradingGFXAndMonNames
+ tradefunc Trade_ShowClearedWindow
+ tradefunc PrintTradeWillTradeText
+ tradefunc PrintTradeFarewellText
+ tradefunc Trade_SwapNames
+ tradefunc Trade_AnimLeftToRight
+ tradefunc Trade_SwapNames
+ tradefunc Trade_ShowClearedWindow
+ tradefunc Trade_DrawOpenEndOfLinkCable
+ tradefunc Trade_ShowEnemyMon
+ tradefunc Trade_SlideTextBoxOffScreen
+ tradefunc Trade_ShowPlayerMon
+ tradefunc Trade_DrawOpenEndOfLinkCable
+ tradefunc Trade_AnimateBallEnteringLinkCable
+ tradefunc Trade_SwapNames
+ tradefunc Trade_AnimRightToLeft
+ tradefunc Trade_SwapNames
+ tradefunc Trade_Delay100
+ tradefunc Trade_ShowClearedWindow
+ tradefunc PrintTradeWentToText
+ tradefunc Trade_Cleanup
+ db $FF
+
+TradeFuncPointerTable:
+ addtradefunc LoadTradingGFXAndMonNames
+ addtradefunc Trade_ShowPlayerMon
+ addtradefunc Trade_DrawOpenEndOfLinkCable
+ addtradefunc Trade_AnimateBallEnteringLinkCable
+ addtradefunc Trade_ShowEnemyMon
+ addtradefunc Trade_AnimLeftToRight
+ addtradefunc Trade_AnimRightToLeft
+ addtradefunc Trade_Delay100
+ addtradefunc Trade_ShowClearedWindow
+ addtradefunc PrintTradeWentToText
+ addtradefunc PrintTradeForSendsText
+ addtradefunc PrintTradeFarewellText
+ addtradefunc PrintTradeTakeCareText
+ addtradefunc PrintTradeWillTradeText
+ addtradefunc Trade_Cleanup
+ addtradefunc Trade_SlideTextBoxOffScreen
+ addtradefunc Trade_SwapNames
+
+Trade_Delay100:
+ ld c, 100
+ jp DelayFrames
+
+Trade_CopyTileMapToVRAM:
+ ld a, $1
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call Delay3
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ ret
+
+Trade_Delay80:
+ ld c, 80
+ jp DelayFrames
+
+Trade_ClearTileMap:
+ coord hl, 0, 0
+ ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+ ld a, " "
+ jp FillMemory
+
+LoadTradingGFXAndMonNames:
+ call Trade_ClearTileMap
+ call DisableLCD
+ ld hl, TradingAnimationGraphics
+ ld de, vChars2 + $310
+ ld bc, TradingAnimationGraphicsEnd - TradingAnimationGraphics
+ ld a, BANK(TradingAnimationGraphics)
+ call FarCopyData2
+ ld hl, TradingAnimationGraphics2
+ ld de, vSprites + $7c0
+ ld bc, TradingAnimationGraphics2End - TradingAnimationGraphics2
+ ld a, BANK(TradingAnimationGraphics2)
+ call FarCopyData2
+ ld hl, vBGMap0
+ ld bc, $800
+ ld a, " "
+ call FillMemory
+ call ClearSprites
+ ld a, $ff
+ ld [wUpdateSpritesEnabled], a
+ ld hl, wd730
+ set 6, [hl] ; turn on instant text printing
+ ld a, [wOnSGB]
+ and a
+ ld a, $e4 ; non-SGB OBP0
+ jr z, .next
+ ld a, $f0 ; SGB OBP0
+.next
+ ld [rOBP0], a
+ call EnableLCD
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ ld a, [wTradedPlayerMonSpecies]
+ ld [wd11e], a
+ call GetMonName
+ ld hl, wcd6d
+ ld de, wcf4b
+ ld bc, NAME_LENGTH
+ call CopyData
+ ld a, [wTradedEnemyMonSpecies]
+ ld [wd11e], a
+ jp GetMonName
+
+Trade_LoadMonPartySpriteGfx:
+ ld a, %11010000
+ ld [rOBP1], a
+ jpba LoadMonPartySpriteGfx
+
+Trade_SwapNames:
+ ld hl, wPlayerName
+ ld de, wBuffer
+ ld bc, NAME_LENGTH
+ call CopyData
+ ld hl, wLinkEnemyTrainerName
+ ld de, wPlayerName
+ ld bc, NAME_LENGTH
+ call CopyData
+ ld hl, wBuffer
+ ld de, wLinkEnemyTrainerName
+ ld bc, NAME_LENGTH
+ jp CopyData
+
+Trade_Cleanup:
+ xor a
+ call LoadGBPal
+ ld hl, wd730
+ res 6, [hl] ; turn off instant text printing
+ ret
+
+Trade_ShowPlayerMon:
+ ld a, %10101011
+ ld [rLCDC], a
+ ld a, $50
+ ld [hWY], a
+ ld a, $86
+ ld [rWX], a
+ ld [hSCX], a
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ coord hl, 4, 0
+ ld b, 6
+ ld c, 10
+ call TextBoxBorder
+ call Trade_PrintPlayerMonInfoText
+ ld b, vBGMap0 / $100
+ call CopyScreenTileBufferToVRAM
+ call ClearScreen
+ ld a, [wTradedPlayerMonSpecies]
+ call Trade_LoadMonSprite
+ ld a, $7e
+.slideScreenLoop
+ push af
+ call DelayFrame
+ pop af
+ ld [rWX], a
+ ld [hSCX], a
+ dec a
+ dec a
+ and a
+ jr nz, .slideScreenLoop
+ call Trade_Delay80
+ ld a, TRADE_BALL_POOF_ANIM
+ call Trade_ShowAnimation
+ ld a, TRADE_BALL_DROP_ANIM
+ call Trade_ShowAnimation ; clears mon pic
+ ld a, [wTradedPlayerMonSpecies]
+ call PlayCry
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ ret
+
+Trade_DrawOpenEndOfLinkCable:
+ call Trade_ClearTileMap
+ ld b, vBGMap0 / $100
+ call CopyScreenTileBufferToVRAM
+ ld b, SET_PAL_GENERIC
+ call RunPaletteCommand
+
+; This function call is pointless. It just copies blank tiles to VRAM that was
+; already filled with blank tiles.
+ ld hl, vBGMap1 + $8c
+ call Trade_CopyCableTilesOffScreen
+
+ ld a, $a0
+ ld [hSCX], a
+ call DelayFrame
+ ld a, %10001011
+ ld [rLCDC], a
+ coord hl, 6, 2
+ ld b, $7 ; open end of link cable tile ID list index
+ call CopyTileIDsFromList_ZeroBaseTileID
+ call Trade_CopyTileMapToVRAM
+ ld a, SFX_HEAL_HP
+ call PlaySound
+ ld c, 20
+.loop
+ ld a, [hSCX]
+ add 4
+ ld [hSCX], a
+ dec c
+ jr nz, .loop
+ ret
+
+Trade_AnimateBallEnteringLinkCable:
+ ld a, TRADE_BALL_SHAKE_ANIM
+ call Trade_ShowAnimation
+ ld c, 10
+ call DelayFrames
+ ld a, %11100100
+ ld [rOBP0], a
+ xor a
+ ld [wLinkCableAnimBulgeToggle], a
+ lb bc, $20, $60
+.moveBallInsideLinkCableLoop
+ push bc
+ xor a
+ ld de, Trade_BallInsideLinkCableOAM
+ call WriteOAMBlock
+ ld a, [wLinkCableAnimBulgeToggle]
+ xor $1
+ ld [wLinkCableAnimBulgeToggle], a
+ add $7e
+ ld hl, wOAMBuffer + $02
+ ld de, 4
+ ld c, e
+.cycleLinkCableBulgeTile
+ ld [hl], a
+ add hl, de
+ dec c
+ jr nz, .cycleLinkCableBulgeTile
+ call Delay3
+ pop bc
+ ld a, c
+ add $4
+ ld c, a
+ cp $a0
+ jr nc, .ballSpriteReachedEdgeOfScreen
+ ld a, SFX_TINK
+ call PlaySound
+ jr .moveBallInsideLinkCableLoop
+.ballSpriteReachedEdgeOfScreen
+ call ClearSprites
+ ld a, $1
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call ClearScreen
+ ld b, $98
+ call CopyScreenTileBufferToVRAM
+ call Delay3
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ ret
+
+Trade_BallInsideLinkCableOAM:
+ db $7E,$00,$7E,$20
+ db $7E,$40,$7E,$60
+
+Trade_ShowEnemyMon:
+ ld a, TRADE_BALL_TILT_ANIM
+ call Trade_ShowAnimation
+ call Trade_ShowClearedWindow
+ coord hl, 4, 10
+ ld b, 6
+ ld c, 10
+ call TextBoxBorder
+ call Trade_PrintEnemyMonInfoText
+ call Trade_CopyTileMapToVRAM
+ ld a, $1
+ ld [H_AUTOBGTRANSFERENABLED], a
+ ld a, [wTradedEnemyMonSpecies]
+ call Trade_LoadMonSprite
+ ld a, TRADE_BALL_POOF_ANIM
+ call Trade_ShowAnimation
+ ld a, $1
+ ld [H_AUTOBGTRANSFERENABLED], a
+ ld a, [wTradedEnemyMonSpecies]
+ call PlayCry
+ call Trade_Delay100
+ coord hl, 4, 10
+ lb bc, 8, 12
+ call ClearScreenArea
+ jp PrintTradeTakeCareText
+
+Trade_AnimLeftToRight:
+; Animates the mon moving from the left GB to the right one.
+ call Trade_InitGameboyTransferGfx
+ ld a, $1
+ ld [wTradedMonMovingRight], a
+ ld a, %11100100
+ ld [rOBP0], a
+ ld a, $54
+ ld [wBaseCoordX], a
+ ld a, $1c
+ ld [wBaseCoordY], a
+ ld a, [wLeftGBMonSpecies]
+ ld [wMonPartySpriteSpecies], a
+ call Trade_WriteCircledMonOAM
+ call Trade_DrawLeftGameboy
+ call Trade_CopyTileMapToVRAM
+ call Trade_DrawCableAcrossScreen
+ ld hl, vBGMap1 + $8c
+ call Trade_CopyCableTilesOffScreen
+ ld b, $6
+ call Trade_AnimMonMoveHorizontal
+ ld a, $1
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call Trade_DrawCableAcrossScreen
+ ld b, $4
+ call Trade_AnimMonMoveHorizontal
+ call Trade_DrawRightGameboy
+ ld b, $6
+ call Trade_AnimMonMoveHorizontal
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call Trade_AnimMonMoveVertical
+ jp ClearSprites
+
+Trade_AnimRightToLeft:
+; Animates the mon moving from the right GB to the left one.
+ call Trade_InitGameboyTransferGfx
+ xor a
+ ld [wTradedMonMovingRight], a
+ ld a, $64
+ ld [wBaseCoordX], a
+ ld a, $44
+ ld [wBaseCoordY], a
+ ld a, [wRightGBMonSpecies]
+ ld [wMonPartySpriteSpecies], a
+ call Trade_WriteCircledMonOAM
+ call Trade_DrawRightGameboy
+ call Trade_CopyTileMapToVRAM
+ call Trade_DrawCableAcrossScreen
+ ld hl, vBGMap1 + $94
+ call Trade_CopyCableTilesOffScreen
+ call Trade_AnimMonMoveVertical
+ ld b, $6
+ call Trade_AnimMonMoveHorizontal
+ ld a, $1
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call Trade_DrawCableAcrossScreen
+ ld b, $4
+ call Trade_AnimMonMoveHorizontal
+ call Trade_DrawLeftGameboy
+ ld b, $6
+ call Trade_AnimMonMoveHorizontal
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ jp ClearSprites
+
+Trade_InitGameboyTransferGfx:
+; Initialises the graphics for showing a mon moving between gameboys.
+ ld a, $1
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call ClearScreen
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call Trade_LoadMonPartySpriteGfx
+ call DelayFrame
+ ld a, %10101011
+ ld [rLCDC], a
+ xor a
+ ld [hSCX], a
+ ld a, $90
+ ld [hWY], a
+ ret
+
+Trade_DrawLeftGameboy:
+ call Trade_ClearTileMap
+
+; draw link cable
+ coord hl, 11, 4
+ ld a, $5d
+ ld [hli], a
+ ld a, $5e
+ ld c, 8
+.loop
+ ld [hli], a
+ dec c
+ jr nz, .loop
+
+; draw gameboy pic
+ coord hl, 5, 3
+ ld b, $6
+ call CopyTileIDsFromList_ZeroBaseTileID
+
+; draw text box with player name below gameboy pic
+ coord hl, 4, 12
+ ld b, 2
+ ld c, 7
+ call TextBoxBorder
+ coord hl, 5, 14
+ ld de, wPlayerName
+ call PlaceString
+
+ jp DelayFrame
+
+Trade_DrawRightGameboy:
+ call Trade_ClearTileMap
+
+; draw horizontal segment of link cable
+ coord hl, 0, 4
+ ld a, $5e
+ ld c, $e
+.loop
+ ld [hli], a
+ dec c
+ jr nz, .loop
+
+; draw vertical segment of link cable
+ ld a, $5f
+ ld [hl], a
+ ld de, SCREEN_WIDTH
+ add hl, de
+ ld a, $61
+ ld [hl], a
+ add hl, de
+ ld [hl], a
+ add hl, de
+ ld [hl], a
+ add hl, de
+ ld [hl], a
+ add hl, de
+ ld a, $60
+ ld [hld], a
+ ld a, $5d
+ ld [hl], a
+
+; draw gameboy pic
+ coord hl, 7, 8
+ ld b, $6
+ call CopyTileIDsFromList_ZeroBaseTileID
+
+; draw text box with enemy name above link cable
+ coord hl, 6, 0
+ ld b, 2
+ ld c, 7
+ call TextBoxBorder
+ coord hl, 7, 2
+ ld de, wLinkEnemyTrainerName
+ call PlaceString
+
+ jp DelayFrame
+
+Trade_DrawCableAcrossScreen:
+; Draws the link cable across the screen.
+ call Trade_ClearTileMap
+ coord hl, 0, 4
+ ld a, $5e
+ ld c, SCREEN_WIDTH
+.loop
+ ld [hli], a
+ dec c
+ jr nz, .loop
+ ret
+
+Trade_CopyCableTilesOffScreen:
+; This is used to copy the link cable tiles off screen so that the cable
+; continues when the screen is scrolled.
+ push hl
+ coord hl, 0, 4
+ call CopyToRedrawRowOrColumnSrcTiles
+ pop hl
+ ld a, h
+ ld [hRedrawRowOrColumnDest + 1], a
+ ld a, l
+ ld [hRedrawRowOrColumnDest], a
+ ld a, REDRAW_ROW
+ ld [hRedrawRowOrColumnMode], a
+ ld c, 10
+ jp DelayFrames
+
+Trade_AnimMonMoveHorizontal:
+; Animates the mon going through the link cable horizontally over a distance of
+; b 16-pixel units.
+ ld a, [wTradedMonMovingRight]
+ ld e, a
+ ld d, $8
+.scrollLoop
+ ld a, e
+ dec a
+ jr z, .movingRight
+; moving left
+ ld a, [hSCX]
+ sub $2
+ jr .next
+.movingRight
+ ld a, [hSCX]
+ add $2
+.next
+ ld [hSCX], a
+ call DelayFrame
+ dec d
+ jr nz, .scrollLoop
+ call Trade_AnimCircledMon
+ dec b
+ jr nz, Trade_AnimMonMoveHorizontal
+ ret
+
+Trade_AnimCircledMon:
+; Cycles between the two animation frames of the mon party sprite, cycles
+; between a circle and an oval around the mon sprite, and makes the cable flash.
+ push de
+ push bc
+ push hl
+ ld a, [rBGP]
+ xor $3c ; make link cable flash
+ ld [rBGP], a
+ ld hl, wOAMBuffer + $02
+ ld de, $4
+ ld c, $14
+.loop
+ ld a, [hl]
+ xor $40
+ ld [hl], a
+ add hl, de
+ dec c
+ jr nz, .loop
+ pop hl
+ pop bc
+ pop de
+ ret
+
+Trade_WriteCircledMonOAM:
+ callba WriteMonPartySpriteOAMBySpecies
+ call Trade_WriteCircleOAM
+
+Trade_AddOffsetsToOAMCoords:
+ ld hl, wOAMBuffer
+ ld c, $14
+.loop
+ ld a, [wBaseCoordY]
+ add [hl]
+ ld [hli], a
+ ld a, [wBaseCoordX]
+ add [hl]
+ ld [hli], a
+ inc hl
+ inc hl
+ dec c
+ jr nz, .loop
+ ret
+
+Trade_AnimMonMoveVertical:
+; Animates the mon going through the link cable vertically as well as
+; horizontally for a bit. The last bit of horizontal movement (when moving
+; right) or the first bit of horizontal movement (when moving left) are done
+; here instead of Trade_AnimMonMoveHorizontal because this function moves the
+; sprite itself rather than scrolling the screen around the sprite. Moving the
+; sprite itself is necessary because the vertical segment of the link cable is
+; to the right of the screen position that the mon sprite has when
+; Trade_AnimMonMoveHorizontal is executing.
+ ld a, [wTradedMonMovingRight]
+ and a
+ jr z, .movingLeft
+; moving right
+ lb bc, 4, 0 ; move right
+ call .doAnim
+ lb bc, 0, 10 ; move down
+ jr .doAnim
+.movingLeft
+ lb bc, 0, -10 ; move up
+ call .doAnim
+ lb bc, -4, 0 ; move left
+.doAnim
+ ld a, b
+ ld [wBaseCoordX], a
+ ld a, c
+ ld [wBaseCoordY], a
+ ld d, $4
+.loop
+ call Trade_AddOffsetsToOAMCoords
+ call Trade_AnimCircledMon
+ ld c, 8
+ call DelayFrames
+ dec d
+ jr nz, .loop
+ ret
+
+Trade_WriteCircleOAM:
+; Writes the OAM blocks for the circle around the traded mon as it passes
+; the link cable.
+ ld hl, Trade_CircleOAMPointers
+ ld c, $4
+ xor a
+.loop
+ push bc
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ inc hl
+ ld c, [hl]
+ inc hl
+ ld b, [hl]
+ inc hl
+ push hl
+ inc a
+ push af
+ call WriteOAMBlock
+ pop af
+ pop hl
+ pop bc
+ dec c
+ jr nz, .loop
+ ret
+
+Trade_CircleOAMPointers:
+ dw Trade_CircleOAM0
+ db $08,$08
+ dw Trade_CircleOAM1
+ db $18,$08
+ dw Trade_CircleOAM2
+ db $08,$18
+ dw Trade_CircleOAM3
+ db $18,$18
+
+Trade_CircleOAM0:
+ db $38,$10,$39,$10
+ db $3A,$10,$3B,$10
+
+Trade_CircleOAM1:
+ db $39,$30,$38,$30
+ db $3B,$30,$3A,$30
+
+Trade_CircleOAM2:
+ db $3A,$50,$3B,$50
+ db $38,$50,$39,$50
+
+Trade_CircleOAM3:
+ db $3B,$70,$3A,$70
+ db $39,$70,$38,$70
+
+; a = species
+Trade_LoadMonSprite:
+ ld [wcf91], a
+ ld [wd0b5], a
+ ld [wWholeScreenPaletteMonSpecies], a
+ ld b, SET_PAL_POKEMON_WHOLE_SCREEN
+ ld c, 0
+ call RunPaletteCommand
+ ld a, [H_AUTOBGTRANSFERENABLED]
+ xor $1
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call GetMonHeader
+ coord hl, 7, 2
+ call LoadFlippedFrontSpriteByMonIndex
+ ld c, 10
+ jp DelayFrames
+
+Trade_ShowClearedWindow:
+; clears the window and covers the BG entirely with the window
+ ld a, $1
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call ClearScreen
+ ld a, %11100011
+ ld [rLCDC], a
+ ld a, $7
+ ld [rWX], a
+ xor a
+ ld [hWY], a
+ ld a, $90
+ ld [hSCX], a
+ ret
+
+Trade_SlideTextBoxOffScreen:
+; Slides the window right until it's off screen. The window usually just has
+; a text box at the bottom when this is called. However, when this is called
+; after Trade_ShowEnemyMon in the external clock sequence, there is a mon pic
+; above the text box and it is also scrolled off the screen.
+ ld c, 50
+ call DelayFrames
+.loop
+ call DelayFrame
+ ld a, [rWX]
+ inc a
+ inc a
+ ld [rWX], a
+ cp $a1
+ jr nz, .loop
+ call Trade_ClearTileMap
+ ld c, 10
+ call DelayFrames
+ ld a, $7
+ ld [rWX], a
+ ret
+
+PrintTradeWentToText:
+ ld hl, TradeWentToText
+ call PrintText
+ ld c, 200
+ call DelayFrames
+ jp Trade_SlideTextBoxOffScreen
+
+TradeWentToText:
+ TX_FAR _TradeWentToText
+ db "@"
+
+PrintTradeForSendsText:
+ ld hl, TradeForText
+ call PrintText
+ call Trade_Delay80
+ ld hl, TradeSendsText
+ call PrintText
+ jp Trade_Delay80
+
+TradeForText:
+ TX_FAR _TradeForText
+ db "@"
+
+TradeSendsText:
+ TX_FAR _TradeSendsText
+ db "@"
+
+PrintTradeFarewellText:
+ ld hl, TradeWavesFarewellText
+ call PrintText
+ call Trade_Delay80
+ ld hl, TradeTransferredText
+ call PrintText
+ call Trade_Delay80
+ jp Trade_SlideTextBoxOffScreen
+
+TradeWavesFarewellText:
+ TX_FAR _TradeWavesFarewellText
+ db "@"
+
+TradeTransferredText:
+ TX_FAR _TradeTransferredText
+ db "@"
+
+PrintTradeTakeCareText:
+ ld hl, TradeTakeCareText
+ call PrintText
+ jp Trade_Delay80
+
+TradeTakeCareText:
+ TX_FAR _TradeTakeCareText
+ db "@"
+
+PrintTradeWillTradeText:
+ ld hl, TradeWillTradeText
+ call PrintText
+ call Trade_Delay80
+ ld hl, TradeforText
+ call PrintText
+ jp Trade_Delay80
+
+TradeWillTradeText:
+ TX_FAR _TradeWillTradeText
+ db "@"
+
+TradeforText:
+ TX_FAR _TradeforText
+ db "@"
+
+Trade_ShowAnimation:
+ ld [wAnimationID], a
+ xor a
+ ld [wAnimationType], a
+ predef_jump MoveAnimation
--- /dev/null
+++ b/engine/movie/trade2.asm
@@ -1,0 +1,48 @@
+Trade_PrintPlayerMonInfoText:
+ coord hl, 5, 0
+ ld de, Trade_MonInfoText
+ call PlaceString
+ ld a, [wTradedPlayerMonSpecies]
+ ld [wd11e], a
+ predef IndexToPokedex
+ coord hl, 9, 0
+ ld de, wd11e
+ lb bc, LEADING_ZEROES | 1, 3
+ call PrintNumber
+ coord hl, 5, 2
+ ld de, wcf4b
+ call PlaceString
+ coord hl, 8, 4
+ ld de, wTradedPlayerMonOT
+ call PlaceString
+ coord hl, 8, 6
+ ld de, wTradedPlayerMonOTID
+ lb bc, LEADING_ZEROES | 2, 5
+ jp PrintNumber
+
+Trade_PrintEnemyMonInfoText:
+ coord hl, 5, 10
+ ld de, Trade_MonInfoText
+ call PlaceString
+ ld a, [wTradedEnemyMonSpecies]
+ ld [wd11e], a
+ predef IndexToPokedex
+ coord hl, 9, 10
+ ld de, wd11e
+ lb bc, LEADING_ZEROES | 1, 3
+ call PrintNumber
+ coord hl, 5, 12
+ ld de, wcd6d
+ call PlaceString
+ coord hl, 8, 14
+ ld de, wTradedEnemyMonOT
+ call PlaceString
+ coord hl, 8, 16
+ ld de, wTradedEnemyMonOTID
+ lb bc, LEADING_ZEROES | 2, 5
+ jp PrintNumber
+
+Trade_MonInfoText:
+ db "──№⠄",$4E
+ next "OT/"
+ next $73,"№⠄","@"
--- a/engine/multiply_divide.asm
+++ /dev/null
@@ -1,143 +1,0 @@
-_Multiply::
- ld a, $8
- ld b, a
- xor a
- ld [H_PRODUCT], a
- ld [H_MULTIPLYBUFFER], a
- ld [H_MULTIPLYBUFFER+1], a
- ld [H_MULTIPLYBUFFER+2], a
- ld [H_MULTIPLYBUFFER+3], a
-.loop
- ld a, [H_MULTIPLIER]
- srl a
- ld [H_MULTIPLIER], a ; (aliases: H_DIVISOR, H_MULTIPLIER, H_POWEROFTEN)
- jr nc, .smallMultiplier
- ld a, [H_MULTIPLYBUFFER+3]
- ld c, a
- ld a, [H_MULTIPLICAND+2]
- add c
- ld [H_MULTIPLYBUFFER+3], a
- ld a, [H_MULTIPLYBUFFER+2]
- ld c, a
- ld a, [H_MULTIPLICAND+1]
- adc c
- ld [H_MULTIPLYBUFFER+2], a
- ld a, [H_MULTIPLYBUFFER+1]
- ld c, a
- ld a, [H_MULTIPLICAND] ; (aliases: H_MULTIPLICAND)
- adc c
- ld [H_MULTIPLYBUFFER+1], a
- ld a, [H_MULTIPLYBUFFER]
- ld c, a
- ld a, [H_PRODUCT] ; (aliases: H_PRODUCT, H_PASTLEADINGZEROES, H_QUOTIENT)
- adc c
- ld [H_MULTIPLYBUFFER], a
-.smallMultiplier
- dec b
- jr z, .done
- ld a, [H_MULTIPLICAND+2]
- sla a
- ld [H_MULTIPLICAND+2], a
- ld a, [H_MULTIPLICAND+1]
- rl a
- ld [H_MULTIPLICAND+1], a
- ld a, [H_MULTIPLICAND]
- rl a
- ld [H_MULTIPLICAND], a
- ld a, [H_PRODUCT]
- rl a
- ld [H_PRODUCT], a
- jr .loop
-.done
- ld a, [H_MULTIPLYBUFFER+3]
- ld [H_PRODUCT+3], a
- ld a, [H_MULTIPLYBUFFER+2]
- ld [H_PRODUCT+2], a
- ld a, [H_MULTIPLYBUFFER+1]
- ld [H_PRODUCT+1], a
- ld a, [H_MULTIPLYBUFFER]
- ld [H_PRODUCT], a
- ret
-
-_Divide::
- xor a
- ld [H_DIVIDEBUFFER], a
- ld [H_DIVIDEBUFFER+1], a
- ld [H_DIVIDEBUFFER+2], a
- ld [H_DIVIDEBUFFER+3], a
- ld [H_DIVIDEBUFFER+4], a
- ld a, $9
- ld e, a
-.asm_37db3
- ld a, [H_DIVIDEBUFFER]
- ld c, a
- ld a, [H_DIVIDEND+1] ; (aliases: H_MULTIPLICAND)
- sub c
- ld d, a
- ld a, [H_DIVISOR] ; (aliases: H_DIVISOR, H_MULTIPLIER, H_POWEROFTEN)
- ld c, a
- ld a, [H_DIVIDEND] ; (aliases: H_PRODUCT, H_PASTLEADINGZEROES, H_QUOTIENT)
- sbc c
- jr c, .asm_37dce
- ld [H_DIVIDEND], a ; (aliases: H_PRODUCT, H_PASTLEADINGZEROES, H_QUOTIENT)
- ld a, d
- ld [H_DIVIDEND+1], a ; (aliases: H_MULTIPLICAND)
- ld a, [H_DIVIDEBUFFER+4]
- inc a
- ld [H_DIVIDEBUFFER+4], a
- jr .asm_37db3
-.asm_37dce
- ld a, b
- cp $1
- jr z, .asm_37e18
- ld a, [H_DIVIDEBUFFER+4]
- sla a
- ld [H_DIVIDEBUFFER+4], a
- ld a, [H_DIVIDEBUFFER+3]
- rl a
- ld [H_DIVIDEBUFFER+3], a
- ld a, [H_DIVIDEBUFFER+2]
- rl a
- ld [H_DIVIDEBUFFER+2], a
- ld a, [H_DIVIDEBUFFER+1]
- rl a
- ld [H_DIVIDEBUFFER+1], a
- dec e
- jr nz, .asm_37e04
- ld a, $8
- ld e, a
- ld a, [H_DIVIDEBUFFER]
- ld [H_DIVISOR], a ; (aliases: H_DIVISOR, H_MULTIPLIER, H_POWEROFTEN)
- xor a
- ld [H_DIVIDEBUFFER], a
- ld a, [H_DIVIDEND+1] ; (aliases: H_MULTIPLICAND)
- ld [H_DIVIDEND], a ; (aliases: H_PRODUCT, H_PASTLEADINGZEROES, H_QUOTIENT)
- ld a, [H_DIVIDEND+2]
- ld [H_DIVIDEND+1], a ; (aliases: H_MULTIPLICAND)
- ld a, [H_DIVIDEND+3]
- ld [H_DIVIDEND+2], a
-.asm_37e04
- ld a, e
- cp $1
- jr nz, .asm_37e0a
- dec b
-.asm_37e0a
- ld a, [H_DIVISOR] ; (aliases: H_DIVISOR, H_MULTIPLIER, H_POWEROFTEN)
- srl a
- ld [H_DIVISOR], a ; (aliases: H_DIVISOR, H_MULTIPLIER, H_POWEROFTEN)
- ld a, [H_DIVIDEBUFFER]
- rr a
- ld [H_DIVIDEBUFFER], a
- jr .asm_37db3
-.asm_37e18
- ld a, [H_DIVIDEND+1] ; (aliases: H_MULTIPLICAND)
- ld [H_REMAINDER], a ; (aliases: H_DIVISOR, H_MULTIPLIER, H_POWEROFTEN)
- ld a, [H_DIVIDEBUFFER+4]
- ld [H_QUOTIENT+3], a
- ld a, [H_DIVIDEBUFFER+3]
- ld [H_QUOTIENT+2], a
- ld a, [H_DIVIDEBUFFER+2]
- ld [H_QUOTIENT+1], a ; (aliases: H_MULTIPLICAND)
- ld a, [H_DIVIDEBUFFER+1]
- ld [H_DIVIDEND], a ; (aliases: H_PRODUCT, H_PASTLEADINGZEROES, H_QUOTIENT)
- ret
--- a/engine/oak_speech.asm
+++ /dev/null
@@ -1,233 +1,0 @@
-SetDefaultNames:
- ld a, [wLetterPrintingDelayFlags]
- push af
- ld a, [wOptions]
- push af
- ld a, [wd732]
- push af
- ld hl, wPlayerName
- ld bc, wBoxDataEnd - wPlayerName
- xor a
- call FillMemory
- ld hl, wSpriteStateData1
- ld bc, $200
- xor a
- call FillMemory
- pop af
- ld [wd732], a
- pop af
- ld [wOptions], a
- pop af
- ld [wLetterPrintingDelayFlags], a
- ld a, [wOptionsInitialized]
- and a
- call z, InitOptions
- ld hl, NintenText
- ld de, wPlayerName
- ld bc, NAME_LENGTH
- call CopyData
- ld hl, SonyText
- ld de, wRivalName
- ld bc, NAME_LENGTH
- jp CopyData
-
-OakSpeech:
- ld a, $FF
- call PlaySound ; stop music
- ld a, BANK(Music_Routes2)
- ld c, a
- ld a, MUSIC_ROUTES2
- call PlayMusic
- call ClearScreen
- call LoadTextBoxTilePatterns
- call SetDefaultNames
- predef InitPlayerData2
- ld hl, wNumBoxItems
- ld a, POTION
- ld [wcf91], a
- ld a, 1
- ld [wItemQuantity], a
- call AddItemToInventory ; give one potion
- ld a, [wDefaultMap]
- ld [wDestinationMap], a
- call SpecialWarpIn
- xor a
- ld [hTilesetType], a
- ld a, [wd732]
- bit 1, a ; possibly a debug mode bit
- jp nz, .skipChoosingNames
- ld de, ProfOakPic
- lb bc, Bank(ProfOakPic), $00
- call IntroDisplayPicCenteredOrUpperRight
- call FadeInIntroPic
- ld hl, OakSpeechText1
- call PrintText
- call GBFadeOutToWhite
- call ClearScreen
- ld a, NIDORINO
- ld [wd0b5], a
- ld [wcf91], a
- call GetMonHeader
- coord hl, 6, 4
- call LoadFlippedFrontSpriteByMonIndex
- call MovePicLeft
- ld hl, OakSpeechText2
- call PrintText
- call GBFadeOutToWhite
- call ClearScreen
- ld de, RedPicFront
- lb bc, Bank(RedPicFront), $00
- call IntroDisplayPicCenteredOrUpperRight
- call MovePicLeft
- ld hl, IntroducePlayerText
- call PrintText
- call ChoosePlayerName
- call GBFadeOutToWhite
- call ClearScreen
- ld de, Rival1Pic
- lb bc, Bank(Rival1Pic), $00
- call IntroDisplayPicCenteredOrUpperRight
- call FadeInIntroPic
- ld hl, IntroduceRivalText
- call PrintText
- call ChooseRivalName
-.skipChoosingNames
- call GBFadeOutToWhite
- call ClearScreen
- ld de, RedPicFront
- lb bc, Bank(RedPicFront), $00
- call IntroDisplayPicCenteredOrUpperRight
- call GBFadeInFromWhite
- ld a, [wd72d]
- and a
- jr nz, .next
- ld hl, OakSpeechText3
- call PrintText
-.next
- ld a, [H_LOADEDROMBANK]
- push af
- ld a, SFX_SHRINK
- call PlaySound
- pop af
- ld [H_LOADEDROMBANK], a
- ld [MBC1RomBank], a
- ld c, 4
- call DelayFrames
- ld de, RedSprite
- ld hl, vSprites
- lb bc, BANK(RedSprite), $0C
- call CopyVideoData
- ld de, ShrinkPic1
- lb bc, BANK(ShrinkPic1), $00
- call IntroDisplayPicCenteredOrUpperRight
- ld c, 4
- call DelayFrames
- ld de, ShrinkPic2
- lb bc, BANK(ShrinkPic2), $00
- call IntroDisplayPicCenteredOrUpperRight
- call ResetPlayerSpriteData
- ld a, [H_LOADEDROMBANK]
- push af
- ld a, BANK(Music_PalletTown)
- ld [wAudioROMBank], a
- ld [wAudioSavedROMBank], a
- ld a, 10
- ld [wAudioFadeOutControl], a
- ld a, $FF
- ld [wNewSoundID], a
- call PlaySound ; stop music
- pop af
- ld [H_LOADEDROMBANK], a
- ld [MBC1RomBank], a
- ld c, 20
- call DelayFrames
- coord hl, 6, 5
- ld b, 7
- ld c, 7
- call ClearScreenArea
- call LoadTextBoxTilePatterns
- ld a, 1
- ld [wUpdateSpritesEnabled], a
- ld c, 50
- call DelayFrames
- call GBFadeOutToWhite
- jp ClearScreen
-OakSpeechText1:
- TX_FAR _OakSpeechText1
- db "@"
-OakSpeechText2:
- TX_FAR _OakSpeechText2A
- TX_CRY_NIDORINA
- TX_FAR _OakSpeechText2B
- db "@"
-IntroducePlayerText:
- TX_FAR _IntroducePlayerText
- db "@"
-IntroduceRivalText:
- TX_FAR _IntroduceRivalText
- db "@"
-OakSpeechText3:
- TX_FAR _OakSpeechText3
- db "@"
-
-FadeInIntroPic:
- ld hl, IntroFadePalettes
- ld b, 6
-.next
- ld a, [hli]
- ld [rBGP], a
- ld c, 10
- call DelayFrames
- dec b
- jr nz, .next
- ret
-
-IntroFadePalettes:
- db %01010100
- db %10101000
- db %11111100
- db %11111000
- db %11110100
- db %11100100
-
-MovePicLeft:
- ld a, 119
- ld [rWX], a
- call DelayFrame
-
- ld a, %11100100
- ld [rBGP], a
-.next
- call DelayFrame
- ld a, [rWX]
- sub 8
- cp $FF
- ret z
- ld [rWX], a
- jr .next
-
-DisplayPicCenteredOrUpperRight:
- call GetPredefRegisters
-IntroDisplayPicCenteredOrUpperRight:
-; b = bank
-; de = address of compressed pic
-; c: 0 = centred, non-zero = upper-right
- push bc
- ld a, b
- call UncompressSpriteFromDE
- ld hl, sSpriteBuffer1
- ld de, sSpriteBuffer0
- ld bc, $310
- call CopyData
- ld de, vFrontPic
- call InterlaceMergeSpriteBuffers
- pop bc
- ld a, c
- and a
- coord hl, 15, 1
- jr nz, .next
- coord hl, 6, 4
-.next
- xor a
- ld [hStartTileID], a
- predef_jump CopyUncompressedPicToTilemap
--- a/engine/oak_speech2.asm
+++ /dev/null
@@ -1,219 +1,0 @@
-ChoosePlayerName:
- call OakSpeechSlidePicRight
- ld de, DefaultNamesPlayer
- call DisplayIntroNameTextBox
- ld a, [wCurrentMenuItem]
- and a
- jr z, .customName
- ld hl, DefaultNamesPlayerList
- call GetDefaultName
- ld de, wPlayerName
- call OakSpeechSlidePicLeft
- jr .done
-.customName
- ld hl, wPlayerName
- xor a ; NAME_PLAYER_SCREEN
- ld [wNamingScreenType], a
- call DisplayNamingScreen
- ld a, [wcf4b]
- cp "@"
- jr z, .customName
- call ClearScreen
- call Delay3
- ld de, RedPicFront
- ld b, BANK(RedPicFront)
- call IntroDisplayPicCenteredOrUpperRight
-.done
- ld hl, YourNameIsText
- jp PrintText
-
-YourNameIsText:
- TX_FAR _YourNameIsText
- db "@"
-
-ChooseRivalName:
- call OakSpeechSlidePicRight
- ld de, DefaultNamesRival
- call DisplayIntroNameTextBox
- ld a, [wCurrentMenuItem]
- and a
- jr z, .customName
- ld hl, DefaultNamesRivalList
- call GetDefaultName
- ld de, wRivalName
- call OakSpeechSlidePicLeft
- jr .done
-.customName
- ld hl, wRivalName
- ld a, NAME_RIVAL_SCREEN
- ld [wNamingScreenType], a
- call DisplayNamingScreen
- ld a, [wcf4b]
- cp "@"
- jr z, .customName
- call ClearScreen
- call Delay3
- ld de, Rival1Pic
- ld b, $13
- call IntroDisplayPicCenteredOrUpperRight
-.done
- ld hl, HisNameIsText
- jp PrintText
-
-HisNameIsText:
- TX_FAR _HisNameIsText
- db "@"
-
-OakSpeechSlidePicLeft:
- push de
- coord hl, 0, 0
- lb bc, 12, 11
- call ClearScreenArea ; clear the name list text box
- ld c, 10
- call DelayFrames
- pop de
- ld hl, wcd6d
- ld bc, NAME_LENGTH
- call CopyData
- call Delay3
- coord hl, 12, 4
- lb de, 6, 6 * SCREEN_WIDTH + 5
- ld a, $ff
- jr OakSpeechSlidePicCommon
-
-OakSpeechSlidePicRight:
- coord hl, 5, 4
- lb de, 6, 6 * SCREEN_WIDTH + 5
- xor a
-
-OakSpeechSlidePicCommon:
- push hl
- push de
- push bc
- ld [hSlideDirection], a
- ld a, d
- ld [hSlideAmount], a
- ld a, e
- ld [hSlidingRegionSize], a
- ld c, a
- ld a, [hSlideDirection]
- and a
- jr nz, .next
-; If sliding right, point hl to the end of the pic's tiles.
- ld d, 0
- add hl, de
-.next
- ld d, h
- ld e, l
-.loop
- xor a
- ld [H_AUTOBGTRANSFERENABLED], a
- ld a, [hSlideDirection]
- and a
- jr nz, .slideLeft
-; sliding right
- ld a, [hli]
- ld [hld], a
- dec hl
- jr .next2
-.slideLeft
- ld a, [hld]
- ld [hli], a
- inc hl
-.next2
- dec c
- jr nz, .loop
- ld a, [hSlideDirection]
- and a
- jr z, .next3
-; If sliding left, we need to zero the last tile in the pic (there is no need
-; to take a corresponding action when sliding right because hl initially points
-; to a 0 tile in that case).
- xor a
- dec hl
- ld [hl], a
-.next3
- ld a, 1
- ld [H_AUTOBGTRANSFERENABLED], a
- call Delay3
- ld a, [hSlidingRegionSize]
- ld c, a
- ld h, d
- ld l, e
- ld a, [hSlideDirection]
- and a
- jr nz, .slideLeft2
- inc hl
- jr .next4
-.slideLeft2
- dec hl
-.next4
- ld d, h
- ld e, l
- ld a, [hSlideAmount]
- dec a
- ld [hSlideAmount], a
- jr nz, .loop
- pop bc
- pop de
- pop hl
- ret
-
-DisplayIntroNameTextBox:
- push de
- coord hl, 0, 0
- ld b, $a
- ld c, $9
- call TextBoxBorder
- coord hl, 3, 0
- ld de, .namestring
- call PlaceString
- pop de
- coord hl, 2, 2
- call PlaceString
- call UpdateSprites
- xor a
- ld [wCurrentMenuItem], a
- ld [wLastMenuItem], a
- inc a
- ld [wTopMenuItemX], a
- ld [wMenuWatchedKeys], a ; A_BUTTON
- inc a
- ld [wTopMenuItemY], a
- inc a
- ld [wMaxMenuItem], a
- jp HandleMenuInput
-
-.namestring
- db "NAME@"
-
-INCLUDE "text/player_names.asm"
-
-GetDefaultName:
-; a = name index
-; hl = name list
- ld b, a
- ld c, 0
-.loop
- ld d, h
- ld e, l
-.innerLoop
- ld a, [hli]
- cp "@"
- jr nz, .innerLoop
- ld a, b
- cp c
- jr z, .foundName
- inc c
- jr .loop
-.foundName
- ld h, d
- ld l, e
- ld de, wcd6d
- ld bc, $14
- jp CopyData
-
-INCLUDE "text/player_names_list.asm"
-
-TextTerminator_6b20:
- db "@"
--- a/engine/oam_dma.asm
+++ /dev/null
@@ -1,26 +1,0 @@
-WriteDMACodeToHRAM::
-; Since no other memory is available during OAM DMA,
-; DMARoutine is copied to HRAM and executed there.
- ld c, $ff80 % $100
- ld b, DMARoutineEnd - DMARoutine
- ld hl, DMARoutine
-.copy
- ld a, [hli]
- ld [$ff00+c], a
- inc c
- dec b
- jr nz, .copy
- ret
-
-DMARoutine:
- ; initiate DMA
- ld a, wOAMBuffer / $100
- ld [rDMA], a
-
- ; wait for DMA to finish
- ld a, $28
-.wait
- dec a
- jr nz, .wait
- ret
-DMARoutineEnd:
--- /dev/null
+++ b/engine/overworld/auto_movement.asm
@@ -1,0 +1,292 @@
+PlayerStepOutFromDoor::
+ ld hl, wd730
+ res 1, [hl]
+ call IsPlayerStandingOnDoorTile
+ jr nc, .notStandingOnDoor
+ ld a, $fc
+ ld [wJoyIgnore], a
+ ld hl, wd736
+ set 1, [hl]
+ ld a, $1
+ ld [wSimulatedJoypadStatesIndex], a
+ ld a, D_DOWN
+ ld [wSimulatedJoypadStatesEnd], a
+ xor a
+ ld [wSpriteStateData1 + 2], a
+ call StartSimulatingJoypadStates
+ ret
+.notStandingOnDoor
+ xor a
+ ld [wWastedByteCD3A], a
+ ld [wSimulatedJoypadStatesIndex], a
+ ld [wSimulatedJoypadStatesEnd], a
+ ld hl, wd736
+ res 0, [hl]
+ res 1, [hl]
+ ld hl, wd730
+ res 7, [hl]
+ ret
+
+_EndNPCMovementScript::
+ ld hl, wd730
+ res 7, [hl]
+ ld hl, wd72e
+ res 7, [hl]
+ ld hl, wd736
+ res 0, [hl]
+ res 1, [hl]
+ xor a
+ ld [wNPCMovementScriptSpriteOffset], a
+ ld [wNPCMovementScriptPointerTableNum], a
+ ld [wNPCMovementScriptFunctionNum], a
+ ld [wWastedByteCD3A], a
+ ld [wSimulatedJoypadStatesIndex], a
+ ld [wSimulatedJoypadStatesEnd], a
+ ret
+
+PalletMovementScriptPointerTable::
+ dw PalletMovementScript_OakMoveLeft
+ dw PalletMovementScript_PlayerMoveLeft
+ dw PalletMovementScript_WaitAndWalkToLab
+ dw PalletMovementScript_WalkToLab
+ dw PalletMovementScript_Done
+
+PalletMovementScript_OakMoveLeft:
+ ld a, [wXCoord]
+ sub $a
+ ld [wNumStepsToTake], a
+ jr z, .playerOnLeftTile
+; The player is on the right tile of the northern path out of Pallet Town and
+; Prof. Oak is below.
+; Make Prof. Oak step to the left.
+ ld b, 0
+ ld c, a
+ ld hl, wNPCMovementDirections2
+ ld a, NPC_MOVEMENT_LEFT
+ call FillMemory
+ ld [hl], $ff
+ ld a, [wSpriteIndex]
+ ld [H_SPRITEINDEX], a
+ ld de, wNPCMovementDirections2
+ call MoveSprite
+ ld a, $1
+ ld [wNPCMovementScriptFunctionNum], a
+ jr .done
+; The player is on the left tile of the northern path out of Pallet Town and
+; Prof. Oak is below.
+; Prof. Oak is already where he needs to be.
+.playerOnLeftTile
+ ld a, $3
+ ld [wNPCMovementScriptFunctionNum], a
+.done
+ ld hl, wFlags_D733
+ set 1, [hl]
+ ld a, $fc
+ ld [wJoyIgnore], a
+ ret
+
+PalletMovementScript_PlayerMoveLeft:
+ ld a, [wd730]
+ bit 0, a ; is an NPC being moved by a script?
+ ret nz ; return if Oak is still moving
+ ld a, [wNumStepsToTake]
+ ld [wSimulatedJoypadStatesIndex], a
+ ld [hNPCMovementDirections2Index], a
+ predef ConvertNPCMovementDirectionsToJoypadMasks
+ call StartSimulatingJoypadStates
+ ld a, $2
+ ld [wNPCMovementScriptFunctionNum], a
+ ret
+
+PalletMovementScript_WaitAndWalkToLab:
+ ld a, [wSimulatedJoypadStatesIndex]
+ and a ; is the player done moving left yet?
+ ret nz
+
+PalletMovementScript_WalkToLab:
+ xor a
+ ld [wOverrideSimulatedJoypadStatesMask], a
+ ld a, [wSpriteIndex]
+ swap a
+ ld [wNPCMovementScriptSpriteOffset], a
+ xor a
+ ld [wSpriteStateData2 + $06], a
+ ld hl, wSimulatedJoypadStatesEnd
+ ld de, RLEList_PlayerWalkToLab
+ call DecodeRLEList
+ dec a
+ ld [wSimulatedJoypadStatesIndex], a
+ ld hl, wNPCMovementDirections2
+ ld de, RLEList_ProfOakWalkToLab
+ call DecodeRLEList
+ ld hl, wd72e
+ res 7, [hl]
+ ld hl, wd730
+ set 7, [hl]
+ ld a, $4
+ ld [wNPCMovementScriptFunctionNum], a
+ ret
+
+RLEList_ProfOakWalkToLab:
+ db NPC_MOVEMENT_DOWN, $05
+ db NPC_MOVEMENT_LEFT, $01
+ db NPC_MOVEMENT_DOWN, $05
+ db NPC_MOVEMENT_RIGHT, $03
+ db NPC_MOVEMENT_UP, $01
+ db $E0, $01 ; stand still
+ db $FF
+
+RLEList_PlayerWalkToLab:
+ db D_UP, $02
+ db D_RIGHT, $03
+ db D_DOWN, $05
+ db D_LEFT, $01
+ db D_DOWN, $06
+ db $FF
+
+PalletMovementScript_Done:
+ ld a, [wSimulatedJoypadStatesIndex]
+ and a
+ ret nz
+ ld a, HS_PALLET_TOWN_OAK
+ ld [wMissableObjectIndex], a
+ predef HideObject
+ ld hl, wd730
+ res 7, [hl]
+ ld hl, wd72e
+ res 7, [hl]
+ jp EndNPCMovementScript
+
+PewterMuseumGuyMovementScriptPointerTable::
+ dw PewterMovementScript_WalkToMuseum
+ dw PewterMovementScript_Done
+
+PewterMovementScript_WalkToMuseum:
+ ld a, BANK(Music_MuseumGuy)
+ ld [wAudioROMBank], a
+ ld [wAudioSavedROMBank], a
+ ld a, MUSIC_MUSEUM_GUY
+ ld [wNewSoundID], a
+ call PlaySound
+ ld a, [wSpriteIndex]
+ swap a
+ ld [wNPCMovementScriptSpriteOffset], a
+ call StartSimulatingJoypadStates
+ ld hl, wSimulatedJoypadStatesEnd
+ ld de, RLEList_PewterMuseumPlayer
+ call DecodeRLEList
+ dec a
+ ld [wSimulatedJoypadStatesIndex], a
+ xor a
+ ld [wWhichPewterGuy], a
+ predef PewterGuys
+ ld hl, wNPCMovementDirections2
+ ld de, RLEList_PewterMuseumGuy
+ call DecodeRLEList
+ ld hl, wd72e
+ res 7, [hl]
+ ld a, $1
+ ld [wNPCMovementScriptFunctionNum], a
+ ret
+
+RLEList_PewterMuseumPlayer:
+ db 0, $01
+ db D_UP, $03
+ db D_LEFT, $0D
+ db D_UP, $06
+ db $FF
+
+RLEList_PewterMuseumGuy:
+ db NPC_MOVEMENT_UP, $06
+ db NPC_MOVEMENT_LEFT, $0D
+ db NPC_MOVEMENT_UP, $03
+ db NPC_MOVEMENT_LEFT, $01
+ db $FF
+
+PewterMovementScript_Done:
+ ld a, [wSimulatedJoypadStatesIndex]
+ and a
+ ret nz
+ ld hl, wd730
+ res 7, [hl]
+ ld hl, wd72e
+ res 7, [hl]
+ jp EndNPCMovementScript
+
+PewterGymGuyMovementScriptPointerTable::
+ dw PewterMovementScript_WalkToGym
+ dw PewterMovementScript_Done
+
+PewterMovementScript_WalkToGym:
+ ld a, BANK(Music_MuseumGuy)
+ ld [wAudioROMBank], a
+ ld [wAudioSavedROMBank], a
+ ld a, MUSIC_MUSEUM_GUY
+ ld [wNewSoundID], a
+ call PlaySound
+ ld a, [wSpriteIndex]
+ swap a
+ ld [wNPCMovementScriptSpriteOffset], a
+ xor a
+ ld [wSpriteStateData2 + $06], a
+ ld hl, wSimulatedJoypadStatesEnd
+ ld de, RLEList_PewterGymPlayer
+ call DecodeRLEList
+ dec a
+ ld [wSimulatedJoypadStatesIndex], a
+ ld a, 1
+ ld [wWhichPewterGuy], a
+ predef PewterGuys
+ ld hl, wNPCMovementDirections2
+ ld de, RLEList_PewterGymGuy
+ call DecodeRLEList
+ ld hl, wd72e
+ res 7, [hl]
+ ld hl, wd730
+ set 7, [hl]
+ ld a, $1
+ ld [wNPCMovementScriptFunctionNum], a
+ ret
+
+RLEList_PewterGymPlayer:
+ db 0, $01
+ db D_RIGHT, $02
+ db D_DOWN, $05
+ db D_LEFT, $0B
+ db D_UP, $05
+ db D_LEFT, $0F
+ db $FF
+
+RLEList_PewterGymGuy:
+ db NPC_MOVEMENT_DOWN, $02
+ db NPC_MOVEMENT_LEFT, $0F
+ db NPC_MOVEMENT_UP, $05
+ db NPC_MOVEMENT_LEFT, $0B
+ db NPC_MOVEMENT_DOWN, $05
+ db NPC_MOVEMENT_RIGHT, $03
+ db $FF
+
+FreezeEnemyTrainerSprite::
+ ld a, [wCurMap]
+ cp POKEMON_TOWER_7F
+ ret z ; the Rockets on Pokemon Tower 7F leave after battling, so don't freeze them
+ ld hl, RivalIDs
+ ld a, [wEngagedTrainerClass]
+ ld b, a
+.loop
+ ld a, [hli]
+ cp $ff
+ jr z, .notRival
+ cp b
+ ret z ; the rival leaves after battling, so don't freeze him
+ jr .loop
+.notRival
+ ld a, [wSpriteIndex]
+ ld [H_SPRITEINDEX], a
+ jp SetSpriteMovementBytesToFF
+
+RivalIDs:
+ db OPP_SONY1
+ db OPP_SONY2
+ db OPP_SONY3
+ db $ff
--- a/engine/overworld/cable_club_npc.asm
+++ /dev/null
@@ -1,151 +1,0 @@
-CableClubNPC::
- ld hl, CableClubNPCWelcomeText
- call PrintText
- CheckEvent EVENT_GOT_POKEDEX
- jp nz, .receivedPokedex
-; if the player hasn't received the pokedex
- ld c, 60
- call DelayFrames
- ld hl, CableClubNPCMakingPreparationsText
- call PrintText
- jp .didNotConnect
-.receivedPokedex
- ld a, $1
- ld [wMenuJoypadPollCount], a
- ld a, 90
- ld [wLinkTimeoutCounter], a
-.establishConnectionLoop
- ld a, [hSerialConnectionStatus]
- cp USING_INTERNAL_CLOCK
- jr z, .establishedConnection
- cp USING_EXTERNAL_CLOCK
- jr z, .establishedConnection
- ld a, CONNECTION_NOT_ESTABLISHED
- ld [hSerialConnectionStatus], a
- ld a, ESTABLISH_CONNECTION_WITH_EXTERNAL_CLOCK
- ld [rSB], a
- xor a
- ld [hSerialReceiveData], a
- ld a, START_TRANSFER_EXTERNAL_CLOCK
- ld [rSC], a
- ld a, [wLinkTimeoutCounter]
- dec a
- ld [wLinkTimeoutCounter], a
- jr z, .failedToEstablishConnection
- ld a, ESTABLISH_CONNECTION_WITH_INTERNAL_CLOCK
- ld [rSB], a
- ld a, START_TRANSFER_INTERNAL_CLOCK
- ld [rSC], a
- call DelayFrame
- jr .establishConnectionLoop
-.establishedConnection
- call Serial_SendZeroByte
- call DelayFrame
- call Serial_SendZeroByte
- ld c, 50
- call DelayFrames
- ld hl, CableClubNPCPleaseApplyHereHaveToSaveText
- call PrintText
- xor a
- ld [wMenuJoypadPollCount], a
- call YesNoChoice
- ld a, $1
- ld [wMenuJoypadPollCount], a
- ld a, [wCurrentMenuItem]
- and a
- jr nz, .choseNo
- callab SaveSAVtoSRAM
- call WaitForSoundToFinish
- ld a, SFX_SAVE
- call PlaySoundWaitForCurrent
- ld hl, CableClubNPCPleaseWaitText
- call PrintText
- ld hl, wUnknownSerialCounter
- ld a, $3
- ld [hli], a
- xor a
- ld [hl], a
- ld [hSerialReceivedNewData], a
- ld [wSerialExchangeNybbleSendData], a
- call Serial_SyncAndExchangeNybble
- ld hl, wUnknownSerialCounter
- ld a, [hli]
- inc a
- jr nz, .connected
- ld a, [hl]
- inc a
- jr nz, .connected
- ld b, 10
-.syncLoop
- call DelayFrame
- call Serial_SendZeroByte
- dec b
- jr nz, .syncLoop
- call CloseLinkConnection
- ld hl, CableClubNPCLinkClosedBecauseOfInactivityText
- call PrintText
- jr .didNotConnect
-.failedToEstablishConnection
- ld hl, CableClubNPCAreaReservedFor2FriendsLinkedByCableText
- call PrintText
- jr .didNotConnect
-.choseNo
- call CloseLinkConnection
- ld hl, CableClubNPCPleaseComeAgainText
- call PrintText
-.didNotConnect
- xor a
- ld hl, wUnknownSerialCounter
- ld [hli], a
- ld [hl], a
- ld hl, wd72e
- res 6, [hl]
- xor a
- ld [wMenuJoypadPollCount], a
- ret
-.connected
- xor a
- ld [hld], a
- ld [hl], a
- jpab LinkMenu
-
-CableClubNPCAreaReservedFor2FriendsLinkedByCableText:
- TX_FAR _CableClubNPCAreaReservedFor2FriendsLinkedByCableText
- db "@"
-
-CableClubNPCWelcomeText:
- TX_FAR _CableClubNPCWelcomeText
- db "@"
-
-CableClubNPCPleaseApplyHereHaveToSaveText:
- TX_FAR _CableClubNPCPleaseApplyHereHaveToSaveText
- db "@"
-
-CableClubNPCPleaseWaitText:
- TX_FAR _CableClubNPCPleaseWaitText
- TX_DELAY
- db "@"
-
-CableClubNPCLinkClosedBecauseOfInactivityText:
- TX_FAR _CableClubNPCLinkClosedBecauseOfInactivityText
- db "@"
-
-CableClubNPCPleaseComeAgainText:
- TX_FAR _CableClubNPCPleaseComeAgainText
- db "@"
-
-CableClubNPCMakingPreparationsText:
- TX_FAR _CableClubNPCMakingPreparationsText
- db "@"
-
-CloseLinkConnection:
- call Delay3
- ld a, CONNECTION_NOT_ESTABLISHED
- ld [hSerialConnectionStatus], a
- ld a, ESTABLISH_CONNECTION_WITH_EXTERNAL_CLOCK
- ld [rSB], a
- xor a
- ld [hSerialReceiveData], a
- ld a, START_TRANSFER_EXTERNAL_CLOCK
- ld [rSC], a
- ret
--- a/engine/overworld/card_key.asm
+++ /dev/null
@@ -1,112 +1,0 @@
-PrintCardKeyText:
- ld hl, SilphCoMapList
- ld a, [wCurMap]
- ld b, a
-.silphCoMapListLoop
- ld a, [hli]
- cp $ff
- ret z
- cp b
- jr nz, .silphCoMapListLoop
- predef GetTileAndCoordsInFrontOfPlayer
- ld a, [wTileInFrontOfPlayer]
- cp $18
- jr z, .cardKeyDoorInFrontOfPlayer
- cp $24
- jr z, .cardKeyDoorInFrontOfPlayer
- ld b, a
- ld a, [wCurMap]
- cp SILPH_CO_11F
- ret nz
- ld a, b
- cp $5e
- ret nz
-.cardKeyDoorInFrontOfPlayer
- ld b, CARD_KEY
- call IsItemInBag
- jr z, .noCardKey
- call GetCoordsInFrontOfPlayer
- push de
- tx_pre_id CardKeySuccessText
- ld [hSpriteIndexOrTextID], a
- call PrintPredefTextID
- pop de
- srl d
- ld a, d
- ld b, a
- ld [wCardKeyDoorY], a
- srl e
- ld a, e
- ld c, a
- ld [wCardKeyDoorX], a
- ld a, [wCurMap]
- cp SILPH_CO_11F
- jr nz, .notSilphCo11F
- ld a, $3
- jr .replaceCardKeyDoorTileBlock
-.notSilphCo11F
- ld a, $e
-.replaceCardKeyDoorTileBlock
- ld [wNewTileBlockID], a
- predef ReplaceTileBlock
- ld hl, wCurrentMapScriptFlags
- set 5, [hl]
- ld a, SFX_GO_INSIDE
- jp PlaySound
-.noCardKey
- tx_pre_id CardKeyFailText
- ld [hSpriteIndexOrTextID], a
- jp PrintPredefTextID
-
-SilphCoMapList:
- db SILPH_CO_2F
- db SILPH_CO_3F
- db SILPH_CO_4F
- db SILPH_CO_5F
- db SILPH_CO_6F
- db SILPH_CO_7F
- db SILPH_CO_8F
- db SILPH_CO_9F
- db SILPH_CO_10F
- db SILPH_CO_11F
- db $FF
-
-CardKeySuccessText::
- TX_FAR _CardKeySuccessText1
- TX_SFX_ITEM_1
- TX_FAR _CardKeySuccessText2
- db "@"
-
-CardKeyFailText::
- TX_FAR _CardKeyFailText
- db "@"
-
-; d = Y
-; e = X
-GetCoordsInFrontOfPlayer:
- ld a, [wYCoord]
- ld d, a
- ld a, [wXCoord]
- ld e, a
- ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction
- and a
- jr nz, .notFacingDown
-; facing down
- inc d
- ret
-.notFacingDown
- cp SPRITE_FACING_UP
- jr nz, .notFacingUp
-; facing up
- dec d
- ret
-.notFacingUp
- cp SPRITE_FACING_LEFT
- jr nz, .notFacingLeft
-; facing left
- dec e
- ret
-.notFacingLeft
-; facing right
- inc e
- ret
--- a/engine/overworld/cinnabar_lab.asm
+++ /dev/null
@@ -1,123 +1,0 @@
-GiveFossilToCinnabarLab::
- ld hl, wd730
- set 6, [hl]
- xor a
- ld [wCurrentMenuItem], a
- ld a, A_BUTTON | B_BUTTON
- ld [wMenuWatchedKeys], a
- ld a, [wFilteredBagItemsCount]
- dec a
- ld [wMaxMenuItem], a
- ld a, 2
- ld [wTopMenuItemY], a
- ld a, 1
- ld [wTopMenuItemX], a
- ld a, [wFilteredBagItemsCount]
- dec a
- ld bc, 2
- ld hl, 3
- call AddNTimes
- dec l
- ld b, l
- ld c, $d
- coord hl, 0, 0
- call TextBoxBorder
- call UpdateSprites
- call PrintFossilsInBag
- ld hl, wd730
- res 6, [hl]
- call HandleMenuInput
- bit 1, a ; pressed B?
- jr nz, .cancelledGivingFossil
- ld hl, wFilteredBagItems
- ld a, [wCurrentMenuItem]
- ld d, 0
- ld e, a
- add hl, de
- ld a, [hl]
- ld [$ffdb], a
- cp DOME_FOSSIL
- jr z, .choseDomeFossil
- cp HELIX_FOSSIL
- jr z, .choseHelixFossil
- ld b, AERODACTYL
- jr .fossilSelected
-.choseHelixFossil
- ld b, OMANYTE
- jr .fossilSelected
-.choseDomeFossil
- ld b, KABUTO
-.fossilSelected
- ld [wFossilItem], a
- ld a, b
- ld [wFossilMon], a
- call LoadFossilItemAndMonName
- ld hl, LabFossil_610ae
- call PrintText
- call YesNoChoice
- ld a, [wCurrentMenuItem]
- and a
- jr nz, .cancelledGivingFossil
- ld hl, LabFossil_610b3
- call PrintText
- ld a, [wFossilItem]
- ld [hItemToRemoveID], a
- callba RemoveItemByID
- ld hl, LabFossil_610b8
- call PrintText
- SetEvents EVENT_GAVE_FOSSIL_TO_LAB, EVENT_LAB_STILL_REVIVING_FOSSIL
- ret
-.cancelledGivingFossil
- ld hl, LabFossil_610bd
- call PrintText
- ret
-
-LabFossil_610ae:
- TX_FAR _Lab4Text_610ae
- db "@"
-
-LabFossil_610b3:
- TX_FAR _Lab4Text_610b3
- db "@"
-
-LabFossil_610b8:
- TX_FAR _Lab4Text_610b8
- db "@"
-
-LabFossil_610bd:
- TX_FAR _Lab4Text_610bd
- db "@"
-
-PrintFossilsInBag:
-; Prints each fossil in the player's bag on a separate line in the menu.
- ld hl, wFilteredBagItems
- xor a
- ld [hItemCounter], a
-.loop
- ld a, [hli]
- cp $ff
- ret z
- push hl
- ld [wd11e], a
- call GetItemName
- coord hl, 2, 2
- ld a, [hItemCounter]
- ld bc, SCREEN_WIDTH * 2
- call AddNTimes
- ld de, wcd6d
- call PlaceString
- ld hl, hItemCounter
- inc [hl]
- pop hl
- jr .loop
-
-; loads the names of the fossil item and the resulting mon
-LoadFossilItemAndMonName::
- ld a, [wFossilMon]
- ld [wd11e], a
- call GetMonName
- call CopyStringToCF4B
- ld a, [wFossilItem]
- ld [wd11e], a
- call GetItemName
- ret
--- /dev/null
+++ b/engine/overworld/dust_smoke.asm
@@ -1,0 +1,93 @@
+AnimateBoulderDust:
+ ld a, $1
+ ld [wWhichAnimationOffsets], a ; select the boulder dust offsets
+ ld a, [wUpdateSpritesEnabled]
+ push af
+ ld a, $ff
+ ld [wUpdateSpritesEnabled], a
+ ld a, %11100100
+ ld [rOBP1], a
+ call LoadSmokeTileFourTimes
+ callba WriteCutOrBoulderDustAnimationOAMBlock
+ ld c, 8 ; number of steps in animation
+.loop
+ push bc
+ call GetMoveBoulderDustFunctionPointer
+ ld bc, .returnAddress
+ push bc
+ ld c, 4
+ jp hl
+.returnAddress
+ ld a, [rOBP1]
+ xor %01100100
+ ld [rOBP1], a
+ call Delay3
+ pop bc
+ dec c
+ jr nz, .loop
+ pop af
+ ld [wUpdateSpritesEnabled], a
+ jp LoadPlayerSpriteGraphics
+
+GetMoveBoulderDustFunctionPointer:
+ ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction
+ ld hl, MoveBoulderDustFunctionPointerTable
+ ld c, a
+ ld b, $0
+ add hl, bc
+ ld a, [hli]
+ ld [wCoordAdjustmentAmount], a
+ ld a, [hli]
+ ld e, a
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ push hl
+ ld hl, wOAMBuffer + $90
+ ld d, $0
+ add hl, de
+ ld e, l
+ ld d, h
+ pop hl
+ ret
+
+MoveBoulderDustFunctionPointerTable:
+; facing down
+ db $FF,$00
+ dw AdjustOAMBlockYPos
+
+; facing up
+ db $01,$00
+ dw AdjustOAMBlockYPos
+
+; facing left
+ db $01,$01
+ dw AdjustOAMBlockXPos
+
+; facing right
+ db $FF,$01
+ dw AdjustOAMBlockXPos
+
+LoadSmokeTileFourTimes::
+ ld hl, vChars1 + $7c0
+ ld c, $4
+.loop
+ push bc
+ push hl
+ call LoadSmokeTile
+ pop hl
+ ld bc, $10
+ add hl, bc
+ pop bc
+ dec c
+ jr nz, .loop
+ ret
+
+LoadSmokeTile:
+ ld de, SSAnneSmokePuffTile
+ lb bc, BANK(SSAnneSmokePuffTile), (SSAnneSmokePuffTileEnd - SSAnneSmokePuffTile) / $10
+ jp CopyVideoData
+
+SSAnneSmokePuffTile:
+ INCBIN "gfx/overworld/smoke.2bpp"
+SSAnneSmokePuffTileEnd:
--- a/engine/overworld/hidden_items.asm
+++ /dev/null
@@ -1,161 +1,0 @@
-HiddenItems:
- ld hl, HiddenItemCoords
- call FindHiddenItemOrCoinsIndex
- ld [wHiddenItemOrCoinsIndex], a
- ld hl, wObtainedHiddenItemsFlags
- ld a, [wHiddenItemOrCoinsIndex]
- ld c, a
- ld b, FLAG_TEST
- predef FlagActionPredef
- ld a, c
- and a
- ret nz
- call EnableAutoTextBoxDrawing
- ld a, 1
- ld [wDoNotWaitForButtonPressAfterDisplayingText], a
- ld a, [wHiddenObjectFunctionArgument] ; item ID
- ld [wd11e], a
- call GetItemName
- tx_pre_jump FoundHiddenItemText
-
-INCLUDE "data/hidden_item_coords.asm"
-
-FoundHiddenItemText::
- TX_FAR _FoundHiddenItemText
- TX_ASM
- ld a, [wHiddenObjectFunctionArgument] ; item ID
- ld b, a
- ld c, 1
- call GiveItem
- jr nc, .bagFull
- ld hl, wObtainedHiddenItemsFlags
- ld a, [wHiddenItemOrCoinsIndex]
- ld c, a
- ld b, FLAG_SET
- predef FlagActionPredef
- ld a, SFX_GET_ITEM_2
- call PlaySoundWaitForCurrent
- call WaitForSoundToFinish
- jp TextScriptEnd
-.bagFull
- call WaitForTextScrollButtonPress ; wait for button press
- xor a
- ld [wDoNotWaitForButtonPressAfterDisplayingText], a
- ld hl, HiddenItemBagFullText
- call PrintText
- jp TextScriptEnd
-
-HiddenItemBagFullText::
- TX_FAR _HiddenItemBagFullText
- db "@"
-
-HiddenCoins:
- ld b, COIN_CASE
- predef GetQuantityOfItemInBag
- ld a, b
- and a
- ret z
- ld hl, HiddenCoinCoords
- call FindHiddenItemOrCoinsIndex
- ld [wHiddenItemOrCoinsIndex], a
- ld hl, wObtainedHiddenCoinsFlags
- ld a, [wHiddenItemOrCoinsIndex]
- ld c, a
- ld b, FLAG_TEST
- predef FlagActionPredef
- ld a, c
- and a
- ret nz
- xor a
- ld [hUnusedCoinsByte], a
- ld [hCoins], a
- ld [hCoins + 1], a
- ld a, [wHiddenObjectFunctionArgument]
- sub COIN
- cp 10
- jr z, .bcd10
- cp 20
- jr z, .bcd20
- cp 40
- jr z, .bcd20 ; should be bcd40
- jr .bcd100
-.bcd10
- ld a, $10
- ld [hCoins + 1], a
- jr .bcdDone
-.bcd20
- ld a, $20
- ld [hCoins + 1], a
- jr .bcdDone
-.bcd40 ; due to a typo, this is never used
- ld a, $40
- ld [hCoins + 1], a
- jr .bcdDone
-.bcd100
- ld a, $1
- ld [hCoins], a
-.bcdDone
- ld de, wPlayerCoins + 1
- ld hl, hCoins + 1
- ld c, $2
- predef AddBCDPredef
- ld hl, wObtainedHiddenCoinsFlags
- ld a, [wHiddenItemOrCoinsIndex]
- ld c, a
- ld b, FLAG_SET
- predef FlagActionPredef
- call EnableAutoTextBoxDrawing
- ld a, [wPlayerCoins]
- cp $99
- jr nz, .roomInCoinCase
- ld a, [wPlayerCoins + 1]
- cp $99
- jr nz, .roomInCoinCase
- tx_pre_id DroppedHiddenCoinsText
- jr .done
-.roomInCoinCase
- tx_pre_id FoundHiddenCoinsText
-.done
- jp PrintPredefTextID
-
-INCLUDE "data/hidden_coins.asm"
-
-FoundHiddenCoinsText::
- TX_FAR _FoundHiddenCoinsText
- TX_SFX_ITEM_2
- db "@"
-
-DroppedHiddenCoinsText::
- TX_FAR _FoundHiddenCoins2Text
- TX_SFX_ITEM_2
- TX_FAR _DroppedHiddenCoinsText
- db "@"
-
-FindHiddenItemOrCoinsIndex:
- ld a, [wHiddenObjectY]
- ld d, a
- ld a, [wHiddenObjectX]
- ld e, a
- ld a, [wCurMap]
- ld b, a
- ld c, -1
-.loop
- inc c
- ld a, [hli]
- cp $ff ; end of the list?
- ret z ; if so, we're done here
- cp b
- jr nz, .next1
- ld a, [hli]
- cp d
- jr nz, .next2
- ld a, [hli]
- cp e
- jr nz, .loop
- ld a, c
- ret
-.next1
- inc hl
-.next2
- inc hl
- jr .loop
--- a/engine/overworld/item.asm
+++ /dev/null
@@ -1,54 +1,0 @@
-PickUpItem:
- call EnableAutoTextBoxDrawing
-
- ld a, [hSpriteIndexOrTextID]
- ld b, a
- ld hl, wMissableObjectList
-.missableObjectsListLoop
- ld a, [hli]
- cp $ff
- ret z
- cp b
- jr z, .isMissable
- inc hl
- jr .missableObjectsListLoop
-
-.isMissable
- ld a, [hl]
- ld [$ffdb], a
-
- ld hl, wMapSpriteExtraData
- ld a, [hSpriteIndexOrTextID]
- dec a
- add a
- ld d, 0
- ld e, a
- add hl, de
- ld a, [hl]
- ld b, a ; item
- ld c, 1 ; quantity
- call GiveItem
- jr nc, .BagFull
-
- ld a, [$ffdb]
- ld [wMissableObjectIndex], a
- predef HideObject
- ld a, 1
- ld [wDoNotWaitForButtonPressAfterDisplayingText], a
- ld hl, FoundItemText
- jr .print
-
-.BagFull
- ld hl, NoMoreRoomForItemText
- call PrintText
- ret
-
-FoundItemText:
- TX_FAR _FoundItemText
- TX_SFX_ITEM_1
- db "@"
-
-NoMoreRoomForItemText:
- TX_FAR _NoMoreRoomForItemText
- db "@"
--- a/engine/overworld/map_sprite_functions1.asm
+++ /dev/null
@@ -1,356 +1,0 @@
-_UpdateSprites::
- ld h, $c1
- inc h
- ld a, $e ; wSpriteStateData2 + $0e
-.spriteLoop
- ld l, a
- sub $e
- ld c, a
- ld [H_CURRENTSPRITEOFFSET], a
- ld a, [hl]
- and a
- jr z, .skipSprite ; tests $c2Xe
- push hl
- push de
- push bc
- call .updateCurrentSprite
- pop bc
- pop de
- pop hl
-.skipSprite
- ld a, l
- add $10 ; move to next sprite
- cp $e ; test for overflow (back at $0e)
- jr nz, .spriteLoop
- ret
-.updateCurrentSprite
- cp $1
- jp nz, UpdateNonPlayerSprite
- jp UpdatePlayerSprite
-
-UpdateNonPlayerSprite:
- dec a
- swap a
- ld [$ff93], a ; $10 * sprite#
- ld a, [wNPCMovementScriptSpriteOffset] ; some sprite offset?
- ld b, a
- ld a, [H_CURRENTSPRITEOFFSET]
- cp b
- jr nz, .unequal
- jp DoScriptedNPCMovement
-.unequal
- jp UpdateNPCSprite
-
-; This detects if the current sprite (whose offset is at H_CURRENTSPRITEOFFSET)
-; is going to collide with another sprite by looping over the other sprites.
-; The current sprite's offset will be labelled with i (e.g. $c1i0).
-; The loop sprite's offset will labelled with j (e.g. $c1j0).
-;
-; Note that the Y coordinate of the sprite (in [$c1k4]) is one of the following
-; 9 values when the sprite is aligned with the grid: $fc, $0c, $1c, $2c, ..., $7c.
-; The reason that 4 is added below to the coordinate is to make it align with a
-; multiple of $10 to make comparisons easier.
-DetectCollisionBetweenSprites:
- nop
-
- ld h, wSpriteStateData1 / $100
- ld a, [H_CURRENTSPRITEOFFSET]
- add wSpriteStateData1 % $100
- ld l, a
-
- ld a, [hl] ; a = [$c1i0] (picture) (0 if slot is unused)
- and a ; is this sprite slot slot used?
- ret z ; return if not used
-
- ld a, l
- add 3
- ld l, a
-
- ld a, [hli] ; a = [$c1i3] (delta Y) (-1, 0, or 1)
- call SetSpriteCollisionValues
-
- ld a, [hli] ; a = [$C1i4] (Y screen coordinate)
- add 4 ; align with multiple of $10
-
-; The effect of the following 3 lines is to
-; add 7 to a if moving south or
-; subtract 7 from a if moving north.
- add b
- and $f0
- or c
-
- ld [$ff90], a ; store Y coordinate adjusted for direction of movement
-
- ld a, [hli] ; a = [$c1i5] (delta X) (-1, 0, or 1)
- call SetSpriteCollisionValues
- ld a, [hl] ; a = [$C1i6] (X screen coordinate)
-
-; The effect of the following 3 lines is to
-; add 7 to a if moving east or
-; subtract 7 from a if moving west.
- add b
- and $f0
- or c
-
- ld [$ff91], a ; store X coordinate adjusted for direction of movement
-
- ld a, l
- add 7
- ld l, a
-
- xor a
- ld [hld], a ; zero [$c1id] XXX what's [$c1id] for?
- ld [hld], a ; zero [$c1ic] (directions in which collisions occurred)
-
- ld a, [$ff91]
- ld [hld], a ; [$c1ib] = adjusted X coordinate
- ld a, [$ff90]
- ld [hl], a ; [$c1ia] = adjusted Y coordinate
-
- xor a ; zero the loop counter
-
-.loop
- ld [$ff8f], a ; store loop counter
- swap a
- ld e, a
- ld a, [H_CURRENTSPRITEOFFSET]
- cp e ; does the loop sprite match the current sprite?
- jp z, .next ; go to the next sprite if they match
-
- ld d, h
- ld a, [de] ; a = [$c1j0] (picture) (0 if slot is unused)
- and a ; is this sprite slot slot used?
- jp z, .next ; go the next sprite if not used
-
- inc e
- inc e
- ld a, [de] ; a = [$c1j2] ($ff means the sprite is offscreen)
- inc a
- jp z, .next ; go the next sprite if offscreen
-
- ld a, [H_CURRENTSPRITEOFFSET]
- add 10
- ld l, a
-
- inc e
- ld a, [de] ; a = [$c1j3] (delta Y)
- call SetSpriteCollisionValues
-
- inc e
- ld a, [de] ; a = [$C1j4] (Y screen coordinate)
- add 4 ; align with multiple of $10
-
-; The effect of the following 3 lines is to
-; add 7 to a if moving south or
-; subtract 7 from a if moving north.
- add b
- and $f0
- or c
-
- sub [hl] ; subtract the adjusted Y coordinate of sprite i ([$c1ia]) from that of sprite j
-
-; calculate the absolute value of the difference to get the distance
- jr nc, .noCarry1
- cpl
- inc a
-.noCarry1
- ld [$ff90], a ; store the distance between the two sprites' adjusted Y values
-
-; Use the carry flag set by the above subtraction to determine which sprite's
-; Y coordinate is larger. This information is used later to set [$c1ic],
-; which stores which direction the collision occurred in.
-; The following 5 lines set the lowest 2 bits of c, which are later shifted left by 2.
-; If sprite i's Y is larger, set lowest 2 bits of c to 10.
-; If sprite j's Y is larger or both are equal, set lowest 2 bits of c to 01.
- push af
- rl c
- pop af
- ccf
- rl c
-
-; If sprite i's delta Y is 0, then b = 7, else b = 9.
- ld b, 7
- ld a, [hl] ; a = [$c1ia] (adjusted Y coordinate)
- and $f
- jr z, .next1
- ld b, 9
-
-.next1
- ld a, [$ff90] ; a = distance between adjusted Y coordinates
- sub b
- ld [$ff92], a ; store distance adjusted using sprite i's direction
- ld a, b
- ld [$ff90], a ; store 7 or 9 depending on sprite i's delta Y
- jr c, .checkXDistance
-
-; If sprite j's delta Y is 0, then b = 7, else b = 9.
- ld b, 7
- dec e
- ld a, [de] ; a = [$c1j3] (delta Y)
- inc e
- and a
- jr z, .next2
- ld b, 9
-
-.next2
- ld a, [$ff92] ; a = distance adjusted using sprite i's direction
- sub b ; adjust distance using sprite j's direction
- jr z, .checkXDistance
- jr nc, .next ; go to next sprite if distance is still positive after both adjustments
-
-.checkXDistance
- inc e
- inc l
- ld a, [de] ; a = [$c1j5] (delta X)
-
- push bc
-
- call SetSpriteCollisionValues
- inc e
- ld a, [de] ; a = [$c1j6] (X screen coordinate)
-
-; The effect of the following 3 lines is to
-; add 7 to a if moving east or
-; subtract 7 from a if moving west.
- add b
- and $f0
- or c
-
- pop bc
-
- sub [hl] ; subtract the adjusted X coordinate of sprite i ([$c1ib]) from that of sprite j
-
-; calculate the absolute value of the difference to get the distance
- jr nc, .noCarry2
- cpl
- inc a
-.noCarry2
- ld [$ff91], a ; store the distance between the two sprites' adjusted X values
-
-; Use the carry flag set by the above subtraction to determine which sprite's
-; X coordinate is larger. This information is used later to set [$c1ic],
-; which stores which direction the collision occurred in.
-; The following 5 lines set the lowest 2 bits of c.
-; If sprite i's X is larger, set lowest 2 bits of c to 10.
-; If sprite j's X is larger or both are equal, set lowest 2 bits of c to 01.
- push af
- rl c
- pop af
- ccf
- rl c
-
-; If sprite i's delta X is 0, then b = 7, else b = 9.
- ld b, 7
- ld a, [hl] ; a = [$c1ib] (adjusted X coordinate)
- and $f
- jr z, .next3
- ld b, 9
-
-.next3
- ld a, [$ff91] ; a = distance between adjusted X coordinates
- sub b
- ld [$ff92], a ; store distance adjusted using sprite i's direction
- ld a, b
- ld [$ff91], a ; store 7 or 9 depending on sprite i's delta X
- jr c, .collision
-
-; If sprite j's delta X is 0, then b = 7, else b = 9.
- ld b, 7
- dec e
- ld a, [de] ; a = [$c1j5] (delta X)
- inc e
- and a
- jr z, .next4
- ld b, 9
-
-.next4
- ld a, [$ff92] ; a = distance adjusted using sprite i's direction
- sub b ; adjust distance using sprite j's direction
- jr z, .collision
- jr nc, .next ; go to next sprite if distance is still positive after both adjustments
-
-.collision
- ld a, [$ff91] ; a = 7 or 9 depending on sprite i's delta X
- ld b, a
- ld a, [$ff90] ; a = 7 or 9 depending on sprite i's delta Y
- inc l
-
-; If delta X isn't 0 and delta Y is 0, then b = %0011, else b = %1100.
-; (note that normally if delta X isn't 0, then delta Y must be 0 and vice versa)
- cp b
- jr c, .next5
- ld b, %1100
- jr .next6
-.next5
- ld b, %0011
-
-.next6
- ld a, c ; c has 2 bits set (one of bits 0-1 is set for the X axis and one of bits 2-3 for the Y axis)
- and b ; we select either the bit in bits 0-1 or bits 2-3 based on the calculation immediately above
- or [hl] ; or with existing collision direction bits in [$c1ic]
- ld [hl], a ; store new value
- ld a, c ; useless code because a is overwritten before being used again
-
-; set bit in [$c1ie] or [$c1if] to indicate which sprite the collision occurred with
- inc l
- inc l
- ld a, [$ff8f] ; a = loop counter
- ld de, SpriteCollisionBitTable
- add a
- add e
- ld e, a
- jr nc, .noCarry3
- inc d
-.noCarry3
- ld a, [de]
- or [hl]
- ld [hli], a
- inc de
- ld a, [de]
- or [hl]
- ld [hl], a
-
-.next
- ld a, [$ff8f] ; a = loop counter
- inc a
- cp $10
- jp nz, .loop
- ret
-
-; takes delta X or delta Y in a
-; b = delta X/Y
-; c = 0 if delta X/Y is 0
-; c = 7 if delta X/Y is 1
-; c = 9 if delta X/Y is -1
-SetSpriteCollisionValues:
- and a
- ld b, 0
- ld c, 0
- jr z, .done
- ld c, 9
- cp -1
- jr z, .ok
- ld c, 7
- ld a, 0
-.ok
- ld b, a
-.done
- ret
-
-SpriteCollisionBitTable:
- db %00000000,%00000001
- db %00000000,%00000010
- db %00000000,%00000100
- db %00000000,%00001000
- db %00000000,%00010000
- db %00000000,%00100000
- db %00000000,%01000000
- db %00000000,%10000000
- db %00000001,%00000000
- db %00000010,%00000000
- db %00000100,%00000000
- db %00001000,%00000000
- db %00010000,%00000000
- db %00100000,%00000000
- db %01000000,%00000000
- db %10000000,%00000000
--- a/engine/overworld/npc_movement.asm
+++ /dev/null
@@ -1,292 +1,0 @@
-PlayerStepOutFromDoor::
- ld hl, wd730
- res 1, [hl]
- call IsPlayerStandingOnDoorTile
- jr nc, .notStandingOnDoor
- ld a, $fc
- ld [wJoyIgnore], a
- ld hl, wd736
- set 1, [hl]
- ld a, $1
- ld [wSimulatedJoypadStatesIndex], a
- ld a, D_DOWN
- ld [wSimulatedJoypadStatesEnd], a
- xor a
- ld [wSpriteStateData1 + 2], a
- call StartSimulatingJoypadStates
- ret
-.notStandingOnDoor
- xor a
- ld [wWastedByteCD3A], a
- ld [wSimulatedJoypadStatesIndex], a
- ld [wSimulatedJoypadStatesEnd], a
- ld hl, wd736
- res 0, [hl]
- res 1, [hl]
- ld hl, wd730
- res 7, [hl]
- ret
-
-_EndNPCMovementScript::
- ld hl, wd730
- res 7, [hl]
- ld hl, wd72e
- res 7, [hl]
- ld hl, wd736
- res 0, [hl]
- res 1, [hl]
- xor a
- ld [wNPCMovementScriptSpriteOffset], a
- ld [wNPCMovementScriptPointerTableNum], a
- ld [wNPCMovementScriptFunctionNum], a
- ld [wWastedByteCD3A], a
- ld [wSimulatedJoypadStatesIndex], a
- ld [wSimulatedJoypadStatesEnd], a
- ret
-
-PalletMovementScriptPointerTable::
- dw PalletMovementScript_OakMoveLeft
- dw PalletMovementScript_PlayerMoveLeft
- dw PalletMovementScript_WaitAndWalkToLab
- dw PalletMovementScript_WalkToLab
- dw PalletMovementScript_Done
-
-PalletMovementScript_OakMoveLeft:
- ld a, [wXCoord]
- sub $a
- ld [wNumStepsToTake], a
- jr z, .playerOnLeftTile
-; The player is on the right tile of the northern path out of Pallet Town and
-; Prof. Oak is below.
-; Make Prof. Oak step to the left.
- ld b, 0
- ld c, a
- ld hl, wNPCMovementDirections2
- ld a, NPC_MOVEMENT_LEFT
- call FillMemory
- ld [hl], $ff
- ld a, [wSpriteIndex]
- ld [H_SPRITEINDEX], a
- ld de, wNPCMovementDirections2
- call MoveSprite
- ld a, $1
- ld [wNPCMovementScriptFunctionNum], a
- jr .done
-; The player is on the left tile of the northern path out of Pallet Town and
-; Prof. Oak is below.
-; Prof. Oak is already where he needs to be.
-.playerOnLeftTile
- ld a, $3
- ld [wNPCMovementScriptFunctionNum], a
-.done
- ld hl, wFlags_D733
- set 1, [hl]
- ld a, $fc
- ld [wJoyIgnore], a
- ret
-
-PalletMovementScript_PlayerMoveLeft:
- ld a, [wd730]
- bit 0, a ; is an NPC being moved by a script?
- ret nz ; return if Oak is still moving
- ld a, [wNumStepsToTake]
- ld [wSimulatedJoypadStatesIndex], a
- ld [hNPCMovementDirections2Index], a
- predef ConvertNPCMovementDirectionsToJoypadMasks
- call StartSimulatingJoypadStates
- ld a, $2
- ld [wNPCMovementScriptFunctionNum], a
- ret
-
-PalletMovementScript_WaitAndWalkToLab:
- ld a, [wSimulatedJoypadStatesIndex]
- and a ; is the player done moving left yet?
- ret nz
-
-PalletMovementScript_WalkToLab:
- xor a
- ld [wOverrideSimulatedJoypadStatesMask], a
- ld a, [wSpriteIndex]
- swap a
- ld [wNPCMovementScriptSpriteOffset], a
- xor a
- ld [wSpriteStateData2 + $06], a
- ld hl, wSimulatedJoypadStatesEnd
- ld de, RLEList_PlayerWalkToLab
- call DecodeRLEList
- dec a
- ld [wSimulatedJoypadStatesIndex], a
- ld hl, wNPCMovementDirections2
- ld de, RLEList_ProfOakWalkToLab
- call DecodeRLEList
- ld hl, wd72e
- res 7, [hl]
- ld hl, wd730
- set 7, [hl]
- ld a, $4
- ld [wNPCMovementScriptFunctionNum], a
- ret
-
-RLEList_ProfOakWalkToLab:
- db NPC_MOVEMENT_DOWN, $05
- db NPC_MOVEMENT_LEFT, $01
- db NPC_MOVEMENT_DOWN, $05
- db NPC_MOVEMENT_RIGHT, $03
- db NPC_MOVEMENT_UP, $01
- db $E0, $01 ; stand still
- db $FF
-
-RLEList_PlayerWalkToLab:
- db D_UP, $02
- db D_RIGHT, $03
- db D_DOWN, $05
- db D_LEFT, $01
- db D_DOWN, $06
- db $FF
-
-PalletMovementScript_Done:
- ld a, [wSimulatedJoypadStatesIndex]
- and a
- ret nz
- ld a, HS_PALLET_TOWN_OAK
- ld [wMissableObjectIndex], a
- predef HideObject
- ld hl, wd730
- res 7, [hl]
- ld hl, wd72e
- res 7, [hl]
- jp EndNPCMovementScript
-
-PewterMuseumGuyMovementScriptPointerTable::
- dw PewterMovementScript_WalkToMuseum
- dw PewterMovementScript_Done
-
-PewterMovementScript_WalkToMuseum:
- ld a, BANK(Music_MuseumGuy)
- ld [wAudioROMBank], a
- ld [wAudioSavedROMBank], a
- ld a, MUSIC_MUSEUM_GUY
- ld [wNewSoundID], a
- call PlaySound
- ld a, [wSpriteIndex]
- swap a
- ld [wNPCMovementScriptSpriteOffset], a
- call StartSimulatingJoypadStates
- ld hl, wSimulatedJoypadStatesEnd
- ld de, RLEList_PewterMuseumPlayer
- call DecodeRLEList
- dec a
- ld [wSimulatedJoypadStatesIndex], a
- xor a
- ld [wWhichPewterGuy], a
- predef PewterGuys
- ld hl, wNPCMovementDirections2
- ld de, RLEList_PewterMuseumGuy
- call DecodeRLEList
- ld hl, wd72e
- res 7, [hl]
- ld a, $1
- ld [wNPCMovementScriptFunctionNum], a
- ret
-
-RLEList_PewterMuseumPlayer:
- db 0, $01
- db D_UP, $03
- db D_LEFT, $0D
- db D_UP, $06
- db $FF
-
-RLEList_PewterMuseumGuy:
- db NPC_MOVEMENT_UP, $06
- db NPC_MOVEMENT_LEFT, $0D
- db NPC_MOVEMENT_UP, $03
- db NPC_MOVEMENT_LEFT, $01
- db $FF
-
-PewterMovementScript_Done:
- ld a, [wSimulatedJoypadStatesIndex]
- and a
- ret nz
- ld hl, wd730
- res 7, [hl]
- ld hl, wd72e
- res 7, [hl]
- jp EndNPCMovementScript
-
-PewterGymGuyMovementScriptPointerTable::
- dw PewterMovementScript_WalkToGym
- dw PewterMovementScript_Done
-
-PewterMovementScript_WalkToGym:
- ld a, BANK(Music_MuseumGuy)
- ld [wAudioROMBank], a
- ld [wAudioSavedROMBank], a
- ld a, MUSIC_MUSEUM_GUY
- ld [wNewSoundID], a
- call PlaySound
- ld a, [wSpriteIndex]
- swap a
- ld [wNPCMovementScriptSpriteOffset], a
- xor a
- ld [wSpriteStateData2 + $06], a
- ld hl, wSimulatedJoypadStatesEnd
- ld de, RLEList_PewterGymPlayer
- call DecodeRLEList
- dec a
- ld [wSimulatedJoypadStatesIndex], a
- ld a, 1
- ld [wWhichPewterGuy], a
- predef PewterGuys
- ld hl, wNPCMovementDirections2
- ld de, RLEList_PewterGymGuy
- call DecodeRLEList
- ld hl, wd72e
- res 7, [hl]
- ld hl, wd730
- set 7, [hl]
- ld a, $1
- ld [wNPCMovementScriptFunctionNum], a
- ret
-
-RLEList_PewterGymPlayer:
- db 0, $01
- db D_RIGHT, $02
- db D_DOWN, $05
- db D_LEFT, $0B
- db D_UP, $05
- db D_LEFT, $0F
- db $FF
-
-RLEList_PewterGymGuy:
- db NPC_MOVEMENT_DOWN, $02
- db NPC_MOVEMENT_LEFT, $0F
- db NPC_MOVEMENT_UP, $05
- db NPC_MOVEMENT_LEFT, $0B
- db NPC_MOVEMENT_DOWN, $05
- db NPC_MOVEMENT_RIGHT, $03
- db $FF
-
-FreezeEnemyTrainerSprite::
- ld a, [wCurMap]
- cp POKEMON_TOWER_7F
- ret z ; the Rockets on Pokemon Tower 7F leave after battling, so don't freeze them
- ld hl, RivalIDs
- ld a, [wEngagedTrainerClass]
- ld b, a
-.loop
- ld a, [hli]
- cp $ff
- jr z, .notRival
- cp b
- ret z ; the rival leaves after battling, so don't freeze him
- jr .loop
-.notRival
- ld a, [wSpriteIndex]
- ld [H_SPRITEINDEX], a
- jp SetSpriteMovementBytesToFF
-
-RivalIDs:
- db OPP_SONY1
- db OPP_SONY2
- db OPP_SONY3
- db $ff
--- a/engine/overworld/oaks_aide.asm
+++ /dev/null
@@ -1,71 +1,0 @@
-OaksAideScript:
- ld hl, OaksAideHiText
- call PrintText
- call YesNoChoice
- ld a, [wCurrentMenuItem]
- and a
- jr nz, .choseNo
- ld hl, wPokedexOwned
- ld b, wPokedexOwnedEnd - wPokedexOwned
- call CountSetBits
- ld a, [wNumSetBits]
- ld [hOaksAideNumMonsOwned], a
- ld b, a
- ld a, [hOaksAideRequirement]
- cp b
- jr z, .giveItem
- jr nc, .notEnoughOwnedMons
-.giveItem
- ld hl, OaksAideHereYouGoText
- call PrintText
- ld a, [hOaksAideRewardItem]
- ld b, a
- ld c, 1
- call GiveItem
- jr nc, .bagFull
- ld hl, OaksAideGotItemText
- call PrintText
- ld a, $1
- jr .done
-.bagFull
- ld hl, OaksAideNoRoomText
- call PrintText
- xor a
- jr .done
-.notEnoughOwnedMons
- ld hl, OaksAideUhOhText
- call PrintText
- ld a, $80
- jr .done
-.choseNo
- ld hl, OaksAideComeBackText
- call PrintText
- ld a, $ff
-.done
- ld [hOaksAideResult], a
- ret
-
-OaksAideHiText:
- TX_FAR _OaksAideHiText
- db "@"
-
-OaksAideUhOhText:
- TX_FAR _OaksAideUhOhText
- db "@"
-
-OaksAideComeBackText:
- TX_FAR _OaksAideComeBackText
- db "@"
-
-OaksAideHereYouGoText:
- TX_FAR _OaksAideHereYouGoText
- db "@"
-
-OaksAideGotItemText:
- TX_FAR _OaksAideGotItemText
- TX_SFX_ITEM_1
- db "@"
-
-OaksAideNoRoomText:
- TX_FAR _OaksAideNoRoomText
- db "@"
--- a/engine/overworld/oam.asm
+++ /dev/null
@@ -1,189 +1,0 @@
-PrepareOAMData::
-; Determine OAM data for currently visible
-; sprites and write it to wOAMBuffer.
-
- ld a, [wUpdateSpritesEnabled]
- dec a
- jr z, .updateEnabled
-
- cp -1
- ret nz
- ld [wUpdateSpritesEnabled], a
- jp HideSprites
-
-.updateEnabled
- xor a
- ld [hOAMBufferOffset], a
-
-.spriteLoop
- ld [hSpriteOffset2], a
-
- ld d, wSpriteStateData1 / $100
- ld a, [hSpriteOffset2]
- ld e, a
- ld a, [de] ; c1x0
- and a
- jp z, .nextSprite
-
- inc e
- inc e
- ld a, [de] ; c1x2 (facing/anim)
- ld [wd5cd], a
- cp $ff ; off-screen (don't draw)
- jr nz, .visible
-
- call GetSpriteScreenXY
- jr .nextSprite
-
-.visible
- cp $a0 ; is the sprite unchanging like an item ball or boulder?
- jr c, .usefacing
-
-; unchanging
- and $f
- add $10 ; skip to the second half of the table which doesn't account for facing direction
- jr .next
-
-.usefacing
- and $f
-
-.next
- ld l, a
-
-; get sprite priority
- push de
- inc d
- ld a, e
- add $5
- ld e, a
- ld a, [de] ; c2x7
- and $80
- ld [hSpritePriority], a ; temp store sprite priority
- pop de
-
-; read the entry from the table
- ld h, 0
- ld bc, SpriteFacingAndAnimationTable
- add hl, hl
- add hl, hl
- add hl, bc
- ld a, [hli]
- ld c, a
- ld a, [hli]
- ld b, a
- ld a, [hli]
- ld h, [hl]
- ld l, a
-
- call GetSpriteScreenXY
-
- ld a, [hOAMBufferOffset]
- ld e, a
- ld d, wOAMBuffer / $100
-
-.tileLoop
- ld a, [hSpriteScreenY] ; temp for sprite Y position
- add $10 ; Y=16 is top of screen (Y=0 is invisible)
- add [hl] ; add Y offset from table
- ld [de], a ; write new sprite OAM Y position
- inc hl
- ld a, [hSpriteScreenX] ; temp for sprite X position
- add $8 ; X=8 is left of screen (X=0 is invisible)
- add [hl] ; add X offset from table
- inc e
- ld [de], a ; write new sprite OAM X position
- inc e
- ld a, [bc] ; read pattern number offset (accommodates orientation (offset 0,4 or 8) and animation (offset 0 or $80))
- inc bc
- push bc
- ld b, a
-
- ld a, [wd5cd] ; temp copy of c1x2
- swap a ; high nybble determines sprite used (0 is always player sprite, next are some npcs)
- and $f
-
- ; Sprites $a and $b have one face (and therefore 4 tiles instead of 12).
- ; As a result, sprite $b's tile offset is less than normal.
- cp $b
- jr nz, .notFourTileSprite
- ld a, $a * 12 + 4
- jr .next2
-
-.notFourTileSprite
- ; a *= 12
- sla a
- sla a
- ld c, a
- sla a
- add c
-
-.next2
- add b ; add the tile offset from the table (based on frame and facing direction)
- pop bc
- ld [de], a ; tile id
- inc hl
- inc e
- ld a, [hl]
- bit 1, a ; is the tile allowed to set the sprite priority bit?
- jr z, .skipPriority
- ld a, [hSpritePriority]
- or [hl]
-.skipPriority
- inc hl
- ld [de], a
- inc e
- bit 0, a ; OAMFLAG_ENDOFDATA
- jr z, .tileLoop
-
- ld a, e
- ld [hOAMBufferOffset], a
-
-.nextSprite
- ld a, [hSpriteOffset2]
- add $10
- cp $100 % $100
- jp nz, .spriteLoop
-
- ; Clear unused OAM.
- ld a, [hOAMBufferOffset]
- ld l, a
- ld h, wOAMBuffer / $100
- ld de, $4
- ld b, $a0
- ld a, [wd736]
- bit 6, a ; jumping down ledge or fishing animation?
- ld a, $a0
- jr z, .clear
-
-; Don't clear the last 4 entries because they are used for the shadow in the
-; jumping down ledge animation and the rod in the fishing animation.
- ld a, $90
-
-.clear
- cp l
- ret z
- ld [hl], b
- add hl, de
- jr .clear
-
-GetSpriteScreenXY:
- inc e
- inc e
- ld a, [de] ; c1x4
- ld [hSpriteScreenY], a
- inc e
- inc e
- ld a, [de] ; c1x6
- ld [hSpriteScreenX], a
- ld a, 4
- add e
- ld e, a
- ld a, [hSpriteScreenY]
- add 4
- and $f0
- ld [de], a ; c1xa (y)
- inc e
- ld a, [hSpriteScreenX]
- and $f0
- ld [de], a ; c1xb (x)
- ret
--- /dev/null
+++ b/engine/overworld/pathfinding.asm
@@ -1,0 +1,201 @@
+FindPathToPlayer:
+ xor a
+ ld hl, hFindPathNumSteps
+ ld [hli], a ; hFindPathNumSteps
+ ld [hli], a ; hFindPathFlags
+ ld [hli], a ; hFindPathYProgress
+ ld [hl], a ; hFindPathXProgress
+ ld hl, wNPCMovementDirections2
+ ld de, $0
+.loop
+ ld a, [hFindPathYProgress]
+ ld b, a
+ ld a, [hNPCPlayerYDistance] ; Y distance in steps
+ call CalcDifference
+ ld d, a
+ and a
+ jr nz, .asm_f8da
+ ld a, [hFindPathFlags]
+ set 0, a ; current end of path matches the player's Y coordinate
+ ld [hFindPathFlags], a
+.asm_f8da
+ ld a, [hFindPathXProgress]
+ ld b, a
+ ld a, [hNPCPlayerXDistance] ; X distance in steps
+ call CalcDifference
+ ld e, a
+ and a
+ jr nz, .asm_f8ec
+ ld a, [hFindPathFlags]
+ set 1, a ; current end of path matches the player's X coordinate
+ ld [hFindPathFlags], a
+.asm_f8ec
+ ld a, [hFindPathFlags]
+ cp $3 ; has the end of the path reached the player's position?
+ jr z, .done
+; Compare whether the X distance between the player and the current of the path
+; is greater or if the Y distance is. Then, try to reduce whichever is greater.
+ ld a, e
+ cp d
+ jr c, .yDistanceGreater
+; x distance is greater
+ ld a, [hNPCPlayerRelativePosFlags]
+ bit 1, a
+ jr nz, .playerIsLeftOfNPC
+ ld d, NPC_MOVEMENT_RIGHT
+ jr .next1
+.playerIsLeftOfNPC
+ ld d, NPC_MOVEMENT_LEFT
+.next1
+ ld a, [hFindPathXProgress]
+ add 1
+ ld [hFindPathXProgress], a
+ jr .storeDirection
+.yDistanceGreater
+ ld a, [hNPCPlayerRelativePosFlags]
+ bit 0, a
+ jr nz, .playerIsAboveNPC
+ ld d, NPC_MOVEMENT_DOWN
+ jr .next2
+.playerIsAboveNPC
+ ld d, NPC_MOVEMENT_UP
+.next2
+ ld a, [hFindPathYProgress]
+ add 1
+ ld [hFindPathYProgress], a
+.storeDirection
+ ld a, d
+ ld [hli], a
+ ld a, [hFindPathNumSteps]
+ inc a
+ ld [hFindPathNumSteps], a
+ jp .loop
+.done
+ ld [hl], $ff
+ ret
+
+CalcPositionOfPlayerRelativeToNPC:
+ xor a
+ ld [hNPCPlayerRelativePosFlags], a
+ ld a, [wSpriteStateData1 + 4] ; player's sprite screen Y position in pixels
+ ld d, a
+ ld a, [wSpriteStateData1 + 6] ; player's sprite screen X position in pixels
+ ld e, a
+ ld hl, wSpriteStateData1
+ ld a, [hNPCSpriteOffset]
+ add l
+ add $4
+ ld l, a
+ jr nc, .noCarry
+ inc h
+.noCarry
+ ld a, d
+ ld b, a
+ ld a, [hli] ; NPC sprite screen Y position in pixels
+ call CalcDifference
+ jr nc, .NPCSouthOfOrAlignedWithPlayer
+.NPCNorthOfPlayer
+ push hl
+ ld hl, hNPCPlayerRelativePosFlags
+ bit 0, [hl]
+ set 0, [hl]
+ pop hl
+ jr .divideYDistance
+.NPCSouthOfOrAlignedWithPlayer
+ push hl
+ ld hl, hNPCPlayerRelativePosFlags
+ bit 0, [hl]
+ res 0, [hl]
+ pop hl
+.divideYDistance
+ push hl
+ ld hl, hDividend2
+ ld [hli], a
+ ld a, 16
+ ld [hli], a
+ call DivideBytes ; divide Y absolute distance by 16
+ ld a, [hl] ; quotient
+ ld [hNPCPlayerYDistance], a
+ pop hl
+ inc hl
+ ld b, e
+ ld a, [hl] ; NPC sprite screen X position in pixels
+ call CalcDifference
+ jr nc, .NPCEastOfOrAlignedWithPlayer
+.NPCWestOfPlayer
+ push hl
+ ld hl, hNPCPlayerRelativePosFlags
+ bit 1, [hl]
+ set 1, [hl]
+ pop hl
+ jr .divideXDistance
+.NPCEastOfOrAlignedWithPlayer
+ push hl
+ ld hl, hNPCPlayerRelativePosFlags
+ bit 1, [hl]
+ res 1, [hl]
+ pop hl
+.divideXDistance
+ ld [hDividend2], a
+ ld a, 16
+ ld [hDivisor2], a
+ call DivideBytes ; divide X absolute distance by 16
+ ld a, [hQuotient2]
+ ld [hNPCPlayerXDistance], a
+ ld a, [hNPCPlayerRelativePosPerspective]
+ and a
+ ret z
+ ld a, [hNPCPlayerRelativePosFlags]
+ cpl
+ and $3
+ ld [hNPCPlayerRelativePosFlags], a
+ ret
+
+ConvertNPCMovementDirectionsToJoypadMasks:
+ ld a, [hNPCMovementDirections2Index]
+ ld [wNPCMovementDirections2Index], a
+ dec a
+ ld de, wSimulatedJoypadStatesEnd
+ ld hl, wNPCMovementDirections2
+ add l
+ ld l, a
+ jr nc, .loop
+ inc h
+.loop
+ ld a, [hld]
+ call ConvertNPCMovementDirectionToJoypadMask
+ ld [de], a
+ inc de
+ ld a, [hNPCMovementDirections2Index]
+ dec a
+ ld [hNPCMovementDirections2Index], a
+ jr nz, .loop
+ ret
+
+ConvertNPCMovementDirectionToJoypadMask:
+ push hl
+ ld b, a
+ ld hl, NPCMovementDirectionsToJoypadMasksTable
+.loop
+ ld a, [hli]
+ cp $ff
+ jr z, .done
+ cp b
+ jr z, .loadJoypadMask
+ inc hl
+ jr .loop
+.loadJoypadMask
+ ld a, [hl]
+.done
+ pop hl
+ ret
+
+NPCMovementDirectionsToJoypadMasksTable:
+ db NPC_MOVEMENT_UP, D_UP
+ db NPC_MOVEMENT_DOWN, D_DOWN
+ db NPC_MOVEMENT_LEFT, D_LEFT
+ db NPC_MOVEMENT_RIGHT, D_RIGHT
+ db $ff
+
+; unreferenced
+ ret
--- a/engine/overworld/pewter_guys.asm
+++ /dev/null
@@ -1,102 +1,0 @@
-PewterGuys:
- ld hl, wSimulatedJoypadStatesEnd
- ld a, [wSimulatedJoypadStatesIndex]
- dec a ; this decrement causes it to overwrite the last byte before $FF in the list
- ld [wSimulatedJoypadStatesIndex], a
- ld d, 0
- ld e, a
- add hl, de
- ld d, h
- ld e, l
- ld hl, PointerTable_37ce6
- ld a, [wWhichPewterGuy]
- add a
- ld b, 0
- ld c, a
- add hl, bc
- ld a, [hli]
- ld h, [hl]
- ld l, a
- ld a, [wYCoord]
- ld b, a
- ld a, [wXCoord]
- ld c, a
-.findMatchingCoordsLoop
- ld a, [hli]
- cp b
- jr nz, .nextEntry1
- ld a, [hli]
- cp c
- jr nz, .nextEntry2
- ld a, [hli]
- ld h, [hl]
- ld l, a
-.copyMovementDataLoop
- ld a, [hli]
- cp $ff
- ret z
- ld [de], a
- inc de
- ld a, [wSimulatedJoypadStatesIndex]
- inc a
- ld [wSimulatedJoypadStatesIndex], a
- jr .copyMovementDataLoop
-.nextEntry1
- inc hl
-.nextEntry2
- inc hl
- inc hl
- jr .findMatchingCoordsLoop
-
-PointerTable_37ce6:
- dw PewterMuseumGuyCoords
- dw PewterGymGuyCoords
-
-; these are the four coordinates of the spaces below, above, to the left and
-; to the right of the museum guy, and pointers to different movements for
-; the player to make to get positioned before the main movement.
-PewterMuseumGuyCoords:
- db 18, 27
- dw .down
- db 16, 27
- dw .up
- db 17, 26
- dw .left
- db 17, 28
- dw .right
-
-.down
- db D_UP, D_UP, $ff
-.up
- db D_RIGHT, D_LEFT, $ff
-.left
- db D_UP, D_RIGHT, $ff
-.right
- db D_UP, D_LEFT, $ff
-
-; these are the five coordinates which trigger the gym guy and pointers to
-; different movements for the player to make to get positioned before the
-; main movement
-; $00 is a pause
-PewterGymGuyCoords:
- db 16, 34
- dw .one
- db 17, 35
- dw .two
- db 18, 37
- dw .three
- db 19, 37
- dw .four
- db 17, 36
- dw .five
-
-.one
- db D_LEFT, D_DOWN, D_DOWN, D_RIGHT, $ff
-.two
- db D_LEFT, D_DOWN, D_RIGHT, D_LEFT, $ff
-.three
- db D_LEFT, D_LEFT, D_LEFT, $00, $00, $00, $00, $00, $00, $00, $00, $ff
-.four
- db D_LEFT, D_LEFT, D_UP, D_LEFT, $ff
-.five
- db D_LEFT, D_DOWN, D_LEFT, $00, $00, $00, $00, $00, $00, $00, $00, $ff
--- a/engine/overworld/poison.asm
+++ /dev/null
@@ -1,112 +1,0 @@
-ApplyOutOfBattlePoisonDamage:
- ld a, [wd730]
- add a
- jp c, .noBlackOut ; no black out if joypad states are being simulated
- ld a, [wPartyCount]
- and a
- jp z, .noBlackOut
- call IncrementDayCareMonExp
- ld a, [wStepCounter]
- and $3 ; is the counter a multiple of 4?
- jp nz, .noBlackOut ; only apply poison damage every fourth step
- ld [wWhichPokemon], a
- ld hl, wPartyMon1Status
- ld de, wPartySpecies
-.applyDamageLoop
- ld a, [hl]
- and (1 << PSN)
- jr z, .nextMon2 ; not poisoned
- dec hl
- dec hl
- ld a, [hld]
- ld b, a
- ld a, [hli]
- or b
- jr z, .nextMon ; already fainted
-; subtract 1 from HP
- ld a, [hl]
- dec a
- ld [hld], a
- inc a
- jr nz, .noBorrow
-; borrow 1 from upper byte of HP
- dec [hl]
- inc hl
- jr .nextMon
-.noBorrow
- ld a, [hli]
- or [hl]
- jr nz, .nextMon ; didn't faint from damage
-; the mon fainted from the damage
- push hl
- inc hl
- inc hl
- ld [hl], a
- ld a, [de]
- ld [wd11e], a
- push de
- ld a, [wWhichPokemon]
- ld hl, wPartyMonNicks
- call GetPartyMonName
- xor a
- ld [wJoyIgnore], a
- call EnableAutoTextBoxDrawing
- ld a, TEXT_MON_FAINTED
- ld [hSpriteIndexOrTextID], a
- call DisplayTextID
- pop de
- pop hl
-.nextMon
- inc hl
- inc hl
-.nextMon2
- inc de
- ld a, [de]
- inc a
- jr z, .applyDamageLoopDone
- ld bc, wPartyMon2 - wPartyMon1
- add hl, bc
- push hl
- ld hl, wWhichPokemon
- inc [hl]
- pop hl
- jr .applyDamageLoop
-.applyDamageLoopDone
- ld hl, wPartyMon1Status
- ld a, [wPartyCount]
- ld d, a
- ld e, 0
-.countPoisonedLoop
- ld a, [hl]
- and (1 << PSN)
- or e
- ld e, a
- ld bc, wPartyMon2 - wPartyMon1
- add hl, bc
- dec d
- jr nz, .countPoisonedLoop
- ld a, e
- and a ; are any party members poisoned?
- jr z, .skipPoisonEffectAndSound
- ld b, $2
- predef ChangeBGPalColor0_4Frames ; change BG white to dark grey for 4 frames
- ld a, SFX_POISONED
- call PlaySound
-.skipPoisonEffectAndSound
- predef AnyPartyAlive
- ld a, d
- and a
- jr nz, .noBlackOut
- call EnableAutoTextBoxDrawing
- ld a, TEXT_BLACKED_OUT
- ld [hSpriteIndexOrTextID], a
- call DisplayTextID
- ld hl, wd72e
- set 5, [hl]
- ld a, $ff
- jr .done
-.noBlackOut
- xor a
-.done
- ld [wOutOfBattleBlackout], a
- ret
--- a/engine/overworld/pokecenter.asm
+++ /dev/null
@@ -1,68 +1,0 @@
-DisplayPokemonCenterDialogue_::
- call SaveScreenTilesToBuffer1 ; save screen
- ld hl, PokemonCenterWelcomeText
- call PrintText
- ld hl, wd72e
- bit 2, [hl]
- set 1, [hl]
- set 2, [hl]
- jr nz, .skipShallWeHealYourPokemon
- ld hl, ShallWeHealYourPokemonText
- call PrintText
-.skipShallWeHealYourPokemon
- call YesNoChoicePokeCenter ; yes/no menu
- ld a, [wCurrentMenuItem]
- and a
- jr nz, .declinedHealing ; if the player chose No
- call SetLastBlackoutMap
- call LoadScreenTilesFromBuffer1 ; restore screen
- ld hl, NeedYourPokemonText
- call PrintText
- ld a, $18
- ld [wSpriteStateData1 + $12], a ; make the nurse turn to face the machine
- call Delay3
- predef HealParty
- callba AnimateHealingMachine ; do the healing machine animation
- xor a
- ld [wAudioFadeOutControl], a
- ld a, [wAudioSavedROMBank]
- ld [wAudioROMBank], a
- ld a, [wMapMusicSoundID]
- ld [wLastMusicSoundID], a
- ld [wNewSoundID], a
- call PlaySound
- ld hl, PokemonFightingFitText
- call PrintText
- ld a, $14
- ld [wSpriteStateData1 + $12], a ; make the nurse bow
- ld c, a
- call DelayFrames
- jr .done
-.declinedHealing
- call LoadScreenTilesFromBuffer1 ; restore screen
-.done
- ld hl, PokemonCenterFarewellText
- call PrintText
- jp UpdateSprites
-
-PokemonCenterWelcomeText:
- TX_FAR _PokemonCenterWelcomeText
- db "@"
-
-ShallWeHealYourPokemonText:
- TX_DELAY
- TX_FAR _ShallWeHealYourPokemonText
- db "@"
-
-NeedYourPokemonText:
- TX_FAR _NeedYourPokemonText
- db "@"
-
-PokemonFightingFitText:
- TX_FAR _PokemonFightingFitText
- db "@"
-
-PokemonCenterFarewellText:
- TX_DELAY
- TX_FAR _PokemonCenterFarewellText
- db "@"
--- a/engine/overworld/pokemart.asm
+++ /dev/null
@@ -1,272 +1,0 @@
-DisplayPokemartDialogue_::
- ld a, [wListScrollOffset]
- ld [wSavedListScrollOffset], a
- call UpdateSprites
- xor a
- ld [wBoughtOrSoldItemInMart], a
-.loop
- xor a
- ld [wListScrollOffset], a
- ld [wCurrentMenuItem], a
- ld [wPlayerMonNumber], a
- inc a
- ld [wPrintItemPrices], a
- ld a, MONEY_BOX
- ld [wTextBoxID], a
- call DisplayTextBoxID
- ld a, BUY_SELL_QUIT_MENU
- ld [wTextBoxID], a
- call DisplayTextBoxID
-
-; This code is useless. It copies the address of the pokemart's inventory to hl,
-; but the address is never used.
- ld hl, wItemListPointer
- ld a, [hli]
- ld l, [hl]
- ld h, a
-
- ld a, [wMenuExitMethod]
- cp CANCELLED_MENU
- jp z, .done
- ld a, [wChosenMenuItem]
- and a ; buying?
- jp z, .buyMenu
- dec a ; selling?
- jp z, .sellMenu
- dec a ; quitting?
- jp z, .done
-.sellMenu
-
-; the same variables are set again below, so this code has no effect
- xor a
- ld [wPrintItemPrices], a
- ld a, INIT_BAG_ITEM_LIST
- ld [wInitListType], a
- callab InitList
-
- ld a, [wNumBagItems]
- and a
- jp z, .bagEmpty
- ld hl, PokemonSellingGreetingText
- call PrintText
- call SaveScreenTilesToBuffer1 ; save screen
-.sellMenuLoop
- call LoadScreenTilesFromBuffer1 ; restore saved screen
- ld a, MONEY_BOX
- ld [wTextBoxID], a
- call DisplayTextBoxID ; draw money text box
- ld hl, wNumBagItems
- ld a, l
- ld [wListPointer], a
- ld a, h
- ld [wListPointer + 1], a
- xor a
- ld [wPrintItemPrices], a
- ld [wCurrentMenuItem], a
- ld a, ITEMLISTMENU
- ld [wListMenuID], a
- call DisplayListMenuID
- jp c, .returnToMainPokemartMenu ; if the player closed the menu
-.confirmItemSale ; if the player is trying to sell a specific item
- call IsKeyItem
- ld a, [wIsKeyItem]
- and a
- jr nz, .unsellableItem
- ld a, [wcf91]
- call IsItemHM
- jr c, .unsellableItem
- ld a, PRICEDITEMLISTMENU
- ld [wListMenuID], a
- ld [hHalveItemPrices], a ; halve prices when selling
- call DisplayChooseQuantityMenu
- inc a
- jr z, .sellMenuLoop ; if the player closed the choose quantity menu with the B button
- ld hl, PokemartTellSellPriceText
- lb bc, 14, 1 ; location that PrintText always prints to, this is useless
- call PrintText
- coord hl, 14, 7
- lb bc, 8, 15
- ld a, TWO_OPTION_MENU
- ld [wTextBoxID], a
- call DisplayTextBoxID ; yes/no menu
- ld a, [wMenuExitMethod]
- cp CHOSE_SECOND_ITEM
- jr z, .sellMenuLoop ; if the player chose No or pressed the B button
-
-; The following code is supposed to check if the player chose No, but the above
-; check already catches it.
- ld a, [wChosenMenuItem]
- dec a
- jr z, .sellMenuLoop
-
-.sellItem
- ld a, [wBoughtOrSoldItemInMart]
- and a
- jr nz, .skipSettingFlag1
- inc a
- ld [wBoughtOrSoldItemInMart], a
-.skipSettingFlag1
- call AddAmountSoldToMoney
- ld hl, wNumBagItems
- call RemoveItemFromInventory
- jp .sellMenuLoop
-.unsellableItem
- ld hl, PokemartUnsellableItemText
- call PrintText
- jp .returnToMainPokemartMenu
-.bagEmpty
- ld hl, PokemartItemBagEmptyText
- call PrintText
- call SaveScreenTilesToBuffer1
- jp .returnToMainPokemartMenu
-.buyMenu
-
-; the same variables are set again below, so this code has no effect
- ld a, 1
- ld [wPrintItemPrices], a
- ld a, INIT_OTHER_ITEM_LIST
- ld [wInitListType], a
- callab InitList
-
- ld hl, PokemartBuyingGreetingText
- call PrintText
- call SaveScreenTilesToBuffer1
-.buyMenuLoop
- call LoadScreenTilesFromBuffer1
- ld a, MONEY_BOX
- ld [wTextBoxID], a
- call DisplayTextBoxID
- ld hl, wItemList
- ld a, l
- ld [wListPointer], a
- ld a, h
- ld [wListPointer + 1], a
- xor a
- ld [wCurrentMenuItem], a
- inc a
- ld [wPrintItemPrices], a
- inc a ; a = 2 (PRICEDITEMLISTMENU)
- ld [wListMenuID], a
- call DisplayListMenuID
- jr c, .returnToMainPokemartMenu ; if the player closed the menu
- ld a, 99
- ld [wMaxItemQuantity], a
- xor a
- ld [hHalveItemPrices], a ; don't halve item prices when buying
- call DisplayChooseQuantityMenu
- inc a
- jr z, .buyMenuLoop ; if the player closed the choose quantity menu with the B button
- ld a, [wcf91] ; item ID
- ld [wd11e], a ; store item ID for GetItemName
- call GetItemName
- call CopyStringToCF4B ; copy name to wcf4b
- ld hl, PokemartTellBuyPriceText
- call PrintText
- coord hl, 14, 7
- lb bc, 8, 15
- ld a, TWO_OPTION_MENU
- ld [wTextBoxID], a
- call DisplayTextBoxID ; yes/no menu
- ld a, [wMenuExitMethod]
- cp CHOSE_SECOND_ITEM
- jp z, .buyMenuLoop ; if the player chose No or pressed the B button
-
-; The following code is supposed to check if the player chose No, but the above
-; check already catches it.
- ld a, [wChosenMenuItem]
- dec a
- jr z, .buyMenuLoop
-
-.buyItem
- call .isThereEnoughMoney
- jr c, .notEnoughMoney
- ld hl, wNumBagItems
- call AddItemToInventory
- jr nc, .bagFull
- call SubtractAmountPaidFromMoney
- ld a, [wBoughtOrSoldItemInMart]
- and a
- jr nz, .skipSettingFlag2
- ld a, 1
- ld [wBoughtOrSoldItemInMart], a
-.skipSettingFlag2
- ld a, SFX_PURCHASE
- call PlaySoundWaitForCurrent
- call WaitForSoundToFinish
- ld hl, PokemartBoughtItemText
- call PrintText
- jp .buyMenuLoop
-.returnToMainPokemartMenu
- call LoadScreenTilesFromBuffer1
- ld a, MONEY_BOX
- ld [wTextBoxID], a
- call DisplayTextBoxID
- ld hl, PokemartAnythingElseText
- call PrintText
- jp .loop
-.isThereEnoughMoney
- ld de, wPlayerMoney
- ld hl, hMoney
- ld c, 3 ; length of money in bytes
- jp StringCmp
-.notEnoughMoney
- ld hl, PokemartNotEnoughMoneyText
- call PrintText
- jr .returnToMainPokemartMenu
-.bagFull
- ld hl, PokemartItemBagFullText
- call PrintText
- jr .returnToMainPokemartMenu
-.done
- ld hl, PokemartThankYouText
- call PrintText
- ld a, 1
- ld [wUpdateSpritesEnabled], a
- call UpdateSprites
- ld a, [wSavedListScrollOffset]
- ld [wListScrollOffset], a
- ret
-
-PokemartBuyingGreetingText:
- TX_FAR _PokemartBuyingGreetingText
- db "@"
-
-PokemartTellBuyPriceText:
- TX_FAR _PokemartTellBuyPriceText
- db "@"
-
-PokemartBoughtItemText:
- TX_FAR _PokemartBoughtItemText
- db "@"
-
-PokemartNotEnoughMoneyText:
- TX_FAR _PokemartNotEnoughMoneyText
- db "@"
-
-PokemartItemBagFullText:
- TX_FAR _PokemartItemBagFullText
- db "@"
-
-PokemonSellingGreetingText:
- TX_FAR _PokemonSellingGreetingText
- db "@"
-
-PokemartTellSellPriceText:
- TX_FAR _PokemartTellSellPriceText
- db "@"
-
-PokemartItemBagEmptyText:
- TX_FAR _PokemartItemBagEmptyText
- db "@"
-
-PokemartUnsellableItemText:
- TX_FAR _PokemartUnsellableItemText
- db "@"
-
-PokemartThankYouText:
- TX_FAR _PokemartThankYouText
- db "@"
-
-PokemartAnythingElseText:
- TX_FAR _PokemartAnythingElseText
- db "@"
--- a/engine/overworld/saffron_guards.asm
+++ /dev/null
@@ -1,15 +1,0 @@
-RemoveGuardDrink::
- ld hl, GuardDrinksList
-.drinkLoop
- ld a, [hli]
- ld [$ffdb], a
- and a
- ret z
- push hl
- ld b, a
- call IsItemInBag
- pop hl
- jr z, .drinkLoop
- jpba RemoveItemByID
-
-INCLUDE "data/guard_drink_items.asm"
--- a/engine/overworld/set_blackout_map.asm
+++ /dev/null
@@ -1,25 +1,0 @@
-SetLastBlackoutMap:
-; Set the map to return to when
-; blacking out or using Teleport or Dig.
-; Safari rest houses don't count.
-
- push hl
- ld hl, SafariZoneRestHouses
- ld a, [wCurMap]
- ld b, a
-.loop
- ld a, [hli]
- cp -1
- jr z, .notresthouse
- cp b
- jr nz, .loop
- jr .done
-
-.notresthouse
- ld a, [wLastMap]
- ld [wLastBlackoutMap], a
-.done
- pop hl
- ret
-
-INCLUDE "data/rest_house_maps.asm"
--- /dev/null
+++ b/engine/overworld/special_warps.asm
@@ -1,0 +1,149 @@
+SpecialWarpIn::
+ call LoadSpecialWarpData
+ predef LoadTilesetHeader
+ ld hl, wd732
+ bit 2, [hl] ; dungeon warp or fly warp?
+ res 2, [hl]
+ jr z, .next
+; if dungeon warp or fly warp
+ ld a, [wDestinationMap]
+ jr .next2
+.next
+ bit 1, [hl]
+ jr z, .next3
+ call EmptyFunc
+.next3
+ ld a, 0
+.next2
+ ld b, a
+ ld a, [wd72d]
+ and a
+ jr nz, .next4
+ ld a, b
+.next4
+ ld hl, wd732
+ bit 4, [hl] ; dungeon warp?
+ ret nz
+; if not dungeon warp
+ ld [wLastMap], a
+ ret
+
+; gets the map ID, tile block map view pointer, tileset, and coordinates
+LoadSpecialWarpData:
+ ld a, [wd72d]
+ cp TRADE_CENTER
+ jr nz, .notTradeCenter
+ ld hl, TradeCenterSpec1
+ ld a, [hSerialConnectionStatus]
+ cp USING_INTERNAL_CLOCK ; which gameboy is clocking determines who is on the left and who is on the right
+ jr z, .copyWarpData
+ ld hl, TradeCenterSpec2
+ jr .copyWarpData
+.notTradeCenter
+ cp COLOSSEUM
+ jr nz, .notColosseum
+ ld hl, ColosseumSpec1
+ ld a, [hSerialConnectionStatus]
+ cp USING_INTERNAL_CLOCK
+ jr z, .copyWarpData
+ ld hl, ColosseumSpec2
+ jr .copyWarpData
+.notColosseum
+ ld a, [wd732]
+ bit 1, a
+ jr nz, .notFirstMap
+ bit 2, a
+ jr nz, .notFirstMap
+ ld hl, FirstMapSpec
+.copyWarpData
+ ld de, wCurMap
+ ld c, $7
+.copyWarpDataLoop
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .copyWarpDataLoop
+ ld a, [hli]
+ ld [wCurMapTileset], a
+ xor a
+ jr .done
+.notFirstMap
+ ld a, [wLastMap] ; this value is overwritten before it's ever read
+ ld hl, wd732
+ bit 4, [hl] ; used dungeon warp (jumped down hole/waterfall)?
+ jr nz, .usedDunegonWarp
+ bit 6, [hl] ; return to last pokemon center (or player's house)?
+ res 6, [hl]
+ jr z, .otherDestination
+; return to last pokemon center or player's house
+ ld a, [wLastBlackoutMap]
+ jr .usedFlyWarp
+.usedDunegonWarp
+ ld hl, wd72d
+ res 4, [hl]
+ ld a, [wDungeonWarpDestinationMap]
+ ld b, a
+ ld [wCurMap], a
+ ld a, [wWhichDungeonWarp]
+ ld c, a
+ ld hl, DungeonWarpList
+ ld de, 0
+ ld a, 6
+ ld [wDungeonWarpDataEntrySize], a
+.dungeonWarpListLoop
+ ld a, [hli]
+ cp b
+ jr z, .matchedDungeonWarpDestinationMap
+ inc hl
+ jr .nextDungeonWarp
+.matchedDungeonWarpDestinationMap
+ ld a, [hli]
+ cp c
+ jr z, .matchedDungeonWarpID
+.nextDungeonWarp
+ ld a, [wDungeonWarpDataEntrySize]
+ add e
+ ld e, a
+ jr .dungeonWarpListLoop
+.matchedDungeonWarpID
+ ld hl, DungeonWarpData
+ add hl, de
+ jr .copyWarpData2
+.otherDestination
+ ld a, [wDestinationMap]
+.usedFlyWarp
+ ld b, a
+ ld [wCurMap], a
+ ld hl, FlyWarpDataPtr
+.flyWarpDataPtrLoop
+ ld a, [hli]
+ inc hl
+ cp b
+ jr z, .foundFlyWarpMatch
+ inc hl
+ inc hl
+ jr .flyWarpDataPtrLoop
+.foundFlyWarpMatch
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+.copyWarpData2
+ ld de, wCurrentTileBlockMapViewPointer
+ ld c, $6
+.copyWarpDataLoop2
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .copyWarpDataLoop2
+ xor a ; OVERWORLD
+ ld [wCurMapTileset], a
+.done
+ ld [wYOffsetSinceLastSpecialWarp], a
+ ld [wXOffsetSinceLastSpecialWarp], a
+ ld a, $ff ; the player's coordinates have already been updated using a special warp, so don't use any of the normal warps
+ ld [wDestinationWarpID], a
+ ret
+
+INCLUDE "data/special_warps.asm"
--- /dev/null
+++ b/engine/overworld/sprite_collisions.asm
@@ -1,0 +1,356 @@
+_UpdateSprites::
+ ld h, $c1
+ inc h
+ ld a, $e ; wSpriteStateData2 + $0e
+.spriteLoop
+ ld l, a
+ sub $e
+ ld c, a
+ ld [H_CURRENTSPRITEOFFSET], a
+ ld a, [hl]
+ and a
+ jr z, .skipSprite ; tests $c2Xe
+ push hl
+ push de
+ push bc
+ call .updateCurrentSprite
+ pop bc
+ pop de
+ pop hl
+.skipSprite
+ ld a, l
+ add $10 ; move to next sprite
+ cp $e ; test for overflow (back at $0e)
+ jr nz, .spriteLoop
+ ret
+.updateCurrentSprite
+ cp $1
+ jp nz, UpdateNonPlayerSprite
+ jp UpdatePlayerSprite
+
+UpdateNonPlayerSprite:
+ dec a
+ swap a
+ ld [$ff93], a ; $10 * sprite#
+ ld a, [wNPCMovementScriptSpriteOffset] ; some sprite offset?
+ ld b, a
+ ld a, [H_CURRENTSPRITEOFFSET]
+ cp b
+ jr nz, .unequal
+ jp DoScriptedNPCMovement
+.unequal
+ jp UpdateNPCSprite
+
+; This detects if the current sprite (whose offset is at H_CURRENTSPRITEOFFSET)
+; is going to collide with another sprite by looping over the other sprites.
+; The current sprite's offset will be labelled with i (e.g. $c1i0).
+; The loop sprite's offset will labelled with j (e.g. $c1j0).
+;
+; Note that the Y coordinate of the sprite (in [$c1k4]) is one of the following
+; 9 values when the sprite is aligned with the grid: $fc, $0c, $1c, $2c, ..., $7c.
+; The reason that 4 is added below to the coordinate is to make it align with a
+; multiple of $10 to make comparisons easier.
+DetectCollisionBetweenSprites:
+ nop
+
+ ld h, wSpriteStateData1 / $100
+ ld a, [H_CURRENTSPRITEOFFSET]
+ add wSpriteStateData1 % $100
+ ld l, a
+
+ ld a, [hl] ; a = [$c1i0] (picture) (0 if slot is unused)
+ and a ; is this sprite slot slot used?
+ ret z ; return if not used
+
+ ld a, l
+ add 3
+ ld l, a
+
+ ld a, [hli] ; a = [$c1i3] (delta Y) (-1, 0, or 1)
+ call SetSpriteCollisionValues
+
+ ld a, [hli] ; a = [$C1i4] (Y screen coordinate)
+ add 4 ; align with multiple of $10
+
+; The effect of the following 3 lines is to
+; add 7 to a if moving south or
+; subtract 7 from a if moving north.
+ add b
+ and $f0
+ or c
+
+ ld [$ff90], a ; store Y coordinate adjusted for direction of movement
+
+ ld a, [hli] ; a = [$c1i5] (delta X) (-1, 0, or 1)
+ call SetSpriteCollisionValues
+ ld a, [hl] ; a = [$C1i6] (X screen coordinate)
+
+; The effect of the following 3 lines is to
+; add 7 to a if moving east or
+; subtract 7 from a if moving west.
+ add b
+ and $f0
+ or c
+
+ ld [$ff91], a ; store X coordinate adjusted for direction of movement
+
+ ld a, l
+ add 7
+ ld l, a
+
+ xor a
+ ld [hld], a ; zero [$c1id] XXX what's [$c1id] for?
+ ld [hld], a ; zero [$c1ic] (directions in which collisions occurred)
+
+ ld a, [$ff91]
+ ld [hld], a ; [$c1ib] = adjusted X coordinate
+ ld a, [$ff90]
+ ld [hl], a ; [$c1ia] = adjusted Y coordinate
+
+ xor a ; zero the loop counter
+
+.loop
+ ld [$ff8f], a ; store loop counter
+ swap a
+ ld e, a
+ ld a, [H_CURRENTSPRITEOFFSET]
+ cp e ; does the loop sprite match the current sprite?
+ jp z, .next ; go to the next sprite if they match
+
+ ld d, h
+ ld a, [de] ; a = [$c1j0] (picture) (0 if slot is unused)
+ and a ; is this sprite slot slot used?
+ jp z, .next ; go the next sprite if not used
+
+ inc e
+ inc e
+ ld a, [de] ; a = [$c1j2] ($ff means the sprite is offscreen)
+ inc a
+ jp z, .next ; go the next sprite if offscreen
+
+ ld a, [H_CURRENTSPRITEOFFSET]
+ add 10
+ ld l, a
+
+ inc e
+ ld a, [de] ; a = [$c1j3] (delta Y)
+ call SetSpriteCollisionValues
+
+ inc e
+ ld a, [de] ; a = [$C1j4] (Y screen coordinate)
+ add 4 ; align with multiple of $10
+
+; The effect of the following 3 lines is to
+; add 7 to a if moving south or
+; subtract 7 from a if moving north.
+ add b
+ and $f0
+ or c
+
+ sub [hl] ; subtract the adjusted Y coordinate of sprite i ([$c1ia]) from that of sprite j
+
+; calculate the absolute value of the difference to get the distance
+ jr nc, .noCarry1
+ cpl
+ inc a
+.noCarry1
+ ld [$ff90], a ; store the distance between the two sprites' adjusted Y values
+
+; Use the carry flag set by the above subtraction to determine which sprite's
+; Y coordinate is larger. This information is used later to set [$c1ic],
+; which stores which direction the collision occurred in.
+; The following 5 lines set the lowest 2 bits of c, which are later shifted left by 2.
+; If sprite i's Y is larger, set lowest 2 bits of c to 10.
+; If sprite j's Y is larger or both are equal, set lowest 2 bits of c to 01.
+ push af
+ rl c
+ pop af
+ ccf
+ rl c
+
+; If sprite i's delta Y is 0, then b = 7, else b = 9.
+ ld b, 7
+ ld a, [hl] ; a = [$c1ia] (adjusted Y coordinate)
+ and $f
+ jr z, .next1
+ ld b, 9
+
+.next1
+ ld a, [$ff90] ; a = distance between adjusted Y coordinates
+ sub b
+ ld [$ff92], a ; store distance adjusted using sprite i's direction
+ ld a, b
+ ld [$ff90], a ; store 7 or 9 depending on sprite i's delta Y
+ jr c, .checkXDistance
+
+; If sprite j's delta Y is 0, then b = 7, else b = 9.
+ ld b, 7
+ dec e
+ ld a, [de] ; a = [$c1j3] (delta Y)
+ inc e
+ and a
+ jr z, .next2
+ ld b, 9
+
+.next2
+ ld a, [$ff92] ; a = distance adjusted using sprite i's direction
+ sub b ; adjust distance using sprite j's direction
+ jr z, .checkXDistance
+ jr nc, .next ; go to next sprite if distance is still positive after both adjustments
+
+.checkXDistance
+ inc e
+ inc l
+ ld a, [de] ; a = [$c1j5] (delta X)
+
+ push bc
+
+ call SetSpriteCollisionValues
+ inc e
+ ld a, [de] ; a = [$c1j6] (X screen coordinate)
+
+; The effect of the following 3 lines is to
+; add 7 to a if moving east or
+; subtract 7 from a if moving west.
+ add b
+ and $f0
+ or c
+
+ pop bc
+
+ sub [hl] ; subtract the adjusted X coordinate of sprite i ([$c1ib]) from that of sprite j
+
+; calculate the absolute value of the difference to get the distance
+ jr nc, .noCarry2
+ cpl
+ inc a
+.noCarry2
+ ld [$ff91], a ; store the distance between the two sprites' adjusted X values
+
+; Use the carry flag set by the above subtraction to determine which sprite's
+; X coordinate is larger. This information is used later to set [$c1ic],
+; which stores which direction the collision occurred in.
+; The following 5 lines set the lowest 2 bits of c.
+; If sprite i's X is larger, set lowest 2 bits of c to 10.
+; If sprite j's X is larger or both are equal, set lowest 2 bits of c to 01.
+ push af
+ rl c
+ pop af
+ ccf
+ rl c
+
+; If sprite i's delta X is 0, then b = 7, else b = 9.
+ ld b, 7
+ ld a, [hl] ; a = [$c1ib] (adjusted X coordinate)
+ and $f
+ jr z, .next3
+ ld b, 9
+
+.next3
+ ld a, [$ff91] ; a = distance between adjusted X coordinates
+ sub b
+ ld [$ff92], a ; store distance adjusted using sprite i's direction
+ ld a, b
+ ld [$ff91], a ; store 7 or 9 depending on sprite i's delta X
+ jr c, .collision
+
+; If sprite j's delta X is 0, then b = 7, else b = 9.
+ ld b, 7
+ dec e
+ ld a, [de] ; a = [$c1j5] (delta X)
+ inc e
+ and a
+ jr z, .next4
+ ld b, 9
+
+.next4
+ ld a, [$ff92] ; a = distance adjusted using sprite i's direction
+ sub b ; adjust distance using sprite j's direction
+ jr z, .collision
+ jr nc, .next ; go to next sprite if distance is still positive after both adjustments
+
+.collision
+ ld a, [$ff91] ; a = 7 or 9 depending on sprite i's delta X
+ ld b, a
+ ld a, [$ff90] ; a = 7 or 9 depending on sprite i's delta Y
+ inc l
+
+; If delta X isn't 0 and delta Y is 0, then b = %0011, else b = %1100.
+; (note that normally if delta X isn't 0, then delta Y must be 0 and vice versa)
+ cp b
+ jr c, .next5
+ ld b, %1100
+ jr .next6
+.next5
+ ld b, %0011
+
+.next6
+ ld a, c ; c has 2 bits set (one of bits 0-1 is set for the X axis and one of bits 2-3 for the Y axis)
+ and b ; we select either the bit in bits 0-1 or bits 2-3 based on the calculation immediately above
+ or [hl] ; or with existing collision direction bits in [$c1ic]
+ ld [hl], a ; store new value
+ ld a, c ; useless code because a is overwritten before being used again
+
+; set bit in [$c1ie] or [$c1if] to indicate which sprite the collision occurred with
+ inc l
+ inc l
+ ld a, [$ff8f] ; a = loop counter
+ ld de, SpriteCollisionBitTable
+ add a
+ add e
+ ld e, a
+ jr nc, .noCarry3
+ inc d
+.noCarry3
+ ld a, [de]
+ or [hl]
+ ld [hli], a
+ inc de
+ ld a, [de]
+ or [hl]
+ ld [hl], a
+
+.next
+ ld a, [$ff8f] ; a = loop counter
+ inc a
+ cp $10
+ jp nz, .loop
+ ret
+
+; takes delta X or delta Y in a
+; b = delta X/Y
+; c = 0 if delta X/Y is 0
+; c = 7 if delta X/Y is 1
+; c = 9 if delta X/Y is -1
+SetSpriteCollisionValues:
+ and a
+ ld b, 0
+ ld c, 0
+ jr z, .done
+ ld c, 9
+ cp -1
+ jr z, .ok
+ ld c, 7
+ ld a, 0
+.ok
+ ld b, a
+.done
+ ret
+
+SpriteCollisionBitTable:
+ db %00000000,%00000001
+ db %00000000,%00000010
+ db %00000000,%00000100
+ db %00000000,%00001000
+ db %00000000,%00010000
+ db %00000000,%00100000
+ db %00000000,%01000000
+ db %00000000,%10000000
+ db %00000001,%00000000
+ db %00000010,%00000000
+ db %00000100,%00000000
+ db %00001000,%00000000
+ db %00010000,%00000000
+ db %00100000,%00000000
+ db %01000000,%00000000
+ db %10000000,%00000000
--- a/engine/overworld/ssanne.asm
+++ /dev/null
@@ -1,93 +1,0 @@
-AnimateBoulderDust:
- ld a, $1
- ld [wWhichAnimationOffsets], a ; select the boulder dust offsets
- ld a, [wUpdateSpritesEnabled]
- push af
- ld a, $ff
- ld [wUpdateSpritesEnabled], a
- ld a, %11100100
- ld [rOBP1], a
- call LoadSmokeTileFourTimes
- callba WriteCutOrBoulderDustAnimationOAMBlock
- ld c, 8 ; number of steps in animation
-.loop
- push bc
- call GetMoveBoulderDustFunctionPointer
- ld bc, .returnAddress
- push bc
- ld c, 4
- jp hl
-.returnAddress
- ld a, [rOBP1]
- xor %01100100
- ld [rOBP1], a
- call Delay3
- pop bc
- dec c
- jr nz, .loop
- pop af
- ld [wUpdateSpritesEnabled], a
- jp LoadPlayerSpriteGraphics
-
-GetMoveBoulderDustFunctionPointer:
- ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction
- ld hl, MoveBoulderDustFunctionPointerTable
- ld c, a
- ld b, $0
- add hl, bc
- ld a, [hli]
- ld [wCoordAdjustmentAmount], a
- ld a, [hli]
- ld e, a
- ld a, [hli]
- ld h, [hl]
- ld l, a
- push hl
- ld hl, wOAMBuffer + $90
- ld d, $0
- add hl, de
- ld e, l
- ld d, h
- pop hl
- ret
-
-MoveBoulderDustFunctionPointerTable:
-; facing down
- db $FF,$00
- dw AdjustOAMBlockYPos
-
-; facing up
- db $01,$00
- dw AdjustOAMBlockYPos
-
-; facing left
- db $01,$01
- dw AdjustOAMBlockXPos
-
-; facing right
- db $FF,$01
- dw AdjustOAMBlockXPos
-
-LoadSmokeTileFourTimes::
- ld hl, vChars1 + $7c0
- ld c, $4
-.loop
- push bc
- push hl
- call LoadSmokeTile
- pop hl
- ld bc, $10
- add hl, bc
- pop bc
- dec c
- jr nz, .loop
- ret
-
-LoadSmokeTile:
- ld de, SSAnneSmokePuffTile
- lb bc, BANK(SSAnneSmokePuffTile), (SSAnneSmokePuffTileEnd - SSAnneSmokePuffTile) / $10
- jp CopyVideoData
-
-SSAnneSmokePuffTile:
- INCBIN "gfx/overworld/smoke.2bpp"
-SSAnneSmokePuffTileEnd:
--- a/engine/overworld/tileset_header.asm
+++ /dev/null
@@ -1,60 +1,0 @@
-LoadTilesetHeader:
- call GetPredefRegisters
- push hl
- ld d, 0
- ld a, [wCurMapTileset]
- add a
- add a
- ld b, a
- add a
- add b ; a = tileset * 12
- jr nc, .noCarry
- inc d
-.noCarry
- ld e, a
- ld hl, Tilesets
- add hl, de
- ld de, wTilesetBank
- ld c, $b
-.copyTilesetHeaderLoop
- ld a, [hli]
- ld [de], a
- inc de
- dec c
- jr nz, .copyTilesetHeaderLoop
- ld a, [hl]
- ld [hTilesetType], a
- xor a
- ld [$ffd8], a
- pop hl
- ld a, [wCurMapTileset]
- push hl
- push de
- ld hl, DungeonTilesets
- ld de, $1
- call IsInArray
- pop de
- pop hl
- jr c, .asm_c797
- ld a, [wCurMapTileset]
- ld b, a
- ld a, [hPreviousTileset]
- cp b
- jr z, .done
-.asm_c797
- ld a, [wDestinationWarpID]
- cp $ff
- jr z, .done
- call LoadDestinationWarpPosition
- ld a, [wYCoord]
- and $1
- ld [wYBlockCoord], a
- ld a, [wXCoord]
- and $1
- ld [wXBlockCoord], a
-.done
- ret
-
-INCLUDE "data/dungeon_tilesets.asm"
-
-INCLUDE "data/tileset_headers.asm"
--- /dev/null
+++ b/engine/overworld/tilesets.asm
@@ -1,0 +1,60 @@
+LoadTilesetHeader:
+ call GetPredefRegisters
+ push hl
+ ld d, 0
+ ld a, [wCurMapTileset]
+ add a
+ add a
+ ld b, a
+ add a
+ add b ; a = tileset * 12
+ jr nc, .noCarry
+ inc d
+.noCarry
+ ld e, a
+ ld hl, Tilesets
+ add hl, de
+ ld de, wTilesetBank
+ ld c, $b
+.copyTilesetHeaderLoop
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .copyTilesetHeaderLoop
+ ld a, [hl]
+ ld [hTilesetType], a
+ xor a
+ ld [$ffd8], a
+ pop hl
+ ld a, [wCurMapTileset]
+ push hl
+ push de
+ ld hl, DungeonTilesets
+ ld de, $1
+ call IsInArray
+ pop de
+ pop hl
+ jr c, .asm_c797
+ ld a, [wCurMapTileset]
+ ld b, a
+ ld a, [hPreviousTileset]
+ cp b
+ jr z, .done
+.asm_c797
+ ld a, [wDestinationWarpID]
+ cp $ff
+ jr z, .done
+ call LoadDestinationWarpPosition
+ ld a, [wYCoord]
+ and $1
+ ld [wYBlockCoord], a
+ ld a, [wXCoord]
+ and $1
+ ld [wXBlockCoord], a
+.done
+ ret
+
+INCLUDE "data/dungeon_tilesets.asm"
+
+INCLUDE "data/tileset_headers.asm"
--- /dev/null
+++ b/engine/overworld/trainer_sight.asm
@@ -1,0 +1,349 @@
+_GetSpritePosition1::
+ ld hl, wSpriteStateData1
+ ld de, $4
+ ld a, [wSpriteIndex]
+ ld [H_SPRITEINDEX], a
+ call GetSpriteDataPointer
+ ld a, [hli] ; c1x4 (screen Y pos)
+ ld [$ffeb], a
+ inc hl
+ ld a, [hl] ; c1x6 (screen X pos)
+ ld [$ffec], a
+ ld de, (wSpriteStateData2 + $4) - (wSpriteStateData1 + $6)
+ add hl, de
+ ld a, [hli] ; c2x4 (map Y pos)
+ ld [$ffed], a
+ ld a, [hl] ; c2x5 (map X pos)
+ ld [$ffee], a
+ ret
+
+_GetSpritePosition2::
+ ld hl, wSpriteStateData1
+ ld de, $4
+ ld a, [wSpriteIndex]
+ ld [H_SPRITEINDEX], a
+ call GetSpriteDataPointer
+ ld a, [hli] ; c1x4 (screen Y pos)
+ ld [wSavedSpriteScreenY], a
+ inc hl
+ ld a, [hl] ; c1x6 (screen X pos)
+ ld [wSavedSpriteScreenX], a
+ ld de, (wSpriteStateData2 + $4) - (wSpriteStateData1 + $6)
+ add hl, de
+ ld a, [hli] ; c2x4 (map Y pos)
+ ld [wSavedSpriteMapY], a
+ ld a, [hl] ; c2x5 (map X pos)
+ ld [wSavedSpriteMapX], a
+ ret
+
+_SetSpritePosition1::
+ ld hl, wSpriteStateData1
+ ld de, $4
+ ld a, [wSpriteIndex]
+ ld [H_SPRITEINDEX], a
+ call GetSpriteDataPointer
+ ld a, [$ffeb] ; c1x4 (screen Y pos)
+ ld [hli], a
+ inc hl
+ ld a, [$ffec] ; c1x6 (screen X pos)
+ ld [hl], a
+ ld de, (wSpriteStateData2 + $4) - (wSpriteStateData1 + $6)
+ add hl, de
+ ld a, [$ffed] ; c2x4 (map Y pos)
+ ld [hli], a
+ ld a, [$ffee] ; c2x5 (map X pos)
+ ld [hl], a
+ ret
+
+_SetSpritePosition2::
+ ld hl, wSpriteStateData1
+ ld de, 4
+ ld a, [wSpriteIndex]
+ ld [H_SPRITEINDEX], a
+ call GetSpriteDataPointer
+ ld a, [wSavedSpriteScreenY]
+ ld [hli], a ; c1x4 (screen Y pos)
+ inc hl
+ ld a, [wSavedSpriteScreenX]
+ ld [hl], a ; c1x6 (screen X pos)
+ ld de, (wSpriteStateData2 + $4) - (wSpriteStateData1 + $6)
+ add hl, de
+ ld a, [wSavedSpriteMapY]
+ ld [hli], a ; c2x4 (map Y pos)
+ ld a, [wSavedSpriteMapX]
+ ld [hl], a ; c2x5 (map X pos)
+ ret
+
+TrainerWalkUpToPlayer::
+ ld a, [wSpriteIndex]
+ swap a
+ ld [wTrainerSpriteOffset], a
+ call ReadTrainerScreenPosition
+ ld a, [wTrainerFacingDirection]
+ and a ; SPRITE_FACING_DOWN
+ jr z, .facingDown
+ cp SPRITE_FACING_UP
+ jr z, .facingUp
+ cp SPRITE_FACING_LEFT
+ jr z, .facingLeft
+ jr .facingRight
+.facingDown
+ ld a, [wTrainerScreenY]
+ ld b, a
+ ld a, $3c ; (fixed) player screen Y pos
+ call CalcDifference
+ cp $10 ; trainer is right above player
+ ret z
+ swap a
+ dec a
+ ld c, a ; bc = steps yet to go to reach player
+ xor a
+ ld b, a ; a = direction to go to
+ jr .writeWalkScript
+.facingUp
+ ld a, [wTrainerScreenY]
+ ld b, a
+ ld a, $3c ; (fixed) player screen Y pos
+ call CalcDifference
+ cp $10 ; trainer is right below player
+ ret z
+ swap a
+ dec a
+ ld c, a ; bc = steps yet to go to reach player
+ ld b, $0
+ ld a, $40 ; a = direction to go to
+ jr .writeWalkScript
+.facingRight
+ ld a, [wTrainerScreenX]
+ ld b, a
+ ld a, $40 ; (fixed) player screen X pos
+ call CalcDifference
+ cp $10 ; trainer is directly left of player
+ ret z
+ swap a
+ dec a
+ ld c, a ; bc = steps yet to go to reach player
+ ld b, $0
+ ld a, $c0 ; a = direction to go to
+ jr .writeWalkScript
+.facingLeft
+ ld a, [wTrainerScreenX]
+ ld b, a
+ ld a, $40 ; (fixed) player screen X pos
+ call CalcDifference
+ cp $10 ; trainer is directly right of player
+ ret z
+ swap a
+ dec a
+ ld c, a ; bc = steps yet to go to reach player
+ ld b, $0
+ ld a, $80 ; a = direction to go to
+.writeWalkScript
+ ld hl, wNPCMovementDirections2
+ ld de, wNPCMovementDirections2
+ call FillMemory ; write the necessary steps to reach player
+ ld [hl], $ff ; write end of list sentinel
+ ld a, [wSpriteIndex]
+ ld [H_SPRITEINDEX], a
+ jp MoveSprite_
+
+; input: de = offset within sprite entry
+; output: hl = pointer to sprite data
+GetSpriteDataPointer:
+ push de
+ add hl, de
+ ld a, [H_SPRITEINDEX]
+ swap a
+ ld d, $0
+ ld e, a
+ add hl, de
+ pop de
+ ret
+
+; tests if this trainer is in the right position to engage the player and do so if she is.
+TrainerEngage:
+ push hl
+ push de
+ ld a, [wTrainerSpriteOffset]
+ add $2
+ ld d, $0
+ ld e, a
+ ld hl, wSpriteStateData1
+ add hl, de
+ ld a, [hl] ; c1x2: sprite image index
+ sub $ff
+ jr nz, .spriteOnScreen ; test if sprite is on screen
+ jp .noEngage
+.spriteOnScreen
+ ld a, [wTrainerSpriteOffset]
+ add $9
+ ld d, $0
+ ld e, a
+ ld hl, wSpriteStateData1
+ add hl, de
+ ld a, [hl] ; c1x9: facing direction
+ ld [wTrainerFacingDirection], a
+ call ReadTrainerScreenPosition
+ ld a, [wTrainerScreenY] ; sprite screen Y pos
+ ld b, a
+ ld a, $3c
+ cp b
+ jr z, .linedUpY
+ ld a, [wTrainerScreenX] ; sprite screen X pos
+ ld b, a
+ ld a, $40
+ cp b
+ jr z, .linedUpX
+ xor a
+ jp .noEngage
+.linedUpY
+ ld a, [wTrainerScreenX] ; sprite screen X pos
+ ld b, a
+ ld a, $40 ; (fixed) player X position
+ call CalcDifference ; calc distance
+ jr z, .noEngage ; exact same position as player
+ call CheckSpriteCanSeePlayer
+ jr c, .engage
+ xor a
+ jr .noEngage
+.linedUpX
+ ld a, [wTrainerScreenY] ; sprite screen Y pos
+ ld b, a
+ ld a, $3c ; (fixed) player Y position
+ call CalcDifference ; calc distance
+ jr z, .noEngage ; exact same position as player
+ call CheckSpriteCanSeePlayer
+ jr c, .engage
+ xor a
+ jp .noEngage
+.engage
+ call CheckPlayerIsInFrontOfSprite
+ ld a, [wTrainerSpriteOffset]
+ and a
+ jr z, .noEngage
+ ld hl, wFlags_0xcd60
+ set 0, [hl]
+ call EngageMapTrainer
+ ld a, $ff
+.noEngage
+ ld [wTrainerSpriteOffset], a
+ pop de
+ pop hl
+ ret
+
+; reads trainer's Y position to wTrainerScreenY and X position to wTrainerScreenX
+ReadTrainerScreenPosition:
+ ld a, [wTrainerSpriteOffset]
+ add $4
+ ld d, $0
+ ld e, a
+ ld hl, wSpriteStateData1
+ add hl, de
+ ld a, [hl] ; c1x4 (sprite Y pos)
+ ld [wTrainerScreenY], a
+ ld a, [wTrainerSpriteOffset]
+ add $6
+ ld d, $0
+ ld e, a
+ ld hl, wSpriteStateData1
+ add hl, de
+ ld a, [hl] ; c1x6 (sprite X pos)
+ ld [wTrainerScreenX], a
+ ret
+
+; checks if the sprite is properly lined up with the player with respect to the direction it's looking. Also checks the distance between player and sprite
+; note that this does not necessarily mean the sprite is seeing the player, he could be behind it's back
+; a: distance player to sprite
+CheckSpriteCanSeePlayer:
+ ld b, a
+ ld a, [wTrainerEngageDistance] ; how far the trainer can see
+ cp b
+ jr nc, .checkIfLinedUp
+ jr .notInLine ; player too far away
+.checkIfLinedUp
+ ld a, [wTrainerFacingDirection] ; sprite facing direction
+ cp SPRITE_FACING_DOWN
+ jr z, .checkXCoord
+ cp SPRITE_FACING_UP
+ jr z, .checkXCoord
+ cp SPRITE_FACING_LEFT
+ jr z, .checkYCoord
+ cp SPRITE_FACING_RIGHT
+ jr z, .checkYCoord
+ jr .notInLine
+.checkXCoord
+ ld a, [wTrainerScreenX] ; sprite screen X position
+ ld b, a
+ cp $40
+ jr z, .inLine
+ jr .notInLine
+.checkYCoord
+ ld a, [wTrainerScreenY] ; sprite screen Y position
+ ld b, a
+ cp $3c
+ jr nz, .notInLine
+.inLine
+ scf
+ ret
+.notInLine
+ and a
+ ret
+
+; tests if the player is in front of the sprite (rather than behind it)
+CheckPlayerIsInFrontOfSprite:
+ ld a, [wCurMap]
+ cp POWER_PLANT
+ jp z, .engage ; bypass this for power plant to get voltorb fake items to work
+ ld a, [wTrainerSpriteOffset]
+ add $4
+ ld d, $0
+ ld e, a
+ ld hl, wSpriteStateData1
+ add hl, de
+ ld a, [hl] ; c1x4 (sprite screen Y pos)
+ cp $fc
+ jr nz, .notOnTopmostTile ; special case if sprite is on topmost tile (Y = $fc (-4)), make it come down a block
+ ld a, $c
+.notOnTopmostTile
+ ld [wTrainerScreenY], a
+ ld a, [wTrainerSpriteOffset]
+ add $6
+ ld d, $0
+ ld e, a
+ ld hl, wSpriteStateData1
+ add hl, de
+ ld a, [hl] ; c1x6 (sprite screen X pos)
+ ld [wTrainerScreenX], a
+ ld a, [wTrainerFacingDirection] ; facing direction
+ cp SPRITE_FACING_DOWN
+ jr nz, .notFacingDown
+ ld a, [wTrainerScreenY] ; sprite screen Y pos
+ cp $3c
+ jr c, .engage ; sprite above player
+ jr .noEngage ; sprite below player
+.notFacingDown
+ cp SPRITE_FACING_UP
+ jr nz, .notFacingUp
+ ld a, [wTrainerScreenY] ; sprite screen Y pos
+ cp $3c
+ jr nc, .engage ; sprite below player
+ jr .noEngage ; sprite above player
+.notFacingUp
+ cp SPRITE_FACING_LEFT
+ jr nz, .notFacingLeft
+ ld a, [wTrainerScreenX] ; sprite screen X pos
+ cp $40
+ jr nc, .engage ; sprite right of player
+ jr .noEngage ; sprite left of player
+.notFacingLeft
+ ld a, [wTrainerScreenX] ; sprite screen X pos
+ cp $40
+ jr nc, .noEngage ; sprite right of player
+.engage
+ ld a, $ff
+ jr .done
+.noEngage
+ xor a
+.done
+ ld [wTrainerSpriteOffset], a
+ ret
--- a/engine/overworld/trainers.asm
+++ /dev/null
@@ -1,349 +1,0 @@
-_GetSpritePosition1::
- ld hl, wSpriteStateData1
- ld de, $4
- ld a, [wSpriteIndex]
- ld [H_SPRITEINDEX], a
- call GetSpriteDataPointer
- ld a, [hli] ; c1x4 (screen Y pos)
- ld [$ffeb], a
- inc hl
- ld a, [hl] ; c1x6 (screen X pos)
- ld [$ffec], a
- ld de, (wSpriteStateData2 + $4) - (wSpriteStateData1 + $6)
- add hl, de
- ld a, [hli] ; c2x4 (map Y pos)
- ld [$ffed], a
- ld a, [hl] ; c2x5 (map X pos)
- ld [$ffee], a
- ret
-
-_GetSpritePosition2::
- ld hl, wSpriteStateData1
- ld de, $4
- ld a, [wSpriteIndex]
- ld [H_SPRITEINDEX], a
- call GetSpriteDataPointer
- ld a, [hli] ; c1x4 (screen Y pos)
- ld [wSavedSpriteScreenY], a
- inc hl
- ld a, [hl] ; c1x6 (screen X pos)
- ld [wSavedSpriteScreenX], a
- ld de, (wSpriteStateData2 + $4) - (wSpriteStateData1 + $6)
- add hl, de
- ld a, [hli] ; c2x4 (map Y pos)
- ld [wSavedSpriteMapY], a
- ld a, [hl] ; c2x5 (map X pos)
- ld [wSavedSpriteMapX], a
- ret
-
-_SetSpritePosition1::
- ld hl, wSpriteStateData1
- ld de, $4
- ld a, [wSpriteIndex]
- ld [H_SPRITEINDEX], a
- call GetSpriteDataPointer
- ld a, [$ffeb] ; c1x4 (screen Y pos)
- ld [hli], a
- inc hl
- ld a, [$ffec] ; c1x6 (screen X pos)
- ld [hl], a
- ld de, (wSpriteStateData2 + $4) - (wSpriteStateData1 + $6)
- add hl, de
- ld a, [$ffed] ; c2x4 (map Y pos)
- ld [hli], a
- ld a, [$ffee] ; c2x5 (map X pos)
- ld [hl], a
- ret
-
-_SetSpritePosition2::
- ld hl, wSpriteStateData1
- ld de, 4
- ld a, [wSpriteIndex]
- ld [H_SPRITEINDEX], a
- call GetSpriteDataPointer
- ld a, [wSavedSpriteScreenY]
- ld [hli], a ; c1x4 (screen Y pos)
- inc hl
- ld a, [wSavedSpriteScreenX]
- ld [hl], a ; c1x6 (screen X pos)
- ld de, (wSpriteStateData2 + $4) - (wSpriteStateData1 + $6)
- add hl, de
- ld a, [wSavedSpriteMapY]
- ld [hli], a ; c2x4 (map Y pos)
- ld a, [wSavedSpriteMapX]
- ld [hl], a ; c2x5 (map X pos)
- ret
-
-TrainerWalkUpToPlayer::
- ld a, [wSpriteIndex]
- swap a
- ld [wTrainerSpriteOffset], a
- call ReadTrainerScreenPosition
- ld a, [wTrainerFacingDirection]
- and a ; SPRITE_FACING_DOWN
- jr z, .facingDown
- cp SPRITE_FACING_UP
- jr z, .facingUp
- cp SPRITE_FACING_LEFT
- jr z, .facingLeft
- jr .facingRight
-.facingDown
- ld a, [wTrainerScreenY]
- ld b, a
- ld a, $3c ; (fixed) player screen Y pos
- call CalcDifference
- cp $10 ; trainer is right above player
- ret z
- swap a
- dec a
- ld c, a ; bc = steps yet to go to reach player
- xor a
- ld b, a ; a = direction to go to
- jr .writeWalkScript
-.facingUp
- ld a, [wTrainerScreenY]
- ld b, a
- ld a, $3c ; (fixed) player screen Y pos
- call CalcDifference
- cp $10 ; trainer is right below player
- ret z
- swap a
- dec a
- ld c, a ; bc = steps yet to go to reach player
- ld b, $0
- ld a, $40 ; a = direction to go to
- jr .writeWalkScript
-.facingRight
- ld a, [wTrainerScreenX]
- ld b, a
- ld a, $40 ; (fixed) player screen X pos
- call CalcDifference
- cp $10 ; trainer is directly left of player
- ret z
- swap a
- dec a
- ld c, a ; bc = steps yet to go to reach player
- ld b, $0
- ld a, $c0 ; a = direction to go to
- jr .writeWalkScript
-.facingLeft
- ld a, [wTrainerScreenX]
- ld b, a
- ld a, $40 ; (fixed) player screen X pos
- call CalcDifference
- cp $10 ; trainer is directly right of player
- ret z
- swap a
- dec a
- ld c, a ; bc = steps yet to go to reach player
- ld b, $0
- ld a, $80 ; a = direction to go to
-.writeWalkScript
- ld hl, wNPCMovementDirections2
- ld de, wNPCMovementDirections2
- call FillMemory ; write the necessary steps to reach player
- ld [hl], $ff ; write end of list sentinel
- ld a, [wSpriteIndex]
- ld [H_SPRITEINDEX], a
- jp MoveSprite_
-
-; input: de = offset within sprite entry
-; output: hl = pointer to sprite data
-GetSpriteDataPointer:
- push de
- add hl, de
- ld a, [H_SPRITEINDEX]
- swap a
- ld d, $0
- ld e, a
- add hl, de
- pop de
- ret
-
-; tests if this trainer is in the right position to engage the player and do so if she is.
-TrainerEngage:
- push hl
- push de
- ld a, [wTrainerSpriteOffset]
- add $2
- ld d, $0
- ld e, a
- ld hl, wSpriteStateData1
- add hl, de
- ld a, [hl] ; c1x2: sprite image index
- sub $ff
- jr nz, .spriteOnScreen ; test if sprite is on screen
- jp .noEngage
-.spriteOnScreen
- ld a, [wTrainerSpriteOffset]
- add $9
- ld d, $0
- ld e, a
- ld hl, wSpriteStateData1
- add hl, de
- ld a, [hl] ; c1x9: facing direction
- ld [wTrainerFacingDirection], a
- call ReadTrainerScreenPosition
- ld a, [wTrainerScreenY] ; sprite screen Y pos
- ld b, a
- ld a, $3c
- cp b
- jr z, .linedUpY
- ld a, [wTrainerScreenX] ; sprite screen X pos
- ld b, a
- ld a, $40
- cp b
- jr z, .linedUpX
- xor a
- jp .noEngage
-.linedUpY
- ld a, [wTrainerScreenX] ; sprite screen X pos
- ld b, a
- ld a, $40 ; (fixed) player X position
- call CalcDifference ; calc distance
- jr z, .noEngage ; exact same position as player
- call CheckSpriteCanSeePlayer
- jr c, .engage
- xor a
- jr .noEngage
-.linedUpX
- ld a, [wTrainerScreenY] ; sprite screen Y pos
- ld b, a
- ld a, $3c ; (fixed) player Y position
- call CalcDifference ; calc distance
- jr z, .noEngage ; exact same position as player
- call CheckSpriteCanSeePlayer
- jr c, .engage
- xor a
- jp .noEngage
-.engage
- call CheckPlayerIsInFrontOfSprite
- ld a, [wTrainerSpriteOffset]
- and a
- jr z, .noEngage
- ld hl, wFlags_0xcd60
- set 0, [hl]
- call EngageMapTrainer
- ld a, $ff
-.noEngage
- ld [wTrainerSpriteOffset], a
- pop de
- pop hl
- ret
-
-; reads trainer's Y position to wTrainerScreenY and X position to wTrainerScreenX
-ReadTrainerScreenPosition:
- ld a, [wTrainerSpriteOffset]
- add $4
- ld d, $0
- ld e, a
- ld hl, wSpriteStateData1
- add hl, de
- ld a, [hl] ; c1x4 (sprite Y pos)
- ld [wTrainerScreenY], a
- ld a, [wTrainerSpriteOffset]
- add $6
- ld d, $0
- ld e, a
- ld hl, wSpriteStateData1
- add hl, de
- ld a, [hl] ; c1x6 (sprite X pos)
- ld [wTrainerScreenX], a
- ret
-
-; checks if the sprite is properly lined up with the player with respect to the direction it's looking. Also checks the distance between player and sprite
-; note that this does not necessarily mean the sprite is seeing the player, he could be behind it's back
-; a: distance player to sprite
-CheckSpriteCanSeePlayer:
- ld b, a
- ld a, [wTrainerEngageDistance] ; how far the trainer can see
- cp b
- jr nc, .checkIfLinedUp
- jr .notInLine ; player too far away
-.checkIfLinedUp
- ld a, [wTrainerFacingDirection] ; sprite facing direction
- cp SPRITE_FACING_DOWN
- jr z, .checkXCoord
- cp SPRITE_FACING_UP
- jr z, .checkXCoord
- cp SPRITE_FACING_LEFT
- jr z, .checkYCoord
- cp SPRITE_FACING_RIGHT
- jr z, .checkYCoord
- jr .notInLine
-.checkXCoord
- ld a, [wTrainerScreenX] ; sprite screen X position
- ld b, a
- cp $40
- jr z, .inLine
- jr .notInLine
-.checkYCoord
- ld a, [wTrainerScreenY] ; sprite screen Y position
- ld b, a
- cp $3c
- jr nz, .notInLine
-.inLine
- scf
- ret
-.notInLine
- and a
- ret
-
-; tests if the player is in front of the sprite (rather than behind it)
-CheckPlayerIsInFrontOfSprite:
- ld a, [wCurMap]
- cp POWER_PLANT
- jp z, .engage ; bypass this for power plant to get voltorb fake items to work
- ld a, [wTrainerSpriteOffset]
- add $4
- ld d, $0
- ld e, a
- ld hl, wSpriteStateData1
- add hl, de
- ld a, [hl] ; c1x4 (sprite screen Y pos)
- cp $fc
- jr nz, .notOnTopmostTile ; special case if sprite is on topmost tile (Y = $fc (-4)), make it come down a block
- ld a, $c
-.notOnTopmostTile
- ld [wTrainerScreenY], a
- ld a, [wTrainerSpriteOffset]
- add $6
- ld d, $0
- ld e, a
- ld hl, wSpriteStateData1
- add hl, de
- ld a, [hl] ; c1x6 (sprite screen X pos)
- ld [wTrainerScreenX], a
- ld a, [wTrainerFacingDirection] ; facing direction
- cp SPRITE_FACING_DOWN
- jr nz, .notFacingDown
- ld a, [wTrainerScreenY] ; sprite screen Y pos
- cp $3c
- jr c, .engage ; sprite above player
- jr .noEngage ; sprite below player
-.notFacingDown
- cp SPRITE_FACING_UP
- jr nz, .notFacingUp
- ld a, [wTrainerScreenY] ; sprite screen Y pos
- cp $3c
- jr nc, .engage ; sprite below player
- jr .noEngage ; sprite above player
-.notFacingUp
- cp SPRITE_FACING_LEFT
- jr nz, .notFacingLeft
- ld a, [wTrainerScreenX] ; sprite screen X pos
- cp $40
- jr nc, .engage ; sprite right of player
- jr .noEngage ; sprite left of player
-.notFacingLeft
- ld a, [wTrainerScreenX] ; sprite screen X pos
- cp $40
- jr nc, .noEngage ; sprite right of player
-.engage
- ld a, $ff
- jr .done
-.noEngage
- xor a
-.done
- ld [wTrainerSpriteOffset], a
- ret
--- /dev/null
+++ b/engine/overworld/turn_sprite.asm
@@ -1,0 +1,25 @@
+UpdateSpriteFacingOffsetAndDelayMovement::
+ ld h, $c2
+ ld a, [H_CURRENTSPRITEOFFSET]
+ add $8
+ ld l, a
+ ld a, $7f ; maximum movement delay
+ ld [hl], a ; c2x8 (movement delay)
+ dec h
+ ld a, [H_CURRENTSPRITEOFFSET]
+ add $9
+ ld l, a
+ ld a, [hld] ; c1x9 (facing direction)
+ ld b, a
+ xor a
+ ld [hld], a
+ ld [hl], a ; c1x8 (walk animation frame)
+ ld a, [H_CURRENTSPRITEOFFSET]
+ add $2
+ ld l, a
+ ld a, [hl] ; c1x2 (facing and animation table offset)
+ or b ; or in the facing direction
+ ld [hld], a
+ ld a, $2 ; delayed movement status
+ ld [hl], a ; c1x1 (movement status)
+ ret
--- a/engine/palettes.asm
+++ /dev/null
@@ -1,641 +1,0 @@
-_RunPaletteCommand:
- call GetPredefRegisters
- ld a, b
- cp $ff
- jr nz, .next
- ld a, [wDefaultPaletteCommand] ; use default command if command ID is $ff
-.next
- cp UPDATE_PARTY_MENU_BLK_PACKET
- jp z, UpdatePartyMenuBlkPacket
- ld l, a
- ld h, 0
- add hl, hl
- ld de, SetPalFunctions
- add hl, de
- ld a, [hli]
- ld h, [hl]
- ld l, a
- ld de, SendSGBPackets
- push de
- jp hl
-
-SetPal_BattleBlack:
- ld hl, PalPacket_Black
- ld de, BlkPacket_Battle
- ret
-
-; uses PalPacket_Empty to build a packet based on mon IDs and health color
-SetPal_Battle:
- ld hl, PalPacket_Empty
- ld de, wPalPacket
- ld bc, $10
- call CopyData
- ld a, [wPlayerBattleStatus3]
- ld hl, wBattleMonSpecies
- call DeterminePaletteID
- ld b, a
- ld a, [wEnemyBattleStatus3]
- ld hl, wEnemyMonSpecies2
- call DeterminePaletteID
- ld c, a
- ld hl, wPalPacket + 1
- ld a, [wPlayerHPBarColor]
- add PAL_GREENBAR
- ld [hli], a
- inc hl
- ld a, [wEnemyHPBarColor]
- add PAL_GREENBAR
- ld [hli], a
- inc hl
- ld a, b
- ld [hli], a
- inc hl
- ld a, c
- ld [hl], a
- ld hl, wPalPacket
- ld de, BlkPacket_Battle
- ld a, SET_PAL_BATTLE
- ld [wDefaultPaletteCommand], a
- ret
-
-SetPal_TownMap:
- ld hl, PalPacket_TownMap
- ld de, BlkPacket_WholeScreen
- ret
-
-; uses PalPacket_Empty to build a packet based the mon ID
-SetPal_StatusScreen:
- ld hl, PalPacket_Empty
- ld de, wPalPacket
- ld bc, $10
- call CopyData
- ld a, [wcf91]
- cp NUM_POKEMON_INDEXES + 1
- jr c, .pokemon
- ld a, $1 ; not pokemon
-.pokemon
- call DeterminePaletteIDOutOfBattle
- push af
- ld hl, wPalPacket + 1
- ld a, [wStatusScreenHPBarColor]
- add PAL_GREENBAR
- ld [hli], a
- inc hl
- pop af
- ld [hl], a
- ld hl, wPalPacket
- ld de, BlkPacket_StatusScreen
- ret
-
-SetPal_PartyMenu:
- ld hl, PalPacket_PartyMenu
- ld de, wPartyMenuBlkPacket
- ret
-
-SetPal_Pokedex:
- ld hl, PalPacket_Pokedex
- ld de, wPalPacket
- ld bc, $10
- call CopyData
- ld a, [wcf91]
- call DeterminePaletteIDOutOfBattle
- ld hl, wPalPacket + 3
- ld [hl], a
- ld hl, wPalPacket
- ld de, BlkPacket_Pokedex
- ret
-
-SetPal_Slots:
- ld hl, PalPacket_Slots
- ld de, BlkPacket_Slots
- ret
-
-SetPal_TitleScreen:
- ld hl, PalPacket_Titlescreen
- ld de, BlkPacket_Titlescreen
- ret
-
-; used mostly for menus and the Oak intro
-SetPal_Generic:
- ld hl, PalPacket_Generic
- ld de, BlkPacket_WholeScreen
- ret
-
-SetPal_NidorinoIntro:
- ld hl, PalPacket_NidorinoIntro
- ld de, BlkPacket_NidorinoIntro
- ret
-
-SetPal_GameFreakIntro:
- ld hl, PalPacket_GameFreakIntro
- ld de, BlkPacket_GameFreakIntro
- ld a, SET_PAL_GENERIC
- ld [wDefaultPaletteCommand], a
- ret
-
-; uses PalPacket_Empty to build a packet based on the current map
-SetPal_Overworld:
- ld hl, PalPacket_Empty
- ld de, wPalPacket
- ld bc, $10
- call CopyData
- ld a, [wCurMapTileset]
- cp CEMETERY
- jr z, .PokemonTowerOrAgatha
- cp CAVERN
- jr z, .caveOrBruno
- ld a, [wCurMap]
- cp REDS_HOUSE_1F
- jr c, .townOrRoute
- cp CERULEAN_CAVE_2F
- jr c, .normalDungeonOrBuilding
- cp NAME_RATERS_HOUSE
- jr c, .caveOrBruno
- cp LORELEIS_ROOM
- jr z, .Lorelei
- cp BRUNOS_ROOM
- jr z, .caveOrBruno
-.normalDungeonOrBuilding
- ld a, [wLastMap] ; town or route that current dungeon or building is located
-.townOrRoute
- cp SAFFRON_CITY + 1
- jr c, .town
- ld a, PAL_ROUTE - 1
-.town
- inc a ; a town's palette ID is its map ID + 1
- ld hl, wPalPacket + 1
- ld [hld], a
- ld de, BlkPacket_WholeScreen
- ld a, SET_PAL_OVERWORLD
- ld [wDefaultPaletteCommand], a
- ret
-.PokemonTowerOrAgatha
- ld a, PAL_GREYMON - 1
- jr .town
-.caveOrBruno
- ld a, PAL_CAVE - 1
- jr .town
-.Lorelei
- xor a
- jr .town
-
-; used when a Pokemon is the only thing on the screen
-; such as evolution, trading and the Hall of Fame
-SetPal_PokemonWholeScreen:
- push bc
- ld hl, PalPacket_Empty
- ld de, wPalPacket
- ld bc, $10
- call CopyData
- pop bc
- ld a, c
- and a
- ld a, PAL_BLACK
- jr nz, .next
- ld a, [wWholeScreenPaletteMonSpecies]
- call DeterminePaletteIDOutOfBattle
-.next
- ld [wPalPacket + 1], a
- ld hl, wPalPacket
- ld de, BlkPacket_WholeScreen
- ret
-
-SetPal_TrainerCard:
- ld hl, BlkPacket_TrainerCard
- ld de, wTrainerCardBlkPacket
- ld bc, $40
- call CopyData
- ld de, BadgeBlkDataLengths
- ld hl, wTrainerCardBlkPacket + 2
- ld a, [wObtainedBadges]
- ld c, 8
-.badgeLoop
- srl a
- push af
- jr c, .haveBadge
-; The player doens't have the badge, so zero the badge's blk data.
- push bc
- ld a, [de]
- ld c, a
- xor a
-.zeroBadgeDataLoop
- ld [hli], a
- dec c
- jr nz, .zeroBadgeDataLoop
- pop bc
- jr .nextBadge
-.haveBadge
-; The player does have the badge, so skip past the badge's blk data.
- ld a, [de]
-.skipBadgeDataLoop
- inc hl
- dec a
- jr nz, .skipBadgeDataLoop
-.nextBadge
- pop af
- inc de
- dec c
- jr nz, .badgeLoop
- ld hl, PalPacket_TrainerCard
- ld de, wTrainerCardBlkPacket
- ret
-
-SetPalFunctions:
- dw SetPal_BattleBlack
- dw SetPal_Battle
- dw SetPal_TownMap
- dw SetPal_StatusScreen
- dw SetPal_Pokedex
- dw SetPal_Slots
- dw SetPal_TitleScreen
- dw SetPal_NidorinoIntro
- dw SetPal_Generic
- dw SetPal_Overworld
- dw SetPal_PartyMenu
- dw SetPal_PokemonWholeScreen
- dw SetPal_GameFreakIntro
- dw SetPal_TrainerCard
-
-; The length of the blk data of each badge on the Trainer Card.
-; The Rainbow Badge has 3 entries because of its many colors.
-BadgeBlkDataLengths:
- db 6 ; Boulder Badge
- db 6 ; Cascade Badge
- db 6 ; Thunder Badge
- db 6 * 3 ; Rainbow Badge
- db 6 ; Soul Badge
- db 6 ; Marsh Badge
- db 6 ; Volcano Badge
- db 6 ; Earth Badge
-
-DeterminePaletteID:
- bit TRANSFORMED, a ; a is battle status 3
- ld a, PAL_GREYMON ; if the mon has used Transform, use Ditto's palette
- ret nz
- ld a, [hl]
-DeterminePaletteIDOutOfBattle:
- ld [wd11e], a
- and a ; is the mon index 0?
- jr z, .skipDexNumConversion
- push bc
- predef IndexToPokedex
- pop bc
- ld a, [wd11e]
-.skipDexNumConversion
- ld e, a
- ld d, 0
- ld hl, MonsterPalettes ; not just for Pokemon, Trainers use it too
- add hl, de
- ld a, [hl]
- ret
-
-InitPartyMenuBlkPacket:
- ld hl, BlkPacket_PartyMenu
- ld de, wPartyMenuBlkPacket
- ld bc, $30
- jp CopyData
-
-UpdatePartyMenuBlkPacket:
-; Update the blk packet with the palette of the HP bar that is
-; specified in [wWhichPartyMenuHPBar].
- ld hl, wPartyMenuHPBarColors
- ld a, [wWhichPartyMenuHPBar]
- ld e, a
- ld d, 0
- add hl, de
- ld e, l
- ld d, h
- ld a, [de]
- and a
- ld e, (1 << 2) | 1 ; green
- jr z, .next
- dec a
- ld e, (2 << 2) | 2 ; yellow
- jr z, .next
- ld e, (3 << 2) | 3 ; red
-.next
- push de
- ld hl, wPartyMenuBlkPacket + 8 + 1
- ld bc, 6
- ld a, [wWhichPartyMenuHPBar]
- call AddNTimes
- pop de
- ld [hl], e
- ret
-
-SendSGBPacket:
-;check number of packets
- ld a, [hl]
- and $07
- ret z
-; store number of packets in B
- ld b, a
-.loop2
-; save B for later use
- push bc
-; disable ReadJoypad to prevent it from interfering with sending the packet
- ld a, 1
- ld [hDisableJoypadPolling], a
-; send RESET signal (P14=LOW, P15=LOW)
- xor a
- ld [rJOYP], a
-; set P14=HIGH, P15=HIGH
- ld a, $30
- ld [rJOYP], a
-;load length of packets (16 bytes)
- ld b, $10
-.nextByte
-;set bit counter (8 bits per byte)
- ld e, $08
-; get next byte in the packet
- ld a, [hli]
- ld d, a
-.nextBit0
- bit 0, d
-; if 0th bit is not zero set P14=HIGH,P15=LOW (send bit 1)
- ld a, $10
- jr nz, .next0
-; else (if 0th bit is zero) set P14=LOW,P15=HIGH (send bit 0)
- ld a, $20
-.next0
- ld [rJOYP], a
-; must set P14=HIGH,P15=HIGH between each "pulse"
- ld a, $30
- ld [rJOYP], a
-; rotation will put next bit in 0th position (so we can always use command
-; "bit 0,d" to fetch the bit that has to be sent)
- rr d
-; decrease bit counter so we know when we have sent all 8 bits of current byte
- dec e
- jr nz, .nextBit0
- dec b
- jr nz, .nextByte
-; send bit 1 as a "stop bit" (end of parameter data)
- ld a, $20
- ld [rJOYP], a
-; set P14=HIGH,P15=HIGH
- ld a, $30
- ld [rJOYP], a
- xor a
- ld [hDisableJoypadPolling], a
-; wait for about 70000 cycles
- call Wait7000
-; restore (previously pushed) number of packets
- pop bc
- dec b
-; return if there are no more packets
- ret z
-; else send 16 more bytes
- jr .loop2
-
-LoadSGB:
- xor a
- ld [wOnSGB], a
- call CheckSGB
- ret nc
- ld a, 1
- ld [wOnSGB], a
- ld a, [wGBC]
- and a
- jr z, .notGBC
- ret
-.notGBC
- di
- call PrepareSuperNintendoVRAMTransfer
- ei
- ld a, 1
- ld [wCopyingSGBTileData], a
- ld de, ChrTrnPacket
- ld hl, SGBBorderGraphics
- call CopyGfxToSuperNintendoVRAM
- xor a
- ld [wCopyingSGBTileData], a
- ld de, PctTrnPacket
- ld hl, BorderPalettes
- call CopyGfxToSuperNintendoVRAM
- xor a
- ld [wCopyingSGBTileData], a
- ld de, PalTrnPacket
- ld hl, SuperPalettes
- call CopyGfxToSuperNintendoVRAM
- call ClearVram
- ld hl, MaskEnCancelPacket
- jp SendSGBPacket
-
-PrepareSuperNintendoVRAMTransfer:
- ld hl, .packetPointers
- ld c, 9
-.loop
- push bc
- ld a, [hli]
- push hl
- ld h, [hl]
- ld l, a
- call SendSGBPacket
- pop hl
- inc hl
- pop bc
- dec c
- jr nz, .loop
- ret
-
-.packetPointers
-; Only the first packet is needed.
- dw MaskEnFreezePacket
- dw DataSnd_72548
- dw DataSnd_72558
- dw DataSnd_72568
- dw DataSnd_72578
- dw DataSnd_72588
- dw DataSnd_72598
- dw DataSnd_725a8
- dw DataSnd_725b8
-
-CheckSGB:
-; Returns whether the game is running on an SGB in carry.
- ld hl, MltReq2Packet
- di
- call SendSGBPacket
- ld a, 1
- ld [hDisableJoypadPolling], a
- ei
- call Wait7000
- ld a, [rJOYP]
- and $3
- cp $3
- jr nz, .isSGB
- ld a, $20
- ld [rJOYP], a
- ld a, [rJOYP]
- ld a, [rJOYP]
- call Wait7000
- call Wait7000
- ld a, $30
- ld [rJOYP], a
- call Wait7000
- call Wait7000
- ld a, $10
- ld [rJOYP], a
- ld a, [rJOYP]
- ld a, [rJOYP]
- ld a, [rJOYP]
- ld a, [rJOYP]
- ld a, [rJOYP]
- ld a, [rJOYP]
- call Wait7000
- call Wait7000
- ld a, $30
- ld [rJOYP], a
- ld a, [rJOYP]
- ld a, [rJOYP]
- ld a, [rJOYP]
- call Wait7000
- call Wait7000
- ld a, [rJOYP]
- and $3
- cp $3
- jr nz, .isSGB
- call SendMltReq1Packet
- and a
- ret
-.isSGB
- call SendMltReq1Packet
- scf
- ret
-
-SendMltReq1Packet:
- ld hl, MltReq1Packet
- call SendSGBPacket
- jp Wait7000
-
-CopyGfxToSuperNintendoVRAM:
- di
- push de
- call DisableLCD
- ld a, $e4
- ld [rBGP], a
- ld de, vChars1
- ld a, [wCopyingSGBTileData]
- and a
- jr z, .notCopyingTileData
- call CopySGBBorderTiles
- jr .next
-.notCopyingTileData
- ld bc, $1000
- call CopyData
-.next
- ld hl, vBGMap0
- ld de, $c
- ld a, $80
- ld c, $d
-.loop
- ld b, $14
-.innerLoop
- ld [hli], a
- inc a
- dec b
- jr nz, .innerLoop
- add hl, de
- dec c
- jr nz, .loop
- ld a, $e3
- ld [rLCDC], a
- pop hl
- call SendSGBPacket
- xor a
- ld [rBGP], a
- ei
- ret
-
-Wait7000:
-; Each loop takes 9 cycles so this routine actually waits 63000 cycles.
- ld de, 7000
-.loop
- nop
- nop
- nop
- dec de
- ld a, d
- or e
- jr nz, .loop
- ret
-
-SendSGBPackets:
- ld a, [wGBC]
- and a
- jr z, .notGBC
- push de
- call InitGBCPalettes
- pop hl
- call EmptyFunc5
- ret
-.notGBC
- push de
- call SendSGBPacket
- pop hl
- jp SendSGBPacket
-
-InitGBCPalettes:
- ld a, $80 ; index 0 with auto-increment
- ld [rBGPI], a
- inc hl
- ld c, $20
-.loop
- ld a, [hli]
- inc hl
- add a
- add a
- add a
- ld de, SuperPalettes
- add e
- jr nc, .noCarry
- inc d
-.noCarry
- ld a, [de]
- ld [rBGPD], a
- dec c
- jr nz, .loop
- ret
-
-EmptyFunc5:
- ret
-
-CopySGBBorderTiles:
-; SGB tile data is stored in a 4BPP planar format.
-; Each tile is 32 bytes. The first 16 bytes contain bit planes 1 and 2, while
-; the second 16 bytes contain bit planes 3 and 4.
-; This function converts 2BPP planar data into this format by mapping
-; 2BPP colors 0-3 to 4BPP colors 0-3. 4BPP colors 4-15 are not used.
- ld b, 128
-
-.tileLoop
-
-; Copy bit planes 1 and 2 of the tile data.
- ld c, 16
-.copyLoop
- ld a, [hli]
- ld [de], a
- inc de
- dec c
- jr nz, .copyLoop
-
-; Zero bit planes 3 and 4.
- ld c, 16
- xor a
-.zeroLoop
- ld [de], a
- inc de
- dec c
- jr nz, .zeroLoop
-
- dec b
- jr nz, .tileLoop
- ret
-
-INCLUDE "data/sgb_packets.asm"
-
-INCLUDE "data/mon_palettes.asm"
-
-INCLUDE "data/super_palettes.asm"
-
-INCLUDE "data/sgb_border.asm"
--- a/engine/pathfinding.asm
+++ /dev/null
@@ -1,201 +1,0 @@
-FindPathToPlayer:
- xor a
- ld hl, hFindPathNumSteps
- ld [hli], a ; hFindPathNumSteps
- ld [hli], a ; hFindPathFlags
- ld [hli], a ; hFindPathYProgress
- ld [hl], a ; hFindPathXProgress
- ld hl, wNPCMovementDirections2
- ld de, $0
-.loop
- ld a, [hFindPathYProgress]
- ld b, a
- ld a, [hNPCPlayerYDistance] ; Y distance in steps
- call CalcDifference
- ld d, a
- and a
- jr nz, .asm_f8da
- ld a, [hFindPathFlags]
- set 0, a ; current end of path matches the player's Y coordinate
- ld [hFindPathFlags], a
-.asm_f8da
- ld a, [hFindPathXProgress]
- ld b, a
- ld a, [hNPCPlayerXDistance] ; X distance in steps
- call CalcDifference
- ld e, a
- and a
- jr nz, .asm_f8ec
- ld a, [hFindPathFlags]
- set 1, a ; current end of path matches the player's X coordinate
- ld [hFindPathFlags], a
-.asm_f8ec
- ld a, [hFindPathFlags]
- cp $3 ; has the end of the path reached the player's position?
- jr z, .done
-; Compare whether the X distance between the player and the current of the path
-; is greater or if the Y distance is. Then, try to reduce whichever is greater.
- ld a, e
- cp d
- jr c, .yDistanceGreater
-; x distance is greater
- ld a, [hNPCPlayerRelativePosFlags]
- bit 1, a
- jr nz, .playerIsLeftOfNPC
- ld d, NPC_MOVEMENT_RIGHT
- jr .next1
-.playerIsLeftOfNPC
- ld d, NPC_MOVEMENT_LEFT
-.next1
- ld a, [hFindPathXProgress]
- add 1
- ld [hFindPathXProgress], a
- jr .storeDirection
-.yDistanceGreater
- ld a, [hNPCPlayerRelativePosFlags]
- bit 0, a
- jr nz, .playerIsAboveNPC
- ld d, NPC_MOVEMENT_DOWN
- jr .next2
-.playerIsAboveNPC
- ld d, NPC_MOVEMENT_UP
-.next2
- ld a, [hFindPathYProgress]
- add 1
- ld [hFindPathYProgress], a
-.storeDirection
- ld a, d
- ld [hli], a
- ld a, [hFindPathNumSteps]
- inc a
- ld [hFindPathNumSteps], a
- jp .loop
-.done
- ld [hl], $ff
- ret
-
-CalcPositionOfPlayerRelativeToNPC:
- xor a
- ld [hNPCPlayerRelativePosFlags], a
- ld a, [wSpriteStateData1 + 4] ; player's sprite screen Y position in pixels
- ld d, a
- ld a, [wSpriteStateData1 + 6] ; player's sprite screen X position in pixels
- ld e, a
- ld hl, wSpriteStateData1
- ld a, [hNPCSpriteOffset]
- add l
- add $4
- ld l, a
- jr nc, .noCarry
- inc h
-.noCarry
- ld a, d
- ld b, a
- ld a, [hli] ; NPC sprite screen Y position in pixels
- call CalcDifference
- jr nc, .NPCSouthOfOrAlignedWithPlayer
-.NPCNorthOfPlayer
- push hl
- ld hl, hNPCPlayerRelativePosFlags
- bit 0, [hl]
- set 0, [hl]
- pop hl
- jr .divideYDistance
-.NPCSouthOfOrAlignedWithPlayer
- push hl
- ld hl, hNPCPlayerRelativePosFlags
- bit 0, [hl]
- res 0, [hl]
- pop hl
-.divideYDistance
- push hl
- ld hl, hDividend2
- ld [hli], a
- ld a, 16
- ld [hli], a
- call DivideBytes ; divide Y absolute distance by 16
- ld a, [hl] ; quotient
- ld [hNPCPlayerYDistance], a
- pop hl
- inc hl
- ld b, e
- ld a, [hl] ; NPC sprite screen X position in pixels
- call CalcDifference
- jr nc, .NPCEastOfOrAlignedWithPlayer
-.NPCWestOfPlayer
- push hl
- ld hl, hNPCPlayerRelativePosFlags
- bit 1, [hl]
- set 1, [hl]
- pop hl
- jr .divideXDistance
-.NPCEastOfOrAlignedWithPlayer
- push hl
- ld hl, hNPCPlayerRelativePosFlags
- bit 1, [hl]
- res 1, [hl]
- pop hl
-.divideXDistance
- ld [hDividend2], a
- ld a, 16
- ld [hDivisor2], a
- call DivideBytes ; divide X absolute distance by 16
- ld a, [hQuotient2]
- ld [hNPCPlayerXDistance], a
- ld a, [hNPCPlayerRelativePosPerspective]
- and a
- ret z
- ld a, [hNPCPlayerRelativePosFlags]
- cpl
- and $3
- ld [hNPCPlayerRelativePosFlags], a
- ret
-
-ConvertNPCMovementDirectionsToJoypadMasks:
- ld a, [hNPCMovementDirections2Index]
- ld [wNPCMovementDirections2Index], a
- dec a
- ld de, wSimulatedJoypadStatesEnd
- ld hl, wNPCMovementDirections2
- add l
- ld l, a
- jr nc, .loop
- inc h
-.loop
- ld a, [hld]
- call ConvertNPCMovementDirectionToJoypadMask
- ld [de], a
- inc de
- ld a, [hNPCMovementDirections2Index]
- dec a
- ld [hNPCMovementDirections2Index], a
- jr nz, .loop
- ret
-
-ConvertNPCMovementDirectionToJoypadMask:
- push hl
- ld b, a
- ld hl, NPCMovementDirectionsToJoypadMasksTable
-.loop
- ld a, [hli]
- cp $ff
- jr z, .done
- cp b
- jr z, .loadJoypadMask
- inc hl
- jr .loop
-.loadJoypadMask
- ld a, [hl]
-.done
- pop hl
- ret
-
-NPCMovementDirectionsToJoypadMasksTable:
- db NPC_MOVEMENT_UP, D_UP
- db NPC_MOVEMENT_DOWN, D_DOWN
- db NPC_MOVEMENT_LEFT, D_LEFT
- db NPC_MOVEMENT_RIGHT, D_RIGHT
- db $ff
-
-; unreferenced
- ret
--- a/engine/pokedex_rating.asm
+++ /dev/null
@@ -1,154 +1,0 @@
-DisplayDexRating:
- ld hl, wPokedexSeen
- ld b, wPokedexSeenEnd - wPokedexSeen
- call CountSetBits
- ld a, [wNumSetBits]
- ld [hDexRatingNumMonsSeen], a
- ld hl, wPokedexOwned
- ld b, wPokedexOwnedEnd - wPokedexOwned
- call CountSetBits
- ld a, [wNumSetBits]
- ld [hDexRatingNumMonsOwned], a
- ld hl, DexRatingsTable
-.findRating
- ld a, [hli]
- ld b, a
- ld a, [hDexRatingNumMonsOwned]
- cp b
- jr c, .foundRating
- inc hl
- inc hl
- jr .findRating
-.foundRating
- ld a, [hli]
- ld h, [hl]
- ld l, a ; load text pointer into hl
- CheckAndResetEventA EVENT_HALL_OF_FAME_DEX_RATING
- jr nz, .hallOfFame
- push hl
- ld hl, PokedexRatingText_441cc
- call PrintText
- pop hl
- call PrintText
- callba PlayPokedexRatingSfx
- jp WaitForTextScrollButtonPress
-.hallOfFame
- ld de, wDexRatingNumMonsSeen
- ld a, [hDexRatingNumMonsSeen]
- ld [de], a
- inc de
- ld a, [hDexRatingNumMonsOwned]
- ld [de], a
- inc de
-.copyRatingTextLoop
- ld a, [hli]
- cp "@"
- jr z, .doneCopying
- ld [de], a
- inc de
- jr .copyRatingTextLoop
-.doneCopying
- ld [de], a
- ret
-
-PokedexRatingText_441cc:
- TX_FAR _OaksLabText_441cc
- db "@"
-
-DexRatingsTable:
- db 10
- dw PokedexRatingText_44201
- db 20
- dw PokedexRatingText_44206
- db 30
- dw PokedexRatingText_4420b
- db 40
- dw PokedexRatingText_44210
- db 50
- dw PokedexRatingText_44215
- db 60
- dw PokedexRatingText_4421a
- db 70
- dw PokedexRatingText_4421f
- db 80
- dw PokedexRatingText_44224
- db 90
- dw PokedexRatingText_44229
- db 100
- dw PokedexRatingText_4422e
- db 110
- dw PokedexRatingText_44233
- db 120
- dw PokedexRatingText_44238
- db 130
- dw PokedexRatingText_4423d
- db 140
- dw PokedexRatingText_44242
- db 150
- dw PokedexRatingText_44247
- db NUM_POKEMON + 1
- dw PokedexRatingText_4424c
-
-PokedexRatingText_44201:
- TX_FAR _OaksLabText_44201
- db "@"
-
-PokedexRatingText_44206:
- TX_FAR _OaksLabText_44206
- db "@"
-
-PokedexRatingText_4420b:
- TX_FAR _OaksLabText_4420b
- db "@"
-
-PokedexRatingText_44210:
- TX_FAR _OaksLabText_44210
- db "@"
-
-PokedexRatingText_44215:
- TX_FAR _OaksLabText_44215
- db "@"
-
-PokedexRatingText_4421a:
- TX_FAR _OaksLabText_4421a
- db "@"
-
-PokedexRatingText_4421f:
- TX_FAR _OaksLabText_4421f
- db "@"
-
-PokedexRatingText_44224:
- TX_FAR _OaksLabText_44224
- db "@"
-
-PokedexRatingText_44229:
- TX_FAR _OaksLabText_44229
- db "@"
-
-PokedexRatingText_4422e:
- TX_FAR _OaksLabText_4422e
- db "@"
-
-PokedexRatingText_44233:
- TX_FAR _OaksLabText_44233
- db "@"
-
-PokedexRatingText_44238:
- TX_FAR _OaksLabText_44238
- db "@"
-
-PokedexRatingText_4423d:
- TX_FAR _OaksLabText_4423d
- db "@"
-
-PokedexRatingText_44242:
- TX_FAR _OaksLabText_44242
- db "@"
-
-PokedexRatingText_44247:
- TX_FAR _OaksLabText_44247
- db "@"
-
-PokedexRatingText_4424c:
- TX_FAR _OaksLabText_4424c
- db "@"
--- /dev/null
+++ b/engine/pokemon/add_mon.asm
@@ -1,0 +1,516 @@
+_AddPartyMon::
+; Adds a new mon to the player's or enemy's party.
+; [wMonDataLocation] is used in an unusual way in this function.
+; If the lower nybble is 0, the mon is added to the player's party, else the enemy's.
+; If the entire value is 0, then the player is allowed to name the mon.
+ ld de, wPartyCount
+ ld a, [wMonDataLocation]
+ and $f
+ jr z, .next
+ ld de, wEnemyPartyCount
+.next
+ ld a, [de]
+ inc a
+ cp PARTY_LENGTH + 1
+ ret nc ; return if the party is already full
+ ld [de], a
+ ld a, [de]
+ ld [hNewPartyLength], a
+ add e
+ ld e, a
+ jr nc, .noCarry
+ inc d
+.noCarry
+ ld a, [wcf91]
+ ld [de], a ; write species of new mon in party list
+ inc de
+ ld a, $ff ; terminator
+ ld [de], a
+ ld hl, wPartyMonOT
+ ld a, [wMonDataLocation]
+ and $f
+ jr z, .next2
+ ld hl, wEnemyMonOT
+.next2
+ ld a, [hNewPartyLength]
+ dec a
+ call SkipFixedLengthTextEntries
+ ld d, h
+ ld e, l
+ ld hl, wPlayerName
+ ld bc, NAME_LENGTH
+ call CopyData
+ ld a, [wMonDataLocation]
+ and a
+ jr nz, .skipNaming
+ ld hl, wPartyMonNicks
+ ld a, [hNewPartyLength]
+ dec a
+ call SkipFixedLengthTextEntries
+ ld a, NAME_MON_SCREEN
+ ld [wNamingScreenType], a
+ predef AskName
+.skipNaming
+ ld hl, wPartyMons
+ ld a, [wMonDataLocation]
+ and $f
+ jr z, .next3
+ ld hl, wEnemyMons
+.next3
+ ld a, [hNewPartyLength]
+ dec a
+ ld bc, wPartyMon2 - wPartyMon1
+ call AddNTimes
+ ld e, l
+ ld d, h
+ push hl
+ ld a, [wcf91]
+ ld [wd0b5], a
+ call GetMonHeader
+ ld hl, wMonHeader
+ ld a, [hli]
+ ld [de], a ; species
+ inc de
+ pop hl
+ push hl
+ ld a, [wMonDataLocation]
+ and $f
+ ld a, $98 ; set enemy trainer mon IVs to fixed average values
+ ld b, $88
+ jr nz, .next4
+
+; If the mon is being added to the player's party, update the pokedex.
+ ld a, [wcf91]
+ ld [wd11e], a
+ push de
+ predef IndexToPokedex
+ pop de
+ ld a, [wd11e]
+ dec a
+ ld c, a
+ ld b, FLAG_TEST
+ ld hl, wPokedexOwned
+ call FlagAction
+ ld a, c ; whether the mon was already flagged as owned
+ ld [wUnusedD153], a ; not read
+ ld a, [wd11e]
+ dec a
+ ld c, a
+ ld b, FLAG_SET
+ push bc
+ call FlagAction
+ pop bc
+ ld hl, wPokedexSeen
+ call FlagAction
+
+ pop hl
+ push hl
+
+ ld a, [wIsInBattle]
+ and a ; is this a wild mon caught in battle?
+ jr nz, .copyEnemyMonData
+
+; Not wild.
+ call Random ; generate random IVs
+ ld b, a
+ call Random
+
+.next4
+ push bc
+ ld bc, wPartyMon1DVs - wPartyMon1
+ add hl, bc
+ pop bc
+ ld [hli], a
+ ld [hl], b ; write IVs
+ ld bc, (wPartyMon1HPExp - 1) - (wPartyMon1DVs + 1)
+ add hl, bc
+ ld a, 1
+ ld c, a
+ xor a
+ ld b, a
+ call CalcStat ; calc HP stat (set cur Hp to max HP)
+ ld a, [H_MULTIPLICAND+1]
+ ld [de], a
+ inc de
+ ld a, [H_MULTIPLICAND+2]
+ ld [de], a
+ inc de
+ xor a
+ ld [de], a ; box level
+ inc de
+ ld [de], a ; status ailments
+ inc de
+ jr .copyMonTypesAndMoves
+.copyEnemyMonData
+ ld bc, wEnemyMon1DVs - wEnemyMon1
+ add hl, bc
+ ld a, [wEnemyMonDVs] ; copy IVs from cur enemy mon
+ ld [hli], a
+ ld a, [wEnemyMonDVs + 1]
+ ld [hl], a
+ ld a, [wEnemyMonHP] ; copy HP from cur enemy mon
+ ld [de], a
+ inc de
+ ld a, [wEnemyMonHP+1]
+ ld [de], a
+ inc de
+ xor a
+ ld [de], a ; box level
+ inc de
+ ld a, [wEnemyMonStatus] ; copy status ailments from cur enemy mon
+ ld [de], a
+ inc de
+.copyMonTypesAndMoves
+ ld hl, wMonHTypes
+ ld a, [hli] ; type 1
+ ld [de], a
+ inc de
+ ld a, [hli] ; type 2
+ ld [de], a
+ inc de
+ ld a, [hli] ; catch rate (held item in gen 2)
+ ld [de], a
+ ld hl, wMonHMoves
+ ld a, [hli]
+ inc de
+ push de
+ ld [de], a
+ ld a, [hli]
+ inc de
+ ld [de], a
+ ld a, [hli]
+ inc de
+ ld [de], a
+ ld a, [hli]
+ inc de
+ ld [de], a
+ push de
+ dec de
+ dec de
+ dec de
+ xor a
+ ld [wLearningMovesFromDayCare], a
+ predef WriteMonMoves
+ pop de
+ ld a, [wPlayerID] ; set trainer ID to player ID
+ inc de
+ ld [de], a
+ ld a, [wPlayerID + 1]
+ inc de
+ ld [de], a
+ push de
+ ld a, [wCurEnemyLVL]
+ ld d, a
+ callab CalcExperience
+ pop de
+ inc de
+ ld a, [hExperience] ; write experience
+ ld [de], a
+ inc de
+ ld a, [hExperience + 1]
+ ld [de], a
+ inc de
+ ld a, [hExperience + 2]
+ ld [de], a
+ xor a
+ ld b, NUM_STATS * 2
+.writeEVsLoop ; set all EVs to 0
+ inc de
+ ld [de], a
+ dec b
+ jr nz, .writeEVsLoop
+ inc de
+ inc de
+ pop hl
+ call AddPartyMon_WriteMovePP
+ inc de
+ ld a, [wCurEnemyLVL]
+ ld [de], a
+ inc de
+ ld a, [wIsInBattle]
+ dec a
+ jr nz, .calcFreshStats
+ ld hl, wEnemyMonMaxHP
+ ld bc, $a
+ call CopyData ; copy stats of cur enemy mon
+ pop hl
+ jr .done
+.calcFreshStats
+ pop hl
+ ld bc, wPartyMon1HPExp - 1 - wPartyMon1
+ add hl, bc
+ ld b, $0
+ call CalcStats ; calculate fresh set of stats
+.done
+ scf
+ ret
+
+LoadMovePPs:
+ call GetPredefRegisters
+ ; fallthrough
+AddPartyMon_WriteMovePP:
+ ld b, NUM_MOVES
+.pploop
+ ld a, [hli] ; read move ID
+ and a
+ jr z, .empty
+ dec a
+ push hl
+ push de
+ push bc
+ ld hl, Moves
+ ld bc, MoveEnd - Moves
+ call AddNTimes
+ ld de, wcd6d
+ ld a, BANK(Moves)
+ call FarCopyData
+ pop bc
+ pop de
+ pop hl
+ ld a, [wcd6d + 5] ; PP is byte 5 of move data
+.empty
+ inc de
+ ld [de], a
+ dec b
+ jr nz, .pploop ; there are still moves to read
+ ret
+
+; adds enemy mon [wcf91] (at position [wWhichPokemon] in enemy list) to own party
+; used in the cable club trade center
+_AddEnemyMonToPlayerParty::
+ ld hl, wPartyCount
+ ld a, [hl]
+ cp PARTY_LENGTH
+ scf
+ ret z ; party full, return failure
+ inc a
+ ld [hl], a ; add 1 to party members
+ ld c, a
+ ld b, $0
+ add hl, bc
+ ld a, [wcf91]
+ ld [hli], a ; add mon as last list entry
+ ld [hl], $ff ; write new sentinel
+ ld hl, wPartyMons
+ ld a, [wPartyCount]
+ dec a
+ ld bc, wPartyMon2 - wPartyMon1
+ call AddNTimes
+ ld e, l
+ ld d, h
+ ld hl, wLoadedMon
+ call CopyData ; write new mon's data (from wLoadedMon)
+ ld hl, wPartyMonOT
+ ld a, [wPartyCount]
+ dec a
+ call SkipFixedLengthTextEntries
+ ld d, h
+ ld e, l
+ ld hl, wEnemyMonOT
+ ld a, [wWhichPokemon]
+ call SkipFixedLengthTextEntries
+ ld bc, NAME_LENGTH
+ call CopyData ; write new mon's OT name (from an enemy mon)
+ ld hl, wPartyMonNicks
+ ld a, [wPartyCount]
+ dec a
+ call SkipFixedLengthTextEntries
+ ld d, h
+ ld e, l
+ ld hl, wEnemyMonNicks
+ ld a, [wWhichPokemon]
+ call SkipFixedLengthTextEntries
+ ld bc, NAME_LENGTH
+ call CopyData ; write new mon's nickname (from an enemy mon)
+ ld a, [wcf91]
+ ld [wd11e], a
+ predef IndexToPokedex
+ ld a, [wd11e]
+ dec a
+ ld c, a
+ ld b, FLAG_SET
+ ld hl, wPokedexOwned
+ push bc
+ call FlagAction ; add to owned pokemon
+ pop bc
+ ld hl, wPokedexSeen
+ call FlagAction ; add to seen pokemon
+ and a
+ ret ; return success
+
+_MoveMon::
+ ld a, [wMoveMonType]
+ and a ; BOX_TO_PARTY
+ jr z, .checkPartyMonSlots
+ cp DAYCARE_TO_PARTY
+ jr z, .checkPartyMonSlots
+ cp PARTY_TO_DAYCARE
+ ld hl, wDayCareMon
+ jr z, .findMonDataSrc
+ ; else it's PARTY_TO_BOX
+ ld hl, wNumInBox
+ ld a, [hl]
+ cp MONS_PER_BOX
+ jr nz, .partyOrBoxNotFull
+ jr .boxFull
+.checkPartyMonSlots
+ ld hl, wPartyCount
+ ld a, [hl]
+ cp PARTY_LENGTH
+ jr nz, .partyOrBoxNotFull
+.boxFull
+ scf
+ ret
+.partyOrBoxNotFull
+ inc a
+ ld [hl], a ; increment number of mons in party/box
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [wMoveMonType]
+ cp DAYCARE_TO_PARTY
+ ld a, [wDayCareMon]
+ jr z, .copySpecies
+ ld a, [wcf91]
+.copySpecies
+ ld [hli], a ; write new mon ID
+ ld [hl], $ff ; write new sentinel
+.findMonDataDest
+ ld a, [wMoveMonType]
+ dec a
+ ld hl, wPartyMons
+ ld bc, wPartyMon2 - wPartyMon1 ; $2c
+ ld a, [wPartyCount]
+ jr nz, .addMonOffset
+ ; if it's PARTY_TO_BOX
+ ld hl, wBoxMons
+ ld bc, wBoxMon2 - wBoxMon1 ; $21
+ ld a, [wNumInBox]
+.addMonOffset
+ dec a
+ call AddNTimes
+.findMonDataSrc
+ push hl
+ ld e, l
+ ld d, h
+ ld a, [wMoveMonType]
+ and a
+ ld hl, wBoxMons
+ ld bc, wBoxMon2 - wBoxMon1 ; $21
+ jr z, .addMonOffset2
+ cp DAYCARE_TO_PARTY
+ ld hl, wDayCareMon
+ jr z, .copyMonData
+ ld hl, wPartyMons
+ ld bc, wPartyMon2 - wPartyMon1 ; $2c
+.addMonOffset2
+ ld a, [wWhichPokemon]
+ call AddNTimes
+.copyMonData
+ push hl
+ push de
+ ld bc, wBoxMon2 - wBoxMon1
+ call CopyData
+ pop de
+ pop hl
+ ld a, [wMoveMonType]
+ and a ; BOX_TO_PARTY
+ jr z, .findOTdest
+ cp DAYCARE_TO_PARTY
+ jr z, .findOTdest
+ ld bc, wBoxMon2 - wBoxMon1
+ add hl, bc
+ ld a, [hl] ; hl = Level
+ inc de
+ inc de
+ inc de
+ ld [de], a ; de = BoxLevel
+.findOTdest
+ ld a, [wMoveMonType]
+ cp PARTY_TO_DAYCARE
+ ld de, wDayCareMonOT
+ jr z, .findOTsrc
+ dec a
+ ld hl, wPartyMonOT
+ ld a, [wPartyCount]
+ jr nz, .addOToffset
+ ld hl, wBoxMonOT
+ ld a, [wNumInBox]
+.addOToffset
+ dec a
+ call SkipFixedLengthTextEntries
+ ld d, h
+ ld e, l
+.findOTsrc
+ ld hl, wBoxMonOT
+ ld a, [wMoveMonType]
+ and a
+ jr z, .addOToffset2
+ ld hl, wDayCareMonOT
+ cp DAYCARE_TO_PARTY
+ jr z, .copyOT
+ ld hl, wPartyMonOT
+.addOToffset2
+ ld a, [wWhichPokemon]
+ call SkipFixedLengthTextEntries
+.copyOT
+ ld bc, NAME_LENGTH
+ call CopyData
+ ld a, [wMoveMonType]
+.findNickDest
+ cp PARTY_TO_DAYCARE
+ ld de, wDayCareMonName
+ jr z, .findNickSrc
+ dec a
+ ld hl, wPartyMonNicks
+ ld a, [wPartyCount]
+ jr nz, .addNickOffset
+ ld hl, wBoxMonNicks
+ ld a, [wNumInBox]
+.addNickOffset
+ dec a
+ call SkipFixedLengthTextEntries
+ ld d, h
+ ld e, l
+.findNickSrc
+ ld hl, wBoxMonNicks
+ ld a, [wMoveMonType]
+ and a
+ jr z, .addNickOffset2
+ ld hl, wDayCareMonName
+ cp DAYCARE_TO_PARTY
+ jr z, .copyNick
+ ld hl, wPartyMonNicks
+.addNickOffset2
+ ld a, [wWhichPokemon]
+ call SkipFixedLengthTextEntries
+.copyNick
+ ld bc, NAME_LENGTH
+ call CopyData
+ pop hl
+ ld a, [wMoveMonType]
+ cp PARTY_TO_BOX
+ jr z, .done
+ cp PARTY_TO_DAYCARE
+ jr z, .done
+ push hl
+ srl a
+ add $2
+ ld [wMonDataLocation], a
+ call LoadMonData
+ callba CalcLevelFromExperience
+ ld a, d
+ ld [wCurEnemyLVL], a
+ pop hl
+ ld bc, wBoxMon2 - wBoxMon1
+ add hl, bc
+ ld [hli], a
+ ld d, h
+ ld e, l
+ ld bc, -18
+ add hl, bc
+ ld b, $1
+ call CalcStats
+.done
+ and a
+ ret
--- /dev/null
+++ b/engine/pokemon/bills_pc.asm
@@ -1,0 +1,548 @@
+DisplayPCMainMenu::
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call SaveScreenTilesToBuffer2
+ ld a, [wNumHoFTeams]
+ and a
+ jr nz, .leaguePCAvailable
+ CheckEvent EVENT_GOT_POKEDEX
+ jr z, .noOaksPC
+ ld a, [wNumHoFTeams]
+ and a
+ jr nz, .leaguePCAvailable
+ coord hl, 0, 0
+ ld b, 8
+ ld c, 14
+ jr .next
+.noOaksPC
+ coord hl, 0, 0
+ ld b, 6
+ ld c, 14
+ jr .next
+.leaguePCAvailable
+ coord hl, 0, 0
+ ld b, 10
+ ld c, 14
+.next
+ call TextBoxBorder
+ call UpdateSprites
+ ld a, 3
+ ld [wMaxMenuItem], a
+ CheckEvent EVENT_MET_BILL
+ jr nz, .metBill
+ coord hl, 2, 2
+ ld de, SomeonesPCText
+ jr .next2
+.metBill
+ coord hl, 2, 2
+ ld de, BillsPCText
+.next2
+ call PlaceString
+ coord hl, 2, 4
+ ld de, wPlayerName
+ call PlaceString
+ ld l, c
+ ld h, b
+ ld de, PlayersPCText
+ call PlaceString
+ CheckEvent EVENT_GOT_POKEDEX
+ jr z, .noOaksPC2
+ coord hl, 2, 6
+ ld de, OaksPCText
+ call PlaceString
+ ld a, [wNumHoFTeams]
+ and a
+ jr z, .noLeaguePC
+ ld a, 4
+ ld [wMaxMenuItem], a
+ coord hl, 2, 8
+ ld de, PKMNLeaguePCText
+ call PlaceString
+ coord hl, 2, 10
+ ld de, LogOffPCText
+ jr .next3
+.noLeaguePC
+ coord hl, 2, 8
+ ld de, LogOffPCText
+ jr .next3
+.noOaksPC2
+ ld a, $2
+ ld [wMaxMenuItem], a
+ coord hl, 2, 6
+ ld de, LogOffPCText
+.next3
+ call PlaceString
+ ld a, A_BUTTON | B_BUTTON
+ ld [wMenuWatchedKeys], a
+ ld a, 2
+ ld [wTopMenuItemY], a
+ ld a, 1
+ ld [wTopMenuItemX], a
+ xor a
+ ld [wCurrentMenuItem], a
+ ld [wLastMenuItem], a
+ ld a, 1
+ ld [H_AUTOBGTRANSFERENABLED], a
+ ret
+
+SomeonesPCText: db "SOMEONE's PC@"
+BillsPCText: db "BILL's PC@"
+PlayersPCText: db "'s PC@"
+OaksPCText: db "PROF.OAK's PC@"
+PKMNLeaguePCText: db "<pkmn>LEAGUE@"
+LogOffPCText: db "LOG OFF@"
+
+BillsPC_::
+ ld hl, wd730
+ set 6, [hl]
+ xor a
+ ld [wParentMenuItem], a
+ inc a ; MONSTER_NAME
+ ld [wNameListType], a
+ call LoadHpBarAndStatusTilePatterns
+ ld a, [wListScrollOffset]
+ push af
+ ld a, [wFlags_0xcd60]
+ bit 3, a ; accessing Bill's PC through another PC?
+ jr nz, BillsPCMenu
+; accessing it directly
+ ld a, SFX_TURN_ON_PC
+ call PlaySound
+ ld hl, SwitchOnText
+ call PrintText
+
+BillsPCMenu:
+ ld a, [wParentMenuItem]
+ ld [wCurrentMenuItem], a
+ ld hl, vChars2 + $780
+ ld de, PokeballTileGraphics
+ lb bc, BANK(PokeballTileGraphics), $01
+ call CopyVideoData
+ call LoadScreenTilesFromBuffer2DisableBGTransfer
+ coord hl, 0, 0
+ ld b, 10
+ ld c, 12
+ call TextBoxBorder
+ coord hl, 2, 2
+ ld de, BillsPCMenuText
+ call PlaceString
+ ld hl, wTopMenuItemY
+ ld a, 2
+ ld [hli], a ; wTopMenuItemY
+ dec a
+ ld [hli], a ; wTopMenuItemX
+ inc hl
+ inc hl
+ ld a, 4
+ ld [hli], a ; wMaxMenuItem
+ ld a, A_BUTTON | B_BUTTON
+ ld [hli], a ; wMenuWatchedKeys
+ xor a
+ ld [hli], a ; wLastMenuItem
+ ld [hli], a ; wPartyAndBillsPCSavedMenuItem
+ ld hl, wListScrollOffset
+ ld [hli], a ; wListScrollOffset
+ ld [hl], a ; wMenuWatchMovingOutOfBounds
+ ld [wPlayerMonNumber], a
+ ld hl, WhatText
+ call PrintText
+ coord hl, 9, 14
+ ld b, 2
+ ld c, 9
+ call TextBoxBorder
+ ld a, [wCurrentBoxNum]
+ and $7f
+ cp 9
+ jr c, .singleDigitBoxNum
+; two digit box num
+ sub 9
+ coord hl, 17, 16
+ ld [hl], "1"
+ add "0"
+ jr .next
+.singleDigitBoxNum
+ add "1"
+.next
+ Coorda 18, 16
+ coord hl, 10, 16
+ ld de, BoxNoPCText
+ call PlaceString
+ ld a, 1
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call Delay3
+ call HandleMenuInput
+ bit 1, a
+ jp nz, ExitBillsPC ; b button
+ call PlaceUnfilledArrowMenuCursor
+ ld a, [wCurrentMenuItem]
+ ld [wParentMenuItem], a
+ and a
+ jp z, BillsPCWithdraw ; withdraw
+ cp $1
+ jp z, BillsPCDeposit ; deposit
+ cp $2
+ jp z, BillsPCRelease ; release
+ cp $3
+ jp z, BillsPCChangeBox ; change box
+
+ExitBillsPC:
+ ld a, [wFlags_0xcd60]
+ bit 3, a ; accessing Bill's PC through another PC?
+ jr nz, .next
+; accessing it directly
+ call LoadTextBoxTilePatterns
+ ld a, SFX_TURN_OFF_PC
+ call PlaySound
+ call WaitForSoundToFinish
+.next
+ ld hl, wFlags_0xcd60
+ res 5, [hl]
+ call LoadScreenTilesFromBuffer2
+ pop af
+ ld [wListScrollOffset], a
+ ld hl, wd730
+ res 6, [hl]
+ ret
+
+BillsPCDeposit:
+ ld a, [wPartyCount]
+ dec a
+ jr nz, .partyLargeEnough
+ ld hl, CantDepositLastMonText
+ call PrintText
+ jp BillsPCMenu
+.partyLargeEnough
+ ld a, [wNumInBox]
+ cp MONS_PER_BOX
+ jr nz, .boxNotFull
+ ld hl, BoxFullText
+ call PrintText
+ jp BillsPCMenu
+.boxNotFull
+ ld hl, wPartyCount
+ call DisplayMonListMenu
+ jp c, BillsPCMenu
+ call DisplayDepositWithdrawMenu
+ jp nc, BillsPCMenu
+ ld a, [wcf91]
+ call GetCryData
+ call PlaySoundWaitForCurrent
+ ld a, PARTY_TO_BOX
+ ld [wMoveMonType], a
+ call MoveMon
+ xor a
+ ld [wRemoveMonFromBox], a
+ call RemovePokemon
+ call WaitForSoundToFinish
+ ld hl, wBoxNumString
+ ld a, [wCurrentBoxNum]
+ and $7f
+ cp 9
+ jr c, .singleDigitBoxNum
+ sub 9
+ ld [hl], "1"
+ inc hl
+ add "0"
+ jr .next
+.singleDigitBoxNum
+ add "1"
+.next
+ ld [hli], a
+ ld [hl], "@"
+ ld hl, MonWasStoredText
+ call PrintText
+ jp BillsPCMenu
+
+BillsPCWithdraw:
+ ld a, [wNumInBox]
+ and a
+ jr nz, .boxNotEmpty
+ ld hl, NoMonText
+ call PrintText
+ jp BillsPCMenu
+.boxNotEmpty
+ ld a, [wPartyCount]
+ cp PARTY_LENGTH
+ jr nz, .partyNotFull
+ ld hl, CantTakeMonText
+ call PrintText
+ jp BillsPCMenu
+.partyNotFull
+ ld hl, wNumInBox
+ call DisplayMonListMenu
+ jp c, BillsPCMenu
+ call DisplayDepositWithdrawMenu
+ jp nc, BillsPCMenu
+ ld a, [wWhichPokemon]
+ ld hl, wBoxMonNicks
+ call GetPartyMonName
+ ld a, [wcf91]
+ call GetCryData
+ call PlaySoundWaitForCurrent
+ xor a ; BOX_TO_PARTY
+ ld [wMoveMonType], a
+ call MoveMon
+ ld a, 1
+ ld [wRemoveMonFromBox], a
+ call RemovePokemon
+ call WaitForSoundToFinish
+ ld hl, MonIsTakenOutText
+ call PrintText
+ jp BillsPCMenu
+
+BillsPCRelease:
+ ld a, [wNumInBox]
+ and a
+ jr nz, .loop
+ ld hl, NoMonText
+ call PrintText
+ jp BillsPCMenu
+.loop
+ ld hl, wNumInBox
+ call DisplayMonListMenu
+ jp c, BillsPCMenu
+ ld hl, OnceReleasedText
+ call PrintText
+ call YesNoChoice
+ ld a, [wCurrentMenuItem]
+ and a
+ jr nz, .loop
+ inc a
+ ld [wRemoveMonFromBox], a
+ call RemovePokemon
+ call WaitForSoundToFinish
+ ld a, [wcf91]
+ call PlayCry
+ ld hl, MonWasReleasedText
+ call PrintText
+ jp BillsPCMenu
+
+BillsPCChangeBox:
+ callba ChangeBox
+ jp BillsPCMenu
+
+DisplayMonListMenu:
+ ld a, l
+ ld [wListPointer], a
+ ld a, h
+ ld [wListPointer + 1], a
+ xor a
+ ld [wPrintItemPrices], a
+ ld [wListMenuID], a
+ inc a ; MONSTER_NAME
+ ld [wNameListType], a
+ ld a, [wPartyAndBillsPCSavedMenuItem]
+ ld [wCurrentMenuItem], a
+ call DisplayListMenuID
+ ld a, [wCurrentMenuItem]
+ ld [wPartyAndBillsPCSavedMenuItem], a
+ ret
+
+BillsPCMenuText:
+ db "WITHDRAW <pkmn>"
+ next "DEPOSIT <pkmn>"
+ next "RELEASE <pkmn>"
+ next "CHANGE BOX"
+ next "SEE YA!"
+ db "@"
+
+BoxNoPCText:
+ db "BOX No.@"
+
+KnowsHMMove::
+; returns whether mon with party index [wWhichPokemon] knows an HM move
+ ld hl, wPartyMon1Moves
+ ld bc, wPartyMon2 - wPartyMon1
+ jr .next
+; unreachable
+ ld hl, wBoxMon1Moves
+ ld bc, wBoxMon2 - wBoxMon1
+.next
+ ld a, [wWhichPokemon]
+ call AddNTimes
+ ld b, NUM_MOVES
+.loop
+ ld a, [hli]
+ push hl
+ push bc
+ ld hl, HMMoveArray
+ ld de, 1
+ call IsInArray
+ pop bc
+ pop hl
+ ret c
+ dec b
+ jr nz, .loop
+ and a
+ ret
+
+INCLUDE "data/hm_moves.asm"
+
+DisplayDepositWithdrawMenu:
+ coord hl, 9, 10
+ ld b, 6
+ ld c, 9
+ call TextBoxBorder
+ ld a, [wParentMenuItem]
+ and a ; was the Deposit or Withdraw item selected in the parent menu?
+ ld de, DepositPCText
+ jr nz, .next
+ ld de, WithdrawPCText
+.next
+ coord hl, 11, 12
+ call PlaceString
+ coord hl, 11, 14
+ ld de, StatsCancelPCText
+ call PlaceString
+ ld hl, wTopMenuItemY
+ ld a, 12
+ ld [hli], a ; wTopMenuItemY
+ ld a, 10
+ ld [hli], a ; wTopMenuItemX
+ xor a
+ ld [hli], a ; wCurrentMenuItem
+ inc hl
+ ld a, 2
+ ld [hli], a ; wMaxMenuItem
+ ld a, A_BUTTON | B_BUTTON
+ ld [hli], a ; wMenuWatchedKeys
+ xor a
+ ld [hl], a ; wLastMenuItem
+ ld hl, wListScrollOffset
+ ld [hli], a ; wListScrollOffset
+ ld [hl], a ; wMenuWatchMovingOutOfBounds
+ ld [wPlayerMonNumber], a
+ ld [wPartyAndBillsPCSavedMenuItem], a
+.loop
+ call HandleMenuInput
+ bit 1, a ; pressed B?
+ jr nz, .exit
+ ld a, [wCurrentMenuItem]
+ and a
+ jr z, .choseDepositWithdraw
+ dec a
+ jr z, .viewStats
+.exit
+ and a
+ ret
+.choseDepositWithdraw
+ scf
+ ret
+.viewStats
+ call SaveScreenTilesToBuffer1
+ ld a, [wParentMenuItem]
+ and a
+ ld a, PLAYER_PARTY_DATA
+ jr nz, .next2
+ ld a, BOX_DATA
+.next2
+ ld [wMonDataLocation], a
+ predef StatusScreen
+ predef StatusScreen2
+ call LoadScreenTilesFromBuffer1
+ call ReloadTilesetTilePatterns
+ call RunDefaultPaletteCommand
+ call LoadGBPal
+ jr .loop
+
+DepositPCText: db "DEPOSIT@"
+WithdrawPCText: db "WITHDRAW@"
+StatsCancelPCText:
+ db "STATS"
+ next "CANCEL@"
+
+SwitchOnText:
+ TX_FAR _SwitchOnText
+ db "@"
+
+WhatText:
+ TX_FAR _WhatText
+ db "@"
+
+DepositWhichMonText:
+ TX_FAR _DepositWhichMonText
+ db "@"
+
+MonWasStoredText:
+ TX_FAR _MonWasStoredText
+ db "@"
+
+CantDepositLastMonText:
+ TX_FAR _CantDepositLastMonText
+ db "@"
+
+BoxFullText:
+ TX_FAR _BoxFullText
+ db "@"
+
+MonIsTakenOutText:
+ TX_FAR _MonIsTakenOutText
+ db "@"
+
+NoMonText:
+ TX_FAR _NoMonText
+ db "@"
+
+CantTakeMonText:
+ TX_FAR _CantTakeMonText
+ db "@"
+
+ReleaseWhichMonText:
+ TX_FAR _ReleaseWhichMonText
+ db "@"
+
+OnceReleasedText:
+ TX_FAR _OnceReleasedText
+ db "@"
+
+MonWasReleasedText:
+ TX_FAR _MonWasReleasedText
+ db "@"
+
+CableClubLeftGameboy::
+ ld a, [hSerialConnectionStatus]
+ cp USING_EXTERNAL_CLOCK
+ ret z
+ ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction
+ cp SPRITE_FACING_RIGHT
+ ret nz
+ ld a, [wCurMap]
+ cp TRADE_CENTER
+ ld a, LINK_STATE_START_TRADE
+ jr z, .next
+ inc a ; LINK_STATE_START_BATTLE
+.next
+ ld [wLinkState], a
+ call EnableAutoTextBoxDrawing
+ tx_pre_jump JustAMomentText
+
+CableClubRightGameboy::
+ ld a, [hSerialConnectionStatus]
+ cp USING_INTERNAL_CLOCK
+ ret z
+ ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction
+ cp SPRITE_FACING_LEFT
+ ret nz
+ ld a, [wCurMap]
+ cp TRADE_CENTER
+ ld a, LINK_STATE_START_TRADE
+ jr z, .next
+ inc a ; LINK_STATE_START_BATTLE
+.next
+ ld [wLinkState], a
+ call EnableAutoTextBoxDrawing
+ tx_pre_jump JustAMomentText
+
+JustAMomentText::
+ TX_FAR _JustAMomentText
+ db "@"
+
+ ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction
+ cp SPRITE_FACING_UP
+ ret nz
+ call EnableAutoTextBoxDrawing
+ tx_pre_jump OpenBillsPCText
+
+OpenBillsPCText::
+ TX_BILLS_PC
+
--- /dev/null
+++ b/engine/pokemon/evos_moves.asm
@@ -1,0 +1,513 @@
+; try to evolve the mon in [wWhichPokemon]
+TryEvolvingMon:
+ ld hl, wCanEvolveFlags
+ xor a
+ ld [hl], a
+ ld a, [wWhichPokemon]
+ ld c, a
+ ld b, FLAG_SET
+ call Evolution_FlagAction
+
+; this is only called after battle
+; it is supposed to do level up evolutions, though there is a bug that allows item evolutions to occur
+EvolutionAfterBattle:
+ ld a, [hTilesetType]
+ push af
+ xor a
+ ld [wEvolutionOccurred], a
+ dec a
+ ld [wWhichPokemon], a
+ push hl
+ push bc
+ push de
+ ld hl, wPartyCount
+ push hl
+
+Evolution_PartyMonLoop: ; loop over party mons
+ ld hl, wWhichPokemon
+ inc [hl]
+ pop hl
+ inc hl
+ ld a, [hl]
+ cp $ff ; have we reached the end of the party?
+ jp z, .done
+ ld [wEvoOldSpecies], a
+ push hl
+ ld a, [wWhichPokemon]
+ ld c, a
+ ld hl, wCanEvolveFlags
+ ld b, FLAG_TEST
+ call Evolution_FlagAction
+ ld a, c
+ and a ; is the mon's bit set?
+ jp z, Evolution_PartyMonLoop ; if not, go to the next mon
+ ld a, [wEvoOldSpecies]
+ dec a
+ ld b, 0
+ ld hl, EvosMovesPointerTable
+ add a
+ rl b
+ ld c, a
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ push hl
+ ld a, [wcf91]
+ push af
+ xor a ; PLAYER_PARTY_DATA
+ ld [wMonDataLocation], a
+ call LoadMonData
+ pop af
+ ld [wcf91], a
+ pop hl
+
+.evoEntryLoop ; loop over evolution entries
+ ld a, [hli]
+ and a ; have we reached the end of the evolution data?
+ jr z, Evolution_PartyMonLoop
+ ld b, a ; evolution type
+ cp EV_TRADE
+ jr z, .checkTradeEvo
+; not trade evolution
+ ld a, [wLinkState]
+ cp LINK_STATE_TRADING
+ jr z, Evolution_PartyMonLoop ; if trading, go the next mon
+ ld a, b
+ cp EV_ITEM
+ jr z, .checkItemEvo
+ ld a, [wForceEvolution]
+ and a
+ jr nz, Evolution_PartyMonLoop
+ ld a, b
+ cp EV_LEVEL
+ jr z, .checkLevel
+.checkTradeEvo
+ ld a, [wLinkState]
+ cp LINK_STATE_TRADING
+ jp nz, .nextEvoEntry1 ; if not trading, go to the next evolution entry
+ ld a, [hli] ; level requirement
+ ld b, a
+ ld a, [wLoadedMonLevel]
+ cp b ; is the mon's level greater than the evolution requirement?
+ jp c, Evolution_PartyMonLoop ; if so, go the next mon
+ jr .doEvolution
+.checkItemEvo
+ ld a, [hli]
+ ld b, a ; evolution item
+ ld a, [wcf91] ; this is supposed to be the last item used, but it is also used to hold species numbers
+ cp b ; was the evolution item in this entry used?
+ jp nz, .nextEvoEntry1 ; if not, go to the next evolution entry
+.checkLevel
+ ld a, [hli] ; level requirement
+ ld b, a
+ ld a, [wLoadedMonLevel]
+ cp b ; is the mon's level greater than the evolution requirement?
+ jp c, .nextEvoEntry2 ; if so, go the next evolution entry
+.doEvolution
+ ld [wCurEnemyLVL], a
+ ld a, 1
+ ld [wEvolutionOccurred], a
+ push hl
+ ld a, [hl]
+ ld [wEvoNewSpecies], a
+ ld a, [wWhichPokemon]
+ ld hl, wPartyMonNicks
+ call GetPartyMonName
+ call CopyStringToCF4B
+ ld hl, IsEvolvingText
+ call PrintText
+ ld c, 50
+ call DelayFrames
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ coord hl, 0, 0
+ lb bc, 12, 20
+ call ClearScreenArea
+ ld a, $1
+ ld [H_AUTOBGTRANSFERENABLED], a
+ ld a, $ff
+ ld [wUpdateSpritesEnabled], a
+ call ClearSprites
+ callab EvolveMon
+ jp c, CancelledEvolution
+ ld hl, EvolvedText
+ call PrintText
+ pop hl
+ ld a, [hl]
+ ld [wd0b5], a
+ ld [wLoadedMonSpecies], a
+ ld [wEvoNewSpecies], a
+ ld a, MONSTER_NAME
+ ld [wNameListType], a
+ ld a, BANK(TrainerNames) ; bank is not used for monster names
+ ld [wPredefBank], a
+ call GetName
+ push hl
+ ld hl, IntoText
+ call PrintText_NoCreatingTextBox
+ ld a, SFX_GET_ITEM_2
+ call PlaySoundWaitForCurrent
+ call WaitForSoundToFinish
+ ld c, 40
+ call DelayFrames
+ call ClearScreen
+ call RenameEvolvedMon
+ ld a, [wd11e]
+ push af
+ ld a, [wd0b5]
+ ld [wd11e], a
+ predef IndexToPokedex
+ ld a, [wd11e]
+ dec a
+ ld hl, BaseStats
+ ld bc, MonBaseStatsEnd - MonBaseStats
+ call AddNTimes
+ ld de, wMonHeader
+ call CopyData
+ ld a, [wd0b5]
+ ld [wMonHIndex], a
+ pop af
+ ld [wd11e], a
+ ld hl, wLoadedMonHPExp - 1
+ ld de, wLoadedMonStats
+ ld b, $1
+ call CalcStats
+ ld a, [wWhichPokemon]
+ ld hl, wPartyMon1
+ ld bc, wPartyMon2 - wPartyMon1
+ call AddNTimes
+ ld e, l
+ ld d, h
+ push hl
+ push bc
+ ld bc, wPartyMon1MaxHP - wPartyMon1
+ add hl, bc
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+ ld hl, wLoadedMonMaxHP + 1
+ ld a, [hld]
+ sub c
+ ld c, a
+ ld a, [hl]
+ sbc b
+ ld b, a
+ ld hl, wLoadedMonHP + 1
+ ld a, [hl]
+ add c
+ ld [hld], a
+ ld a, [hl]
+ adc b
+ ld [hl], a
+ dec hl
+ pop bc
+ call CopyData
+ ld a, [wd0b5]
+ ld [wd11e], a
+ xor a
+ ld [wMonDataLocation], a
+ call LearnMoveFromLevelUp
+ pop hl
+ predef SetPartyMonTypes
+ ld a, [wIsInBattle]
+ and a
+ call z, Evolution_ReloadTilesetTilePatterns
+ predef IndexToPokedex
+ ld a, [wd11e]
+ dec a
+ ld c, a
+ ld b, FLAG_SET
+ ld hl, wPokedexOwned
+ push bc
+ call Evolution_FlagAction
+ pop bc
+ ld hl, wPokedexSeen
+ call Evolution_FlagAction
+ pop de
+ pop hl
+ ld a, [wLoadedMonSpecies]
+ ld [hl], a
+ push hl
+ ld l, e
+ ld h, d
+ jr .nextEvoEntry2
+
+.nextEvoEntry1
+ inc hl
+
+.nextEvoEntry2
+ inc hl
+ jp .evoEntryLoop
+
+.done
+ pop de
+ pop bc
+ pop hl
+ pop af
+ ld [hTilesetType], a
+ ld a, [wLinkState]
+ cp LINK_STATE_TRADING
+ ret z
+ ld a, [wIsInBattle]
+ and a
+ ret nz
+ ld a, [wEvolutionOccurred]
+ and a
+ call nz, PlayDefaultMusic
+ ret
+
+RenameEvolvedMon:
+; Renames the mon to its new, evolved form's standard name unless it had a
+; nickname, in which case the nickname is kept.
+ ld a, [wd0b5]
+ push af
+ ld a, [wMonHIndex]
+ ld [wd0b5], a
+ call GetName
+ pop af
+ ld [wd0b5], a
+ ld hl, wcd6d
+ ld de, wcf4b
+.compareNamesLoop
+ ld a, [de]
+ inc de
+ cp [hl]
+ inc hl
+ ret nz
+ cp "@"
+ jr nz, .compareNamesLoop
+ ld a, [wWhichPokemon]
+ ld bc, NAME_LENGTH
+ ld hl, wPartyMonNicks
+ call AddNTimes
+ push hl
+ call GetName
+ ld hl, wcd6d
+ pop de
+ jp CopyData
+
+CancelledEvolution:
+ ld hl, StoppedEvolvingText
+ call PrintText
+ call ClearScreen
+ pop hl
+ call Evolution_ReloadTilesetTilePatterns
+ jp Evolution_PartyMonLoop
+
+EvolvedText:
+ TX_FAR _EvolvedText
+ db "@"
+
+IntoText:
+ TX_FAR _IntoText
+ db "@"
+
+StoppedEvolvingText:
+ TX_FAR _StoppedEvolvingText
+ db "@"
+
+IsEvolvingText:
+ TX_FAR _IsEvolvingText
+ db "@"
+
+Evolution_ReloadTilesetTilePatterns:
+ ld a, [wLinkState]
+ cp LINK_STATE_TRADING
+ ret z
+ jp ReloadTilesetTilePatterns
+
+LearnMoveFromLevelUp:
+ ld hl, EvosMovesPointerTable
+ ld a, [wd11e] ; species
+ ld [wcf91], a
+ dec a
+ ld bc, 0
+ ld hl, EvosMovesPointerTable
+ add a
+ rl b
+ ld c, a
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+.skipEvolutionDataLoop ; loop to skip past the evolution data, which comes before the move data
+ ld a, [hli]
+ and a ; have we reached the end of the evolution data?
+ jr nz, .skipEvolutionDataLoop ; if not, jump back up
+.learnSetLoop ; loop over the learn set until we reach a move that is learnt at the current level or the end of the list
+ ld a, [hli]
+ and a ; have we reached the end of the learn set?
+ jr z, .done ; if we've reached the end of the learn set, jump
+ ld b, a ; level the move is learnt at
+ ld a, [wCurEnemyLVL]
+ cp b ; is the move learnt at the mon's current level?
+ ld a, [hli] ; move ID
+ jr nz, .learnSetLoop
+ ld d, a ; ID of move to learn
+ ld a, [wMonDataLocation]
+ and a
+ jr nz, .next
+; If [wMonDataLocation] is 0 (PLAYER_PARTY_DATA), get the address of the mon's
+; current moves in party data. Every call to this function sets
+; [wMonDataLocation] to 0 because other data locations are not supported.
+; If it is not 0, this function will not work properly.
+ ld hl, wPartyMon1Moves
+ ld a, [wWhichPokemon]
+ ld bc, wPartyMon2 - wPartyMon1
+ call AddNTimes
+.next
+ ld b, NUM_MOVES
+.checkCurrentMovesLoop ; check if the move to learn is already known
+ ld a, [hli]
+ cp d
+ jr z, .done ; if already known, jump
+ dec b
+ jr nz, .checkCurrentMovesLoop
+ ld a, d
+ ld [wMoveNum], a
+ ld [wd11e], a
+ call GetMoveName
+ call CopyStringToCF4B
+ predef LearnMove
+.done
+ ld a, [wcf91]
+ ld [wd11e], a
+ ret
+
+; writes the moves a mon has at level [wCurEnemyLVL] to [de]
+; move slots are being filled up sequentially and shifted if all slots are full
+WriteMonMoves:
+ call GetPredefRegisters
+ push hl
+ push de
+ push bc
+ ld hl, EvosMovesPointerTable
+ ld b, 0
+ ld a, [wcf91] ; cur mon ID
+ dec a
+ add a
+ rl b
+ ld c, a
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+.skipEvoEntriesLoop
+ ld a, [hli]
+ and a
+ jr nz, .skipEvoEntriesLoop
+ jr .firstMove
+.nextMove
+ pop de
+.nextMove2
+ inc hl
+.firstMove
+ ld a, [hli] ; read level of next move in learnset
+ and a
+ jp z, .done ; end of list
+ ld b, a
+ ld a, [wCurEnemyLVL]
+ cp b
+ jp c, .done ; mon level < move level (assumption: learnset is sorted by level)
+ ld a, [wLearningMovesFromDayCare]
+ and a
+ jr z, .skipMinLevelCheck
+ ld a, [wDayCareStartLevel]
+ cp b
+ jr nc, .nextMove2 ; min level >= move level
+
+.skipMinLevelCheck
+
+; check if the move is already known
+ push de
+ ld c, NUM_MOVES
+.alreadyKnowsCheckLoop
+ ld a, [de]
+ inc de
+ cp [hl]
+ jr z, .nextMove
+ dec c
+ jr nz, .alreadyKnowsCheckLoop
+
+; try to find an empty move slot
+ pop de
+ push de
+ ld c, NUM_MOVES
+.findEmptySlotLoop
+ ld a, [de]
+ and a
+ jr z, .writeMoveToSlot2
+ inc de
+ dec c
+ jr nz, .findEmptySlotLoop
+
+; no empty move slots found
+ pop de
+ push de
+ push hl
+ ld h, d
+ ld l, e
+ call WriteMonMoves_ShiftMoveData ; shift all moves one up (deleting move 1)
+ ld a, [wLearningMovesFromDayCare]
+ and a
+ jr z, .writeMoveToSlot
+
+; shift PP as well if learning moves from day care
+ push de
+ ld bc, wPartyMon1PP - (wPartyMon1Moves + 3)
+ add hl, bc
+ ld d, h
+ ld e, l
+ call WriteMonMoves_ShiftMoveData ; shift all move PP data one up
+ pop de
+
+.writeMoveToSlot
+ pop hl
+.writeMoveToSlot2
+ ld a, [hl]
+ ld [de], a
+ ld a, [wLearningMovesFromDayCare]
+ and a
+ jr z, .nextMove
+
+; write move PP value if learning moves from day care
+ push hl
+ ld a, [hl]
+ ld hl, wPartyMon1PP - wPartyMon1Moves
+ add hl, de
+ push hl
+ dec a
+ ld hl, Moves
+ ld bc, MoveEnd - Moves
+ call AddNTimes
+ ld de, wBuffer
+ ld a, BANK(Moves)
+ call FarCopyData
+ ld a, [wBuffer + 5]
+ pop hl
+ ld [hl], a
+ pop hl
+ jr .nextMove
+
+.done
+ pop bc
+ pop de
+ pop hl
+ ret
+
+; shifts all move data one up (freeing 4th move slot)
+WriteMonMoves_ShiftMoveData:
+ ld c, NUM_MOVES - 1
+.loop
+ inc de
+ ld a, [de]
+ ld [hli], a
+ dec c
+ jr nz, .loop
+ ret
+
+Evolution_FlagAction:
+ predef_jump FlagActionPredef
+
+INCLUDE "data/evos_moves.asm"
--- /dev/null
+++ b/engine/pokemon/experience.asm
@@ -1,0 +1,149 @@
+; calculates the level a mon should be based on its current exp
+CalcLevelFromExperience::
+ ld a, [wLoadedMonSpecies]
+ ld [wd0b5], a
+ call GetMonHeader
+ ld d, $1 ; init level to 1
+.loop
+ inc d ; increment level
+ call CalcExperience
+ push hl
+ ld hl, wLoadedMonExp + 2 ; current exp
+; compare exp needed for level d with current exp
+ ld a, [hExperience + 2]
+ ld c, a
+ ld a, [hld]
+ sub c
+ ld a, [hExperience + 1]
+ ld c, a
+ ld a, [hld]
+ sbc c
+ ld a, [hExperience]
+ ld c, a
+ ld a, [hl]
+ sbc c
+ pop hl
+ jr nc, .loop ; if exp needed for level d is not greater than exp, try the next level
+ dec d ; since the exp was too high on the last loop iteration, go back to the previous value and return
+ ret
+
+; calculates the amount of experience needed for level d
+CalcExperience::
+ ld a, [wMonHGrowthRate]
+ add a
+ add a
+ ld c, a
+ ld b, 0
+ ld hl, GrowthRateTable
+ add hl, bc
+ call CalcDSquared
+ ld a, d
+ ld [H_MULTIPLIER], a
+ call Multiply
+ ld a, [hl]
+ and $f0
+ swap a
+ ld [H_MULTIPLIER], a
+ call Multiply
+ ld a, [hli]
+ and $f
+ ld [H_DIVISOR], a
+ ld b, $4
+ call Divide
+ ld a, [H_QUOTIENT + 1]
+ push af
+ ld a, [H_QUOTIENT + 2]
+ push af
+ ld a, [H_QUOTIENT + 3]
+ push af
+ call CalcDSquared
+ ld a, [hl]
+ and $7f
+ ld [H_MULTIPLIER], a
+ call Multiply
+ ld a, [H_PRODUCT + 1]
+ push af
+ ld a, [H_PRODUCT + 2]
+ push af
+ ld a, [H_PRODUCT + 3]
+ push af
+ ld a, [hli]
+ push af
+ xor a
+ ld [H_MULTIPLICAND], a
+ ld [H_MULTIPLICAND + 1], a
+ ld a, d
+ ld [H_MULTIPLICAND + 2], a
+ ld a, [hli]
+ ld [H_MULTIPLIER], a
+ call Multiply
+ ld b, [hl]
+ ld a, [H_PRODUCT + 3]
+ sub b
+ ld [H_PRODUCT + 3], a
+ ld b, $0
+ ld a, [H_PRODUCT + 2]
+ sbc b
+ ld [H_PRODUCT + 2], a
+ ld a, [H_PRODUCT + 1]
+ sbc b
+ ld [H_PRODUCT + 1], a
+; The difference of the linear term and the constant term consists of 3 bytes
+; starting at H_PRODUCT + 1. Below, hExperience (an alias of that address) will
+; be used instead for the further work of adding or subtracting the squared
+; term and adding the cubed term.
+ pop af
+ and $80
+ jr nz, .subtractSquaredTerm ; check sign
+ pop bc
+ ld a, [hExperience + 2]
+ add b
+ ld [hExperience + 2], a
+ pop bc
+ ld a, [hExperience + 1]
+ adc b
+ ld [hExperience + 1], a
+ pop bc
+ ld a, [hExperience]
+ adc b
+ ld [hExperience], a
+ jr .addCubedTerm
+.subtractSquaredTerm
+ pop bc
+ ld a, [hExperience + 2]
+ sub b
+ ld [hExperience + 2], a
+ pop bc
+ ld a, [hExperience + 1]
+ sbc b
+ ld [hExperience + 1], a
+ pop bc
+ ld a, [hExperience]
+ sbc b
+ ld [hExperience], a
+.addCubedTerm
+ pop bc
+ ld a, [hExperience + 2]
+ add b
+ ld [hExperience + 2], a
+ pop bc
+ ld a, [hExperience + 1]
+ adc b
+ ld [hExperience + 1], a
+ pop bc
+ ld a, [hExperience]
+ adc b
+ ld [hExperience], a
+ ret
+
+; calculates d*d
+CalcDSquared:
+ xor a
+ ld [H_MULTIPLICAND], a
+ ld [H_MULTIPLICAND + 1], a
+ ld a, d
+ ld [H_MULTIPLICAND + 2], a
+ ld [H_MULTIPLIER], a
+ jp Multiply
+
+INCLUDE "data/growth_rates.asm"
--- /dev/null
+++ b/engine/pokemon/learn_move.asm
@@ -1,0 +1,226 @@
+LearnMove:
+ call SaveScreenTilesToBuffer1
+ ld a, [wWhichPokemon]
+ ld hl, wPartyMonNicks
+ call GetPartyMonName
+ ld hl, wcd6d
+ ld de, wLearnMoveMonName
+ ld bc, NAME_LENGTH
+ call CopyData
+
+DontAbandonLearning:
+ ld hl, wPartyMon1Moves
+ ld bc, wPartyMon2Moves - wPartyMon1Moves
+ ld a, [wWhichPokemon]
+ call AddNTimes
+ ld d, h
+ ld e, l
+ ld b, NUM_MOVES
+.findEmptyMoveSlotLoop
+ ld a, [hl]
+ and a
+ jr z, .next
+ inc hl
+ dec b
+ jr nz, .findEmptyMoveSlotLoop
+ push de
+ call TryingToLearn
+ pop de
+ jp c, AbandonLearning
+ push hl
+ push de
+ ld [wd11e], a
+ call GetMoveName
+ ld hl, OneTwoAndText
+ call PrintText
+ pop de
+ pop hl
+.next
+ ld a, [wMoveNum]
+ ld [hl], a
+ ld bc, wPartyMon1PP - wPartyMon1Moves
+ add hl, bc
+ push hl
+ push de
+ dec a
+ ld hl, Moves
+ ld bc, MoveEnd - Moves
+ call AddNTimes
+ ld de, wBuffer
+ ld a, BANK(Moves)
+ call FarCopyData
+ ld a, [wBuffer + 5] ; a = move's max PP
+ pop de
+ pop hl
+ ld [hl], a
+ ld a, [wIsInBattle]
+ and a
+ jp z, PrintLearnedMove
+ ld a, [wWhichPokemon]
+ ld b, a
+ ld a, [wPlayerMonNumber]
+ cp b
+ jp nz, PrintLearnedMove
+ ld h, d
+ ld l, e
+ ld de, wBattleMonMoves
+ ld bc, NUM_MOVES
+ call CopyData
+ ld bc, wPartyMon1PP - wPartyMon1OTID
+ add hl, bc
+ ld de, wBattleMonPP
+ ld bc, NUM_MOVES
+ call CopyData
+ jp PrintLearnedMove
+
+AbandonLearning:
+ ld hl, AbandonLearningText
+ call PrintText
+ coord hl, 14, 7
+ lb bc, 8, 15
+ ld a, TWO_OPTION_MENU
+ ld [wTextBoxID], a
+ call DisplayTextBoxID ; yes/no menu
+ ld a, [wCurrentMenuItem]
+ and a
+ jp nz, DontAbandonLearning
+ ld hl, DidNotLearnText
+ call PrintText
+ ld b, 0
+ ret
+
+PrintLearnedMove:
+ ld hl, LearnedMove1Text
+ call PrintText
+ ld b, 1
+ ret
+
+TryingToLearn:
+ push hl
+ ld hl, TryingToLearnText
+ call PrintText
+ coord hl, 14, 7
+ lb bc, 8, 15
+ ld a, TWO_OPTION_MENU
+ ld [wTextBoxID], a
+ call DisplayTextBoxID ; yes/no menu
+ pop hl
+ ld a, [wCurrentMenuItem]
+ rra
+ ret c
+ ld bc, -NUM_MOVES
+ add hl, bc
+ push hl
+ ld de, wMoves
+ ld bc, NUM_MOVES
+ call CopyData
+ callab FormatMovesString
+ pop hl
+.loop
+ push hl
+ ld hl, WhichMoveToForgetText
+ call PrintText
+ coord hl, 4, 7
+ ld b, 4
+ ld c, 14
+ call TextBoxBorder
+ coord hl, 6, 8
+ ld de, wMovesString
+ ld a, [hFlags_0xFFF6]
+ set 2, a
+ ld [hFlags_0xFFF6], a
+ call PlaceString
+ ld a, [hFlags_0xFFF6]
+ res 2, a
+ ld [hFlags_0xFFF6], a
+ ld hl, wTopMenuItemY
+ ld a, 8
+ ld [hli], a ; wTopMenuItemY
+ ld a, 5
+ ld [hli], a ; wTopMenuItemX
+ xor a
+ ld [hli], a ; wCurrentMenuItem
+ inc hl
+ ld a, [wNumMovesMinusOne]
+ ld [hli], a ; wMaxMenuItem
+ ld a, A_BUTTON | B_BUTTON
+ ld [hli], a ; wMenuWatchedKeys
+ ld [hl], 0 ; wLastMenuItem
+ ld hl, hFlags_0xFFF6
+ set 1, [hl]
+ call HandleMenuInput
+ ld hl, hFlags_0xFFF6
+ res 1, [hl]
+ push af
+ call LoadScreenTilesFromBuffer1
+ pop af
+ pop hl
+ bit 1, a ; pressed b
+ jr nz, .cancel
+ push hl
+ ld a, [wCurrentMenuItem]
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hl]
+ push af
+ push bc
+ call IsMoveHM
+ pop bc
+ pop de
+ ld a, d
+ jr c, .hm
+ pop hl
+ add hl, bc
+ and a
+ ret
+.hm
+ ld hl, HMCantDeleteText
+ call PrintText
+ pop hl
+ jr .loop
+.cancel
+ scf
+ ret
+
+LearnedMove1Text:
+ TX_FAR _LearnedMove1Text
+ TX_SFX_ITEM_1 ; plays SFX_GET_ITEM_1 in the party menu (rare candy) and plays SFX_LEVEL_UP in battle
+ TX_BLINK
+ db "@"
+
+WhichMoveToForgetText:
+ TX_FAR _WhichMoveToForgetText
+ db "@"
+
+AbandonLearningText:
+ TX_FAR _AbandonLearningText
+ db "@"
+
+DidNotLearnText:
+ TX_FAR _DidNotLearnText
+ db "@"
+
+TryingToLearnText:
+ TX_FAR _TryingToLearnText
+ db "@"
+
+OneTwoAndText:
+ TX_FAR _OneTwoAndText
+ TX_DELAY
+ TX_ASM
+ ld a, SFX_SWAP
+ call PlaySoundWaitForCurrent
+ ld hl, PoofText
+ ret
+
+PoofText:
+ TX_FAR _PoofText
+ TX_DELAY
+ForgotAndText:
+ TX_FAR _ForgotAndText
+ db "@"
+
+HMCantDeleteText:
+ TX_FAR _HMCantDeleteText
+ db "@"
--- /dev/null
+++ b/engine/pokemon/load_mon_data.asm
@@ -1,0 +1,49 @@
+LoadMonData_::
+; Load monster [wWhichPokemon] from list [wMonDataLocation]:
+; 0: partymon
+; 1: enemymon
+; 2: boxmon
+; 3: daycaremon
+; Return monster id at wcf91 and its data at wLoadedMon.
+; Also load base stats at wMonHeader for convenience.
+
+ ld a, [wDayCareMonSpecies]
+ ld [wcf91], a
+ ld a, [wMonDataLocation]
+ cp DAYCARE_DATA
+ jr z, .GetMonHeader
+
+ ld a, [wWhichPokemon]
+ ld e, a
+ callab GetMonSpecies
+
+.GetMonHeader
+ ld a, [wcf91]
+ ld [wd0b5], a ; input for GetMonHeader
+ call GetMonHeader
+
+ ld hl, wPartyMons
+ ld bc, wPartyMon2 - wPartyMon1
+ ld a, [wMonDataLocation]
+ cp ENEMY_PARTY_DATA
+ jr c, .getMonEntry
+
+ ld hl, wEnemyMons
+ jr z, .getMonEntry
+
+ cp 2
+ ld hl, wBoxMons
+ ld bc, wBoxMon2 - wBoxMon1
+ jr z, .getMonEntry
+
+ ld hl, wDayCareMon
+ jr .copyMonData
+
+.getMonEntry
+ ld a, [wWhichPokemon]
+ call AddNTimes
+
+.copyMonData
+ ld de, wLoadedMon
+ ld bc, wPartyMon2 - wPartyMon1
+ jp CopyData
--- /dev/null
+++ b/engine/pokemon/remove_mon.asm
@@ -1,0 +1,95 @@
+_RemovePokemon::
+ ld hl, wPartyCount
+ ld a, [wRemoveMonFromBox]
+ and a
+ jr z, .asm_7b74
+ ld hl, wNumInBox
+.asm_7b74
+ ld a, [hl]
+ dec a
+ ld [hli], a
+ ld a, [wWhichPokemon]
+ ld c, a
+ ld b, $0
+ add hl, bc
+ ld e, l
+ ld d, h
+ inc de
+.asm_7b81
+ ld a, [de]
+ inc de
+ ld [hli], a
+ inc a
+ jr nz, .asm_7b81
+ ld hl, wPartyMonOT
+ ld d, $5
+ ld a, [wRemoveMonFromBox]
+ and a
+ jr z, .asm_7b97
+ ld hl, wBoxMonOT
+ ld d, $13
+.asm_7b97
+ ld a, [wWhichPokemon]
+ call SkipFixedLengthTextEntries
+ ld a, [wWhichPokemon]
+ cp d
+ jr nz, .asm_7ba6
+ ld [hl], $ff
+ ret
+.asm_7ba6
+ ld d, h
+ ld e, l
+ ld bc, NAME_LENGTH
+ add hl, bc
+ ld bc, wPartyMonNicks
+ ld a, [wRemoveMonFromBox]
+ and a
+ jr z, .asm_7bb8
+ ld bc, wBoxMonNicks
+.asm_7bb8
+ call CopyDataUntil
+ ld hl, wPartyMons
+ ld bc, wPartyMon2 - wPartyMon1
+ ld a, [wRemoveMonFromBox]
+ and a
+ jr z, .asm_7bcd
+ ld hl, wBoxMons
+ ld bc, wBoxMon2 - wBoxMon1
+.asm_7bcd
+ ld a, [wWhichPokemon]
+ call AddNTimes
+ ld d, h
+ ld e, l
+ ld a, [wRemoveMonFromBox]
+ and a
+ jr z, .asm_7be4
+ ld bc, wBoxMon2 - wBoxMon1
+ add hl, bc
+ ld bc, wBoxMonOT
+ jr .asm_7beb
+.asm_7be4
+ ld bc, wPartyMon2 - wPartyMon1
+ add hl, bc
+ ld bc, wPartyMonOT
+.asm_7beb
+ call CopyDataUntil
+ ld hl, wPartyMonNicks
+ ld a, [wRemoveMonFromBox]
+ and a
+ jr z, .asm_7bfa
+ ld hl, wBoxMonNicks
+.asm_7bfa
+ ld bc, NAME_LENGTH
+ ld a, [wWhichPokemon]
+ call AddNTimes
+ ld d, h
+ ld e, l
+ ld bc, NAME_LENGTH
+ add hl, bc
+ ld bc, wPokedexOwned
+ ld a, [wRemoveMonFromBox]
+ and a
+ jr z, .asm_7c15
+ ld bc, wBoxMonNicksEnd
+.asm_7c15
+ jp CopyDataUntil
--- /dev/null
+++ b/engine/pokemon/set_types.asm
@@ -1,0 +1,15 @@
+; updates the types of a party mon (pointed to in hl) to the ones of the mon specified in wd11e
+SetPartyMonTypes:
+ call GetPredefRegisters
+ ld bc, wPartyMon1Type - wPartyMon1 ; $5
+ add hl, bc
+ ld a, [wd11e]
+ ld [wd0b5], a
+ push hl
+ call GetMonHeader
+ pop hl
+ ld a, [wMonHType1]
+ ld [hli], a
+ ld a, [wMonHType2]
+ ld [hl], a
+ ret
--- /dev/null
+++ b/engine/pokemon/status_ailments.asm
@@ -1,0 +1,46 @@
+PrintStatusAilment::
+ ld a, [de]
+ bit PSN, a
+ jr nz, .psn
+ bit BRN, a
+ jr nz, .brn
+ bit FRZ, a
+ jr nz, .frz
+ bit PAR, a
+ jr nz, .par
+ and SLP
+ ret z
+ ld a, "S"
+ ld [hli], a
+ ld a, "L"
+ ld [hli], a
+ ld [hl], "P"
+ ret
+.psn
+ ld a, "P"
+ ld [hli], a
+ ld a, "S"
+ ld [hli], a
+ ld [hl], "N"
+ ret
+.brn
+ ld a, "B"
+ ld [hli], a
+ ld a, "R"
+ ld [hli], a
+ ld [hl], "N"
+ ret
+.frz
+ ld a, "F"
+ ld [hli], a
+ ld a, "R"
+ ld [hli], a
+ ld [hl], "Z"
+ ret
+.par
+ ld a, "P"
+ ld [hli], a
+ ld a, "A"
+ ld [hli], a
+ ld [hl], "R"
+ ret
--- /dev/null
+++ b/engine/pokemon/status_screen.asm
@@ -1,0 +1,481 @@
+DrawHP:
+; Draws the HP bar in the stats screen
+ call GetPredefRegisters
+ ld a, $1
+ jr DrawHP_
+
+DrawHP2:
+; Draws the HP bar in the party screen
+ call GetPredefRegisters
+ ld a, $2
+
+DrawHP_:
+ ld [wHPBarType], a
+ push hl
+ ld a, [wLoadedMonHP]
+ ld b, a
+ ld a, [wLoadedMonHP + 1]
+ ld c, a
+ or b
+ jr nz, .nonzeroHP
+ xor a
+ ld c, a
+ ld e, a
+ ld a, $6
+ ld d, a
+ jp .drawHPBarAndPrintFraction
+.nonzeroHP
+ ld a, [wLoadedMonMaxHP]
+ ld d, a
+ ld a, [wLoadedMonMaxHP + 1]
+ ld e, a
+ predef HPBarLength
+ ld a, $6
+ ld d, a
+ ld c, a
+.drawHPBarAndPrintFraction
+ pop hl
+ push de
+ push hl
+ push hl
+ call DrawHPBar
+ pop hl
+ ld a, [hFlags_0xFFF6]
+ bit 0, a
+ jr z, .printFractionBelowBar
+ ld bc, $9 ; right of bar
+ jr .printFraction
+.printFractionBelowBar
+ ld bc, SCREEN_WIDTH + 1 ; below bar
+.printFraction
+ add hl, bc
+ ld de, wLoadedMonHP
+ lb bc, 2, 3
+ call PrintNumber
+ ld a, "/"
+ ld [hli], a
+ ld de, wLoadedMonMaxHP
+ lb bc, 2, 3
+ call PrintNumber
+ pop hl
+ pop de
+ ret
+
+
+; Predef 0x37
+StatusScreen:
+ call LoadMonData
+ ld a, [wMonDataLocation]
+ cp BOX_DATA
+ jr c, .DontRecalculate
+; mon is in a box or daycare
+ ld a, [wLoadedMonBoxLevel]
+ ld [wLoadedMonLevel], a
+ ld [wCurEnemyLVL], a
+ ld hl, wLoadedMonHPExp - 1
+ ld de, wLoadedMonStats
+ ld b, $1
+ call CalcStats ; Recalculate stats
+.DontRecalculate
+ ld hl, wd72c
+ set 1, [hl]
+ ld a, $33
+ ld [rNR50], a ; Reduce the volume
+ call GBPalWhiteOutWithDelay3
+ call ClearScreen
+ call UpdateSprites
+ call LoadHpBarAndStatusTilePatterns
+ ld de, BattleHudTiles1 ; source
+ ld hl, vChars2 + $6d0 ; dest
+ lb bc, BANK(BattleHudTiles1), $03
+ call CopyVideoDataDouble ; ·│ :L and halfarrow line end
+ ld de, BattleHudTiles2
+ ld hl, vChars2 + $780
+ lb bc, BANK(BattleHudTiles2), $01
+ call CopyVideoDataDouble ; │
+ ld de, BattleHudTiles3
+ ld hl, vChars2 + $760
+ lb bc, BANK(BattleHudTiles3), $02
+ call CopyVideoDataDouble ; ─┘
+ ld de, PTile
+ ld hl, vChars2 + $720
+ lb bc, BANK(PTile), (PTileEnd - PTile) / $8
+ call CopyVideoDataDouble ; P (for PP), inline
+ ld a, [hTilesetType]
+ push af
+ xor a
+ ld [hTilesetType], a
+ coord hl, 19, 1
+ lb bc, 6, 10
+ call DrawLineBox ; Draws the box around name, HP and status
+ ld de, -6
+ add hl, de
+ ld [hl], "⠄" ; . after No ("." is a different one)
+ dec hl
+ ld [hl], "№"
+ coord hl, 19, 9
+ lb bc, 8, 6
+ call DrawLineBox ; Draws the box around types, ID No. and OT
+ coord hl, 10, 9
+ ld de, Type1Text
+ call PlaceString ; "TYPE1/"
+ coord hl, 11, 3
+ predef DrawHP
+ ld hl, wStatusScreenHPBarColor
+ call GetHealthBarColor
+ ld b, SET_PAL_STATUS_SCREEN
+ call RunPaletteCommand
+ coord hl, 16, 6
+ ld de, wLoadedMonStatus
+ call PrintStatusCondition
+ jr nz, .StatusWritten
+ coord hl, 16, 6
+ ld de, OKText
+ call PlaceString ; "OK"
+.StatusWritten
+ coord hl, 9, 6
+ ld de, StatusText
+ call PlaceString ; "STATUS/"
+ coord hl, 14, 2
+ call PrintLevel ; Pokémon level
+ ld a, [wMonHIndex]
+ ld [wd11e], a
+ ld [wd0b5], a
+ predef IndexToPokedex
+ coord hl, 3, 7
+ ld de, wd11e
+ lb bc, LEADING_ZEROES | 1, 3
+ call PrintNumber ; Pokémon no.
+ coord hl, 11, 10
+ predef PrintMonType
+ ld hl, NamePointers2
+ call .GetStringPointer
+ ld d, h
+ ld e, l
+ coord hl, 9, 1
+ call PlaceString ; Pokémon name
+ ld hl, OTPointers
+ call .GetStringPointer
+ ld d, h
+ ld e, l
+ coord hl, 12, 16
+ call PlaceString ; OT
+ coord hl, 12, 14
+ ld de, wLoadedMonOTID
+ lb bc, LEADING_ZEROES | 2, 5
+ call PrintNumber ; ID Number
+ ld d, $0
+ call PrintStatsBox
+ call Delay3
+ call GBPalNormal
+ coord hl, 1, 0
+ call LoadFlippedFrontSpriteByMonIndex ; draw Pokémon picture
+ ld a, [wcf91]
+ call PlayCry ; play Pokémon cry
+ call WaitForTextScrollButtonPress ; wait for button
+ pop af
+ ld [hTilesetType], a
+ ret
+
+.GetStringPointer
+ ld a, [wMonDataLocation]
+ add a
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [wMonDataLocation]
+ cp DAYCARE_DATA
+ ret z
+ ld a, [wWhichPokemon]
+ jp SkipFixedLengthTextEntries
+
+OTPointers:
+ dw wPartyMonOT
+ dw wEnemyMonOT
+ dw wBoxMonOT
+ dw wDayCareMonOT
+
+NamePointers2:
+ dw wPartyMonNicks
+ dw wEnemyMonNicks
+ dw wBoxMonNicks
+ dw wDayCareMonName
+
+Type1Text:
+ db "TYPE1/", $4e
+
+Type2Text:
+ db "TYPE2/", $4e
+
+IDNoText:
+ db $73, "№/", $4e
+
+OTText:
+ db "OT/"
+ next "@"
+
+StatusText:
+ db "STATUS/@"
+
+OKText:
+ db "OK@"
+
+; Draws a line starting from hl high b and wide c
+DrawLineBox:
+ ld de, SCREEN_WIDTH ; New line
+.PrintVerticalLine
+ ld [hl], $78 ; │
+ add hl, de
+ dec b
+ jr nz, .PrintVerticalLine
+ ld [hl], $77 ; ┘
+ dec hl
+.PrintHorizLine
+ ld [hl], $76 ; ─
+ dec hl
+ dec c
+ jr nz, .PrintHorizLine
+ ld [hl], $6f ; ← (halfarrow ending)
+ ret
+
+PTile:
+ INCBIN "gfx/font/P.1bpp"
+PTileEnd:
+
+PrintStatsBox:
+ ld a, d
+ and a ; a is 0 from the status screen
+ jr nz, .DifferentBox
+ coord hl, 0, 8
+ ld b, 8
+ ld c, 8
+ call TextBoxBorder ; Draws the box
+ coord hl, 1, 9 ; Start printing stats from here
+ ld bc, $0019 ; Number offset
+ jr .PrintStats
+.DifferentBox
+ coord hl, 9, 2
+ ld b, 8
+ ld c, 9
+ call TextBoxBorder
+ coord hl, 11, 3
+ ld bc, $0018
+.PrintStats
+ push bc
+ push hl
+ ld de, StatsText
+ call PlaceString
+ pop hl
+ pop bc
+ add hl, bc
+ ld de, wLoadedMonAttack
+ lb bc, 2, 3
+ call PrintStat
+ ld de, wLoadedMonDefense
+ call PrintStat
+ ld de, wLoadedMonSpeed
+ call PrintStat
+ ld de, wLoadedMonSpecial
+ jp PrintNumber
+PrintStat:
+ push hl
+ call PrintNumber
+ pop hl
+ ld de, SCREEN_WIDTH * 2
+ add hl, de
+ ret
+
+StatsText:
+ db "ATTACK"
+ next "DEFENSE"
+ next "SPEED"
+ next "SPECIAL@"
+
+StatusScreen2:
+ ld a, [hTilesetType]
+ push af
+ xor a
+ ld [hTilesetType], a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ ld bc, NUM_MOVES + 1
+ ld hl, wMoves
+ call FillMemory
+ ld hl, wLoadedMonMoves
+ ld de, wMoves
+ ld bc, NUM_MOVES
+ call CopyData
+ callab FormatMovesString
+ coord hl, 9, 2
+ lb bc, 5, 10
+ call ClearScreenArea ; Clear under name
+ coord hl, 19, 3
+ ld [hl], $78
+ coord hl, 0, 8
+ ld b, 8
+ ld c, 18
+ call TextBoxBorder ; Draw move container
+ coord hl, 2, 9
+ ld de, wMovesString
+ call PlaceString ; Print moves
+ ld a, [wNumMovesMinusOne]
+ inc a
+ ld c, a
+ ld a, $4
+ sub c
+ ld b, a ; Number of moves ?
+ coord hl, 11, 10
+ ld de, SCREEN_WIDTH * 2
+ ld a, $72 ; special P tile id
+ call StatusScreen_PrintPP ; Print "PP"
+ ld a, b
+ and a
+ jr z, .InitPP
+ ld c, a
+ ld a, "-"
+ call StatusScreen_PrintPP ; Fill the rest with --
+.InitPP
+ ld hl, wLoadedMonMoves
+ coord de, 14, 10
+ ld b, 0
+.PrintPP
+ ld a, [hli]
+ and a
+ jr z, .PPDone
+ push bc
+ push hl
+ push de
+ ld hl, wCurrentMenuItem
+ ld a, [hl]
+ push af
+ ld a, b
+ ld [hl], a
+ push hl
+ callab GetMaxPP
+ pop hl
+ pop af
+ ld [hl], a
+ pop de
+ pop hl
+ push hl
+ ld bc, wPartyMon1PP - wPartyMon1Moves - 1
+ add hl, bc
+ ld a, [hl]
+ and $3f
+ ld [wStatusScreenCurrentPP], a
+ ld h, d
+ ld l, e
+ push hl
+ ld de, wStatusScreenCurrentPP
+ lb bc, 1, 2
+ call PrintNumber
+ ld a, "/"
+ ld [hli], a
+ ld de, wMaxPP
+ lb bc, 1, 2
+ call PrintNumber
+ pop hl
+ ld de, SCREEN_WIDTH * 2
+ add hl, de
+ ld d, h
+ ld e, l
+ pop hl
+ pop bc
+ inc b
+ ld a, b
+ cp $4
+ jr nz, .PrintPP
+.PPDone
+ coord hl, 9, 3
+ ld de, StatusScreenExpText
+ call PlaceString
+ ld a, [wLoadedMonLevel]
+ push af
+ cp MAX_LEVEL
+ jr z, .Level100
+ inc a
+ ld [wLoadedMonLevel], a ; Increase temporarily if not 100
+.Level100
+ coord hl, 14, 6
+ ld [hl], $70 ; 1-tile "to"
+ inc hl
+ inc hl
+ call PrintLevel
+ pop af
+ ld [wLoadedMonLevel], a
+ ld de, wLoadedMonExp
+ coord hl, 12, 4
+ lb bc, 3, 7
+ call PrintNumber ; exp
+ call CalcExpToLevelUp
+ ld de, wLoadedMonExp
+ coord hl, 7, 6
+ lb bc, 3, 7
+ call PrintNumber ; exp needed to level up
+ coord hl, 9, 0
+ call StatusScreen_ClearName
+ coord hl, 9, 1
+ call StatusScreen_ClearName
+ ld a, [wMonHIndex]
+ ld [wd11e], a
+ call GetMonName
+ coord hl, 9, 1
+ call PlaceString
+ ld a, $1
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call Delay3
+ call WaitForTextScrollButtonPress ; wait for button
+ pop af
+ ld [hTilesetType], a
+ ld hl, wd72c
+ res 1, [hl]
+ ld a, $77
+ ld [rNR50], a
+ call GBPalWhiteOut
+ jp ClearScreen
+
+CalcExpToLevelUp:
+ ld a, [wLoadedMonLevel]
+ cp MAX_LEVEL
+ jr z, .atMaxLevel
+ inc a
+ ld d, a
+ callab CalcExperience
+ ld hl, wLoadedMonExp + 2
+ ld a, [hExperience + 2]
+ sub [hl]
+ ld [hld], a
+ ld a, [hExperience + 1]
+ sbc [hl]
+ ld [hld], a
+ ld a, [hExperience]
+ sbc [hl]
+ ld [hld], a
+ ret
+.atMaxLevel
+ ld hl, wLoadedMonExp
+ xor a
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+ ret
+
+StatusScreenExpText:
+ db "EXP POINTS"
+ next "LEVEL UP@"
+
+StatusScreen_ClearName:
+ ld bc, 10
+ ld a, " "
+ jp FillMemory
+
+StatusScreen_PrintPP:
+; print PP or -- c times, going down two rows each time
+ ld [hli], a
+ ld [hld], a
+ add hl, de
+ dec c
+ jr nz, StatusScreen_PrintPP
+ ret
--- a/engine/predefs12.asm
+++ /dev/null
@@ -1,71 +1,0 @@
-; b = new colour for BG colour 0 (usually white) for 4 frames
-ChangeBGPalColor0_4Frames:
- call GetPredefRegisters
- ld a, [rBGP]
- or b
- ld [rBGP], a
- ld c, 4
- call DelayFrames
- ld a, [rBGP]
- and %11111100
- ld [rBGP], a
- ret
-
-PredefShakeScreenVertically:
-; Moves the window down and then back in a sequence of progressively smaller
-; numbers of pixels, starting at b.
- call GetPredefRegisters
- ld a, 1
- ld [wDisableVBlankWYUpdate], a
- xor a
-.loop
- ld [$ff96], a
- call .MutateWY
- call .MutateWY
- dec b
- ld a, b
- jr nz, .loop
- xor a
- ld [wDisableVBlankWYUpdate], a
- ret
-
-.MutateWY
- ld a, [$ff96]
- xor b
- ld [$ff96], a
- ld [rWY], a
- ld c, 3
- jp DelayFrames
-
-PredefShakeScreenHorizontally:
-; Moves the window right and then back in a sequence of progressively smaller
-; numbers of pixels, starting at b.
- call GetPredefRegisters
- xor a
-.loop
- ld [$ff97], a
- call .MutateWX
- ld c, 1
- call DelayFrames
- call .MutateWX
- dec b
- ld a, b
- jr nz, .loop
-
-; restore normal WX
- ld a, 7
- ld [rWX], a
- ret
-
-.MutateWX
- ld a, [$ff97]
- xor b
- ld [$ff97], a
- bit 7, a
- jr z, .skipZeroing
- xor a ; zero a if it's negative
-.skipZeroing
- add 7
- ld [rWX], a
- ld c, 4
- jp DelayFrames
--- a/engine/predefs17.asm
+++ /dev/null
@@ -1,9 +1,0 @@
-; this function temporarily makes the starters (and Ivysaur) seen
-; so that the full Pokedex information gets displayed in Oak's lab
-StarterDex:
- ld a, %01001011 ; set starter flags
- ld [wPokedexOwned], a
- predef ShowPokedexData
- xor a ; unset starter flags
- ld [wPokedexOwned], a
- ret
--- a/engine/predefs17_2.asm
+++ /dev/null
@@ -1,15 +1,0 @@
-; updates the types of a party mon (pointed to in hl) to the ones of the mon specified in wd11e
-SetPartyMonTypes:
- call GetPredefRegisters
- ld bc, wPartyMon1Type - wPartyMon1 ; $5
- add hl, bc
- ld a, [wd11e]
- ld [wd0b5], a
- push hl
- call GetMonHeader
- pop hl
- ld a, [wMonHType1]
- ld [hli], a
- ld a, [wMonHType2]
- ld [hl], a
- ret
--- a/engine/predefs7.asm
+++ /dev/null
@@ -1,48 +1,0 @@
-DisplayElevatorFloorMenu:
- ld hl, WhichFloorText
- call PrintText
- ld hl, wItemList
- ld a, l
- ld [wListPointer], a
- ld a, h
- ld [wListPointer + 1], a
- ld a, [wListScrollOffset]
- push af
- xor a
- ld [wCurrentMenuItem], a
- ld [wListScrollOffset], a
- ld [wPrintItemPrices], a
- ld a, SPECIALLISTMENU
- ld [wListMenuID], a
- call DisplayListMenuID
- pop bc
- ld a, b
- ld [wListScrollOffset], a
- ret c
- ld hl, wCurrentMapScriptFlags
- set 7, [hl]
- ld hl, wElevatorWarpMaps
- ld a, [wWhichPokemon]
- add a
- ld d, 0
- ld e, a
- add hl, de
- ld a, [hli]
- ld b, a
- ld a, [hl]
- ld c, a
- ld hl, wWarpEntries
- call .UpdateWarp
-
-.UpdateWarp
- inc hl
- inc hl
- ld a, b
- ld [hli], a ; destination warp ID
- ld a, c
- ld [hli], a ; destination map ID
- ret
-
-WhichFloorText:
- TX_FAR _WhichFloorText
- db "@"
--- a/engine/print_waiting_text.asm
+++ /dev/null
@@ -1,20 +1,0 @@
-PrintWaitingText::
- coord hl, 3, 10
- ld b, $1
- ld c, $b
- ld a, [wIsInBattle]
- and a
- jr z, .asm_4c17
- call TextBoxBorder
- jr .asm_4c1a
-.asm_4c17
- call CableClub_TextBoxBorder
-.asm_4c1a
- coord hl, 4, 11
- ld de, WaitingText
- call PlaceString
- ld c, 50
- jp DelayFrames
-
-WaitingText:
- db "Waiting...!@"
--- a/engine/random.asm
+++ /dev/null
@@ -1,13 +1,0 @@
-Random_::
-; Generate a random 16-bit value.
- ld a, [rDIV]
- ld b, a
- ld a, [hRandomAdd]
- adc b
- ld [hRandomAdd], a
- ld a, [rDIV]
- ld b, a
- ld a, [hRandomSub]
- sbc b
- ld [hRandomSub], a
- ret
--- a/engine/remove_pokemon.asm
+++ /dev/null
@@ -1,95 +1,0 @@
-_RemovePokemon::
- ld hl, wPartyCount
- ld a, [wRemoveMonFromBox]
- and a
- jr z, .asm_7b74
- ld hl, wNumInBox
-.asm_7b74
- ld a, [hl]
- dec a
- ld [hli], a
- ld a, [wWhichPokemon]
- ld c, a
- ld b, $0
- add hl, bc
- ld e, l
- ld d, h
- inc de
-.asm_7b81
- ld a, [de]
- inc de
- ld [hli], a
- inc a
- jr nz, .asm_7b81
- ld hl, wPartyMonOT
- ld d, $5
- ld a, [wRemoveMonFromBox]
- and a
- jr z, .asm_7b97
- ld hl, wBoxMonOT
- ld d, $13
-.asm_7b97
- ld a, [wWhichPokemon]
- call SkipFixedLengthTextEntries
- ld a, [wWhichPokemon]
- cp d
- jr nz, .asm_7ba6
- ld [hl], $ff
- ret
-.asm_7ba6
- ld d, h
- ld e, l
- ld bc, NAME_LENGTH
- add hl, bc
- ld bc, wPartyMonNicks
- ld a, [wRemoveMonFromBox]
- and a
- jr z, .asm_7bb8
- ld bc, wBoxMonNicks
-.asm_7bb8
- call CopyDataUntil
- ld hl, wPartyMons
- ld bc, wPartyMon2 - wPartyMon1
- ld a, [wRemoveMonFromBox]
- and a
- jr z, .asm_7bcd
- ld hl, wBoxMons
- ld bc, wBoxMon2 - wBoxMon1
-.asm_7bcd
- ld a, [wWhichPokemon]
- call AddNTimes
- ld d, h
- ld e, l
- ld a, [wRemoveMonFromBox]
- and a
- jr z, .asm_7be4
- ld bc, wBoxMon2 - wBoxMon1
- add hl, bc
- ld bc, wBoxMonOT
- jr .asm_7beb
-.asm_7be4
- ld bc, wPartyMon2 - wPartyMon1
- add hl, bc
- ld bc, wPartyMonOT
-.asm_7beb
- call CopyDataUntil
- ld hl, wPartyMonNicks
- ld a, [wRemoveMonFromBox]
- and a
- jr z, .asm_7bfa
- ld hl, wBoxMonNicks
-.asm_7bfa
- ld bc, NAME_LENGTH
- ld a, [wWhichPokemon]
- call AddNTimes
- ld d, h
- ld e, l
- ld bc, NAME_LENGTH
- add hl, bc
- ld bc, wPokedexOwned
- ld a, [wRemoveMonFromBox]
- and a
- jr z, .asm_7c15
- ld bc, wBoxMonNicksEnd
-.asm_7c15
- jp CopyDataUntil
--- a/engine/save.asm
+++ /dev/null
@@ -1,708 +1,0 @@
-LoadSAV:
-;(if carry -> write
-;"the file data is destroyed")
- call ClearScreen
- call LoadFontTilePatterns
- call LoadTextBoxTilePatterns
- call LoadSAV0
- jr c, .badsum
- call LoadSAV1
- jr c, .badsum
- call LoadSAV2
- jr c, .badsum
- ld a, $2 ; good checksum
- jr .goodsum
-.badsum
- ld hl, wd730
- push hl
- set 6, [hl]
- ld hl, FileDataDestroyedText
- call PrintText
- ld c, 100
- call DelayFrames
- pop hl
- res 6, [hl]
- ld a, $1 ; bad checksum
-.goodsum
- ld [wSaveFileStatus], a
- ret
-
-FileDataDestroyedText:
- TX_FAR _FileDataDestroyedText
- db "@"
-
-LoadSAV0:
- ld a, SRAM_ENABLE
- ld [MBC1SRamEnable], a
- ld a, $1
- ld [MBC1SRamBankingMode], a
- ld [MBC1SRamBank], a
- ld hl, sPlayerName ; hero name located in SRAM
- ld bc, sMainDataCheckSum - sPlayerName ; but here checks the full SAV
- call SAVCheckSum
- ld c, a
- ld a, [sMainDataCheckSum] ; SAV's checksum
- cp c
- jp z, .checkSumsMatched
-
-; If the computed checksum didn't match the saved on, try again.
- ld hl, sPlayerName
- ld bc, sMainDataCheckSum - sPlayerName
- call SAVCheckSum
- ld c, a
- ld a, [sMainDataCheckSum] ; SAV's checksum
- cp c
- jp nz, SAVBadCheckSum
-
-.checkSumsMatched
- ld hl, sPlayerName
- ld de, wPlayerName
- ld bc, NAME_LENGTH
- call CopyData
- ld hl, sMainData
- ld de, wMainDataStart
- ld bc, wMainDataEnd - wMainDataStart
- call CopyData
- ld hl, wCurMapTileset
- set 7, [hl]
- ld hl, sSpriteData
- ld de, wSpriteDataStart
- ld bc, wSpriteDataEnd - wSpriteDataStart
- call CopyData
- ld a, [sTilesetType]
- ld [hTilesetType], a
- ld hl, sCurBoxData
- ld de, wBoxDataStart
- ld bc, wBoxDataEnd - wBoxDataStart
- call CopyData
- and a
- jp SAVGoodChecksum
-
-LoadSAV1:
- ld a, SRAM_ENABLE
- ld [MBC1SRamEnable], a
- ld a, $1
- ld [MBC1SRamBankingMode], a
- ld [MBC1SRamBank], a
- ld hl, sPlayerName ; hero name located in SRAM
- ld bc, sMainDataCheckSum - sPlayerName ; but here checks the full SAV
- call SAVCheckSum
- ld c, a
- ld a, [sMainDataCheckSum] ; SAV's checksum
- cp c
- jr nz, SAVBadCheckSum
- ld hl, sCurBoxData
- ld de, wBoxDataStart
- ld bc, wBoxDataEnd - wBoxDataStart
- call CopyData
- and a
- jp SAVGoodChecksum
-
-LoadSAV2:
- ld a, SRAM_ENABLE
- ld [MBC1SRamEnable], a
- ld a, $1
- ld [MBC1SRamBankingMode], a
- ld [MBC1SRamBank], a
- ld hl, sPlayerName ; hero name located in SRAM
- ld bc, sMainDataCheckSum - sPlayerName ; but here checks the full SAV
- call SAVCheckSum
- ld c, a
- ld a, [sMainDataCheckSum] ; SAV's checksum
- cp c
- jp nz, SAVBadCheckSum
- ld hl, sPartyData
- ld de, wPartyDataStart
- ld bc, wPartyDataEnd - wPartyDataStart
- call CopyData
- ld hl, sMainData
- ld de, wPokedexOwned
- ld bc, wPokedexSeenEnd - wPokedexOwned
- call CopyData
- and a
- jp SAVGoodChecksum
-
-SAVBadCheckSum:
- scf
-
-SAVGoodChecksum:
- ld a, $0
- ld [MBC1SRamBankingMode], a
- ld [MBC1SRamEnable], a
- ret
-
-LoadSAVIgnoreBadCheckSum:
-; unused function that loads save data and ignores bad checksums
- call LoadSAV0
- call LoadSAV1
- jp LoadSAV2
-
-SaveSAV:
- callba PrintSaveScreenText
- ld hl, WouldYouLikeToSaveText
- call SaveSAVConfirm
- and a ;|0 = Yes|1 = No|
- ret nz
- ld a, [wSaveFileStatus]
- dec a
- jr z, .save
- call SAVCheckRandomID
- jr z, .save
- ld hl, OlderFileWillBeErasedText
- call SaveSAVConfirm
- and a
- ret nz
-.save
- call SaveSAVtoSRAM
- coord hl, 1, 13
- lb bc, 4, 18
- call ClearScreenArea
- coord hl, 1, 14
- ld de, NowSavingString
- call PlaceString
- ld c, 120
- call DelayFrames
- ld hl, GameSavedText
- call PrintText
- ld a, SFX_SAVE
- call PlaySoundWaitForCurrent
- call WaitForSoundToFinish
- ld c, 30
- jp DelayFrames
-
-NowSavingString:
- db "Now saving...@"
-
-SaveSAVConfirm:
- call PrintText
- coord hl, 0, 7
- lb bc, 8, 1
- ld a, TWO_OPTION_MENU
- ld [wTextBoxID], a
- call DisplayTextBoxID ; yes/no menu
- ld a, [wCurrentMenuItem]
- ret
-
-WouldYouLikeToSaveText:
- TX_FAR _WouldYouLikeToSaveText
- db "@"
-
-GameSavedText:
- TX_FAR _GameSavedText
- db "@"
-
-OlderFileWillBeErasedText:
- TX_FAR _OlderFileWillBeErasedText
- db "@"
-
-SaveSAVtoSRAM0:
- ld a, SRAM_ENABLE
- ld [MBC1SRamEnable], a
- ld a, $1
- ld [MBC1SRamBankingMode], a
- ld [MBC1SRamBank], a
- ld hl, wPlayerName
- ld de, sPlayerName
- ld bc, NAME_LENGTH
- call CopyData
- ld hl, wMainDataStart
- ld de, sMainData
- ld bc, wMainDataEnd - wMainDataStart
- call CopyData
- ld hl, wSpriteDataStart
- ld de, sSpriteData
- ld bc, wSpriteDataEnd - wSpriteDataStart
- call CopyData
- ld hl, wBoxDataStart
- ld de, sCurBoxData
- ld bc, wBoxDataEnd - wBoxDataStart
- call CopyData
- ld a, [hTilesetType]
- ld [sTilesetType], a
- ld hl, sPlayerName
- ld bc, sMainDataCheckSum - sPlayerName
- call SAVCheckSum
- ld [sMainDataCheckSum], a
- xor a
- ld [MBC1SRamBankingMode], a
- ld [MBC1SRamEnable], a
- ret
-
-SaveSAVtoSRAM1:
-; stored pokémon
- ld a, SRAM_ENABLE
- ld [MBC1SRamEnable], a
- ld a, $1
- ld [MBC1SRamBankingMode], a
- ld [MBC1SRamBank], a
- ld hl, wBoxDataStart
- ld de, sCurBoxData
- ld bc, wBoxDataEnd - wBoxDataStart
- call CopyData
- ld hl, sPlayerName
- ld bc, sMainDataCheckSum - sPlayerName
- call SAVCheckSum
- ld [sMainDataCheckSum], a
- xor a
- ld [MBC1SRamBankingMode], a
- ld [MBC1SRamEnable], a
- ret
-
-SaveSAVtoSRAM2:
- ld a, SRAM_ENABLE
- ld [MBC1SRamEnable], a
- ld a, $1
- ld [MBC1SRamBankingMode], a
- ld [MBC1SRamBank], a
- ld hl, wPartyDataStart
- ld de, sPartyData
- ld bc, wPartyDataEnd - wPartyDataStart
- call CopyData
- ld hl, wPokedexOwned ; pokédex only
- ld de, sMainData
- ld bc, wPokedexSeenEnd - wPokedexOwned
- call CopyData
- ld hl, sPlayerName
- ld bc, sMainDataCheckSum - sPlayerName
- call SAVCheckSum
- ld [sMainDataCheckSum], a
- xor a
- ld [MBC1SRamBankingMode], a
- ld [MBC1SRamEnable], a
- ret
-
-SaveSAVtoSRAM::
- ld a, $2
- ld [wSaveFileStatus], a
- call SaveSAVtoSRAM0
- call SaveSAVtoSRAM1
- jp SaveSAVtoSRAM2
-
-SAVCheckSum:
-;Check Sum (result[1 byte] is complemented)
- ld d, 0
-.loop
- ld a, [hli]
- add d
- ld d, a
- dec bc
- ld a, b
- or c
- jr nz, .loop
- ld a, d
- cpl
- ret
-
-CalcIndividualBoxCheckSums:
- ld hl, sBox1 ; sBox7
- ld de, sBank2IndividualBoxChecksums ; sBank3IndividualBoxChecksums
- ld b, NUM_BOXES / 2
-.loop
- push bc
- push de
- ld bc, wBoxDataEnd - wBoxDataStart
- call SAVCheckSum
- pop de
- ld [de], a
- inc de
- pop bc
- dec b
- jr nz, .loop
- ret
-
-GetBoxSRAMLocation:
-; in: a = box num
-; out: b = box SRAM bank, hl = pointer to start of box
- ld hl, BoxSRAMPointerTable
- ld a, [wCurrentBoxNum]
- and $7f
- cp NUM_BOXES / 2
- ld b, 2
- jr c, .next
- inc b
- sub NUM_BOXES / 2
-.next
- ld e, a
- ld d, 0
- add hl, de
- add hl, de
- ld a, [hli]
- ld h, [hl]
- ld l, a
- ret
-
-BoxSRAMPointerTable:
- dw sBox1 ; sBox7
- dw sBox2 ; sBox8
- dw sBox3 ; sBox9
- dw sBox4 ; sBox10
- dw sBox5 ; sBox11
- dw sBox6 ; sBox12
-
-ChangeBox::
- ld hl, WhenYouChangeBoxText
- call PrintText
- call YesNoChoice
- ld a, [wCurrentMenuItem]
- and a
- ret nz ; return if No was chosen
- ld hl, wCurrentBoxNum
- bit 7, [hl] ; is it the first time player is changing the box?
- call z, EmptyAllSRAMBoxes ; if so, empty all boxes in SRAM
- call DisplayChangeBoxMenu
- call UpdateSprites
- ld hl, hFlags_0xFFF6
- set 1, [hl]
- call HandleMenuInput
- ld hl, hFlags_0xFFF6
- res 1, [hl]
- bit 1, a ; pressed b
- ret nz
- call GetBoxSRAMLocation
- ld e, l
- ld d, h
- ld hl, wBoxDataStart
- call CopyBoxToOrFromSRAM ; copy old box from WRAM to SRAM
- ld a, [wCurrentMenuItem]
- set 7, a
- ld [wCurrentBoxNum], a
- call GetBoxSRAMLocation
- ld de, wBoxDataStart
- call CopyBoxToOrFromSRAM ; copy new box from SRAM to WRAM
- ld hl, wMapTextPtr
- ld de, wChangeBoxSavedMapTextPointer
- ld a, [hli]
- ld [de], a
- inc de
- ld a, [hl]
- ld [de], a
- call RestoreMapTextPointer
- call SaveSAVtoSRAM
- ld hl, wChangeBoxSavedMapTextPointer
- call SetMapTextPointer
- ld a, SFX_SAVE
- call PlaySoundWaitForCurrent
- call WaitForSoundToFinish
- ret
-
-WhenYouChangeBoxText:
- TX_FAR _WhenYouChangeBoxText
- db "@"
-
-CopyBoxToOrFromSRAM:
-; copy an entire box from hl to de with b as the SRAM bank
- push hl
- ld a, SRAM_ENABLE
- ld [MBC1SRamEnable], a
- ld a, $1
- ld [MBC1SRamBankingMode], a
- ld a, b
- ld [MBC1SRamBank], a
- ld bc, wBoxDataEnd - wBoxDataStart
- call CopyData
- pop hl
-
-; mark the memory that the box was copied from as am empty box
- xor a
- ld [hli], a
- dec a
- ld [hl], a
-
- ld hl, sBox1 ; sBox7
- ld bc, sBank2AllBoxesChecksum - sBox1
- call SAVCheckSum
- ld [sBank2AllBoxesChecksum], a ; sBank3AllBoxesChecksum
- call CalcIndividualBoxCheckSums
- xor a
- ld [MBC1SRamBankingMode], a
- ld [MBC1SRamEnable], a
- ret
-
-DisplayChangeBoxMenu:
- xor a
- ld [H_AUTOBGTRANSFERENABLED], a
- ld a, A_BUTTON | B_BUTTON
- ld [wMenuWatchedKeys], a
- ld a, 11
- ld [wMaxMenuItem], a
- ld a, 1
- ld [wTopMenuItemY], a
- ld a, 12
- ld [wTopMenuItemX], a
- xor a
- ld [wMenuWatchMovingOutOfBounds], a
- ld a, [wCurrentBoxNum]
- and $7f
- ld [wCurrentMenuItem], a
- ld [wLastMenuItem], a
- coord hl, 0, 0
- ld b, 2
- ld c, 9
- call TextBoxBorder
- ld hl, ChooseABoxText
- call PrintText
- coord hl, 11, 0
- ld b, 12
- ld c, 7
- call TextBoxBorder
- ld hl, hFlags_0xFFF6
- set 2, [hl]
- ld de, BoxNames
- coord hl, 13, 1
- call PlaceString
- ld hl, hFlags_0xFFF6
- res 2, [hl]
- ld a, [wCurrentBoxNum]
- and $7f
- cp 9
- jr c, .singleDigitBoxNum
- sub 9
- coord hl, 8, 2
- ld [hl], "1"
- add "0"
- jr .next
-.singleDigitBoxNum
- add "1"
-.next
- Coorda 9, 2
- coord hl, 1, 2
- ld de, BoxNoText
- call PlaceString
- call GetMonCountsForAllBoxes
- coord hl, 18, 1
- ld de, wBoxMonCounts
- ld bc, SCREEN_WIDTH
- ld a, $c
-.loop
- push af
- ld a, [de]
- and a ; is the box empty?
- jr z, .skipPlacingPokeball
- ld [hl], $78 ; place pokeball tile next to box name if box not empty
-.skipPlacingPokeball
- add hl, bc
- inc de
- pop af
- dec a
- jr nz, .loop
- ld a, 1
- ld [H_AUTOBGTRANSFERENABLED], a
- ret
-
-ChooseABoxText:
- TX_FAR _ChooseABoxText
- db "@"
-
-BoxNames:
- db "BOX 1"
- next "BOX 2"
- next "BOX 3"
- next "BOX 4"
- next "BOX 5"
- next "BOX 6"
- next "BOX 7"
- next "BOX 8"
- next "BOX 9"
- next "BOX10"
- next "BOX11"
- next "BOX12@"
-
-BoxNoText:
- db "BOX No.@"
-
-EmptyAllSRAMBoxes:
-; marks all boxes in SRAM as empty (initialisation for the first time the
-; player changes the box)
- ld a, SRAM_ENABLE
- ld [MBC1SRamEnable], a
- ld a, $1
- ld [MBC1SRamBankingMode], a
- ld a, 2
- ld [MBC1SRamBank], a
- call EmptySRAMBoxesInBank
- ld a, 3
- ld [MBC1SRamBank], a
- call EmptySRAMBoxesInBank
- xor a
- ld [MBC1SRamBankingMode], a
- ld [MBC1SRamEnable], a
- ret
-
-EmptySRAMBoxesInBank:
-; marks every box in the current SRAM bank as empty
- ld hl, sBox1 ; sBox7
- call EmptySRAMBox
- ld hl, sBox2 ; sBox8
- call EmptySRAMBox
- ld hl, sBox3 ; sBox9
- call EmptySRAMBox
- ld hl, sBox4 ; sBox10
- call EmptySRAMBox
- ld hl, sBox5 ; sBox11
- call EmptySRAMBox
- ld hl, sBox6 ; sBox12
- call EmptySRAMBox
- ld hl, sBox1 ; sBox7
- ld bc, sBank2AllBoxesChecksum - sBox1
- call SAVCheckSum
- ld [sBank2AllBoxesChecksum], a ; sBank3AllBoxesChecksum
- call CalcIndividualBoxCheckSums
- ret
-
-EmptySRAMBox:
- xor a
- ld [hli], a
- dec a
- ld [hl], a
- ret
-
-GetMonCountsForAllBoxes:
- ld hl, wBoxMonCounts
- push hl
- ld a, SRAM_ENABLE
- ld [MBC1SRamEnable], a
- ld a, $1
- ld [MBC1SRamBankingMode], a
- ld a, $2
- ld [MBC1SRamBank], a
- call GetMonCountsForBoxesInBank
- ld a, $3
- ld [MBC1SRamBank], a
- call GetMonCountsForBoxesInBank
- xor a
- ld [MBC1SRamBankingMode], a
- ld [MBC1SRamEnable], a
- pop hl
-
-; copy the count for the current box from WRAM
- ld a, [wCurrentBoxNum]
- and $7f
- ld c, a
- ld b, 0
- add hl, bc
- ld a, [wNumInBox]
- ld [hl], a
-
- ret
-
-GetMonCountsForBoxesInBank:
- ld a, [sBox1] ; sBox7
- ld [hli], a
- ld a, [sBox2] ; sBox8
- ld [hli], a
- ld a, [sBox3] ; sBox9
- ld [hli], a
- ld a, [sBox4] ; sBox10
- ld [hli], a
- ld a, [sBox5] ; sBox11
- ld [hli], a
- ld a, [sBox6] ; sBox12
- ld [hli], a
- ret
-
-SAVCheckRandomID:
-;checks if Sav file is the same by checking player's name 1st letter ($a598)
-; and the two random numbers generated at game beginning
-;(which are stored at wPlayerID)s
- ld a, $0a
- ld [MBC1SRamEnable], a
- ld a, $01
- ld [MBC1SRamBankingMode], a
- ld [MBC1SRamBank], a
- ld a, [sPlayerName]
- and a
- jr z, .next
- ld hl, sPlayerName
- ld bc, sMainDataCheckSum - sPlayerName
- call SAVCheckSum
- ld c, a
- ld a, [sMainDataCheckSum]
- cp c
- jr nz, .next
- ld hl, sMainData + (wPlayerID - wMainDataStart) ; player ID
- ld a, [hli]
- ld h, [hl]
- ld l, a
- ld a, [wPlayerID]
- cp l
- jr nz, .next
- ld a, [wPlayerID + 1]
- cp h
-.next
- ld a, $00
- ld [MBC1SRamBankingMode], a
- ld [MBC1SRamEnable], a
- ret
-
-SaveHallOfFameTeams:
- ld a, [wNumHoFTeams]
- dec a
- cp HOF_TEAM_CAPACITY
- jr nc, .shiftHOFTeams
- ld hl, sHallOfFame
- ld bc, HOF_TEAM
- call AddNTimes
- ld e, l
- ld d, h
- ld hl, wHallOfFame
- ld bc, HOF_TEAM
- jr HallOfFame_Copy
-
-.shiftHOFTeams
-; if the space designated for HOF teams is full, then shift all HOF teams to the next slot, making space for the new HOF team
-; this deletes the last HOF team though
- ld hl, sHallOfFame + HOF_TEAM
- ld de, sHallOfFame
- ld bc, HOF_TEAM * (HOF_TEAM_CAPACITY - 1)
- call HallOfFame_Copy
- ld hl, wHallOfFame
- ld de, sHallOfFame + HOF_TEAM * (HOF_TEAM_CAPACITY - 1)
- ld bc, HOF_TEAM
- jr HallOfFame_Copy
-
-LoadHallOfFameTeams:
- ld hl, sHallOfFame
- ld bc, HOF_TEAM
- ld a, [wHoFTeamIndex]
- call AddNTimes
- ld de, wHallOfFame
- ld bc, HOF_TEAM
- ; fallthrough
-
-HallOfFame_Copy:
- ld a, SRAM_ENABLE
- ld [MBC1SRamEnable], a
- ld a, $1
- ld [MBC1SRamBankingMode], a
- xor a
- ld [MBC1SRamBank], a
- call CopyData
- xor a
- ld [MBC1SRamBankingMode], a
- ld [MBC1SRamEnable], a
- ret
-
-ClearSAV:
- ld a, SRAM_ENABLE
- ld [MBC1SRamEnable], a
- ld a, $1
- ld [MBC1SRamBankingMode], a
- xor a
- call PadSRAM_FF
- ld a, $1
- call PadSRAM_FF
- ld a, $2
- call PadSRAM_FF
- ld a, $3
- call PadSRAM_FF
- xor a
- ld [MBC1SRamBankingMode], a
- ld [MBC1SRamEnable], a
- ret
-
-PadSRAM_FF:
- ld [MBC1SRamBank], a
- ld hl, $a000
- ld bc, $2000
- ld a, $ff
- jp FillMemory
--- a/engine/slot_machine.asm
+++ /dev/null
@@ -1,892 +1,0 @@
-PromptUserToPlaySlots:
- call SaveScreenTilesToBuffer2
- ld a, BANK(DisplayTextIDInit)
- ld [wAutoTextBoxDrawingControl], a
- ld b, a
- ld hl, DisplayTextIDInit
- call Bankswitch
- ld hl, PlaySlotMachineText
- call PrintText
- call YesNoChoice
- ld a, [wCurrentMenuItem]
- and a
- jr nz, .done ; if player chose No
- dec a
- ld [wUpdateSpritesEnabled], a
- ld hl, wSlotMachineRerollCounter
- xor a
- ld [hli], a
- ld [hl], SMILE_BUBBLE
- predef EmotionBubble
- call GBPalWhiteOutWithDelay3
- call LoadSlotMachineTiles
- call LoadFontTilePatterns
- ld b, SET_PAL_SLOTS
- call RunPaletteCommand
- call GBPalNormal
- ld a, $e4
- ld [rOBP0], a
- ld hl, wd730
- set 6, [hl]
- xor a
- ld [wSlotMachineAllowMatchesCounter], a
- ld hl, wStoppingWhichSlotMachineWheel
- ld bc, $0014
- call FillMemory
- call MainSlotMachineLoop
- ld hl, wd730
- res 6, [hl]
- xor a
- ld [wSlotMachineAllowMatchesCounter], a
- call GBPalWhiteOutWithDelay3
- ld a, $1
- ld [wUpdateSpritesEnabled], a
- call RunDefaultPaletteCommand
- call ReloadMapSpriteTilePatterns
- call ReloadTilesetTilePatterns
-.done
- call LoadScreenTilesFromBuffer2
- call Delay3
- call GBPalNormal
- ld a, [wSlotMachineSavedROMBank]
- push af
- jp CloseTextDisplay
-
-PlaySlotMachineText:
- TX_FAR _PlaySlotMachineText
- db "@"
-
-MainSlotMachineLoop:
- call SlotMachine_PrintCreditCoins
- xor a
- ld hl, wPayoutCoins
- ld [hli], a
- ld [hl], a
- call SlotMachine_PrintPayoutCoins
- ld hl, BetHowManySlotMachineText
- call PrintText
- call SaveScreenTilesToBuffer1
-.loop
- ld a, A_BUTTON | B_BUTTON
- ld [wMenuWatchedKeys], a
- ld a, 2
- ld [wMaxMenuItem], a
- ld a, 12
- ld [wTopMenuItemY], a
- ld a, 15
- ld [wTopMenuItemX], a
- xor a
- ld [wCurrentMenuItem], a
- ld [wLastMenuItem], a
- ld [wMenuWatchMovingOutOfBounds], a
- coord hl, 14, 11
- ld b, 5
- ld c, 4
- call TextBoxBorder
- coord hl, 16, 12
- ld de, CoinMultiplierSlotMachineText
- call PlaceString
- call HandleMenuInput
- and B_BUTTON
- jp nz, LoadScreenTilesFromBuffer1
- ld a, [wCurrentMenuItem]
- ld b, a
- ld a, 3
- sub b
- ld [wSlotMachineBet], a
- ld hl, wPlayerCoins
- ld c, a
- ld a, [hli]
- and a
- jr nz, .skip1
- ld a, [hl]
- cp c
- jr nc, .skip1
- ld hl, NotEnoughCoinsSlotMachineText
- call PrintText
- jr .loop
-.skip1
- call LoadScreenTilesFromBuffer1
- call SlotMachine_SubtractBetFromPlayerCoins
- call SlotMachine_LightBalls
- call SlotMachine_SetFlags
- ld a, 4
- ld hl, wSlotMachineWheel1SlipCounter
- ld [hli], a
- ld [hli], a
- ld [hl], a
- call WaitForSoundToFinish
- ld a, SFX_SLOTS_NEW_SPIN
- call PlaySound
- ld hl, StartSlotMachineText
- call PrintText
- call SlotMachine_SpinWheels
- call SlotMachine_CheckForMatches
- ld hl, wPlayerCoins
- ld a, [hli]
- or [hl]
- jr nz, .skip2
- ld hl, OutOfCoinsSlotMachineText
- call PrintText
- ld c, 60
- jp DelayFrames
-.skip2
- ld hl, OneMoreGoSlotMachineText
- call PrintText
- coord hl, 14, 12
- lb bc, 13, 15
- xor a ; YES_NO_MENU
- ld [wTwoOptionMenuID], a
- ld a, TWO_OPTION_MENU
- ld [wTextBoxID], a
- call DisplayTextBoxID
- ld a, [wCurrentMenuItem]
- and a
- ret nz
- call SlotMachine_PutOutLitBalls
- jp MainSlotMachineLoop
-
-CoinMultiplierSlotMachineText:
- db "×3"
- next "×2"
- next "×1@"
-
-OutOfCoinsSlotMachineText:
- TX_FAR _OutOfCoinsSlotMachineText
- db "@"
-
-BetHowManySlotMachineText:
- TX_FAR _BetHowManySlotMachineText
- db "@"
-
-StartSlotMachineText:
- TX_FAR _StartSlotMachineText
- db "@"
-
-NotEnoughCoinsSlotMachineText:
- TX_FAR _NotEnoughCoinsSlotMachineText
- db "@"
-
-OneMoreGoSlotMachineText:
- TX_FAR _OneMoreGoSlotMachineText
- db "@"
-
-SlotMachine_SetFlags:
- ld hl, wSlotMachineFlags
- bit 7, [hl]
- ret nz
- ld a, [wSlotMachineAllowMatchesCounter]
- and a
- jr nz, .allowMatches
- call Random
- and a
- jr z, .setAllowMatchesCounter ; 1/256 (~0.4%) chance
- ld b, a
- ld a, [wSlotMachineSevenAndBarModeChance]
- cp b
- jr c, .allowSevenAndBarMatches
- ld a, 210
- cp b
- jr c, .allowMatches ; 55/256 (~21.5%) chance
- ld [hl], 0
- ret
-.allowMatches
- set 6, [hl]
- ret
-.setAllowMatchesCounter
- ld a, 60
- ld [wSlotMachineAllowMatchesCounter], a
- ret
-.allowSevenAndBarMatches
- set 7, [hl]
- ret
-
-SlotMachine_SpinWheels:
- ld c, 20
-.loop1
- push bc
- call SlotMachine_AnimWheel1
- call SlotMachine_AnimWheel2
- call SlotMachine_AnimWheel3
- ld c, 2
- call DelayFrames
- pop bc
- dec c
- jr nz, .loop1
- xor a
- ld [wStoppingWhichSlotMachineWheel], a
-.loop2
- call SlotMachine_HandleInputWhileWheelsSpin
- call SlotMachine_StopOrAnimWheel1
- call SlotMachine_StopOrAnimWheel2
- call SlotMachine_StopOrAnimWheel3
- ret c
- ld a, [wOnSGB]
- xor $1
- inc a
- ld c, a
- call DelayFrames
- jr .loop2
-
-; Note that the wheels can only stop when a symbol is centred in the wheel
-; and thus 3 full symbols rather than 2 full symbols and 2 half symbols are
-; visible. The 3 functions below ensure this by checking if the wheel offset
-; is even before stopping the wheel.
-
-SlotMachine_StopOrAnimWheel1:
- ld a, [wStoppingWhichSlotMachineWheel]
- cp 1
- jr c, .animWheel
- ld de, wSlotMachineWheel1Offset
- ld a, [de]
- rra
- jr nc, .animWheel ; check that a symbol is centred in the wheel
- ld hl, wSlotMachineWheel1SlipCounter
- ld a, [hl]
- and a
- ret z
- dec [hl]
- call SlotMachine_StopWheel1Early
- ret nz
-.animWheel
- jp SlotMachine_AnimWheel1
-
-SlotMachine_StopOrAnimWheel2:
- ld a, [wStoppingWhichSlotMachineWheel]
- cp 2
- jr c, .animWheel
- ld de, wSlotMachineWheel2Offset
- ld a, [de]
- rra
- jr nc, .animWheel ; check that a symbol is centred in the wheel
- ld hl, wSlotMachineWheel2SlipCounter
- ld a, [hl]
- and a
- ret z
- dec [hl]
- call SlotMachine_StopWheel2Early
- ret z
-.animWheel
- jp SlotMachine_AnimWheel2
-
-SlotMachine_StopOrAnimWheel3:
- ld a, [wStoppingWhichSlotMachineWheel]
- cp 3
- jr c, .animWheel
- ld de, wSlotMachineWheel3Offset
- ld a, [de]
- rra
- jr nc, .animWheel ; check that a symbol is centred in the wheel
-; wheel 3 stops as soon as possible
- scf
- ret
-.animWheel
- call SlotMachine_AnimWheel3
- and a
- ret
-
-SlotMachine_StopWheel1Early:
- call SlotMachine_GetWheel1Tiles
- ld hl, wSlotMachineWheel1BottomTile
- ld a, [wSlotMachineFlags]
- and $80
- jr nz, .sevenAndBarMode
-; Stop early if the middle symbol is not a cherry.
- inc hl
- ld a, [hl]
- cp SLOTSCHERRY >> 8
- jr nz, .stopWheel
- ret
-; It looks like this was intended to make the wheel stop when a 7 symbol was
-; visible, but it has a bug and so the wheel stops randomly.
-.sevenAndBarMode
- ld c, $3
-.loop
- ld a, [hli]
- cp SLOTS7 >> 8
- jr c, .stopWheel ; condition never true
- dec c
- jr nz, .loop
- ret
-.stopWheel
- inc a
- ld hl, wSlotMachineWheel1SlipCounter
- ld [hl], 0
- ret
-
-SlotMachine_StopWheel2Early:
- call SlotMachine_GetWheel2Tiles
- ld a, [wSlotMachineFlags]
- and $80
- jr nz, .sevenAndBarMode
-; Stop early if any symbols are lined up in the first two wheels.
- call SlotMachine_FindWheel1Wheel2Matches
- ret nz
- jr .stopWheel
-; Stop early if two 7 symbols or two bar symbols are lined up in the first two
-; wheels OR if no symbols are lined up and the bottom symbol in wheel 2 is a
-; 7 symbol or bar symbol. The second part could be a bug or a way to reduce the
-; player's odds.
-.sevenAndBarMode
- call SlotMachine_FindWheel1Wheel2Matches
- ld a, [de]
- cp (SLOTSBAR >> 8) + 1
- ret nc
-.stopWheel
- xor a
- ld [wSlotMachineWheel2SlipCounter], a
- ret
-
-SlotMachine_FindWheel1Wheel2Matches:
-; return whether wheel 1 and wheel 2's current positions allow a match (given
-; that wheel 3 stops in a good position) in Z
- ld hl, wSlotMachineWheel1BottomTile
- ld de, wSlotMachineWheel2BottomTile
- ld a, [de]
- cp [hl] ; wheel 1 bottom, wheel 2 bottom
- ret z
- inc de
- ld a, [de]
- cp [hl] ; wheel 1 bottom, wheel 2 middle
- ret z
- inc hl
- cp [hl] ; wheel 1 middle, wheel 2 middle
- ret z
- inc hl
- cp [hl] ; wheel 1 top, wheel 2 middle
- ret z
- inc de
- ld a, [de]
- cp [hl] ; wheel 1 top, wheel 2 top
- ret z
- dec de
- dec de
- ret
-
-SlotMachine_CheckForMatches:
- call SlotMachine_GetWheel3Tiles
- ld a, [wSlotMachineBet]
- cp 2
- jr z, .checkMatchesFor2CoinBet
- cp 1
- jr z, .checkMatchFor1CoinBet
-; 3 coin bet allows diagonal matches (plus the matches for 1/2 coin bets)
- ld hl, wSlotMachineWheel1BottomTile
- ld de, wSlotMachineWheel2MiddleTile
- ld bc, wSlotMachineWheel3TopTile
- call SlotMachine_CheckForMatch
- jp z, .foundMatch
- ld hl, wSlotMachineWheel1TopTile
- ld de, wSlotMachineWheel2MiddleTile
- ld bc, wSlotMachineWheel3BottomTile
- call SlotMachine_CheckForMatch
- jr z, .foundMatch
-; 2 coin bet allows top/bottom horizontal matches (plus the match for a 1 coin bet)
-.checkMatchesFor2CoinBet
- ld hl, wSlotMachineWheel1TopTile
- ld de, wSlotMachineWheel2TopTile
- ld bc, wSlotMachineWheel3TopTile
- call SlotMachine_CheckForMatch
- jr z, .foundMatch
- ld hl, wSlotMachineWheel1BottomTile
- ld de, wSlotMachineWheel2BottomTile
- ld bc, wSlotMachineWheel3BottomTile
- call SlotMachine_CheckForMatch
- jr z, .foundMatch
-; 1 coin bet only allows a middle horizontal match
-.checkMatchFor1CoinBet
- ld hl, wSlotMachineWheel1MiddleTile
- ld de, wSlotMachineWheel2MiddleTile
- ld bc, wSlotMachineWheel3MiddleTile
- call SlotMachine_CheckForMatch
- jr z, .foundMatch
- ld a, [wSlotMachineFlags]
- and $c0
- jr z, .noMatch
- ld hl, wSlotMachineRerollCounter
- dec [hl]
- jr nz, .rollWheel3DownByOneSymbol
-.noMatch
- ld hl, NotThisTimeText
- call PrintText
-.done
- xor a
- ld [wMuteAudioAndPauseMusic], a
- ret
-.rollWheel3DownByOneSymbol
- call SlotMachine_AnimWheel3
- call DelayFrame
- call SlotMachine_AnimWheel3
- call DelayFrame
- jp SlotMachine_CheckForMatches
-.foundMatch
- ld a, [wSlotMachineFlags]
- and $c0
- jr z, .rollWheel3DownByOneSymbol ; roll wheel if player isn't allowed to win
- and $80
- jr nz, .acceptMatch
-; if 7/bar matches aren't enabled and the match was a 7/bar symbol, roll wheel
- ld a, [hl]
- cp (SLOTSBAR >> 8) + 1
- jr c, .rollWheel3DownByOneSymbol
-.acceptMatch
- ld a, [hl]
- sub $2
- ld [wSlotMachineWinningSymbol], a
- ld hl, SlotRewardPointers
- ld c, a
- ld b, 0
- add hl, bc
- ld a, [hli]
- ld e, a
- ld a, [hli]
- ld d, a
- push de
- ld a, [hli]
- ld h, [hl]
- ld l, a
- ld de, wcf4b
- ld bc, 4
- call CopyData
- pop hl
- ld de, .flashScreenLoop
- push de
- jp hl
-
-.flashScreenLoop
- ld a, [rBGP]
- xor $40
- ld [rBGP], a
- ld c, 5
- call DelayFrames
- dec b
- jr nz, .flashScreenLoop
- ld hl, wPayoutCoins
- ld [hl], d
- inc hl
- ld [hl], e
- call SlotMachine_PrintPayoutCoins
- ld hl, SymbolLinedUpSlotMachineText
- call PrintText
- call WaitForTextScrollButtonPress
- call SlotMachine_PayCoinsToPlayer
- call SlotMachine_PrintPayoutCoins
- ld a, $e4
- ld [rOBP0], a
- jp .done
-
-SymbolLinedUpSlotMachineText:
- TX_ASM
- push bc
- call SlotMachine_PrintWinningSymbol
- ld hl, LinedUpText
- pop bc
- inc bc
- inc bc
- inc bc
- inc bc
- ret
-
-LinedUpText:
- TX_FAR _LinedUpText
- db "@"
-
-SlotRewardPointers:
- dw SlotReward300Func
- dw SlotReward300Text
- dw SlotReward100Func
- dw SlotReward100Text
- dw SlotReward8Func
- dw SlotReward8Text
- dw SlotReward15Func
- dw SlotReward15Text
- dw SlotReward15Func
- dw SlotReward15Text
- dw SlotReward15Func
- dw SlotReward15Text
-
-SlotReward300Text:
- db "300@"
-
-SlotReward100Text:
- db "100@"
-
-SlotReward8Text:
- db "8@"
-
-SlotReward15Text:
- db "15@"
-
-NotThisTimeText:
- TX_FAR _NotThisTimeText
- db "@"
-
-; compares the slot machine tiles at bc, de, and hl
-SlotMachine_CheckForMatch:
- ld a, [de]
- cp [hl]
- ret nz
- ld a, [bc]
- cp [hl]
- ret
-
-SlotMachine_GetWheel3Tiles:
- ld de, wSlotMachineWheel3BottomTile
- ld hl, SlotMachineWheel3
- ld a, [wSlotMachineWheel3Offset]
- call SlotMachine_GetWheelTiles
-
-SlotMachine_GetWheel2Tiles:
- ld de, wSlotMachineWheel2BottomTile
- ld hl, SlotMachineWheel2
- ld a, [wSlotMachineWheel2Offset]
- call SlotMachine_GetWheelTiles
-
-SlotMachine_GetWheel1Tiles:
- ld de, wSlotMachineWheel1BottomTile
- ld hl, SlotMachineWheel1
- ld a, [wSlotMachineWheel1Offset]
-
-SlotMachine_GetWheelTiles:
- ld c, a
- ld b, 0
- add hl, bc
- ld c, 3
-.loop
- ld a, [hli]
- ld [de], a
- inc de
- inc hl
- dec c
- jr nz, .loop
- ret
-
-SlotReward8Func:
- ld hl, wSlotMachineAllowMatchesCounter
- ld a, [hl]
- and a
- jr z, .skip
- dec [hl]
-.skip
- ld b, $2
- ld de, 8
- ret
-
-SlotReward15Func:
- ld hl, wSlotMachineAllowMatchesCounter
- ld a, [hl]
- and a
- jr z, .skip
- dec [hl]
-.skip
- ld b, $4
- ld de, 15
- ret
-
-SlotReward100Func:
- ld a, SFX_GET_KEY_ITEM
- call PlaySound
- xor a
- ld [wSlotMachineFlags], a
- ld b, $8
- ld de, 100
- ret
-
-SlotReward300Func:
- ld hl, YeahText
- call PrintText
- ld a, SFX_GET_ITEM_2
- call PlaySound
- call Random
- cp $80
- ld a, $0
- jr c, .skip
- ld [wSlotMachineFlags], a
-.skip
- ld [wSlotMachineAllowMatchesCounter], a
- ld b, $14
- ld de, 300
- ret
-
-YeahText:
- TX_FAR _YeahText
- TX_DELAY
- db "@"
-
-SlotMachine_PrintWinningSymbol:
-; prints winning symbol and down arrow in text box
- coord hl, 2, 14
- ld a, [wSlotMachineWinningSymbol]
- add $25
- ld [hli], a
- inc a
- ld [hld], a
- inc a
- ld de, -SCREEN_WIDTH
- add hl, de
- ld [hli], a
- inc a
- ld [hl], a
- coord hl, 18, 16
- ld [hl], "▼"
- ret
-
-SlotMachine_SubtractBetFromPlayerCoins:
- ld hl, wTempCoins2 + 1
- ld a, [wSlotMachineBet]
- ld [hld], a
- xor a
- ld [hli], a
- ld de, wPlayerCoins + 1
- ld c, $2
- predef SubBCDPredef
-
-SlotMachine_PrintCreditCoins:
- coord hl, 5, 1
- ld de, wPlayerCoins
- ld c, $2
- jp PrintBCDNumber
-
-SlotMachine_PrintPayoutCoins:
- coord hl, 11, 1
- ld de, wPayoutCoins
- lb bc, LEADING_ZEROES | 2, 4 ; 2 bytes, 4 digits
- jp PrintNumber
-
-SlotMachine_PayCoinsToPlayer:
- ld a, $1
- ld [wMuteAudioAndPauseMusic], a
- call WaitForSoundToFinish
-
-; Put 1 in the temp coins variable. This value is added to the player's coins
-; repeatedly so the player can watch the value go up 1 coin at a time.
- ld hl, wTempCoins1
- xor a
- ld [hli], a
- inc a
- ld [hl], a
-
- ld a, 5
- ld [wAnimCounter], a
-
-; Subtract 1 from the payout amount and add 1 to the player's coins each
-; iteration until the payout amount reaches 0.
-.loop
- ld a, [wPayoutCoins + 1]
- ld l, a
- ld a, [wPayoutCoins]
- ld h, a
- or l
- ret z
- ld de, -1
- add hl, de
- ld a, l
- ld [wPayoutCoins + 1], a
- ld a, h
- ld [wPayoutCoins], a
- ld hl, wTempCoins1 + 1
- ld de, wPlayerCoins + 1
- ld c, $2
- predef AddBCDPredef
- call SlotMachine_PrintCreditCoins
- call SlotMachine_PrintPayoutCoins
- ld a, SFX_SLOTS_REWARD
- call PlaySound
- ld a, [wAnimCounter]
- dec a
- jr nz, .skip1
- ld a, [rOBP0]
- xor $40 ; make the slot wheel symbols flash
- ld [rOBP0], a
- ld a, 5
-.skip1
- ld [wAnimCounter], a
- ld a, [wSlotMachineWinningSymbol]
- cp (SLOTSBAR >> 8) + 1
- ld c, 8
- jr nc, .skip2
- srl c ; c = 4 (make the the coins transfer faster if the symbol was 7 or bar)
-.skip2
- call DelayFrames
- jr .loop
-
-SlotMachine_PutOutLitBalls:
- ld a, $23
- ld [wNewSlotMachineBallTile], a
- jr SlotMachine_UpdateThreeCoinBallTiles
-
-SlotMachine_LightBalls:
- ld a, $14
- ld [wNewSlotMachineBallTile], a
- ld a, [wSlotMachineBet]
- dec a
- jr z, SlotMachine_UpdateOneCoinBallTiles
- dec a
- jr z, SlotMachine_UpdateTwoCoinBallTiles
-
-SlotMachine_UpdateThreeCoinBallTiles:
- coord hl, 3, 2
- call SlotMachine_UpdateBallTiles
- coord hl, 3, 10
- call SlotMachine_UpdateBallTiles
-
-SlotMachine_UpdateTwoCoinBallTiles:
- coord hl, 3, 4
- call SlotMachine_UpdateBallTiles
- coord hl, 3, 8
- call SlotMachine_UpdateBallTiles
-
-SlotMachine_UpdateOneCoinBallTiles:
- coord hl, 3, 6
-
-SlotMachine_UpdateBallTiles:
- ld a, [wNewSlotMachineBallTile]
- ld [hl], a
- ld bc, 13
- add hl, bc
- ld [hl], a
- ld bc, 7
- add hl, bc
- inc a
- ld [hl], a
- ld bc, 13
- add hl, bc
- ld [hl], a
- ret
-
-SlotMachine_AnimWheel1:
- ld bc, SlotMachineWheel1
- ld de, wSlotMachineWheel1Offset
- ld hl, wOAMBuffer
- ld a, $30
- ld [wBaseCoordX], a
- jr SlotMachine_AnimWheel
-
-SlotMachine_AnimWheel2:
- ld bc, SlotMachineWheel2
- ld de, wSlotMachineWheel2Offset
- ld hl, wOAMBuffer + $30
- ld a, $50
- ld [wBaseCoordX], a
- jr SlotMachine_AnimWheel
-
-SlotMachine_AnimWheel3:
- ld bc, SlotMachineWheel3
- ld de, wSlotMachineWheel3Offset
- ld hl, wOAMBuffer + $60
- ld a, $70
- ld [wBaseCoordX], a
-
-SlotMachine_AnimWheel:
- ld a, $58
- ld [wBaseCoordY], a
- push de
- ld a, [de]
- ld d, b
- add c
- ld e, a
- jr nc, .loop
- inc d
-.loop
- ld a, [wBaseCoordY]
- ld [hli], a
- ld a, [wBaseCoordX]
- ld [hli], a
- ld a, [de]
- ld [hli], a
- ld a, $80
- ld [hli], a
- ld a, [wBaseCoordY]
- ld [hli], a
- ld a, [wBaseCoordX]
- add $8
- ld [hli], a
- ld a, [de]
- inc a
- ld [hli], a
- ld a, $80
- ld [hli], a
- inc de
- ld a, [wBaseCoordY]
- sub $8
- ld [wBaseCoordY], a
- cp $28
- jr nz, .loop
- pop de
- ld a, [de]
- inc a ; advance the offset so that the wheel animates
- cp 30
- jr nz, .skip
- xor a ; wrap around to 0 when the offset reaches 30
-.skip
- ld [de], a
- ret
-
-SlotMachine_HandleInputWhileWheelsSpin:
- call DelayFrame
- call JoypadLowSensitivity
- ld a, [hJoy5]
- and A_BUTTON
- ret z
- ld hl, wStoppingWhichSlotMachineWheel
- ld a, [hl]
- dec a
- ld de, wSlotMachineWheel1SlipCounter
- jr z, .skip
- dec a
- ld de, wSlotMachineWheel2SlipCounter
- jr z, .skip
-.loop
- inc [hl]
- ld a, SFX_SLOTS_STOP_WHEEL
- jp PlaySound
-.skip
- ld a, [de]
- and a
- ret nz
- jr .loop
-
-LoadSlotMachineTiles:
- call DisableLCD
- ld hl, SlotMachineTiles2
- ld de, vChars0
- ld bc, $1c0
- ld a, BANK(SlotMachineTiles2)
- call FarCopyData2
- ld hl, SlotMachineTiles1
- ld de, vChars2
- ld bc, $250
- ld a, BANK(SlotMachineTiles1)
- call FarCopyData2
- ld hl, SlotMachineTiles2
- ld de, vChars2 + $250
- ld bc, $1c0
- ld a, BANK(SlotMachineTiles2)
- call FarCopyData2
- ld hl, SlotMachineMap
- coord de, 0, 0
- ld bc, SlotMachineMapEnd - SlotMachineMap
- call CopyData
- call EnableLCD
- ld hl, wSlotMachineWheel1Offset
- ld a, $1c
- ld [hli], a
- ld [hli], a
- ld [hl], a
- call SlotMachine_AnimWheel1
- call SlotMachine_AnimWheel2
- jp SlotMachine_AnimWheel3
-
-SlotMachineMap:
- INCBIN "gfx/slots/slots.tilemap"
-SlotMachineMapEnd:
-
-INCLUDE "data/slot_machine_wheels.asm"
-
-SlotMachineTiles1:
-IF DEF(_RED)
- INCBIN "gfx/slots/red_slots_1.2bpp"
-ENDC
-IF DEF(_BLUE)
- INCBIN "gfx/slots/blue_slots_1.2bpp"
-ENDC
--- /dev/null
+++ b/engine/slots/game_corner_slots.asm
@@ -1,0 +1,54 @@
+StartSlotMachine:
+ ld a, [wHiddenObjectFunctionArgument]
+ cp $fd
+ jr z, .printOutOfOrder
+ cp $fe
+ jr z, .printOutToLunch
+ cp $ff
+ jr z, .printSomeonesKeys
+ callba AbleToPlaySlotsCheck
+ ld a, [wCanPlaySlots]
+ and a
+ ret z
+ ld a, [wLuckySlotHiddenObjectIndex]
+ ld b, a
+ ld a, [wHiddenObjectIndex]
+ inc a
+ cp b
+ jr z, .match
+ ld a, 253
+ jr .next
+.match
+ ld a, 250
+.next
+ ld [wSlotMachineSevenAndBarModeChance], a
+ ld a, [H_LOADEDROMBANK]
+ ld [wSlotMachineSavedROMBank], a
+ call PromptUserToPlaySlots
+ ret
+.printOutOfOrder
+ tx_pre_id GameCornerOutOfOrderText
+ jr .printText
+.printOutToLunch
+ tx_pre_id GameCornerOutToLunchText
+ jr .printText
+.printSomeonesKeys
+ tx_pre_id GameCornerSomeonesKeysText
+.printText
+ push af
+ call EnableAutoTextBoxDrawing
+ pop af
+ call PrintPredefTextID
+ ret
+
+GameCornerOutOfOrderText::
+ TX_FAR _GameCornerOutOfOrderText
+ db "@"
+
+GameCornerOutToLunchText::
+ TX_FAR _GameCornerOutToLunchText
+ db "@"
+
+GameCornerSomeonesKeysText::
+ TX_FAR _GameCornerSomeonesKeysText
+ db "@"
--- /dev/null
+++ b/engine/slots/game_corner_slots2.asm
@@ -1,0 +1,31 @@
+AbleToPlaySlotsCheck:
+ ld a, [wSpriteStateData1 + 2]
+ and $8
+ jr z, .done ; not able
+ ld b, COIN_CASE
+ predef GetQuantityOfItemInBag
+ ld a, b
+ and a
+ ld b, (GameCornerCoinCaseText_id - TextPredefs) / 2 + 1
+ jr z, .printCoinCaseRequired
+ ld hl, wPlayerCoins
+ ld a, [hli]
+ or [hl]
+ jr nz, .done ; able to play
+ ld b, (GameCornerNoCoinsText_id - TextPredefs) / 2 + 1
+.printCoinCaseRequired
+ call EnableAutoTextBoxDrawing
+ ld a, b
+ call PrintPredefTextID
+ xor a
+.done
+ ld [wCanPlaySlots], a
+ ret
+
+GameCornerCoinCaseText::
+ TX_FAR _GameCornerCoinCaseText
+ db "@"
+
+GameCornerNoCoinsText::
+ TX_FAR _GameCornerNoCoinsText
+ db "@"
--- /dev/null
+++ b/engine/slots/slot_machine.asm
@@ -1,0 +1,892 @@
+PromptUserToPlaySlots:
+ call SaveScreenTilesToBuffer2
+ ld a, BANK(DisplayTextIDInit)
+ ld [wAutoTextBoxDrawingControl], a
+ ld b, a
+ ld hl, DisplayTextIDInit
+ call Bankswitch
+ ld hl, PlaySlotMachineText
+ call PrintText
+ call YesNoChoice
+ ld a, [wCurrentMenuItem]
+ and a
+ jr nz, .done ; if player chose No
+ dec a
+ ld [wUpdateSpritesEnabled], a
+ ld hl, wSlotMachineRerollCounter
+ xor a
+ ld [hli], a
+ ld [hl], SMILE_BUBBLE
+ predef EmotionBubble
+ call GBPalWhiteOutWithDelay3
+ call LoadSlotMachineTiles
+ call LoadFontTilePatterns
+ ld b, SET_PAL_SLOTS
+ call RunPaletteCommand
+ call GBPalNormal
+ ld a, $e4
+ ld [rOBP0], a
+ ld hl, wd730
+ set 6, [hl]
+ xor a
+ ld [wSlotMachineAllowMatchesCounter], a
+ ld hl, wStoppingWhichSlotMachineWheel
+ ld bc, $0014
+ call FillMemory
+ call MainSlotMachineLoop
+ ld hl, wd730
+ res 6, [hl]
+ xor a
+ ld [wSlotMachineAllowMatchesCounter], a
+ call GBPalWhiteOutWithDelay3
+ ld a, $1
+ ld [wUpdateSpritesEnabled], a
+ call RunDefaultPaletteCommand
+ call ReloadMapSpriteTilePatterns
+ call ReloadTilesetTilePatterns
+.done
+ call LoadScreenTilesFromBuffer2
+ call Delay3
+ call GBPalNormal
+ ld a, [wSlotMachineSavedROMBank]
+ push af
+ jp CloseTextDisplay
+
+PlaySlotMachineText:
+ TX_FAR _PlaySlotMachineText
+ db "@"
+
+MainSlotMachineLoop:
+ call SlotMachine_PrintCreditCoins
+ xor a
+ ld hl, wPayoutCoins
+ ld [hli], a
+ ld [hl], a
+ call SlotMachine_PrintPayoutCoins
+ ld hl, BetHowManySlotMachineText
+ call PrintText
+ call SaveScreenTilesToBuffer1
+.loop
+ ld a, A_BUTTON | B_BUTTON
+ ld [wMenuWatchedKeys], a
+ ld a, 2
+ ld [wMaxMenuItem], a
+ ld a, 12
+ ld [wTopMenuItemY], a
+ ld a, 15
+ ld [wTopMenuItemX], a
+ xor a
+ ld [wCurrentMenuItem], a
+ ld [wLastMenuItem], a
+ ld [wMenuWatchMovingOutOfBounds], a
+ coord hl, 14, 11
+ ld b, 5
+ ld c, 4
+ call TextBoxBorder
+ coord hl, 16, 12
+ ld de, CoinMultiplierSlotMachineText
+ call PlaceString
+ call HandleMenuInput
+ and B_BUTTON
+ jp nz, LoadScreenTilesFromBuffer1
+ ld a, [wCurrentMenuItem]
+ ld b, a
+ ld a, 3
+ sub b
+ ld [wSlotMachineBet], a
+ ld hl, wPlayerCoins
+ ld c, a
+ ld a, [hli]
+ and a
+ jr nz, .skip1
+ ld a, [hl]
+ cp c
+ jr nc, .skip1
+ ld hl, NotEnoughCoinsSlotMachineText
+ call PrintText
+ jr .loop
+.skip1
+ call LoadScreenTilesFromBuffer1
+ call SlotMachine_SubtractBetFromPlayerCoins
+ call SlotMachine_LightBalls
+ call SlotMachine_SetFlags
+ ld a, 4
+ ld hl, wSlotMachineWheel1SlipCounter
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+ call WaitForSoundToFinish
+ ld a, SFX_SLOTS_NEW_SPIN
+ call PlaySound
+ ld hl, StartSlotMachineText
+ call PrintText
+ call SlotMachine_SpinWheels
+ call SlotMachine_CheckForMatches
+ ld hl, wPlayerCoins
+ ld a, [hli]
+ or [hl]
+ jr nz, .skip2
+ ld hl, OutOfCoinsSlotMachineText
+ call PrintText
+ ld c, 60
+ jp DelayFrames
+.skip2
+ ld hl, OneMoreGoSlotMachineText
+ call PrintText
+ coord hl, 14, 12
+ lb bc, 13, 15
+ xor a ; YES_NO_MENU
+ ld [wTwoOptionMenuID], a
+ ld a, TWO_OPTION_MENU
+ ld [wTextBoxID], a
+ call DisplayTextBoxID
+ ld a, [wCurrentMenuItem]
+ and a
+ ret nz
+ call SlotMachine_PutOutLitBalls
+ jp MainSlotMachineLoop
+
+CoinMultiplierSlotMachineText:
+ db "×3"
+ next "×2"
+ next "×1@"
+
+OutOfCoinsSlotMachineText:
+ TX_FAR _OutOfCoinsSlotMachineText
+ db "@"
+
+BetHowManySlotMachineText:
+ TX_FAR _BetHowManySlotMachineText
+ db "@"
+
+StartSlotMachineText:
+ TX_FAR _StartSlotMachineText
+ db "@"
+
+NotEnoughCoinsSlotMachineText:
+ TX_FAR _NotEnoughCoinsSlotMachineText
+ db "@"
+
+OneMoreGoSlotMachineText:
+ TX_FAR _OneMoreGoSlotMachineText
+ db "@"
+
+SlotMachine_SetFlags:
+ ld hl, wSlotMachineFlags
+ bit 7, [hl]
+ ret nz
+ ld a, [wSlotMachineAllowMatchesCounter]
+ and a
+ jr nz, .allowMatches
+ call Random
+ and a
+ jr z, .setAllowMatchesCounter ; 1/256 (~0.4%) chance
+ ld b, a
+ ld a, [wSlotMachineSevenAndBarModeChance]
+ cp b
+ jr c, .allowSevenAndBarMatches
+ ld a, 210
+ cp b
+ jr c, .allowMatches ; 55/256 (~21.5%) chance
+ ld [hl], 0
+ ret
+.allowMatches
+ set 6, [hl]
+ ret
+.setAllowMatchesCounter
+ ld a, 60
+ ld [wSlotMachineAllowMatchesCounter], a
+ ret
+.allowSevenAndBarMatches
+ set 7, [hl]
+ ret
+
+SlotMachine_SpinWheels:
+ ld c, 20
+.loop1
+ push bc
+ call SlotMachine_AnimWheel1
+ call SlotMachine_AnimWheel2
+ call SlotMachine_AnimWheel3
+ ld c, 2
+ call DelayFrames
+ pop bc
+ dec c
+ jr nz, .loop1
+ xor a
+ ld [wStoppingWhichSlotMachineWheel], a
+.loop2
+ call SlotMachine_HandleInputWhileWheelsSpin
+ call SlotMachine_StopOrAnimWheel1
+ call SlotMachine_StopOrAnimWheel2
+ call SlotMachine_StopOrAnimWheel3
+ ret c
+ ld a, [wOnSGB]
+ xor $1
+ inc a
+ ld c, a
+ call DelayFrames
+ jr .loop2
+
+; Note that the wheels can only stop when a symbol is centred in the wheel
+; and thus 3 full symbols rather than 2 full symbols and 2 half symbols are
+; visible. The 3 functions below ensure this by checking if the wheel offset
+; is even before stopping the wheel.
+
+SlotMachine_StopOrAnimWheel1:
+ ld a, [wStoppingWhichSlotMachineWheel]
+ cp 1
+ jr c, .animWheel
+ ld de, wSlotMachineWheel1Offset
+ ld a, [de]
+ rra
+ jr nc, .animWheel ; check that a symbol is centred in the wheel
+ ld hl, wSlotMachineWheel1SlipCounter
+ ld a, [hl]
+ and a
+ ret z
+ dec [hl]
+ call SlotMachine_StopWheel1Early
+ ret nz
+.animWheel
+ jp SlotMachine_AnimWheel1
+
+SlotMachine_StopOrAnimWheel2:
+ ld a, [wStoppingWhichSlotMachineWheel]
+ cp 2
+ jr c, .animWheel
+ ld de, wSlotMachineWheel2Offset
+ ld a, [de]
+ rra
+ jr nc, .animWheel ; check that a symbol is centred in the wheel
+ ld hl, wSlotMachineWheel2SlipCounter
+ ld a, [hl]
+ and a
+ ret z
+ dec [hl]
+ call SlotMachine_StopWheel2Early
+ ret z
+.animWheel
+ jp SlotMachine_AnimWheel2
+
+SlotMachine_StopOrAnimWheel3:
+ ld a, [wStoppingWhichSlotMachineWheel]
+ cp 3
+ jr c, .animWheel
+ ld de, wSlotMachineWheel3Offset
+ ld a, [de]
+ rra
+ jr nc, .animWheel ; check that a symbol is centred in the wheel
+; wheel 3 stops as soon as possible
+ scf
+ ret
+.animWheel
+ call SlotMachine_AnimWheel3
+ and a
+ ret
+
+SlotMachine_StopWheel1Early:
+ call SlotMachine_GetWheel1Tiles
+ ld hl, wSlotMachineWheel1BottomTile
+ ld a, [wSlotMachineFlags]
+ and $80
+ jr nz, .sevenAndBarMode
+; Stop early if the middle symbol is not a cherry.
+ inc hl
+ ld a, [hl]
+ cp SLOTSCHERRY >> 8
+ jr nz, .stopWheel
+ ret
+; It looks like this was intended to make the wheel stop when a 7 symbol was
+; visible, but it has a bug and so the wheel stops randomly.
+.sevenAndBarMode
+ ld c, $3
+.loop
+ ld a, [hli]
+ cp SLOTS7 >> 8
+ jr c, .stopWheel ; condition never true
+ dec c
+ jr nz, .loop
+ ret
+.stopWheel
+ inc a
+ ld hl, wSlotMachineWheel1SlipCounter
+ ld [hl], 0
+ ret
+
+SlotMachine_StopWheel2Early:
+ call SlotMachine_GetWheel2Tiles
+ ld a, [wSlotMachineFlags]
+ and $80
+ jr nz, .sevenAndBarMode
+; Stop early if any symbols are lined up in the first two wheels.
+ call SlotMachine_FindWheel1Wheel2Matches
+ ret nz
+ jr .stopWheel
+; Stop early if two 7 symbols or two bar symbols are lined up in the first two
+; wheels OR if no symbols are lined up and the bottom symbol in wheel 2 is a
+; 7 symbol or bar symbol. The second part could be a bug or a way to reduce the
+; player's odds.
+.sevenAndBarMode
+ call SlotMachine_FindWheel1Wheel2Matches
+ ld a, [de]
+ cp (SLOTSBAR >> 8) + 1
+ ret nc
+.stopWheel
+ xor a
+ ld [wSlotMachineWheel2SlipCounter], a
+ ret
+
+SlotMachine_FindWheel1Wheel2Matches:
+; return whether wheel 1 and wheel 2's current positions allow a match (given
+; that wheel 3 stops in a good position) in Z
+ ld hl, wSlotMachineWheel1BottomTile
+ ld de, wSlotMachineWheel2BottomTile
+ ld a, [de]
+ cp [hl] ; wheel 1 bottom, wheel 2 bottom
+ ret z
+ inc de
+ ld a, [de]
+ cp [hl] ; wheel 1 bottom, wheel 2 middle
+ ret z
+ inc hl
+ cp [hl] ; wheel 1 middle, wheel 2 middle
+ ret z
+ inc hl
+ cp [hl] ; wheel 1 top, wheel 2 middle
+ ret z
+ inc de
+ ld a, [de]
+ cp [hl] ; wheel 1 top, wheel 2 top
+ ret z
+ dec de
+ dec de
+ ret
+
+SlotMachine_CheckForMatches:
+ call SlotMachine_GetWheel3Tiles
+ ld a, [wSlotMachineBet]
+ cp 2
+ jr z, .checkMatchesFor2CoinBet
+ cp 1
+ jr z, .checkMatchFor1CoinBet
+; 3 coin bet allows diagonal matches (plus the matches for 1/2 coin bets)
+ ld hl, wSlotMachineWheel1BottomTile
+ ld de, wSlotMachineWheel2MiddleTile
+ ld bc, wSlotMachineWheel3TopTile
+ call SlotMachine_CheckForMatch
+ jp z, .foundMatch
+ ld hl, wSlotMachineWheel1TopTile
+ ld de, wSlotMachineWheel2MiddleTile
+ ld bc, wSlotMachineWheel3BottomTile
+ call SlotMachine_CheckForMatch
+ jr z, .foundMatch
+; 2 coin bet allows top/bottom horizontal matches (plus the match for a 1 coin bet)
+.checkMatchesFor2CoinBet
+ ld hl, wSlotMachineWheel1TopTile
+ ld de, wSlotMachineWheel2TopTile
+ ld bc, wSlotMachineWheel3TopTile
+ call SlotMachine_CheckForMatch
+ jr z, .foundMatch
+ ld hl, wSlotMachineWheel1BottomTile
+ ld de, wSlotMachineWheel2BottomTile
+ ld bc, wSlotMachineWheel3BottomTile
+ call SlotMachine_CheckForMatch
+ jr z, .foundMatch
+; 1 coin bet only allows a middle horizontal match
+.checkMatchFor1CoinBet
+ ld hl, wSlotMachineWheel1MiddleTile
+ ld de, wSlotMachineWheel2MiddleTile
+ ld bc, wSlotMachineWheel3MiddleTile
+ call SlotMachine_CheckForMatch
+ jr z, .foundMatch
+ ld a, [wSlotMachineFlags]
+ and $c0
+ jr z, .noMatch
+ ld hl, wSlotMachineRerollCounter
+ dec [hl]
+ jr nz, .rollWheel3DownByOneSymbol
+.noMatch
+ ld hl, NotThisTimeText
+ call PrintText
+.done
+ xor a
+ ld [wMuteAudioAndPauseMusic], a
+ ret
+.rollWheel3DownByOneSymbol
+ call SlotMachine_AnimWheel3
+ call DelayFrame
+ call SlotMachine_AnimWheel3
+ call DelayFrame
+ jp SlotMachine_CheckForMatches
+.foundMatch
+ ld a, [wSlotMachineFlags]
+ and $c0
+ jr z, .rollWheel3DownByOneSymbol ; roll wheel if player isn't allowed to win
+ and $80
+ jr nz, .acceptMatch
+; if 7/bar matches aren't enabled and the match was a 7/bar symbol, roll wheel
+ ld a, [hl]
+ cp (SLOTSBAR >> 8) + 1
+ jr c, .rollWheel3DownByOneSymbol
+.acceptMatch
+ ld a, [hl]
+ sub $2
+ ld [wSlotMachineWinningSymbol], a
+ ld hl, SlotRewardPointers
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hli]
+ ld e, a
+ ld a, [hli]
+ ld d, a
+ push de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, wcf4b
+ ld bc, 4
+ call CopyData
+ pop hl
+ ld de, .flashScreenLoop
+ push de
+ jp hl
+
+.flashScreenLoop
+ ld a, [rBGP]
+ xor $40
+ ld [rBGP], a
+ ld c, 5
+ call DelayFrames
+ dec b
+ jr nz, .flashScreenLoop
+ ld hl, wPayoutCoins
+ ld [hl], d
+ inc hl
+ ld [hl], e
+ call SlotMachine_PrintPayoutCoins
+ ld hl, SymbolLinedUpSlotMachineText
+ call PrintText
+ call WaitForTextScrollButtonPress
+ call SlotMachine_PayCoinsToPlayer
+ call SlotMachine_PrintPayoutCoins
+ ld a, $e4
+ ld [rOBP0], a
+ jp .done
+
+SymbolLinedUpSlotMachineText:
+ TX_ASM
+ push bc
+ call SlotMachine_PrintWinningSymbol
+ ld hl, LinedUpText
+ pop bc
+ inc bc
+ inc bc
+ inc bc
+ inc bc
+ ret
+
+LinedUpText:
+ TX_FAR _LinedUpText
+ db "@"
+
+SlotRewardPointers:
+ dw SlotReward300Func
+ dw SlotReward300Text
+ dw SlotReward100Func
+ dw SlotReward100Text
+ dw SlotReward8Func
+ dw SlotReward8Text
+ dw SlotReward15Func
+ dw SlotReward15Text
+ dw SlotReward15Func
+ dw SlotReward15Text
+ dw SlotReward15Func
+ dw SlotReward15Text
+
+SlotReward300Text:
+ db "300@"
+
+SlotReward100Text:
+ db "100@"
+
+SlotReward8Text:
+ db "8@"
+
+SlotReward15Text:
+ db "15@"
+
+NotThisTimeText:
+ TX_FAR _NotThisTimeText
+ db "@"
+
+; compares the slot machine tiles at bc, de, and hl
+SlotMachine_CheckForMatch:
+ ld a, [de]
+ cp [hl]
+ ret nz
+ ld a, [bc]
+ cp [hl]
+ ret
+
+SlotMachine_GetWheel3Tiles:
+ ld de, wSlotMachineWheel3BottomTile
+ ld hl, SlotMachineWheel3
+ ld a, [wSlotMachineWheel3Offset]
+ call SlotMachine_GetWheelTiles
+
+SlotMachine_GetWheel2Tiles:
+ ld de, wSlotMachineWheel2BottomTile
+ ld hl, SlotMachineWheel2
+ ld a, [wSlotMachineWheel2Offset]
+ call SlotMachine_GetWheelTiles
+
+SlotMachine_GetWheel1Tiles:
+ ld de, wSlotMachineWheel1BottomTile
+ ld hl, SlotMachineWheel1
+ ld a, [wSlotMachineWheel1Offset]
+
+SlotMachine_GetWheelTiles:
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld c, 3
+.loop
+ ld a, [hli]
+ ld [de], a
+ inc de
+ inc hl
+ dec c
+ jr nz, .loop
+ ret
+
+SlotReward8Func:
+ ld hl, wSlotMachineAllowMatchesCounter
+ ld a, [hl]
+ and a
+ jr z, .skip
+ dec [hl]
+.skip
+ ld b, $2
+ ld de, 8
+ ret
+
+SlotReward15Func:
+ ld hl, wSlotMachineAllowMatchesCounter
+ ld a, [hl]
+ and a
+ jr z, .skip
+ dec [hl]
+.skip
+ ld b, $4
+ ld de, 15
+ ret
+
+SlotReward100Func:
+ ld a, SFX_GET_KEY_ITEM
+ call PlaySound
+ xor a
+ ld [wSlotMachineFlags], a
+ ld b, $8
+ ld de, 100
+ ret
+
+SlotReward300Func:
+ ld hl, YeahText
+ call PrintText
+ ld a, SFX_GET_ITEM_2
+ call PlaySound
+ call Random
+ cp $80
+ ld a, $0
+ jr c, .skip
+ ld [wSlotMachineFlags], a
+.skip
+ ld [wSlotMachineAllowMatchesCounter], a
+ ld b, $14
+ ld de, 300
+ ret
+
+YeahText:
+ TX_FAR _YeahText
+ TX_DELAY
+ db "@"
+
+SlotMachine_PrintWinningSymbol:
+; prints winning symbol and down arrow in text box
+ coord hl, 2, 14
+ ld a, [wSlotMachineWinningSymbol]
+ add $25
+ ld [hli], a
+ inc a
+ ld [hld], a
+ inc a
+ ld de, -SCREEN_WIDTH
+ add hl, de
+ ld [hli], a
+ inc a
+ ld [hl], a
+ coord hl, 18, 16
+ ld [hl], "▼"
+ ret
+
+SlotMachine_SubtractBetFromPlayerCoins:
+ ld hl, wTempCoins2 + 1
+ ld a, [wSlotMachineBet]
+ ld [hld], a
+ xor a
+ ld [hli], a
+ ld de, wPlayerCoins + 1
+ ld c, $2
+ predef SubBCDPredef
+
+SlotMachine_PrintCreditCoins:
+ coord hl, 5, 1
+ ld de, wPlayerCoins
+ ld c, $2
+ jp PrintBCDNumber
+
+SlotMachine_PrintPayoutCoins:
+ coord hl, 11, 1
+ ld de, wPayoutCoins
+ lb bc, LEADING_ZEROES | 2, 4 ; 2 bytes, 4 digits
+ jp PrintNumber
+
+SlotMachine_PayCoinsToPlayer:
+ ld a, $1
+ ld [wMuteAudioAndPauseMusic], a
+ call WaitForSoundToFinish
+
+; Put 1 in the temp coins variable. This value is added to the player's coins
+; repeatedly so the player can watch the value go up 1 coin at a time.
+ ld hl, wTempCoins1
+ xor a
+ ld [hli], a
+ inc a
+ ld [hl], a
+
+ ld a, 5
+ ld [wAnimCounter], a
+
+; Subtract 1 from the payout amount and add 1 to the player's coins each
+; iteration until the payout amount reaches 0.
+.loop
+ ld a, [wPayoutCoins + 1]
+ ld l, a
+ ld a, [wPayoutCoins]
+ ld h, a
+ or l
+ ret z
+ ld de, -1
+ add hl, de
+ ld a, l
+ ld [wPayoutCoins + 1], a
+ ld a, h
+ ld [wPayoutCoins], a
+ ld hl, wTempCoins1 + 1
+ ld de, wPlayerCoins + 1
+ ld c, $2
+ predef AddBCDPredef
+ call SlotMachine_PrintCreditCoins
+ call SlotMachine_PrintPayoutCoins
+ ld a, SFX_SLOTS_REWARD
+ call PlaySound
+ ld a, [wAnimCounter]
+ dec a
+ jr nz, .skip1
+ ld a, [rOBP0]
+ xor $40 ; make the slot wheel symbols flash
+ ld [rOBP0], a
+ ld a, 5
+.skip1
+ ld [wAnimCounter], a
+ ld a, [wSlotMachineWinningSymbol]
+ cp (SLOTSBAR >> 8) + 1
+ ld c, 8
+ jr nc, .skip2
+ srl c ; c = 4 (make the the coins transfer faster if the symbol was 7 or bar)
+.skip2
+ call DelayFrames
+ jr .loop
+
+SlotMachine_PutOutLitBalls:
+ ld a, $23
+ ld [wNewSlotMachineBallTile], a
+ jr SlotMachine_UpdateThreeCoinBallTiles
+
+SlotMachine_LightBalls:
+ ld a, $14
+ ld [wNewSlotMachineBallTile], a
+ ld a, [wSlotMachineBet]
+ dec a
+ jr z, SlotMachine_UpdateOneCoinBallTiles
+ dec a
+ jr z, SlotMachine_UpdateTwoCoinBallTiles
+
+SlotMachine_UpdateThreeCoinBallTiles:
+ coord hl, 3, 2
+ call SlotMachine_UpdateBallTiles
+ coord hl, 3, 10
+ call SlotMachine_UpdateBallTiles
+
+SlotMachine_UpdateTwoCoinBallTiles:
+ coord hl, 3, 4
+ call SlotMachine_UpdateBallTiles
+ coord hl, 3, 8
+ call SlotMachine_UpdateBallTiles
+
+SlotMachine_UpdateOneCoinBallTiles:
+ coord hl, 3, 6
+
+SlotMachine_UpdateBallTiles:
+ ld a, [wNewSlotMachineBallTile]
+ ld [hl], a
+ ld bc, 13
+ add hl, bc
+ ld [hl], a
+ ld bc, 7
+ add hl, bc
+ inc a
+ ld [hl], a
+ ld bc, 13
+ add hl, bc
+ ld [hl], a
+ ret
+
+SlotMachine_AnimWheel1:
+ ld bc, SlotMachineWheel1
+ ld de, wSlotMachineWheel1Offset
+ ld hl, wOAMBuffer
+ ld a, $30
+ ld [wBaseCoordX], a
+ jr SlotMachine_AnimWheel
+
+SlotMachine_AnimWheel2:
+ ld bc, SlotMachineWheel2
+ ld de, wSlotMachineWheel2Offset
+ ld hl, wOAMBuffer + $30
+ ld a, $50
+ ld [wBaseCoordX], a
+ jr SlotMachine_AnimWheel
+
+SlotMachine_AnimWheel3:
+ ld bc, SlotMachineWheel3
+ ld de, wSlotMachineWheel3Offset
+ ld hl, wOAMBuffer + $60
+ ld a, $70
+ ld [wBaseCoordX], a
+
+SlotMachine_AnimWheel:
+ ld a, $58
+ ld [wBaseCoordY], a
+ push de
+ ld a, [de]
+ ld d, b
+ add c
+ ld e, a
+ jr nc, .loop
+ inc d
+.loop
+ ld a, [wBaseCoordY]
+ ld [hli], a
+ ld a, [wBaseCoordX]
+ ld [hli], a
+ ld a, [de]
+ ld [hli], a
+ ld a, $80
+ ld [hli], a
+ ld a, [wBaseCoordY]
+ ld [hli], a
+ ld a, [wBaseCoordX]
+ add $8
+ ld [hli], a
+ ld a, [de]
+ inc a
+ ld [hli], a
+ ld a, $80
+ ld [hli], a
+ inc de
+ ld a, [wBaseCoordY]
+ sub $8
+ ld [wBaseCoordY], a
+ cp $28
+ jr nz, .loop
+ pop de
+ ld a, [de]
+ inc a ; advance the offset so that the wheel animates
+ cp 30
+ jr nz, .skip
+ xor a ; wrap around to 0 when the offset reaches 30
+.skip
+ ld [de], a
+ ret
+
+SlotMachine_HandleInputWhileWheelsSpin:
+ call DelayFrame
+ call JoypadLowSensitivity
+ ld a, [hJoy5]
+ and A_BUTTON
+ ret z
+ ld hl, wStoppingWhichSlotMachineWheel
+ ld a, [hl]
+ dec a
+ ld de, wSlotMachineWheel1SlipCounter
+ jr z, .skip
+ dec a
+ ld de, wSlotMachineWheel2SlipCounter
+ jr z, .skip
+.loop
+ inc [hl]
+ ld a, SFX_SLOTS_STOP_WHEEL
+ jp PlaySound
+.skip
+ ld a, [de]
+ and a
+ ret nz
+ jr .loop
+
+LoadSlotMachineTiles:
+ call DisableLCD
+ ld hl, SlotMachineTiles2
+ ld de, vChars0
+ ld bc, $1c0
+ ld a, BANK(SlotMachineTiles2)
+ call FarCopyData2
+ ld hl, SlotMachineTiles1
+ ld de, vChars2
+ ld bc, $250
+ ld a, BANK(SlotMachineTiles1)
+ call FarCopyData2
+ ld hl, SlotMachineTiles2
+ ld de, vChars2 + $250
+ ld bc, $1c0
+ ld a, BANK(SlotMachineTiles2)
+ call FarCopyData2
+ ld hl, SlotMachineMap
+ coord de, 0, 0
+ ld bc, SlotMachineMapEnd - SlotMachineMap
+ call CopyData
+ call EnableLCD
+ ld hl, wSlotMachineWheel1Offset
+ ld a, $1c
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+ call SlotMachine_AnimWheel1
+ call SlotMachine_AnimWheel2
+ jp SlotMachine_AnimWheel3
+
+SlotMachineMap:
+ INCBIN "gfx/slots/slots.tilemap"
+SlotMachineMapEnd:
+
+INCLUDE "data/slot_machine_wheels.asm"
+
+SlotMachineTiles1:
+IF DEF(_RED)
+ INCBIN "gfx/slots/red_slots_1.2bpp"
+ENDC
+IF DEF(_BLUE)
+ INCBIN "gfx/slots/blue_slots_1.2bpp"
+ENDC
--- a/engine/special_warps.asm
+++ /dev/null
@@ -1,149 +1,0 @@
-SpecialWarpIn::
- call LoadSpecialWarpData
- predef LoadTilesetHeader
- ld hl, wd732
- bit 2, [hl] ; dungeon warp or fly warp?
- res 2, [hl]
- jr z, .next
-; if dungeon warp or fly warp
- ld a, [wDestinationMap]
- jr .next2
-.next
- bit 1, [hl]
- jr z, .next3
- call EmptyFunc
-.next3
- ld a, 0
-.next2
- ld b, a
- ld a, [wd72d]
- and a
- jr nz, .next4
- ld a, b
-.next4
- ld hl, wd732
- bit 4, [hl] ; dungeon warp?
- ret nz
-; if not dungeon warp
- ld [wLastMap], a
- ret
-
-; gets the map ID, tile block map view pointer, tileset, and coordinates
-LoadSpecialWarpData:
- ld a, [wd72d]
- cp TRADE_CENTER
- jr nz, .notTradeCenter
- ld hl, TradeCenterSpec1
- ld a, [hSerialConnectionStatus]
- cp USING_INTERNAL_CLOCK ; which gameboy is clocking determines who is on the left and who is on the right
- jr z, .copyWarpData
- ld hl, TradeCenterSpec2
- jr .copyWarpData
-.notTradeCenter
- cp COLOSSEUM
- jr nz, .notColosseum
- ld hl, ColosseumSpec1
- ld a, [hSerialConnectionStatus]
- cp USING_INTERNAL_CLOCK
- jr z, .copyWarpData
- ld hl, ColosseumSpec2
- jr .copyWarpData
-.notColosseum
- ld a, [wd732]
- bit 1, a
- jr nz, .notFirstMap
- bit 2, a
- jr nz, .notFirstMap
- ld hl, FirstMapSpec
-.copyWarpData
- ld de, wCurMap
- ld c, $7
-.copyWarpDataLoop
- ld a, [hli]
- ld [de], a
- inc de
- dec c
- jr nz, .copyWarpDataLoop
- ld a, [hli]
- ld [wCurMapTileset], a
- xor a
- jr .done
-.notFirstMap
- ld a, [wLastMap] ; this value is overwritten before it's ever read
- ld hl, wd732
- bit 4, [hl] ; used dungeon warp (jumped down hole/waterfall)?
- jr nz, .usedDunegonWarp
- bit 6, [hl] ; return to last pokemon center (or player's house)?
- res 6, [hl]
- jr z, .otherDestination
-; return to last pokemon center or player's house
- ld a, [wLastBlackoutMap]
- jr .usedFlyWarp
-.usedDunegonWarp
- ld hl, wd72d
- res 4, [hl]
- ld a, [wDungeonWarpDestinationMap]
- ld b, a
- ld [wCurMap], a
- ld a, [wWhichDungeonWarp]
- ld c, a
- ld hl, DungeonWarpList
- ld de, 0
- ld a, 6
- ld [wDungeonWarpDataEntrySize], a
-.dungeonWarpListLoop
- ld a, [hli]
- cp b
- jr z, .matchedDungeonWarpDestinationMap
- inc hl
- jr .nextDungeonWarp
-.matchedDungeonWarpDestinationMap
- ld a, [hli]
- cp c
- jr z, .matchedDungeonWarpID
-.nextDungeonWarp
- ld a, [wDungeonWarpDataEntrySize]
- add e
- ld e, a
- jr .dungeonWarpListLoop
-.matchedDungeonWarpID
- ld hl, DungeonWarpData
- add hl, de
- jr .copyWarpData2
-.otherDestination
- ld a, [wDestinationMap]
-.usedFlyWarp
- ld b, a
- ld [wCurMap], a
- ld hl, FlyWarpDataPtr
-.flyWarpDataPtrLoop
- ld a, [hli]
- inc hl
- cp b
- jr z, .foundFlyWarpMatch
- inc hl
- inc hl
- jr .flyWarpDataPtrLoop
-.foundFlyWarpMatch
- ld a, [hli]
- ld h, [hl]
- ld l, a
-.copyWarpData2
- ld de, wCurrentTileBlockMapViewPointer
- ld c, $6
-.copyWarpDataLoop2
- ld a, [hli]
- ld [de], a
- inc de
- dec c
- jr nz, .copyWarpDataLoop2
- xor a ; OVERWORLD
- ld [wCurMapTileset], a
-.done
- ld [wYOffsetSinceLastSpecialWarp], a
- ld [wXOffsetSinceLastSpecialWarp], a
- ld a, $ff ; the player's coordinates have already been updated using a special warp, so don't use any of the normal warps
- ld [wDestinationWarpID], a
- ret
-
-INCLUDE "data/special_warps.asm"
--- a/engine/status_ailments.asm
+++ /dev/null
@@ -1,46 +1,0 @@
-PrintStatusAilment::
- ld a, [de]
- bit PSN, a
- jr nz, .psn
- bit BRN, a
- jr nz, .brn
- bit FRZ, a
- jr nz, .frz
- bit PAR, a
- jr nz, .par
- and SLP
- ret z
- ld a, "S"
- ld [hli], a
- ld a, "L"
- ld [hli], a
- ld [hl], "P"
- ret
-.psn
- ld a, "P"
- ld [hli], a
- ld a, "S"
- ld [hli], a
- ld [hl], "N"
- ret
-.brn
- ld a, "B"
- ld [hli], a
- ld a, "R"
- ld [hli], a
- ld [hl], "N"
- ret
-.frz
- ld a, "F"
- ld [hli], a
- ld a, "R"
- ld [hli], a
- ld [hl], "Z"
- ret
-.par
- ld a, "P"
- ld [hli], a
- ld a, "A"
- ld [hli], a
- ld [hl], "R"
- ret
--- a/engine/subtract_paid_money.asm
+++ /dev/null
@@ -1,17 +1,0 @@
-; subtracts the amount the player paid from their money
-; OUTPUT: carry = 0(success) or 1(fail because there is not enough money)
-SubtractAmountPaidFromMoney_::
- ld de, wPlayerMoney
- ld hl, hMoney ; total price of items
- ld c, 3 ; length of money in bytes
- call StringCmp
- ret c
- ld de, wPlayerMoney + 2
- ld hl, hMoney + 2 ; total price of items
- ld c, 3 ; length of money in bytes
- predef SubBCDPredef ; subtract total price from money
- ld a, MONEY_BOX
- ld [wTextBoxID], a
- call DisplayTextBoxID ; redraw money text box
- and a
- ret
--- a/engine/test_battle.asm
+++ /dev/null
@@ -1,45 +1,0 @@
-TestBattle:
- ret
-
-.loop
- call GBPalNormal
-
- ; Don't mess around
- ; with obedience.
- ld a, %10000000 ; EARTHBADGE
- ld [wObtainedBadges], a
-
- ld hl, wFlags_D733
- set BIT_TEST_BATTLE, [hl]
-
- ; Reset the party.
- ld hl, wPartyCount
- xor a
- ld [hli], a
- dec a
- ld [hl], a
-
- ; Give the player a
- ; level 20 Rhydon.
- ld a, RHYDON
- ld [wcf91], a
- ld a, 20
- ld [wCurEnemyLVL], a
- xor a
- ld [wMonDataLocation], a
- ld [wCurMap], a
- call AddPartyMon
-
- ; Fight against a
- ; level 20 Rhydon.
- ld a, RHYDON
- ld [wCurOpponent], a
-
- predef InitOpponent
-
- ; When the battle ends,
- ; do it all again.
- ld a, 1
- ld [wUpdateSpritesEnabled], a
- ld [H_AUTOBGTRANSFERENABLED], a
- jr .loop
--- a/engine/titlescreen.asm
+++ /dev/null
@@ -1,403 +1,0 @@
-; copy text of fixed length NAME_LENGTH (like player name, rival name, mon names, ...)
-CopyFixedLengthText:
- ld bc, NAME_LENGTH
- jp CopyData
-
-SetDefaultNamesBeforeTitlescreen::
- ld hl, NintenText
- ld de, wPlayerName
- call CopyFixedLengthText
- ld hl, SonyText
- ld de, wRivalName
- call CopyFixedLengthText
- xor a
- ld [hWY], a
- ld [wLetterPrintingDelayFlags], a
- ld hl, wd732
- ld [hli], a
- ld [hli], a
- ld [hl], a
- ld a, BANK(Music_TitleScreen)
- ld [wAudioROMBank], a
- ld [wAudioSavedROMBank], a
-
-DisplayTitleScreen:
- call GBPalWhiteOut
- ld a, $1
- ld [H_AUTOBGTRANSFERENABLED], a
- xor a
- ld [hTilesetType], a
- ld [hSCX], a
- ld a, $40
- ld [hSCY], a
- ld a, $90
- ld [hWY], a
- call ClearScreen
- call DisableLCD
- call LoadFontTilePatterns
- ld hl, NintendoCopyrightLogoGraphics
- ld de, vTitleLogo2 + $100
- ld bc, $50
- ld a, BANK(NintendoCopyrightLogoGraphics)
- call FarCopyData2
- ld hl, GamefreakLogoGraphics
- ld de, vTitleLogo2 + $100 + $50
- ld bc, $90
- ld a, BANK(GamefreakLogoGraphics)
- call FarCopyData2
- ld hl, PokemonLogoGraphics
- ld de, vTitleLogo
- ld bc, $600
- ld a, BANK(PokemonLogoGraphics)
- call FarCopyData2 ; first chunk
- ld hl, PokemonLogoGraphics+$600
- ld de, vTitleLogo2
- ld bc, $100
- ld a, BANK(PokemonLogoGraphics)
- call FarCopyData2 ; second chunk
- ld hl, Version_GFX
- ld de, vChars2 + $600 - (Version_GFXEnd - Version_GFX - $50)
- ld bc, Version_GFXEnd - Version_GFX
- ld a, BANK(Version_GFX)
- call FarCopyDataDouble
- call ClearBothBGMaps
-
-; place tiles for pokemon logo (except for the last row)
- coord hl, 2, 1
- ld a, $80
- ld de, SCREEN_WIDTH
- ld c, 6
-.pokemonLogoTileLoop
- ld b, $10
- push hl
-.pokemonLogoTileRowLoop ; place tiles for one row
- ld [hli], a
- inc a
- dec b
- jr nz, .pokemonLogoTileRowLoop
- pop hl
- add hl, de
- dec c
- jr nz, .pokemonLogoTileLoop
-
-; place tiles for the last row of the pokemon logo
- coord hl, 2, 7
- ld a, $31
- ld b, $10
-.pokemonLogoLastTileRowLoop
- ld [hli], a
- inc a
- dec b
- jr nz, .pokemonLogoLastTileRowLoop
-
- call DrawPlayerCharacter
-
-; put a pokeball in the player's hand
- ld hl, wOAMBuffer + $28
- ld a, $74
- ld [hl], a
-
-; place tiles for title screen copyright
- coord hl, 2, 17
- ld de, .tileScreenCopyrightTiles
- ld b, $10
-.tileScreenCopyrightTilesLoop
- ld a, [de]
- ld [hli], a
- inc de
- dec b
- jr nz, .tileScreenCopyrightTilesLoop
-
- jr .next
-
-.tileScreenCopyrightTiles
- db $41,$42,$43,$42,$44,$42,$45,$46,$47,$48,$49,$4A,$4B,$4C,$4D,$4E ; ©'95.'96.'98 GAME FREAK inc.
-
-.next
- call SaveScreenTilesToBuffer2
- call LoadScreenTilesFromBuffer2
- call EnableLCD
-IF DEF(_RED)
- ld a, CHARMANDER ; which Pokemon to show first on the title screen
-ENDC
-IF DEF(_BLUE)
- ld a, SQUIRTLE ; which Pokemon to show first on the title screen
-ENDC
-
- ld [wTitleMonSpecies], a
- call LoadTitleMonSprite
- ld a, (vBGMap0 + $300) / $100
- call TitleScreenCopyTileMapToVRAM
- call SaveScreenTilesToBuffer1
- ld a, $40
- ld [hWY], a
- call LoadScreenTilesFromBuffer2
- ld a, vBGMap0 / $100
- call TitleScreenCopyTileMapToVRAM
- ld b, SET_PAL_TITLE_SCREEN
- call RunPaletteCommand
- call GBPalNormal
- ld a, %11100100
- ld [rOBP0], a
-
-; make pokemon logo bounce up and down
- ld bc, hSCY ; background scroll Y
- ld hl, .TitleScreenPokemonLogoYScrolls
-.bouncePokemonLogoLoop
- ld a, [hli]
- and a
- jr z, .finishedBouncingPokemonLogo
- ld d, a
- cp -3
- jr nz, .skipPlayingSound
- ld a, SFX_INTRO_CRASH
- call PlaySound
-.skipPlayingSound
- ld a, [hli]
- ld e, a
- call .ScrollTitleScreenPokemonLogo
- jr .bouncePokemonLogoLoop
-
-.TitleScreenPokemonLogoYScrolls:
-; Controls the bouncing effect of the Pokemon logo on the title screen
- db -4,16 ; y scroll amount, number of times to scroll
- db 3,4
- db -3,4
- db 2,2
- db -2,2
- db 1,2
- db -1,2
- db 0 ; terminate list with 0
-
-.ScrollTitleScreenPokemonLogo:
-; Scrolls the Pokemon logo on the title screen to create the bouncing effect
-; Scrolls d pixels e times
- call DelayFrame
- ld a, [bc] ; background scroll Y
- add d
- ld [bc], a
- dec e
- jr nz, .ScrollTitleScreenPokemonLogo
- ret
-
-.finishedBouncingPokemonLogo
- call LoadScreenTilesFromBuffer1
- ld c, 36
- call DelayFrames
- ld a, SFX_INTRO_WHOOSH
- call PlaySound
-
-; scroll game version in from the right
- call PrintGameVersionOnTitleScreen
- ld a, SCREEN_HEIGHT_PIXELS
- ld [hWY], a
- ld d, 144
-.scrollTitleScreenGameVersionLoop
- ld h, d
- ld l, 64
- call ScrollTitleScreenGameVersion
- ld h, 0
- ld l, 80
- call ScrollTitleScreenGameVersion
- ld a, d
- add 4
- ld d, a
- and a
- jr nz, .scrollTitleScreenGameVersionLoop
-
- ld a, vBGMap1 / $100
- call TitleScreenCopyTileMapToVRAM
- call LoadScreenTilesFromBuffer2
- call PrintGameVersionOnTitleScreen
- call Delay3
- call WaitForSoundToFinish
- ld a, MUSIC_TITLE_SCREEN
- ld [wNewSoundID], a
- call PlaySound
- xor a
- ld [wUnusedCC5B], a
-
-; Keep scrolling in new mons indefinitely until the user performs input.
-.awaitUserInterruptionLoop
- ld c, 200
- call CheckForUserInterruption
- jr c, .finishedWaiting
- call TitleScreenScrollInMon
- ld c, 1
- call CheckForUserInterruption
- jr c, .finishedWaiting
- callba TitleScreenAnimateBallIfStarterOut
- call TitleScreenPickNewMon
- jr .awaitUserInterruptionLoop
-
-.finishedWaiting
- ld a, [wTitleMonSpecies]
- call PlayCry
- call WaitForSoundToFinish
- call GBPalWhiteOutWithDelay3
- call ClearSprites
- xor a
- ld [hWY], a
- inc a
- ld [H_AUTOBGTRANSFERENABLED], a
- call ClearScreen
- ld a, vBGMap0 / $100
- call TitleScreenCopyTileMapToVRAM
- ld a, vBGMap1 / $100
- call TitleScreenCopyTileMapToVRAM
- call Delay3
- call LoadGBPal
- ld a, [hJoyHeld]
- ld b, a
- and D_UP | SELECT | B_BUTTON
- cp D_UP | SELECT | B_BUTTON
- jp z, .doClearSaveDialogue
- jp MainMenu
-
-.doClearSaveDialogue
- jpba DoClearSaveDialogue
-
-TitleScreenPickNewMon:
- ld a, vBGMap0 / $100
- call TitleScreenCopyTileMapToVRAM
-
-.loop
-; Keep looping until a mon different from the current one is picked.
- call Random
- and $f
- ld c, a
- ld b, 0
- ld hl, TitleMons
- add hl, bc
- ld a, [hl]
- ld hl, wTitleMonSpecies
-
-; Can't be the same as before.
- cp [hl]
- jr z, .loop
-
- ld [hl], a
- call LoadTitleMonSprite
-
- ld a, $90
- ld [hWY], a
- ld d, 1 ; scroll out
- callba TitleScroll
- ret
-
-TitleScreenScrollInMon:
- ld d, 0 ; scroll in
- callba TitleScroll
- xor a
- ld [hWY], a
- ret
-
-ScrollTitleScreenGameVersion:
-.wait
- ld a, [rLY]
- cp l
- jr nz, .wait
-
- ld a, h
- ld [rSCX], a
-
-.wait2
- ld a, [rLY]
- cp h
- jr z, .wait2
- ret
-
-DrawPlayerCharacter:
- ld hl, PlayerCharacterTitleGraphics
- ld de, vSprites
- ld bc, PlayerCharacterTitleGraphicsEnd - PlayerCharacterTitleGraphics
- ld a, BANK(PlayerCharacterTitleGraphics)
- call FarCopyData2
- call ClearSprites
- xor a
- ld [wPlayerCharacterOAMTile], a
- ld hl, wOAMBuffer
- ld de, $605a
- ld b, 7
-.loop
- push de
- ld c, 5
-.innerLoop
- ld a, d
- ld [hli], a ; Y
- ld a, e
- ld [hli], a ; X
- add 8
- ld e, a
- ld a, [wPlayerCharacterOAMTile]
- ld [hli], a ; tile
- inc a
- ld [wPlayerCharacterOAMTile], a
- inc hl
- dec c
- jr nz, .innerLoop
- pop de
- ld a, 8
- add d
- ld d, a
- dec b
- jr nz, .loop
- ret
-
-ClearBothBGMaps:
- ld hl, vBGMap0
- ld bc, $400 * 2
- ld a, " "
- jp FillMemory
-
-LoadTitleMonSprite:
- ld [wcf91], a
- ld [wd0b5], a
- coord hl, 5, 10
- call GetMonHeader
- jp LoadFrontSpriteByMonIndex
-
-TitleScreenCopyTileMapToVRAM:
- ld [H_AUTOBGTRANSFERDEST + 1], a
- jp Delay3
-
-LoadCopyrightAndTextBoxTiles:
- xor a
- ld [hWY], a
- call ClearScreen
- call LoadTextBoxTilePatterns
-
-LoadCopyrightTiles:
- ld de, NintendoCopyrightLogoGraphics
- ld hl, vChars2 + $600
- lb bc, BANK(NintendoCopyrightLogoGraphics), (GamefreakLogoGraphicsEnd - NintendoCopyrightLogoGraphics) / $10
- call CopyVideoData
- coord hl, 2, 7
- ld de, CopyrightTextString
- jp PlaceString
-
-CopyrightTextString:
- db $60,$61,$62,$61,$63,$61,$64,$7F,$65,$66,$67,$68,$69,$6A ; ©'95.'96.'98 Nintendo
- next $60,$61,$62,$61,$63,$61,$64,$7F,$6B,$6C,$6D,$6E,$6F,$70,$71,$72 ; ©'95.'96.'98 Creatures inc.
- next $60,$61,$62,$61,$63,$61,$64,$7F,$73,$74,$75,$76,$77,$78,$79,$7A,$7B ; ©'95.'96.'98 GAME FREAK inc.
- db "@"
-
-INCLUDE "data/title_mons.asm"
-
-; prints version text (red, blue)
-PrintGameVersionOnTitleScreen:
- coord hl, 7, 8
- ld de, VersionOnTitleScreenText
- jp PlaceString
-
-; these point to special tiles specifically loaded for that purpose and are not usual text
-VersionOnTitleScreenText:
-IF DEF(_RED)
- db $60,$61,$7F,$65,$66,$67,$68,$69,"@" ; "Red Version"
-ENDC
-IF DEF(_BLUE)
- db $61,$62,$63,$64,$65,$66,$67,$68,"@" ; "Blue Version"
-ENDC
-
-NintenText: db "NINTEN@"
-SonyText: db "SONY@"
--- a/engine/titlescreen2.asm
+++ /dev/null
@@ -1,120 +1,0 @@
-TitleScroll_WaitBall:
-; Wait around for the TitleBall animation to play out.
-; hi: speed
-; lo: duration
- db $05, $05, 0
-
-TitleScroll_In:
-; Scroll a TitleMon in from the right.
-; hi: speed
-; lo: duration
- db $a2, $94, $84, $63, $52, $31, $11, 0
-
-TitleScroll_Out:
-; Scroll a TitleMon out to the left.
-; hi: speed
-; lo: duration
- db $12, $22, $32, $42, $52, $62, $83, $93, 0
-
-TitleScroll:
- ld a, d
-
- ld bc, TitleScroll_In
- ld d, $88
- ld e, 0 ; don't animate titleball
-
- and a
- jr nz, .ok
-
- ld bc, TitleScroll_Out
- ld d, $00
- ld e, 0 ; don't animate titleball
-.ok
-
-_TitleScroll:
- ld a, [bc]
- and a
- ret z
-
- inc bc
- push bc
-
- ld b, a
- and $f
- ld c, a
- ld a, b
- and $f0
- swap a
- ld b, a
-
-.loop
- ld h, d
- ld l, $48
- call .ScrollBetween
-
- ld h, $00
- ld l, $88
- call .ScrollBetween
-
- ld a, d
- add b
- ld d, a
-
- call GetTitleBallY
- dec c
- jr nz, .loop
-
- pop bc
- jr _TitleScroll
-
-.ScrollBetween:
-.wait
- ld a, [rLY] ; rLY
- cp l
- jr nz, .wait
-
- ld a, h
- ld [rSCX], a
-
-.wait2
- ld a, [rLY] ; rLY
- cp h
- jr z, .wait2
- ret
-
-TitleBallYTable:
-; OBJ y-positions for the Poke Ball held by Red in the title screen.
-; This is really two 0-terminated lists. Initiated with an index of 1.
- db 0, $71, $6f, $6e, $6d, $6c, $6d, $6e, $6f, $71, $74, 0
-
-TitleScreenAnimateBallIfStarterOut:
-; Animate the TitleBall if a starter just got scrolled out.
- ld a, [wTitleMonSpecies]
- cp STARTER1
- jr z, .ok
- cp STARTER2
- jr z, .ok
- cp STARTER3
- ret nz
-.ok
- ld e, 1 ; animate titleball
- ld bc, TitleScroll_WaitBall
- ld d, 0
- jp _TitleScroll
-
-GetTitleBallY:
-; Get position e from TitleBallYTable
- push de
- push hl
- xor a
- ld d, a
- ld hl, TitleBallYTable
- add hl, de
- ld a, [hl]
- pop hl
- pop de
- and a
- ret z
- ld [wOAMBuffer + $28], a
- inc e
- ret
--- a/engine/town_map.asm
+++ /dev/null
@@ -1,618 +1,0 @@
-DisplayTownMap:
- call LoadTownMap
- ld hl, wUpdateSpritesEnabled
- ld a, [hl]
- push af
- ld [hl], $ff
- push hl
- ld a, $1
- ld [hJoy7], a
- ld a, [wCurMap]
- push af
- ld b, $0
- call DrawPlayerOrBirdSprite ; player sprite
- coord hl, 1, 0
- ld de, wcd6d
- call PlaceString
- ld hl, wOAMBuffer
- ld de, wTileMapBackup
- ld bc, $10
- call CopyData
- ld hl, vSprites + $40
- ld de, TownMapCursor
- lb bc, BANK(TownMapCursor), (TownMapCursorEnd - TownMapCursor) / $8
- call CopyVideoDataDouble
- xor a
- ld [wWhichTownMapLocation], a
- pop af
- jr .enterLoop
-
-.townMapLoop
- coord hl, 0, 0
- lb bc, 1, 20
- call ClearScreenArea
- ld hl, TownMapOrder
- ld a, [wWhichTownMapLocation]
- ld c, a
- ld b, 0
- add hl, bc
- ld a, [hl]
-.enterLoop
- ld de, wTownMapCoords
- call LoadTownMapEntry
- ld a, [de]
- push hl
- call TownMapCoordsToOAMCoords
- ld a, $4
- ld [wOAMBaseTile], a
- ld hl, wOAMBuffer + $10
- call WriteTownMapSpriteOAM ; town map cursor sprite
- pop hl
- ld de, wcd6d
-.copyMapName
- ld a, [hli]
- ld [de], a
- inc de
- cp $50
- jr nz, .copyMapName
- coord hl, 1, 0
- ld de, wcd6d
- call PlaceString
- ld hl, wOAMBuffer + $10
- ld de, wTileMapBackup + 16
- ld bc, $10
- call CopyData
-.inputLoop
- call TownMapSpriteBlinkingAnimation
- call JoypadLowSensitivity
- ld a, [hJoy5]
- ld b, a
- and A_BUTTON | B_BUTTON | D_UP | D_DOWN
- jr z, .inputLoop
- ld a, SFX_TINK
- call PlaySound
- bit 6, b
- jr nz, .pressedUp
- bit 7, b
- jr nz, .pressedDown
- xor a
- ld [wTownMapSpriteBlinkingEnabled], a
- ld [hJoy7], a
- ld [wAnimCounter], a
- call ExitTownMap
- pop hl
- pop af
- ld [hl], a
- ret
-.pressedUp
- ld a, [wWhichTownMapLocation]
- inc a
- cp TownMapOrderEnd - TownMapOrder ; number of list items + 1
- jr nz, .noOverflow
- xor a
-.noOverflow
- ld [wWhichTownMapLocation], a
- jp .townMapLoop
-.pressedDown
- ld a, [wWhichTownMapLocation]
- dec a
- cp -1
- jr nz, .noUnderflow
- ld a, TownMapOrderEnd - TownMapOrder - 1 ; number of list items
-.noUnderflow
- ld [wWhichTownMapLocation], a
- jp .townMapLoop
-
-INCLUDE "data/town_map_order.asm"
-
-TownMapCursor:
- INCBIN "gfx/town_map/town_map_cursor.1bpp"
-TownMapCursorEnd:
-
-LoadTownMap_Nest:
- call LoadTownMap
- ld hl, wUpdateSpritesEnabled
- ld a, [hl]
- push af
- ld [hl], $ff
- push hl
- call DisplayWildLocations
- call GetMonName
- coord hl, 1, 0
- call PlaceString
- ld h, b
- ld l, c
- ld de, MonsNestText
- call PlaceString
- call WaitForTextScrollButtonPress
- call ExitTownMap
- pop hl
- pop af
- ld [hl], a
- ret
-
-MonsNestText:
- db "'s NEST@"
-
-LoadTownMap_Fly::
- call ClearSprites
- call LoadTownMap
- call LoadPlayerSpriteGraphics
- call LoadFontTilePatterns
- ld de, BirdSprite
- ld hl, vSprites + $40
- lb bc, BANK(BirdSprite), $c
- call CopyVideoData
- ld de, TownMapUpArrow
- ld hl, vChars1 + $6d0
- lb bc, BANK(TownMapUpArrow), (TownMapUpArrowEnd - TownMapUpArrow) / $8
- call CopyVideoDataDouble
- call BuildFlyLocationsList
- ld hl, wUpdateSpritesEnabled
- ld a, [hl]
- push af
- ld [hl], $ff
- push hl
- coord hl, 0, 0
- ld de, ToText
- call PlaceString
- ld a, [wCurMap]
- ld b, $0
- call DrawPlayerOrBirdSprite
- ld hl, wFlyLocationsList
- coord de, 18, 0
-.townMapFlyLoop
- ld a, " "
- ld [de], a
- push hl
- push hl
- coord hl, 3, 0
- lb bc, 1, 15
- call ClearScreenArea
- pop hl
- ld a, [hl]
- ld b, $4
- call DrawPlayerOrBirdSprite ; draw bird sprite
- coord hl, 3, 0
- ld de, wcd6d
- call PlaceString
- ld c, 15
- call DelayFrames
- coord hl, 18, 0
- ld [hl], "▲"
- coord hl, 19, 0
- ld [hl], "▼"
- pop hl
-.inputLoop
- push hl
- call DelayFrame
- call JoypadLowSensitivity
- ld a, [hJoy5]
- ld b, a
- pop hl
- and A_BUTTON | B_BUTTON | D_UP | D_DOWN
- jr z, .inputLoop
- bit 0, b
- jr nz, .pressedA
- ld a, SFX_TINK
- call PlaySound
- bit 6, b
- jr nz, .pressedUp
- bit 7, b
- jr nz, .pressedDown
- jr .pressedB
-.pressedA
- ld a, SFX_HEAL_AILMENT
- call PlaySound
- ld a, [hl]
- ld [wDestinationMap], a
- ld hl, wd732
- set 3, [hl]
- inc hl
- set 7, [hl]
-.pressedB
- xor a
- ld [wTownMapSpriteBlinkingEnabled], a
- call GBPalWhiteOutWithDelay3
- pop hl
- pop af
- ld [hl], a
- ret
-.pressedUp
- coord de, 18, 0
- inc hl
- ld a, [hl]
- cp $ff
- jr z, .wrapToStartOfList
- cp $fe
- jr z, .pressedUp ; skip past unvisited towns
- jp .townMapFlyLoop
-.wrapToStartOfList
- ld hl, wFlyLocationsList
- jp .townMapFlyLoop
-.pressedDown
- coord de, 19, 0
- dec hl
- ld a, [hl]
- cp $ff
- jr z, .wrapToEndOfList
- cp $fe
- jr z, .pressedDown ; skip past unvisited towns
- jp .townMapFlyLoop
-.wrapToEndOfList
- ld hl, wFlyLocationsList + 11
- jr .pressedDown
-
-ToText:
- db "To@"
-
-BuildFlyLocationsList:
- ld hl, wFlyLocationsList - 1
- ld [hl], $ff
- inc hl
- ld a, [wTownVisitedFlag]
- ld e, a
- ld a, [wTownVisitedFlag + 1]
- ld d, a
- ld bc, SAFFRON_CITY + 1
-.loop
- srl d
- rr e
- ld a, $fe ; store $fe if the town hasn't been visited
- jr nc, .notVisited
- ld a, b ; store the map number of the town if it has been visited
-.notVisited
- ld [hl], a
- inc hl
- inc b
- dec c
- jr nz, .loop
- ld [hl], $ff
- ret
-
-TownMapUpArrow:
- INCBIN "gfx/town_map/up_arrow.1bpp"
-TownMapUpArrowEnd:
-
-LoadTownMap:
- call GBPalWhiteOutWithDelay3
- call ClearScreen
- call UpdateSprites
- coord hl, 0, 0
- ld b, $12
- ld c, $12
- call TextBoxBorder
- call DisableLCD
- ld hl, WorldMapTileGraphics
- ld de, vChars2 + $600
- ld bc, WorldMapTileGraphicsEnd - WorldMapTileGraphics
- ld a, BANK(WorldMapTileGraphics)
- call FarCopyData2
- ld hl, MonNestIcon
- ld de, vSprites + $40
- ld bc, MonNestIconEnd - MonNestIcon
- ld a, BANK(MonNestIcon)
- call FarCopyDataDouble
- coord hl, 0, 0
- ld de, CompressedMap
-.nextTile
- ld a, [de]
- and a
- jr z, .done
- ld b, a
- and $f
- ld c, a
- ld a, b
- swap a
- and $f
- add $60
-.writeRunLoop
- ld [hli], a
- dec c
- jr nz, .writeRunLoop
- inc de
- jr .nextTile
-.done
- call EnableLCD
- ld b, SET_PAL_TOWN_MAP
- call RunPaletteCommand
- call Delay3
- call GBPalNormal
- xor a
- ld [wAnimCounter], a
- inc a
- ld [wTownMapSpriteBlinkingEnabled], a
- ret
-
-CompressedMap:
- INCBIN "gfx/town_map/town_map.rle"
-
-ExitTownMap:
-; clear town map graphics data and load usual graphics data
- xor a
- ld [wTownMapSpriteBlinkingEnabled], a
- call GBPalWhiteOut
- call ClearScreen
- call ClearSprites
- call LoadPlayerSpriteGraphics
- call LoadFontTilePatterns
- call UpdateSprites
- jp RunDefaultPaletteCommand
-
-DrawPlayerOrBirdSprite:
-; a = map number
-; b = OAM base tile
- push af
- ld a, b
- ld [wOAMBaseTile], a
- pop af
- ld de, wTownMapCoords
- call LoadTownMapEntry
- ld a, [de]
- push hl
- call TownMapCoordsToOAMCoords
- call WritePlayerOrBirdSpriteOAM
- pop hl
- ld de, wcd6d
-.loop
- ld a, [hli]
- ld [de], a
- inc de
- cp "@"
- jr nz, .loop
- ld hl, wOAMBuffer
- ld de, wTileMapBackup
- ld bc, $a0
- jp CopyData
-
-DisplayWildLocations:
- callba FindWildLocationsOfMon
- call ZeroOutDuplicatesInList
- ld hl, wOAMBuffer
- ld de, wTownMapCoords
-.loop
- ld a, [de]
- cp $ff
- jr z, .exitLoop
- and a
- jr z, .nextEntry
- push hl
- call LoadTownMapEntry
- pop hl
- ld a, [de]
- cp $19 ; Cerulean Cave's coordinates
- jr z, .nextEntry ; skip Cerulean Cave
- call TownMapCoordsToOAMCoords
- ld a, $4 ; nest icon tile no.
- ld [hli], a
- xor a
- ld [hli], a
-.nextEntry
- inc de
- jr .loop
-.exitLoop
- ld a, l
- and a ; were any OAM entries written?
- jr nz, .drawPlayerSprite
-; if no OAM entries were written, print area unknown text
- coord hl, 1, 7
- ld b, 2
- ld c, 15
- call TextBoxBorder
- coord hl, 2, 9
- ld de, AreaUnknownText
- call PlaceString
- jr .done
-.drawPlayerSprite
- ld a, [wCurMap]
- ld b, $0
- call DrawPlayerOrBirdSprite
-.done
- ld hl, wOAMBuffer
- ld de, wTileMapBackup
- ld bc, $a0
- jp CopyData
-
-AreaUnknownText:
- db " AREA UNKNOWN@"
-
-TownMapCoordsToOAMCoords:
-; in: lower nybble of a = x, upper nybble of a = y
-; out: b and [hl] = (y * 8) + 24, c and [hl+1] = (x * 8) + 24
- push af
- and $f0
- srl a
- add 24
- ld b, a
- ld [hli], a
- pop af
- and $f
- swap a
- srl a
- add 24
- ld c, a
- ld [hli], a
- ret
-
-WritePlayerOrBirdSpriteOAM:
- ld a, [wOAMBaseTile]
- and a
- ld hl, wOAMBuffer + $90 ; for player sprite
- jr z, WriteTownMapSpriteOAM
- ld hl, wOAMBuffer + $80 ; for bird sprite
-
-WriteTownMapSpriteOAM:
- push hl
-
-; Subtract 4 from c (X coord) and 4 from b (Y coord). However, the carry from c
-; is added to b, so the net result is that only 3 is subtracted from b.
- lb hl, -4, -4
- add hl, bc
-
- ld b, h
- ld c, l
- pop hl
-
-WriteAsymmetricMonPartySpriteOAM:
-; Writes 4 OAM blocks for a helix mon party sprite, since it does not have
-; a vertical line of symmetry.
- lb de, 2, 2
-.loop
- push de
- push bc
-.innerLoop
- ld a, b
- ld [hli], a
- ld a, c
- ld [hli], a
- ld a, [wOAMBaseTile]
- ld [hli], a
- inc a
- ld [wOAMBaseTile], a
- xor a
- ld [hli], a
- inc d
- ld a, 8
- add c
- ld c, a
- dec e
- jr nz, .innerLoop
- pop bc
- pop de
- ld a, 8
- add b
- ld b, a
- dec d
- jr nz, .loop
- ret
-
-WriteSymmetricMonPartySpriteOAM:
-; Writes 4 OAM blocks for a mon party sprite other than a helix. All the
-; sprites other than the helix one have a vertical line of symmetry which allows
-; the X-flip OAM bit to be used so that only 2 rather than 4 tile patterns are
-; needed.
- xor a
- ld [wSymmetricSpriteOAMAttributes], a
- lb de, 2, 2
-.loop
- push de
- push bc
-.innerLoop
- ld a, b
- ld [hli], a ; Y
- ld a, c
- ld [hli], a ; X
- ld a, [wOAMBaseTile]
- ld [hli], a ; tile
- ld a, [wSymmetricSpriteOAMAttributes]
- ld [hli], a ; attributes
- xor (1 << OAM_X_FLIP)
- ld [wSymmetricSpriteOAMAttributes], a
- inc d
- ld a, 8
- add c
- ld c, a
- dec e
- jr nz, .innerLoop
- pop bc
- pop de
- push hl
- ld hl, wOAMBaseTile
- inc [hl]
- inc [hl]
- pop hl
- ld a, 8
- add b
- ld b, a
- dec d
- jr nz, .loop
- ret
-
-ZeroOutDuplicatesInList:
-; replace duplicate bytes in the list of wild pokemon locations with 0
- ld de, wBuffer
-.loop
- ld a, [de]
- inc de
- cp $ff
- ret z
- ld c, a
- ld l, e
- ld h, d
-.zeroDuplicatesLoop
- ld a, [hl]
- cp $ff
- jr z, .loop
- cp c
- jr nz, .skipZeroing
- xor a
- ld [hl], a
-.skipZeroing
- inc hl
- jr .zeroDuplicatesLoop
-
-LoadTownMapEntry:
-; in: a = map number
-; out: lower nybble of [de] = x, upper nybble of [de] = y, hl = address of name
- cp REDS_HOUSE_1F
- jr c, .external
- ld bc, 4
- ld hl, InternalMapEntries
-.loop
- cp [hl]
- jr c, .foundEntry
- add hl, bc
- jr .loop
-.foundEntry
- inc hl
- jr .readEntry
-.external
- ld hl, ExternalMapEntries
- ld c, a
- ld b, 0
- add hl, bc
- add hl, bc
- add hl, bc
-.readEntry
- ld a, [hli]
- ld [de], a
- ld a, [hli]
- ld h, [hl]
- ld l, a
- ret
-
-INCLUDE "data/town_map_entries.asm"
-
-INCLUDE "text/map_names.asm"
-
-MonNestIcon:
- INCBIN "gfx/town_map/mon_nest_icon.1bpp"
-MonNestIconEnd:
-
-TownMapSpriteBlinkingAnimation::
- ld a, [wAnimCounter]
- inc a
- cp 25
- jr z, .hideSprites
- cp 50
- jr nz, .done
-; show sprites when the counter reaches 50
- ld hl, wTileMapBackup
- ld de, wOAMBuffer
- ld bc, $90
- call CopyData
- xor a
- jr .done
-.hideSprites
- ld hl, wOAMBuffer
- ld b, $24
- ld de, $4
-.hideSpritesLoop
- ld [hl], $a0
- add hl, de
- dec b
- jr nz, .hideSpritesLoop
- ld a, 25
-.done
- ld [wAnimCounter], a
- jp DelayFrame
--- a/engine/trade.asm
+++ /dev/null
@@ -1,853 +1,0 @@
-InternalClockTradeAnim:
-; Do the trading animation with the player's gameboy on the left.
-; In-game trades and internally clocked link cable trades use this.
- ld a, [wTradedPlayerMonSpecies]
- ld [wLeftGBMonSpecies], a
- ld a, [wTradedEnemyMonSpecies]
- ld [wRightGBMonSpecies], a
- ld de, InternalClockTradeFuncSequence
- jr TradeAnimCommon
-
-ExternalClockTradeAnim:
-; Do the trading animation with the player's gameboy on the right.
-; Externally clocked link cable trades use this.
- ld a, [wTradedEnemyMonSpecies]
- ld [wLeftGBMonSpecies], a
- ld a, [wTradedPlayerMonSpecies]
- ld [wRightGBMonSpecies], a
- ld de, ExternalClockTradeFuncSequence
-
-TradeAnimCommon:
- ld a, [wOptions]
- push af
- ld a, [hSCY]
- push af
- ld a, [hSCX]
- push af
- xor a
- ld [wOptions], a
- ld [hSCY], a
- ld [hSCX], a
- push de
-.loop
- pop de
- ld a, [de]
- cp $ff
- jr z, .done
- inc de
- push de
- ld hl, TradeFuncPointerTable
- add a
- ld c, a
- ld b, $0
- add hl, bc
- ld a, [hli]
- ld h, [hl]
- ld l, a
- ld de, .loop
- push de
- jp hl ; call trade func, which will return to the top of the loop
-.done
- pop af
- ld [hSCX], a
- pop af
- ld [hSCY], a
- pop af
- ld [wOptions], a
- ret
-
-addtradefunc: MACRO
-\1TradeFunc::
- dw \1
- ENDM
-
-tradefunc: MACRO
- db (\1TradeFunc - TradeFuncPointerTable) / 2
- ENDM
-
-; The functions in the sequences below are executed in order by TradeFuncCommon.
-; They are from opposite perspectives. The external clock one makes use of
-; Trade_SwapNames to swap the player and enemy names for some functions.
-
-InternalClockTradeFuncSequence:
- tradefunc LoadTradingGFXAndMonNames
- tradefunc Trade_ShowPlayerMon
- tradefunc Trade_DrawOpenEndOfLinkCable
- tradefunc Trade_AnimateBallEnteringLinkCable
- tradefunc Trade_AnimLeftToRight
- tradefunc Trade_Delay100
- tradefunc Trade_ShowClearedWindow
- tradefunc PrintTradeWentToText
- tradefunc PrintTradeForSendsText
- tradefunc PrintTradeFarewellText
- tradefunc Trade_AnimRightToLeft
- tradefunc Trade_ShowClearedWindow
- tradefunc Trade_DrawOpenEndOfLinkCable
- tradefunc Trade_ShowEnemyMon
- tradefunc Trade_Delay100
- tradefunc Trade_Cleanup
- db $FF
-
-ExternalClockTradeFuncSequence:
- tradefunc LoadTradingGFXAndMonNames
- tradefunc Trade_ShowClearedWindow
- tradefunc PrintTradeWillTradeText
- tradefunc PrintTradeFarewellText
- tradefunc Trade_SwapNames
- tradefunc Trade_AnimLeftToRight
- tradefunc Trade_SwapNames
- tradefunc Trade_ShowClearedWindow
- tradefunc Trade_DrawOpenEndOfLinkCable
- tradefunc Trade_ShowEnemyMon
- tradefunc Trade_SlideTextBoxOffScreen
- tradefunc Trade_ShowPlayerMon
- tradefunc Trade_DrawOpenEndOfLinkCable
- tradefunc Trade_AnimateBallEnteringLinkCable
- tradefunc Trade_SwapNames
- tradefunc Trade_AnimRightToLeft
- tradefunc Trade_SwapNames
- tradefunc Trade_Delay100
- tradefunc Trade_ShowClearedWindow
- tradefunc PrintTradeWentToText
- tradefunc Trade_Cleanup
- db $FF
-
-TradeFuncPointerTable:
- addtradefunc LoadTradingGFXAndMonNames
- addtradefunc Trade_ShowPlayerMon
- addtradefunc Trade_DrawOpenEndOfLinkCable
- addtradefunc Trade_AnimateBallEnteringLinkCable
- addtradefunc Trade_ShowEnemyMon
- addtradefunc Trade_AnimLeftToRight
- addtradefunc Trade_AnimRightToLeft
- addtradefunc Trade_Delay100
- addtradefunc Trade_ShowClearedWindow
- addtradefunc PrintTradeWentToText
- addtradefunc PrintTradeForSendsText
- addtradefunc PrintTradeFarewellText
- addtradefunc PrintTradeTakeCareText
- addtradefunc PrintTradeWillTradeText
- addtradefunc Trade_Cleanup
- addtradefunc Trade_SlideTextBoxOffScreen
- addtradefunc Trade_SwapNames
-
-Trade_Delay100:
- ld c, 100
- jp DelayFrames
-
-Trade_CopyTileMapToVRAM:
- ld a, $1
- ld [H_AUTOBGTRANSFERENABLED], a
- call Delay3
- xor a
- ld [H_AUTOBGTRANSFERENABLED], a
- ret
-
-Trade_Delay80:
- ld c, 80
- jp DelayFrames
-
-Trade_ClearTileMap:
- coord hl, 0, 0
- ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
- ld a, " "
- jp FillMemory
-
-LoadTradingGFXAndMonNames:
- call Trade_ClearTileMap
- call DisableLCD
- ld hl, TradingAnimationGraphics
- ld de, vChars2 + $310
- ld bc, TradingAnimationGraphicsEnd - TradingAnimationGraphics
- ld a, BANK(TradingAnimationGraphics)
- call FarCopyData2
- ld hl, TradingAnimationGraphics2
- ld de, vSprites + $7c0
- ld bc, TradingAnimationGraphics2End - TradingAnimationGraphics2
- ld a, BANK(TradingAnimationGraphics2)
- call FarCopyData2
- ld hl, vBGMap0
- ld bc, $800
- ld a, " "
- call FillMemory
- call ClearSprites
- ld a, $ff
- ld [wUpdateSpritesEnabled], a
- ld hl, wd730
- set 6, [hl] ; turn on instant text printing
- ld a, [wOnSGB]
- and a
- ld a, $e4 ; non-SGB OBP0
- jr z, .next
- ld a, $f0 ; SGB OBP0
-.next
- ld [rOBP0], a
- call EnableLCD
- xor a
- ld [H_AUTOBGTRANSFERENABLED], a
- ld a, [wTradedPlayerMonSpecies]
- ld [wd11e], a
- call GetMonName
- ld hl, wcd6d
- ld de, wcf4b
- ld bc, NAME_LENGTH
- call CopyData
- ld a, [wTradedEnemyMonSpecies]
- ld [wd11e], a
- jp GetMonName
-
-Trade_LoadMonPartySpriteGfx:
- ld a, %11010000
- ld [rOBP1], a
- jpba LoadMonPartySpriteGfx
-
-Trade_SwapNames:
- ld hl, wPlayerName
- ld de, wBuffer
- ld bc, NAME_LENGTH
- call CopyData
- ld hl, wLinkEnemyTrainerName
- ld de, wPlayerName
- ld bc, NAME_LENGTH
- call CopyData
- ld hl, wBuffer
- ld de, wLinkEnemyTrainerName
- ld bc, NAME_LENGTH
- jp CopyData
-
-Trade_Cleanup:
- xor a
- call LoadGBPal
- ld hl, wd730
- res 6, [hl] ; turn off instant text printing
- ret
-
-Trade_ShowPlayerMon:
- ld a, %10101011
- ld [rLCDC], a
- ld a, $50
- ld [hWY], a
- ld a, $86
- ld [rWX], a
- ld [hSCX], a
- xor a
- ld [H_AUTOBGTRANSFERENABLED], a
- coord hl, 4, 0
- ld b, 6
- ld c, 10
- call TextBoxBorder
- call Trade_PrintPlayerMonInfoText
- ld b, vBGMap0 / $100
- call CopyScreenTileBufferToVRAM
- call ClearScreen
- ld a, [wTradedPlayerMonSpecies]
- call Trade_LoadMonSprite
- ld a, $7e
-.slideScreenLoop
- push af
- call DelayFrame
- pop af
- ld [rWX], a
- ld [hSCX], a
- dec a
- dec a
- and a
- jr nz, .slideScreenLoop
- call Trade_Delay80
- ld a, TRADE_BALL_POOF_ANIM
- call Trade_ShowAnimation
- ld a, TRADE_BALL_DROP_ANIM
- call Trade_ShowAnimation ; clears mon pic
- ld a, [wTradedPlayerMonSpecies]
- call PlayCry
- xor a
- ld [H_AUTOBGTRANSFERENABLED], a
- ret
-
-Trade_DrawOpenEndOfLinkCable:
- call Trade_ClearTileMap
- ld b, vBGMap0 / $100
- call CopyScreenTileBufferToVRAM
- ld b, SET_PAL_GENERIC
- call RunPaletteCommand
-
-; This function call is pointless. It just copies blank tiles to VRAM that was
-; already filled with blank tiles.
- ld hl, vBGMap1 + $8c
- call Trade_CopyCableTilesOffScreen
-
- ld a, $a0
- ld [hSCX], a
- call DelayFrame
- ld a, %10001011
- ld [rLCDC], a
- coord hl, 6, 2
- ld b, $7 ; open end of link cable tile ID list index
- call CopyTileIDsFromList_ZeroBaseTileID
- call Trade_CopyTileMapToVRAM
- ld a, SFX_HEAL_HP
- call PlaySound
- ld c, 20
-.loop
- ld a, [hSCX]
- add 4
- ld [hSCX], a
- dec c
- jr nz, .loop
- ret
-
-Trade_AnimateBallEnteringLinkCable:
- ld a, TRADE_BALL_SHAKE_ANIM
- call Trade_ShowAnimation
- ld c, 10
- call DelayFrames
- ld a, %11100100
- ld [rOBP0], a
- xor a
- ld [wLinkCableAnimBulgeToggle], a
- lb bc, $20, $60
-.moveBallInsideLinkCableLoop
- push bc
- xor a
- ld de, Trade_BallInsideLinkCableOAM
- call WriteOAMBlock
- ld a, [wLinkCableAnimBulgeToggle]
- xor $1
- ld [wLinkCableAnimBulgeToggle], a
- add $7e
- ld hl, wOAMBuffer + $02
- ld de, 4
- ld c, e
-.cycleLinkCableBulgeTile
- ld [hl], a
- add hl, de
- dec c
- jr nz, .cycleLinkCableBulgeTile
- call Delay3
- pop bc
- ld a, c
- add $4
- ld c, a
- cp $a0
- jr nc, .ballSpriteReachedEdgeOfScreen
- ld a, SFX_TINK
- call PlaySound
- jr .moveBallInsideLinkCableLoop
-.ballSpriteReachedEdgeOfScreen
- call ClearSprites
- ld a, $1
- ld [H_AUTOBGTRANSFERENABLED], a
- call ClearScreen
- ld b, $98
- call CopyScreenTileBufferToVRAM
- call Delay3
- xor a
- ld [H_AUTOBGTRANSFERENABLED], a
- ret
-
-Trade_BallInsideLinkCableOAM:
- db $7E,$00,$7E,$20
- db $7E,$40,$7E,$60
-
-Trade_ShowEnemyMon:
- ld a, TRADE_BALL_TILT_ANIM
- call Trade_ShowAnimation
- call Trade_ShowClearedWindow
- coord hl, 4, 10
- ld b, 6
- ld c, 10
- call TextBoxBorder
- call Trade_PrintEnemyMonInfoText
- call Trade_CopyTileMapToVRAM
- ld a, $1
- ld [H_AUTOBGTRANSFERENABLED], a
- ld a, [wTradedEnemyMonSpecies]
- call Trade_LoadMonSprite
- ld a, TRADE_BALL_POOF_ANIM
- call Trade_ShowAnimation
- ld a, $1
- ld [H_AUTOBGTRANSFERENABLED], a
- ld a, [wTradedEnemyMonSpecies]
- call PlayCry
- call Trade_Delay100
- coord hl, 4, 10
- lb bc, 8, 12
- call ClearScreenArea
- jp PrintTradeTakeCareText
-
-Trade_AnimLeftToRight:
-; Animates the mon moving from the left GB to the right one.
- call Trade_InitGameboyTransferGfx
- ld a, $1
- ld [wTradedMonMovingRight], a
- ld a, %11100100
- ld [rOBP0], a
- ld a, $54
- ld [wBaseCoordX], a
- ld a, $1c
- ld [wBaseCoordY], a
- ld a, [wLeftGBMonSpecies]
- ld [wMonPartySpriteSpecies], a
- call Trade_WriteCircledMonOAM
- call Trade_DrawLeftGameboy
- call Trade_CopyTileMapToVRAM
- call Trade_DrawCableAcrossScreen
- ld hl, vBGMap1 + $8c
- call Trade_CopyCableTilesOffScreen
- ld b, $6
- call Trade_AnimMonMoveHorizontal
- ld a, $1
- ld [H_AUTOBGTRANSFERENABLED], a
- call Trade_DrawCableAcrossScreen
- ld b, $4
- call Trade_AnimMonMoveHorizontal
- call Trade_DrawRightGameboy
- ld b, $6
- call Trade_AnimMonMoveHorizontal
- xor a
- ld [H_AUTOBGTRANSFERENABLED], a
- call Trade_AnimMonMoveVertical
- jp ClearSprites
-
-Trade_AnimRightToLeft:
-; Animates the mon moving from the right GB to the left one.
- call Trade_InitGameboyTransferGfx
- xor a
- ld [wTradedMonMovingRight], a
- ld a, $64
- ld [wBaseCoordX], a
- ld a, $44
- ld [wBaseCoordY], a
- ld a, [wRightGBMonSpecies]
- ld [wMonPartySpriteSpecies], a
- call Trade_WriteCircledMonOAM
- call Trade_DrawRightGameboy
- call Trade_CopyTileMapToVRAM
- call Trade_DrawCableAcrossScreen
- ld hl, vBGMap1 + $94
- call Trade_CopyCableTilesOffScreen
- call Trade_AnimMonMoveVertical
- ld b, $6
- call Trade_AnimMonMoveHorizontal
- ld a, $1
- ld [H_AUTOBGTRANSFERENABLED], a
- call Trade_DrawCableAcrossScreen
- ld b, $4
- call Trade_AnimMonMoveHorizontal
- call Trade_DrawLeftGameboy
- ld b, $6
- call Trade_AnimMonMoveHorizontal
- xor a
- ld [H_AUTOBGTRANSFERENABLED], a
- jp ClearSprites
-
-Trade_InitGameboyTransferGfx:
-; Initialises the graphics for showing a mon moving between gameboys.
- ld a, $1
- ld [H_AUTOBGTRANSFERENABLED], a
- call ClearScreen
- xor a
- ld [H_AUTOBGTRANSFERENABLED], a
- call Trade_LoadMonPartySpriteGfx
- call DelayFrame
- ld a, %10101011
- ld [rLCDC], a
- xor a
- ld [hSCX], a
- ld a, $90
- ld [hWY], a
- ret
-
-Trade_DrawLeftGameboy:
- call Trade_ClearTileMap
-
-; draw link cable
- coord hl, 11, 4
- ld a, $5d
- ld [hli], a
- ld a, $5e
- ld c, 8
-.loop
- ld [hli], a
- dec c
- jr nz, .loop
-
-; draw gameboy pic
- coord hl, 5, 3
- ld b, $6
- call CopyTileIDsFromList_ZeroBaseTileID
-
-; draw text box with player name below gameboy pic
- coord hl, 4, 12
- ld b, 2
- ld c, 7
- call TextBoxBorder
- coord hl, 5, 14
- ld de, wPlayerName
- call PlaceString
-
- jp DelayFrame
-
-Trade_DrawRightGameboy:
- call Trade_ClearTileMap
-
-; draw horizontal segment of link cable
- coord hl, 0, 4
- ld a, $5e
- ld c, $e
-.loop
- ld [hli], a
- dec c
- jr nz, .loop
-
-; draw vertical segment of link cable
- ld a, $5f
- ld [hl], a
- ld de, SCREEN_WIDTH
- add hl, de
- ld a, $61
- ld [hl], a
- add hl, de
- ld [hl], a
- add hl, de
- ld [hl], a
- add hl, de
- ld [hl], a
- add hl, de
- ld a, $60
- ld [hld], a
- ld a, $5d
- ld [hl], a
-
-; draw gameboy pic
- coord hl, 7, 8
- ld b, $6
- call CopyTileIDsFromList_ZeroBaseTileID
-
-; draw text box with enemy name above link cable
- coord hl, 6, 0
- ld b, 2
- ld c, 7
- call TextBoxBorder
- coord hl, 7, 2
- ld de, wLinkEnemyTrainerName
- call PlaceString
-
- jp DelayFrame
-
-Trade_DrawCableAcrossScreen:
-; Draws the link cable across the screen.
- call Trade_ClearTileMap
- coord hl, 0, 4
- ld a, $5e
- ld c, SCREEN_WIDTH
-.loop
- ld [hli], a
- dec c
- jr nz, .loop
- ret
-
-Trade_CopyCableTilesOffScreen:
-; This is used to copy the link cable tiles off screen so that the cable
-; continues when the screen is scrolled.
- push hl
- coord hl, 0, 4
- call CopyToRedrawRowOrColumnSrcTiles
- pop hl
- ld a, h
- ld [hRedrawRowOrColumnDest + 1], a
- ld a, l
- ld [hRedrawRowOrColumnDest], a
- ld a, REDRAW_ROW
- ld [hRedrawRowOrColumnMode], a
- ld c, 10
- jp DelayFrames
-
-Trade_AnimMonMoveHorizontal:
-; Animates the mon going through the link cable horizontally over a distance of
-; b 16-pixel units.
- ld a, [wTradedMonMovingRight]
- ld e, a
- ld d, $8
-.scrollLoop
- ld a, e
- dec a
- jr z, .movingRight
-; moving left
- ld a, [hSCX]
- sub $2
- jr .next
-.movingRight
- ld a, [hSCX]
- add $2
-.next
- ld [hSCX], a
- call DelayFrame
- dec d
- jr nz, .scrollLoop
- call Trade_AnimCircledMon
- dec b
- jr nz, Trade_AnimMonMoveHorizontal
- ret
-
-Trade_AnimCircledMon:
-; Cycles between the two animation frames of the mon party sprite, cycles
-; between a circle and an oval around the mon sprite, and makes the cable flash.
- push de
- push bc
- push hl
- ld a, [rBGP]
- xor $3c ; make link cable flash
- ld [rBGP], a
- ld hl, wOAMBuffer + $02
- ld de, $4
- ld c, $14
-.loop
- ld a, [hl]
- xor $40
- ld [hl], a
- add hl, de
- dec c
- jr nz, .loop
- pop hl
- pop bc
- pop de
- ret
-
-Trade_WriteCircledMonOAM:
- callba WriteMonPartySpriteOAMBySpecies
- call Trade_WriteCircleOAM
-
-Trade_AddOffsetsToOAMCoords:
- ld hl, wOAMBuffer
- ld c, $14
-.loop
- ld a, [wBaseCoordY]
- add [hl]
- ld [hli], a
- ld a, [wBaseCoordX]
- add [hl]
- ld [hli], a
- inc hl
- inc hl
- dec c
- jr nz, .loop
- ret
-
-Trade_AnimMonMoveVertical:
-; Animates the mon going through the link cable vertically as well as
-; horizontally for a bit. The last bit of horizontal movement (when moving
-; right) or the first bit of horizontal movement (when moving left) are done
-; here instead of Trade_AnimMonMoveHorizontal because this function moves the
-; sprite itself rather than scrolling the screen around the sprite. Moving the
-; sprite itself is necessary because the vertical segment of the link cable is
-; to the right of the screen position that the mon sprite has when
-; Trade_AnimMonMoveHorizontal is executing.
- ld a, [wTradedMonMovingRight]
- and a
- jr z, .movingLeft
-; moving right
- lb bc, 4, 0 ; move right
- call .doAnim
- lb bc, 0, 10 ; move down
- jr .doAnim
-.movingLeft
- lb bc, 0, -10 ; move up
- call .doAnim
- lb bc, -4, 0 ; move left
-.doAnim
- ld a, b
- ld [wBaseCoordX], a
- ld a, c
- ld [wBaseCoordY], a
- ld d, $4
-.loop
- call Trade_AddOffsetsToOAMCoords
- call Trade_AnimCircledMon
- ld c, 8
- call DelayFrames
- dec d
- jr nz, .loop
- ret
-
-Trade_WriteCircleOAM:
-; Writes the OAM blocks for the circle around the traded mon as it passes
-; the link cable.
- ld hl, Trade_CircleOAMPointers
- ld c, $4
- xor a
-.loop
- push bc
- ld e, [hl]
- inc hl
- ld d, [hl]
- inc hl
- ld c, [hl]
- inc hl
- ld b, [hl]
- inc hl
- push hl
- inc a
- push af
- call WriteOAMBlock
- pop af
- pop hl
- pop bc
- dec c
- jr nz, .loop
- ret
-
-Trade_CircleOAMPointers:
- dw Trade_CircleOAM0
- db $08,$08
- dw Trade_CircleOAM1
- db $18,$08
- dw Trade_CircleOAM2
- db $08,$18
- dw Trade_CircleOAM3
- db $18,$18
-
-Trade_CircleOAM0:
- db $38,$10,$39,$10
- db $3A,$10,$3B,$10
-
-Trade_CircleOAM1:
- db $39,$30,$38,$30
- db $3B,$30,$3A,$30
-
-Trade_CircleOAM2:
- db $3A,$50,$3B,$50
- db $38,$50,$39,$50
-
-Trade_CircleOAM3:
- db $3B,$70,$3A,$70
- db $39,$70,$38,$70
-
-; a = species
-Trade_LoadMonSprite:
- ld [wcf91], a
- ld [wd0b5], a
- ld [wWholeScreenPaletteMonSpecies], a
- ld b, SET_PAL_POKEMON_WHOLE_SCREEN
- ld c, 0
- call RunPaletteCommand
- ld a, [H_AUTOBGTRANSFERENABLED]
- xor $1
- ld [H_AUTOBGTRANSFERENABLED], a
- call GetMonHeader
- coord hl, 7, 2
- call LoadFlippedFrontSpriteByMonIndex
- ld c, 10
- jp DelayFrames
-
-Trade_ShowClearedWindow:
-; clears the window and covers the BG entirely with the window
- ld a, $1
- ld [H_AUTOBGTRANSFERENABLED], a
- call ClearScreen
- ld a, %11100011
- ld [rLCDC], a
- ld a, $7
- ld [rWX], a
- xor a
- ld [hWY], a
- ld a, $90
- ld [hSCX], a
- ret
-
-Trade_SlideTextBoxOffScreen:
-; Slides the window right until it's off screen. The window usually just has
-; a text box at the bottom when this is called. However, when this is called
-; after Trade_ShowEnemyMon in the external clock sequence, there is a mon pic
-; above the text box and it is also scrolled off the screen.
- ld c, 50
- call DelayFrames
-.loop
- call DelayFrame
- ld a, [rWX]
- inc a
- inc a
- ld [rWX], a
- cp $a1
- jr nz, .loop
- call Trade_ClearTileMap
- ld c, 10
- call DelayFrames
- ld a, $7
- ld [rWX], a
- ret
-
-PrintTradeWentToText:
- ld hl, TradeWentToText
- call PrintText
- ld c, 200
- call DelayFrames
- jp Trade_SlideTextBoxOffScreen
-
-TradeWentToText:
- TX_FAR _TradeWentToText
- db "@"
-
-PrintTradeForSendsText:
- ld hl, TradeForText
- call PrintText
- call Trade_Delay80
- ld hl, TradeSendsText
- call PrintText
- jp Trade_Delay80
-
-TradeForText:
- TX_FAR _TradeForText
- db "@"
-
-TradeSendsText:
- TX_FAR _TradeSendsText
- db "@"
-
-PrintTradeFarewellText:
- ld hl, TradeWavesFarewellText
- call PrintText
- call Trade_Delay80
- ld hl, TradeTransferredText
- call PrintText
- call Trade_Delay80
- jp Trade_SlideTextBoxOffScreen
-
-TradeWavesFarewellText:
- TX_FAR _TradeWavesFarewellText
- db "@"
-
-TradeTransferredText:
- TX_FAR _TradeTransferredText
- db "@"
-
-PrintTradeTakeCareText:
- ld hl, TradeTakeCareText
- call PrintText
- jp Trade_Delay80
-
-TradeTakeCareText:
- TX_FAR _TradeTakeCareText
- db "@"
-
-PrintTradeWillTradeText:
- ld hl, TradeWillTradeText
- call PrintText
- call Trade_Delay80
- ld hl, TradeforText
- call PrintText
- jp Trade_Delay80
-
-TradeWillTradeText:
- TX_FAR _TradeWillTradeText
- db "@"
-
-TradeforText:
- TX_FAR _TradeforText
- db "@"
-
-Trade_ShowAnimation:
- ld [wAnimationID], a
- xor a
- ld [wAnimationType], a
- predef_jump MoveAnimation
--- a/engine/trade2.asm
+++ /dev/null
@@ -1,48 +1,0 @@
-Trade_PrintPlayerMonInfoText:
- coord hl, 5, 0
- ld de, Trade_MonInfoText
- call PlaceString
- ld a, [wTradedPlayerMonSpecies]
- ld [wd11e], a
- predef IndexToPokedex
- coord hl, 9, 0
- ld de, wd11e
- lb bc, LEADING_ZEROES | 1, 3
- call PrintNumber
- coord hl, 5, 2
- ld de, wcf4b
- call PlaceString
- coord hl, 8, 4
- ld de, wTradedPlayerMonOT
- call PlaceString
- coord hl, 8, 6
- ld de, wTradedPlayerMonOTID
- lb bc, LEADING_ZEROES | 2, 5
- jp PrintNumber
-
-Trade_PrintEnemyMonInfoText:
- coord hl, 5, 10
- ld de, Trade_MonInfoText
- call PlaceString
- ld a, [wTradedEnemyMonSpecies]
- ld [wd11e], a
- predef IndexToPokedex
- coord hl, 9, 10
- ld de, wd11e
- lb bc, LEADING_ZEROES | 1, 3
- call PrintNumber
- coord hl, 5, 12
- ld de, wcd6d
- call PlaceString
- coord hl, 8, 14
- ld de, wTradedEnemyMonOT
- call PlaceString
- coord hl, 8, 16
- ld de, wTradedEnemyMonOTID
- lb bc, LEADING_ZEROES | 2, 5
- jp PrintNumber
-
-Trade_MonInfoText:
- db "──№⠄",$4E
- next "OT/"
- next $73,"№⠄","@"
--- a/engine/turn_sprite.asm
+++ /dev/null
@@ -1,25 +1,0 @@
-UpdateSpriteFacingOffsetAndDelayMovement::
- ld h, $c2
- ld a, [H_CURRENTSPRITEOFFSET]
- add $8
- ld l, a
- ld a, $7f ; maximum movement delay
- ld [hl], a ; c2x8 (movement delay)
- dec h
- ld a, [H_CURRENTSPRITEOFFSET]
- add $9
- ld l, a
- ld a, [hld] ; c1x9 (facing direction)
- ld b, a
- xor a
- ld [hld], a
- ld [hl], a ; c1x8 (walk animation frame)
- ld a, [H_CURRENTSPRITEOFFSET]
- add $2
- ld l, a
- ld a, [hl] ; c1x2 (facing and animation table offset)
- or b ; or in the facing direction
- ld [hld], a
- ld a, $2 ; delayed movement status
- ld [hl], a ; c1x1 (movement status)
- ret
--- a/home.asm
+++ b/home.asm
@@ -1282,7 +1282,7 @@
TX_FAR _RepelWoreOffText
db "@"
-INCLUDE "engine/menu/start_menu.asm"
+INCLUDE "home/start_menu.asm"
; function to count how many bits are set in a string of bytes
; INPUT:
--- /dev/null
+++ b/home/start_menu.asm
@@ -1,0 +1,85 @@
+DisplayStartMenu::
+ ld a, BANK(StartMenu_Pokedex)
+ ld [H_LOADEDROMBANK], a
+ ld [MBC1RomBank], a
+ ld a, [wWalkBikeSurfState] ; walking/biking/surfing
+ ld [wWalkBikeSurfStateCopy], a
+ ld a, SFX_START_MENU
+ call PlaySound
+
+RedisplayStartMenu::
+ callba DrawStartMenu
+ callba PrintSafariZoneSteps ; print Safari Zone info, if in Safari Zone
+ call UpdateSprites
+.loop
+ call HandleMenuInput
+ ld b, a
+.checkIfUpPressed
+ bit 6, a ; was Up pressed?
+ jr z, .checkIfDownPressed
+ ld a, [wCurrentMenuItem] ; menu selection
+ and a
+ jr nz, .loop
+ ld a, [wLastMenuItem]
+ and a
+ jr nz, .loop
+; if the player pressed tried to go past the top item, wrap around to the bottom
+ CheckEvent EVENT_GOT_POKEDEX
+ ld a, 6 ; there are 7 menu items with the pokedex, so the max index is 6
+ jr nz, .wrapMenuItemId
+ dec a ; there are only 6 menu items without the pokedex
+.wrapMenuItemId
+ ld [wCurrentMenuItem], a
+ call EraseMenuCursor
+ jr .loop
+.checkIfDownPressed
+ bit 7, a
+ jr z, .buttonPressed
+; if the player pressed tried to go past the bottom item, wrap around to the top
+ CheckEvent EVENT_GOT_POKEDEX
+ ld a, [wCurrentMenuItem]
+ ld c, 7 ; there are 7 menu items with the pokedex
+ jr nz, .checkIfPastBottom
+ dec c ; there are only 6 menu items without the pokedex
+.checkIfPastBottom
+ cp c
+ jr nz, .loop
+; the player went past the bottom, so wrap to the top
+ xor a
+ ld [wCurrentMenuItem], a
+ call EraseMenuCursor
+ jr .loop
+.buttonPressed ; A, B, or Start button pressed
+ call PlaceUnfilledArrowMenuCursor
+ ld a, [wCurrentMenuItem]
+ ld [wBattleAndStartSavedMenuItem], a ; save current menu selection
+ ld a, b
+ and %00001010 ; was the Start button or B button pressed?
+ jp nz, CloseStartMenu
+ call SaveScreenTilesToBuffer2 ; copy background from wTileMap to wTileMapBackup2
+ CheckEvent EVENT_GOT_POKEDEX
+ ld a, [wCurrentMenuItem]
+ jr nz, .displayMenuItem
+ inc a ; adjust position to account for missing pokedex menu item
+.displayMenuItem
+ cp 0
+ jp z, StartMenu_Pokedex
+ cp 1
+ jp z, StartMenu_Pokemon
+ cp 2
+ jp z, StartMenu_Item
+ cp 3
+ jp z, StartMenu_TrainerInfo
+ cp 4
+ jp z, StartMenu_SaveReset
+ cp 5
+ jp z, StartMenu_Option
+
+; EXIT falls through to here
+CloseStartMenu::
+ call Joypad
+ ld a, [hJoyPressed]
+ bit 0, a ; was A button newly pressed?
+ jr nz, CloseStartMenu
+ call LoadTextBoxTilePatterns
+ jp CloseTextDisplay
--- a/layout.link
+++ b/layout.link
@@ -94,6 +94,8 @@
"Sound Effect Headers 2"
"Music Headers 2"
"Sound Effects 2"
+ "Low Health Alarm (Audio Engine 2)"
+ "Bill's PC"
"Audio Engine 2"
"Music 2"
--- a/main.asm
+++ b/main.asm
@@ -4,7 +4,7 @@
SECTION "bank1", ROMX
INCLUDE "data/facing.asm"
-INCLUDE "engine/black_out.asm"
+INCLUDE "engine/events/black_out.asm"
MewPicFront:: INCBIN "gfx/pokemon/front/mew.pic"
MewPicBack:: INCBIN "gfx/pokemon/back/mewb.pic"
@@ -11,39 +11,39 @@
INCLUDE "data/baseStats/mew.asm"
INCLUDE "engine/battle/safari_zone.asm"
-INCLUDE "engine/titlescreen.asm"
-INCLUDE "engine/load_mon_data.asm"
+INCLUDE "engine/movie/titlescreen.asm"
+INCLUDE "engine/pokemon/load_mon_data.asm"
INCLUDE "data/item_prices.asm"
INCLUDE "text/item_names.asm"
INCLUDE "text/unused_names.asm"
-INCLUDE "engine/overworld/oam.asm"
-INCLUDE "engine/oam_dma.asm"
-INCLUDE "engine/print_waiting_text.asm"
-INCLUDE "engine/overworld/map_sprite_functions1.asm"
-INCLUDE "engine/test_battle.asm"
-INCLUDE "engine/overworld/item.asm"
+INCLUDE "engine/gfx/sprite_oam.asm"
+INCLUDE "engine/gfx/oam_dma.asm"
+INCLUDE "engine/link/print_waiting_text.asm"
+INCLUDE "engine/overworld/sprite_collisions.asm"
+INCLUDE "engine/debug/test_battle.asm"
+INCLUDE "engine/events/pick_up_item.asm"
INCLUDE "engine/overworld/movement.asm"
-INCLUDE "engine/cable_club.asm"
-INCLUDE "engine/menu/main_menu.asm"
-INCLUDE "engine/oak_speech.asm"
-INCLUDE "engine/special_warps.asm"
-INCLUDE "engine/debug1.asm"
-INCLUDE "engine/menu/naming_screen.asm"
-INCLUDE "engine/oak_speech2.asm"
-INCLUDE "engine/subtract_paid_money.asm"
-INCLUDE "engine/menu/swap_items.asm"
-INCLUDE "engine/overworld/pokemart.asm"
-INCLUDE "engine/learn_move.asm"
-INCLUDE "engine/overworld/pokecenter.asm"
-INCLUDE "engine/overworld/set_blackout_map.asm"
-INCLUDE "engine/display_text_id_init.asm"
-INCLUDE "engine/menu/draw_start_menu.asm"
-INCLUDE "engine/overworld/cable_club_npc.asm"
-INCLUDE "engine/menu/text_box.asm"
-INCLUDE "engine/battle/moveEffects/drain_hp_effect.asm"
-INCLUDE "engine/menu/players_pc.asm"
-INCLUDE "engine/remove_pokemon.asm"
-INCLUDE "engine/display_pokedex.asm"
+INCLUDE "engine/link/cable_club.asm"
+INCLUDE "engine/menus/main_menu.asm"
+INCLUDE "engine/movie/oak_speech/oak_speech.asm"
+INCLUDE "engine/overworld/special_warps.asm"
+INCLUDE "engine/debug/debug_party.asm"
+INCLUDE "engine/menus/naming_screen.asm"
+INCLUDE "engine/movie/oak_speech/oak_speech2.asm"
+INCLUDE "engine/items/subtract_paid_money.asm"
+INCLUDE "engine/menus/swap_items.asm"
+INCLUDE "engine/events/pokemart.asm"
+INCLUDE "engine/pokemon/learn_move.asm"
+INCLUDE "engine/events/pokecenter.asm"
+INCLUDE "engine/events/set_blackout_map.asm"
+INCLUDE "engine/menus/display_text_id_init.asm"
+INCLUDE "engine/menus/draw_start_menu.asm"
+INCLUDE "engine/link/cable_club_npc.asm"
+INCLUDE "engine/menus/text_box.asm"
+INCLUDE "engine/battle/move_effects/drain_hp.asm"
+INCLUDE "engine/menus/players_pc.asm"
+INCLUDE "engine/pokemon/remove_mon.asm"
+INCLUDE "engine/events/display_pokedex.asm"
SECTION "bank3", ROMX
@@ -53,28 +53,28 @@
INCLUDE "data/map_header_banks.asm"
INCLUDE "engine/overworld/clear_variables.asm"
INCLUDE "engine/overworld/player_state.asm"
-INCLUDE "engine/overworld/poison.asm"
-INCLUDE "engine/overworld/tileset_header.asm"
+INCLUDE "engine/events/poison.asm"
+INCLUDE "engine/overworld/tilesets.asm"
INCLUDE "engine/overworld/daycare_exp.asm"
INCLUDE "data/hide_show_data.asm"
INCLUDE "engine/overworld/field_move_messages.asm"
INCLUDE "engine/items/inventory.asm"
INCLUDE "engine/overworld/wild_mons.asm"
-INCLUDE "engine/items/items.asm"
-INCLUDE "engine/menu/draw_badges.asm"
+INCLUDE "engine/items/item_effects.asm"
+INCLUDE "engine/menus/draw_badges.asm"
INCLUDE "engine/overworld/update_map.asm"
INCLUDE "engine/overworld/cut.asm"
INCLUDE "engine/overworld/missable_objects.asm"
INCLUDE "engine/overworld/push_boulder.asm"
-INCLUDE "engine/add_mon.asm"
+INCLUDE "engine/pokemon/add_mon.asm"
INCLUDE "engine/flag_action.asm"
-INCLUDE "engine/heal_party.asm"
-INCLUDE "engine/bcd.asm"
-INCLUDE "engine/init_player_data.asm"
-INCLUDE "engine/get_bag_item_quantity.asm"
-INCLUDE "engine/pathfinding.asm"
-INCLUDE "engine/hp_bar.asm"
-INCLUDE "engine/hidden_object_functions3.asm"
+INCLUDE "engine/events/heal_party.asm"
+INCLUDE "engine/math/bcd.asm"
+INCLUDE "engine/movie/oak_speech/init_player_data.asm"
+INCLUDE "engine/items/get_bag_item_quantity.asm"
+INCLUDE "engine/overworld/pathfinding.asm"
+INCLUDE "engine/gfx/hp_bar.asm"
+INCLUDE "engine/events/hidden_object_functions3.asm"
SECTION "Graphics (BANK 4)", ROMX
@@ -106,33 +106,33 @@
SECTION "Battle (BANK 4)", ROMX
INCLUDE "engine/overworld/is_player_just_outside_map.asm"
-INCLUDE "engine/menu/status_screen.asm"
-INCLUDE "engine/menu/party_menu.asm"
+INCLUDE "engine/pokemon/status_screen.asm"
+INCLUDE "engine/menus/party_menu.asm"
RedPicFront:: INCBIN "gfx/player/red.pic"
ShrinkPic1:: INCBIN "gfx/player/shrink1.pic"
ShrinkPic2:: INCBIN "gfx/player/shrink2.pic"
-INCLUDE "engine/turn_sprite.asm"
-INCLUDE "engine/menu/start_sub_menus.asm"
+INCLUDE "engine/overworld/turn_sprite.asm"
+INCLUDE "engine/menus/start_sub_menus.asm"
INCLUDE "engine/items/tms.asm"
INCLUDE "engine/battle/end_of_battle.asm"
INCLUDE "engine/battle/wild_encounters.asm"
-INCLUDE "engine/battle/moveEffects/recoil_effect.asm"
-INCLUDE "engine/battle/moveEffects/conversion_effect.asm"
-INCLUDE "engine/battle/moveEffects/haze_effect.asm"
+INCLUDE "engine/battle/move_effects/recoil.asm"
+INCLUDE "engine/battle/move_effects/conversion.asm"
+INCLUDE "engine/battle/move_effects/haze.asm"
INCLUDE "engine/battle/get_trainer_name.asm"
-INCLUDE "engine/random.asm"
+INCLUDE "engine/math/random.asm"
SECTION "Battle (BANK 5)", ROMX
-INCLUDE "engine/load_pokedex_tiles.asm"
+INCLUDE "engine/gfx/load_pokedex_tiles.asm"
INCLUDE "engine/overworld/map_sprites.asm"
INCLUDE "engine/overworld/emotion_bubbles.asm"
-INCLUDE "engine/evolve_trade.asm"
-INCLUDE "engine/battle/moveEffects/substitute_effect.asm"
-INCLUDE "engine/menu/pc.asm"
+INCLUDE "engine/events/evolve_trade.asm"
+INCLUDE "engine/battle/move_effects/substitute.asm"
+INCLUDE "engine/menus/pc.asm"
SECTION "bank6_1", ROMX
@@ -142,7 +142,7 @@
SECTION "bank6_2", ROMX
-INCLUDE "engine/overworld/npc_movement.asm"
+INCLUDE "engine/overworld/auto_movement.asm"
INCLUDE "engine/overworld/doors.asm"
INCLUDE "engine/overworld/ledges.asm"
@@ -150,26 +150,31 @@
SECTION "bank7_1", ROMX
INCLUDE "text/monster_names.asm"
-INCLUDE "engine/clear_save.asm"
-INCLUDE "engine/predefs7.asm"
+INCLUDE "engine/movie/oak_speech/clear_save.asm"
+INCLUDE "engine/events/elevator.asm"
SECTION "bank7_2", ROMX
-INCLUDE "engine/menu/oaks_pc.asm"
-INCLUDE "engine/hidden_object_functions7.asm"
+INCLUDE "engine/menus/oaks_pc.asm"
+INCLUDE "engine/events/hidden_object_functions7.asm"
+SECTION "Bill's PC", ROMX
+
+INCLUDE "engine/pokemon/bills_pc.asm"
+
+
SECTION "Battle (BANK 9)", ROMX
INCLUDE "engine/battle/print_type.asm"
INCLUDE "engine/battle/save_trainer_name.asm"
-INCLUDE "engine/battle/moveEffects/focus_energy_effect.asm"
+INCLUDE "engine/battle/move_effects/focus_energy.asm"
SECTION "Battle (BANK A)", ROMX
-INCLUDE "engine/battle/moveEffects/leech_seed_effect.asm"
+INCLUDE "engine/battle/move_effects/leech_seed.asm"
SECTION "Battle (BANK B)", ROMX
@@ -184,24 +189,24 @@
INCLUDE "engine/items/tmhm.asm"
INCLUDE "engine/battle/scale_sprites.asm"
-INCLUDE "engine/battle/moveEffects/pay_day_effect.asm"
-INCLUDE "engine/game_corner_slots2.asm"
+INCLUDE "engine/battle/move_effects/pay_day.asm"
+INCLUDE "engine/slots/game_corner_slots2.asm"
SECTION "Battle (BANK C)", ROMX
-INCLUDE "engine/battle/moveEffects/mist_effect.asm"
-INCLUDE "engine/battle/moveEffects/one_hit_ko_effect.asm"
+INCLUDE "engine/battle/move_effects/mist.asm"
+INCLUDE "engine/battle/move_effects/one_hit_ko.asm"
SECTION "Battle (BANK D)", ROMX
-INCLUDE "engine/titlescreen2.asm"
+INCLUDE "engine/movie/titlescreen2.asm"
INCLUDE "engine/battle/link_battle_versus_text.asm"
-INCLUDE "engine/slot_machine.asm"
-INCLUDE "engine/overworld/pewter_guys.asm"
-INCLUDE "engine/multiply_divide.asm"
-INCLUDE "engine/game_corner_slots.asm"
+INCLUDE "engine/slots/slot_machine.asm"
+INCLUDE "engine/events/pewter_guys.asm"
+INCLUDE "engine/math/multiply_divide.asm"
+INCLUDE "engine/slots/game_corner_slots.asm"
SECTION "bankE", ROMX
@@ -223,10 +228,10 @@
TradingAnimationGraphics2: INCBIN "gfx/trade/cable_ball.2bpp"
TradingAnimationGraphics2End:
-INCLUDE "engine/evos_moves.asm"
-INCLUDE "engine/battle/moveEffects/heal_effect.asm"
-INCLUDE "engine/battle/moveEffects/transform_effect.asm"
-INCLUDE "engine/battle/moveEffects/reflect_light_screen_effect.asm"
+INCLUDE "engine/pokemon/evos_moves.asm"
+INCLUDE "engine/battle/move_effects/heal.asm"
+INCLUDE "engine/battle/move_effects/transform.asm"
+INCLUDE "engine/battle/move_effects/reflect_light_screen.asm"
SECTION "bankF", ROMX
@@ -237,15 +242,15 @@
SECTION "bank10", ROMX
-INCLUDE "engine/menu/pokedex.asm"
-INCLUDE "engine/trade.asm"
-INCLUDE "engine/intro.asm"
-INCLUDE "engine/trade2.asm"
+INCLUDE "engine/menus/pokedex.asm"
+INCLUDE "engine/movie/trade.asm"
+INCLUDE "engine/movie/intro.asm"
+INCLUDE "engine/movie/trade2.asm"
SECTION "bank11_1", ROMX
-INCLUDE "engine/pokedex_rating.asm"
+INCLUDE "engine/events/pokedex_rating.asm"
SECTION "bank11_2", ROMX
@@ -255,12 +260,12 @@
SECTION "bank12", ROMX
-INCLUDE "engine/predefs12.asm"
+INCLUDE "engine/gfx/screen_effects.asm"
SECTION "bank13", ROMX
-INCLUDE "engine/give_pokemon.asm"
+INCLUDE "engine/events/give_pokemon.asm"
INCLUDE "engine/predefs.asm"
@@ -267,10 +272,10 @@
SECTION "bank14", ROMX
INCLUDE "engine/battle/init_battle_variables.asm"
-INCLUDE "engine/battle/moveEffects/paralyze_effect.asm"
-INCLUDE "engine/overworld/card_key.asm"
-INCLUDE "engine/menu/prize_menu.asm"
-INCLUDE "engine/hidden_object_functions14.asm"
+INCLUDE "engine/battle/move_effects/paralyze.asm"
+INCLUDE "engine/events/card_key.asm"
+INCLUDE "engine/events/prize_menu.asm"
+INCLUDE "engine/events/hidden_object_functions14.asm"
SECTION "bank15_1", ROMX
@@ -280,41 +285,41 @@
SECTION "bank15_2", ROMX
-INCLUDE "engine/menu/diploma.asm"
-INCLUDE "engine/overworld/trainers.asm"
+INCLUDE "engine/events/diploma.asm"
+INCLUDE "engine/overworld/trainer_sight.asm"
SECTION "bank16_1", ROMX
INCLUDE "engine/battle/common_text.asm"
-INCLUDE "engine/experience.asm"
-INCLUDE "engine/overworld/oaks_aide.asm"
+INCLUDE "engine/pokemon/experience.asm"
+INCLUDE "engine/events/oaks_aide.asm"
SECTION "bank16_2", ROMX
-INCLUDE "engine/overworld/saffron_guards.asm"
+INCLUDE "engine/events/saffron_guards.asm"
SECTION "bank17_1", ROMX
-INCLUDE "engine/predefs17.asm"
+INCLUDE "engine/events/starter_dex.asm"
SECTION "bank17_2", ROMX
-INCLUDE "engine/predefs17_2.asm"
-INCLUDE "engine/hidden_object_functions17.asm"
+INCLUDE "engine/pokemon/set_types.asm"
+INCLUDE "engine/events/hidden_object_functions17.asm"
SECTION "bank18_1", ROMX
-INCLUDE "engine/overworld/cinnabar_lab.asm"
+INCLUDE "engine/events/cinnabar_lab.asm"
SECTION "bank18_2", ROMX
-INCLUDE "engine/hidden_object_functions18.asm"
+INCLUDE "engine/events/hidden_object_functions18.asm"
SECTION "bank1A", ROMX
@@ -333,35 +338,35 @@
SECTION "bank1C", ROMX
-INCLUDE "engine/gamefreak.asm"
-INCLUDE "engine/hall_of_fame.asm"
+INCLUDE "engine/movie/gamefreak.asm"
+INCLUDE "engine/movie/hall_of_fame.asm"
INCLUDE "engine/overworld/healing_machine.asm"
INCLUDE "engine/overworld/player_animations.asm"
INCLUDE "engine/battle/ghost_marowak_anim.asm"
INCLUDE "engine/battle/battle_transitions.asm"
-INCLUDE "engine/town_map.asm"
-INCLUDE "engine/mon_party_sprites.asm"
-INCLUDE "engine/in_game_trades.asm"
-INCLUDE "engine/palettes.asm"
-INCLUDE "engine/save.asm"
+INCLUDE "engine/items/town_map.asm"
+INCLUDE "engine/gfx/mon_icons.asm"
+INCLUDE "engine/events/in_game_trades.asm"
+INCLUDE "engine/gfx/palettes.asm"
+INCLUDE "engine/menus/save.asm"
SECTION "bank1D_1", ROMX
-INCLUDE "engine/HoF_room_pc.asm"
-INCLUDE "engine/status_ailments.asm"
+INCLUDE "engine/movie/credits.asm"
+INCLUDE "engine/pokemon/status_ailments.asm"
INCLUDE "engine/items/itemfinder.asm"
SECTION "bank1D_2", ROMX
-INCLUDE "engine/menu/vending_machine.asm"
+INCLUDE "engine/events/vending_machine.asm"
SECTION "bank1D_3", ROMX
-INCLUDE "engine/menu/league_pc.asm"
-INCLUDE "engine/overworld/hidden_items.asm"
+INCLUDE "engine/menus/league_pc.asm"
+INCLUDE "engine/events/hidden_items.asm"
SECTION "bank1E", ROMX
@@ -368,7 +373,7 @@
INCLUDE "engine/battle/animations.asm"
INCLUDE "engine/overworld/cut2.asm"
-INCLUDE "engine/overworld/ssanne.asm"
+INCLUDE "engine/overworld/dust_smoke.asm"
RedFishingTilesFront: INCBIN "gfx/overworld/red_fish_front.2bpp"
RedFishingTilesBack: INCBIN "gfx/overworld/red_fish_back.2bpp"
@@ -376,6 +381,6 @@
RedFishingRodTiles: INCBIN "gfx/overworld/fishing_rod.2bpp"
INCLUDE "data/animations.asm"
-INCLUDE "engine/evolution.asm"
+INCLUDE "engine/movie/evolution.asm"
INCLUDE "engine/overworld/elevator.asm"
INCLUDE "engine/items/tm_prices.asm"