summaryrefslogtreecommitdiff
path: root/engine/items
diff options
context:
space:
mode:
Diffstat (limited to 'engine/items')
-rw-r--r--engine/items/get_bag_item_quantity.asm18
-rw-r--r--engine/items/inventory.asm8
-rwxr-xr-xengine/items/item_effects.asm (renamed from engine/items/items.asm)479
-rw-r--r--engine/items/subtract_paid_money.asm17
-rwxr-xr-xengine/items/tm_prices.asm14
-rwxr-xr-xengine/items/tmhm.asm4
-rwxr-xr-xengine/items/tms.asm2
-rwxr-xr-xengine/items/town_map.asm629
8 files changed, 893 insertions, 278 deletions
diff --git a/engine/items/get_bag_item_quantity.asm b/engine/items/get_bag_item_quantity.asm
new file mode 100644
index 00000000..f10df1a0
--- /dev/null
+++ b/engine/items/get_bag_item_quantity.asm
@@ -0,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
diff --git a/engine/items/inventory.asm b/engine/items/inventory.asm
index 58bcf7e9..c2e0b2b4 100644
--- a/engine/items/inventory.asm
+++ b/engine/items/inventory.asm
@@ -4,7 +4,7 @@
; [wcf91] = item ID
; [wItemQuantity] = item quantity
; sets carry flag if successful, unsets carry flag if unsuccessful
-AddItemToInventory_:
+AddItemToInventory_::
ld a, [wItemQuantity] ; a = item quantity
push af
push bc
@@ -12,10 +12,10 @@ AddItemToInventory_:
push hl
push hl
ld d, PC_ITEM_CAPACITY ; how many items the PC can hold
- ld a, wNumBagItems & $FF
+ ld a, LOW(wNumBagItems)
cp l
jr nz, .checkIfInventoryFull
- ld a, wNumBagItems >> 8
+ ld a, HIGH(wNumBagItems)
cp h
jr nz, .checkIfInventoryFull
; if the destination is the bag
@@ -98,7 +98,7 @@ AddItemToInventory_:
; hl = address of inventory (either wNumBagItems or wNumBoxItems)
; [wWhichPokemon] = index (within the inventory) of the item to remove
; [wItemQuantity] = quantity to remove
-RemoveItemFromInventory_:
+RemoveItemFromInventory_::
push hl
inc hl
ld a, [wWhichPokemon] ; index (within the inventory) of the item being removed
diff --git a/engine/items/items.asm b/engine/items/item_effects.asm
index e935f292..b1b458ab 100755
--- a/engine/items/items.asm
+++ b/engine/items/item_effects.asm
@@ -1,8 +1,8 @@
-UseItem_:
+UseItem_::
ld a, 1
ld [wActionResultOrTookBattleTurn], a ; initialise to success value
ld a, [wcf91] ;contains item_ID
- cp HM_01
+ cp HM01
jp nc, ItemUseTMHM
ld hl, ItemUsePtrTable
dec a
@@ -16,6 +16,7 @@ UseItem_:
jp hl
ItemUsePtrTable:
+; entries correspond to item ids
dw ItemUseBall ; MASTER_BALL
dw ItemUseBall ; ULTRA_BALL
dw ItemUseBall ; GREAT_BALL
@@ -149,7 +150,7 @@ ItemUseBall:
; 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
+ callfar IsGhostBattle
ld b, $10 ; can't be caught value
jp z, .setAnimData
@@ -167,12 +168,12 @@ ItemUseBall:
call CopyData ; save the player's name in the Wild Monster data (part of the Cinnabar Island Missingno. glitch)
ld a, [wBattleType]
cp BATTLE_TYPE_OLD_MAN
- jp nz,.captured
- ld a,$1
+ jp nz, .captured
+ ld a, $1
ld [wCapturedMonSpecies], a
CheckEvent EVENT_02F
ld b, $63
- jp nz,.setAnimData
+ jp nz, .setAnimData
jp .captured
.notOldManBattle
; If the player is fighting the ghost Marowak, set the value that indicates the
@@ -251,14 +252,14 @@ ItemUseBall:
; Calculate MaxHP * 255.
xor a
- ld [H_MULTIPLICAND], a
+ ldh [hMultiplicand], a
ld hl, wEnemyMonMaxHP
ld a, [hli]
- ld [H_MULTIPLICAND + 1], a
+ ldh [hMultiplicand + 1], a
ld a, [hl]
- ld [H_MULTIPLICAND + 2], a
+ ldh [hMultiplicand + 2], a
ld a, 255
- ld [H_MULTIPLIER], a
+ ldh [hMultiplier], a
call Multiply
; Determine BallFactor. It's 8 for Great Balls and 12 for the others.
@@ -272,7 +273,7 @@ ItemUseBall:
; Note that the results of all division operations are floored.
; Calculate (MaxHP * 255) / BallFactor.
- ld [H_DIVISOR], a
+ ldh [hDivisor], a
ld b, 4 ; number of bytes in dividend
call Divide
@@ -294,17 +295,17 @@ ItemUseBall:
.skip2
; Let W = ((MaxHP * 255) / BallFactor) / max(HP / 4, 1). Calculate W.
- ld [H_DIVISOR], a
+ ldh [hDivisor], 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]
+; If W > 255, store 255 in [hQuotient + 3].
+; Let X = min(W, 255) = [hQuotient + 3].
+ ldh a, [hQuotient + 2]
and a
jr z, .skip3
ld a, 255
- ld [H_QUOTIENT + 3], a
+ ldh [hQuotient + 3], a
.skip3
pop bc ; b = Rand1 - Status
@@ -315,7 +316,7 @@ ItemUseBall:
jr c, .failedToCapture
; If W > 255, the ball captures the Pokémon.
- ld a, [H_QUOTIENT + 2]
+ ldh a, [hQuotient + 2]
and a
jr nz, .captured
@@ -323,7 +324,7 @@ ItemUseBall:
; If Rand2 > X, the ball fails to capture the Pokémon.
ld b, a
- ld a, [H_QUOTIENT + 3]
+ ldh a, [hQuotient + 3]
cp b
jr c, .failedToCapture
@@ -331,17 +332,17 @@ ItemUseBall:
jr .skipShakeCalculations
.failedToCapture
- ld a, [H_QUOTIENT + 3]
+ ldh a, [hQuotient + 3]
ld [wPokeBallCaptureCalcTemp], a ; Save X.
; Calculate CatchRate * 100.
xor a
- ld [H_MULTIPLICAND], a
- ld [H_MULTIPLICAND + 1], a
+ ldh [hMultiplicand], a
+ ldh [hMultiplicand + 1], a
ld a, [wEnemyMonActualCatchRate]
- ld [H_MULTIPLICAND + 2], a
+ ldh [hMultiplicand + 2], a
ld a, 100
- ld [H_MULTIPLIER], a
+ ldh [hMultiplier], a
call Multiply
; Determine BallFactor2.
@@ -363,26 +364,26 @@ ItemUseBall:
; Let Y = (CatchRate * 100) / BallFactor2. Calculate Y.
ld a, b
- ld [H_DIVISOR], a
+ ldh [hDivisor], 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]
+ ldh a, [hQuotient + 2]
and a
ld b, $63 ; 3 shakes
jr nz, .setAnimData
; Calculate X * Y.
ld a, [wPokeBallCaptureCalcTemp]
- ld [H_MULTIPLIER], a
+ ldh [hMultiplier], a
call Multiply
; Calculate (X * Y) / 255.
ld a, 255
- ld [H_DIVISOR], a
+ ldh [hDivisor], a
ld b, 4
call Divide
@@ -400,19 +401,19 @@ ItemUseBall:
.addAilmentValue
; If the Pokémon has a status ailment, add Status2.
- ld a, [H_QUOTIENT + 3]
+ ldh a, [hQuotient + 3]
add b
- ld [H_QUOTIENT + 3], a
+ ldh [hQuotient + 3], a
.skip5
; Finally determine the number of shakes.
-; Let Z = ((X * Y) / 255) + Status2 = [H_QUOTIENT + 3].
+; Let Z = ((X * Y) / 255) + Status2 = [hQuotient + 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]
+ ldh a, [hQuotient + 3]
cp 10
ld b, $20
jr c, .setAnimData
@@ -436,7 +437,7 @@ ItemUseBall:
ld a, TOSS_ANIM
ld [wAnimationID], a
xor a
- ld [H_WHOSETURN], a
+ ldh [hWhoseTurn], a
ld [wAnimationType], a
ld [wDamageMultipliers], a
ld a, [wWhichPokemon]
@@ -509,7 +510,7 @@ ItemUseBall:
ld [wcf91], a
ld a, [wEnemyMonLevel]
ld [wCurEnemyLVL], a
- callab LoadEnemyMonData
+ callfar LoadEnemyMonData
pop af
ld [wcf91], a
pop hl
@@ -610,53 +611,53 @@ ItemUseBall:
ItemUseBallText00:
;"It dodged the thrown ball!"
;"This pokemon can't be caught"
- TX_FAR _ItemUseBallText00
- db "@"
+ text_far _ItemUseBallText00
+ text_end
ItemUseBallText01:
;"You missed the pokemon!"
- TX_FAR _ItemUseBallText01
- db "@"
+ text_far _ItemUseBallText01
+ text_end
ItemUseBallText02:
;"Darn! The pokemon broke free!"
- TX_FAR _ItemUseBallText02
- db "@"
+ text_far _ItemUseBallText02
+ text_end
ItemUseBallText03:
;"Aww! It appeared to be caught!"
- TX_FAR _ItemUseBallText03
- db "@"
+ text_far _ItemUseBallText03
+ text_end
ItemUseBallText04:
;"Shoot! It was so close too!"
- TX_FAR _ItemUseBallText04
- db "@"
+ text_far _ItemUseBallText04
+ text_end
ItemUseBallText05:
;"All right! {MonName} was caught!"
;play sound
- TX_FAR _ItemUseBallText05
- TX_SFX_CAUGHT_MON
- TX_BLINK
- db "@"
+ text_far _ItemUseBallText05
+ sound_caught_mon
+ text_promptbutton
+ text_end
ItemUseBallText07:
;"X was transferred to Bill's PC"
- TX_FAR _ItemUseBallText07
- db "@"
+ text_far _ItemUseBallText07
+ text_end
ItemUseBallText08:
;"X was transferred to someone's PC"
- TX_FAR _ItemUseBallText08
- db "@"
+ text_far _ItemUseBallText08
+ text_end
ItemUseBallText06:
;"New DEX data will be added..."
;play sound
- TX_FAR _ItemUseBallText06
- TX_SFX_DEX_PAGE_ADDED
- TX_BLINK
- db "@"
+ text_far _ItemUseBallText06
+ sound_dex_page_added
+ text_promptbutton
+ text_end
ItemUseTownMap:
ld a, [wIsInBattle]
and a
jp nz, ItemUseNotTime
- jpba DisplayTownMap
+ farjp DisplayTownMap
ItemUseBicycle:
ld a, [wIsInBattle]
@@ -683,7 +684,7 @@ ItemUseBicycle:
jp nc, NoCyclingAllowedHere
call ItemUseReloadOverworldData
xor a ; no keys pressed
- ld [hJoyHeld], a ; current joypad state
+ ldh [hJoyHeld], a ; current joypad state
ld a, $1
ld [wWalkBikeSurfState], a ; change player state to bicycling
call PlayDefaultMusic ; play bike riding music
@@ -719,11 +720,11 @@ ItemUseSurfboard:
.tryToStopSurfing
xor a
- ld [hSpriteIndexOrTextID], a
+ ldh [hSpriteIndexOrTextID], a
ld d, 16 ; talking range in pixels (normal range)
call IsSpriteInFrontOfPlayer2
res 7, [hl]
- ld a, [hSpriteIndexOrTextID]
+ ldh a, [hSpriteIndexOrTextID]
and a ; is there a sprite in the way?
jr nz, .cannotStopSurfing
ld hl, TilePairCollisionsWater
@@ -776,12 +777,12 @@ ItemUseSurfboard:
ret
SurfingGotOnText:
- TX_FAR _SurfingGotOnText
- db "@"
+ text_far _SurfingGotOnText
+ text_end
SurfingNoPlaceToGetOffText:
- TX_FAR _SurfingNoPlaceToGetOffText
- db "@"
+ text_far _SurfingNoPlaceToGetOffText
+ text_end
ItemUsePokedex:
predef_jump ShowPokedexMenu
@@ -808,10 +809,10 @@ ItemUseEvoStone:
ld [wcf91], a
call Func_d85d
jr nc, .noEffect
- callab IsThisPartymonStarterPikachu_Party
+ callfar IsThisPartymonStarterPikachu_Party
jr nc, .notPlayerPikachu
ld e, $1b
- callab PlayPikachuSoundClip
+ callfar PlayPikachuSoundClip
ld a, [wWhichPokemon]
ld hl, wPartyMonNicks
call GetPartyMonName
@@ -829,7 +830,7 @@ ItemUseEvoStone:
call WaitForSoundToFinish
ld a, $01
ld [wForceEvolution], a
- callab TryEvolvingMon ; try to evolve pokemon
+ callfar TryEvolvingMon ; try to evolve pokemon
pop af
ld [wWhichPokemon], a
ld hl, wNumBagItems
@@ -891,8 +892,8 @@ Func_d85d:
ret
RefusingText:
- TX_FAR _RefusingText
- db "@"
+ text_far _RefusingText
+ text_end
ItemUseVitamin:
ld a, [wIsInBattle]
@@ -1036,7 +1037,7 @@ ItemUseMedicine:
push hl
push de
push bc
- callab Func_2fd6a
+ callfar Func_2fd6a
pop bc
pop de
pop hl
@@ -1135,18 +1136,18 @@ ItemUseMedicine:
call AddNTimes
ld a, [hli]
ld [wHPBarMaxHP + 1], a
- ld [H_DIVIDEND], a
+ ldh [hDividend], a
ld a, [hl]
ld [wHPBarMaxHP], a
- ld [H_DIVIDEND + 1], a
+ ldh [hDividend + 1], a
ld a, 5
- ld [H_DIVISOR], a
+ ldh [hDivisor], 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]
+ ldh a, [hQuotient + 3]
push af
ld b, a
ld a, [hl]
@@ -1154,28 +1155,28 @@ ItemUseMedicine:
sub b
ld [hld], a
ld [wHPBarNewHP], a
- ld a, [H_QUOTIENT + 2]
+ ldh a, [hQuotient + 2]
ld b, a
ld a, [hl]
ld [wHPBarOldHP+1], a
sbc b
ld [hl], a
ld [wHPBarNewHP+1], a
- coord hl, 4, 1
+ hlcoord 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_0xFFFA]
+ ldh a, [hFlagsFFFA]
set 0, a
- ld [hFlags_0xFFFA], a
+ ldh [hFlagsFFFA], a
ld a, $02
ld [wHPBarType], a
predef UpdateHPBar2 ; animate HP bar decrease of pokemon that used Softboiled
- ld a, [hFlags_0xFFFA]
+ ldh a, [hFlagsFFFA]
res 0, a
- ld [hFlags_0xFFFA], a
+ ldh [hFlagsFFFA], a
pop af
ld b, a ; store heal amount (1/5 of max HP)
ld hl, wHPBarOldHP + 1
@@ -1322,15 +1323,15 @@ ItemUseMedicine:
jr z, .playStatusAilmentCuringSound
ld a, SFX_HEAL_HP
call PlaySoundWaitForCurrent
- ld a, [hFlags_0xFFFA]
+ ldh a, [hFlagsFFFA]
set 0, a
- ld [hFlags_0xFFFA], a
+ ldh [hFlagsFFFA], a
ld a, $02
ld [wHPBarType], a
predef UpdateHPBar2 ; animate the HP bar lengthening
- ld a, [hFlags_0xFFFA]
+ ldh a, [hFlagsFFFA]
res 0, a
- ld [hFlags_0xFFFA], a
+ ldh [hFlagsFFFA], a
ld a, REVIVE_MSG
ld [wPartyMenuTypeOrMessageID], a
ld a, [wcf91]
@@ -1347,13 +1348,13 @@ ItemUseMedicine:
call PlaySoundWaitForCurrent
.showHealingItemMessage
xor a
- ld [H_AUTOBGTRANSFERENABLED], a
+ ldh [hAutoBGTransferEnabled], 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
+ ldh [hAutoBGTransferEnabled], a
ld c, 50
call DelayFrames
call WaitForTextScrollButtonPress
@@ -1469,17 +1470,17 @@ ItemUseMedicine:
push hl
push de
ld d, a
- callab CalcExperience ; calculate experience for next level and store it at $ff96
+ callfar CalcExperience ; calculate experience for next level and store it at hExperience
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]
+ ldh a, [hExperience]
ld [hli], a
- ld a, [hExperience + 1]
+ ldh a, [hExperience + 1]
ld [hli], a
- ld a, [hExperience + 2]
+ ldh a, [hExperience + 2]
ld [hl], a
pop hl
ld a, [wWhichPokemon]
@@ -1528,7 +1529,7 @@ ItemUseMedicine:
ld [wMonDataLocation], a
call LoadMonData
ld d, $01
- callab PrintStatsBox ; display new stats text box
+ callfar PrintStatsBox ; display new stats text box
call WaitForTextScrollButtonPress ; wait for button press
xor a ; PLAYER_PARTY_DATA
ld [wMonDataLocation], a
@@ -1541,11 +1542,11 @@ ItemUseMedicine:
push af
ld a, [wUsedItemOnWhichPokemon]
ld [wWhichPokemon], a
- callab Func_2fd6a ; evolve pokemon, if appropriate
+ callfar Func_2fd6a ; evolve pokemon, if appropriate
pop af
ld [wWhichPokemon], a
- callab TryEvolvingMon
+ callfar TryEvolvingMon
ld a, $01
ld [wUpdateSpritesEnabled], a
pop af
@@ -1555,12 +1556,12 @@ ItemUseMedicine:
jp RemoveUsedItem
VitaminStatRoseText:
- TX_FAR _VitaminStatRoseText
- db "@"
+ text_far _VitaminStatRoseText
+ text_end
VitaminNoEffectText:
- TX_FAR _VitaminNoEffectText
- db "@"
+ text_far _VitaminNoEffectText
+ text_end
VitaminText:
db "HEALTH@"
@@ -1597,7 +1598,7 @@ BaitRockCommon:
ld [wAnimationID], a
xor a
ld [wAnimationType], a
- ld [H_WHOSETURN], a
+ ldh [hWhoseTurn], 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
@@ -1617,12 +1618,12 @@ BaitRockCommon:
jp DelayFrames
ThrewBaitText:
- TX_FAR _ThrewBaitText
- db "@"
+ text_far _ThrewBaitText
+ text_end
ThrewRockText:
- TX_FAR _ThrewRockText
- db "@"
+ text_far _ThrewRockText
+ text_end
; also used for Dig out-of-battle effect
ItemUseEscapeRope:
@@ -1669,9 +1670,7 @@ ItemUseEscapeRope:
.notUsable
jp ItemUseNotTime
-EscapeRopeTilesets:
- db FOREST, CEMETERY, CAVERN, FACILITY, INTERIOR
- db $ff ; terminator
+INCLUDE "data/tilesets/escape_rope_tilesets.asm"
ItemUseRepel:
ld b, 100
@@ -1721,7 +1720,7 @@ ItemUseCardKey:
ld b, a
.loop
ld a, [hli]
- cp $ff
+ cp -1
jp z, ItemUseNotTime
cp b
jr nz, .nextEntry1
@@ -1750,46 +1749,7 @@ ItemUseCardKey:
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
+INCLUDE "data/events/card_key_coords.asm"
ItemUsePokedoll:
ld a, [wIsInBattle]
@@ -1866,8 +1826,8 @@ ItemUseXStat:
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
+ ldh [hWhoseTurn], a ; set turn to player's turn
+ farcall StatModifierUpEffect ; do stat increase move
ld a, [wWhichPokemon]
push af
@@ -1923,13 +1883,13 @@ ItemUsePokeflute:
jr nz, .noSnorlaxOrPikachuToWakeUp
call CheckPikachuFollowingPlayer
jr z, .noSnorlaxOrPikachuToWakeUp
- callab IsPikachuRightNextToPlayer
+ callfar IsPikachuRightNextToPlayer
jr nc, .noSnorlaxOrPikachuToWakeUp
ld hl, PlayedFluteHadEffectText
call PrintText
call ItemUseReloadOverworldData
ldpikaemotion e, PikachuEmotion26
- callab PlaySpecificPikachuEmotion
+ callfar PlaySpecificPikachuEmotion
ret
.noSnorlaxOrPikachuToWakeUp
@@ -1976,7 +1936,7 @@ ItemUsePokeflute:
and $80
jr nz, .skipMusic
call WaitForSoundToFinish ; wait for sound to end
- callba Music_PokeFluteInBattle ; play in-battle pokeflute music
+ farcall Music_PokeFluteInBattle ; play in-battle pokeflute music
.musicWaitLoop ; wait for music to finish playing
ld a, [wChannelSoundIDs + Ch7]
and a ; music off?
@@ -2011,41 +1971,35 @@ WakeUpEntireParty:
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
+ dbmapcoord 9, 62 ; one space West of Snorlax
+ dbmapcoord 10, 61 ; one space North of Snorlax
+ dbmapcoord 10, 63 ; one space South of Snorlax
+ dbmapcoord 11, 62 ; one space East of Snorlax
+ db -1 ; end
-; 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
+ dbmapcoord 27, 10 ; one space East of Snorlax
+ dbmapcoord 25, 10 ; one space West of Snorlax
+ db -1 ; end
PlayedFluteNoEffectText:
- TX_FAR _PlayedFluteNoEffectText
- db "@"
+ text_far _PlayedFluteNoEffectText
+ text_end
FluteWokeUpText:
- TX_FAR _FluteWokeUpText
- db "@"
+ text_far _FluteWokeUpText
+ text_end
PlayedFluteHadEffectText:
- TX_FAR _PlayedFluteHadEffectText
- TX_BLINK
- TX_ASM
+ text_far _PlayedFluteHadEffectText
+ text_promptbutton
+ text_asm
ld a, [wIsInBattle]
and a
jr nz, .done
; play out-of-battle pokeflute music
- call StopAllMusic ; turn off music
+ call StopAllMusic
ld a, SFX_POKEFLUTE
ld c, BANK(SFX_Pokeflute)
call PlayMusic
@@ -2065,8 +2019,8 @@ ItemUseCoinCase:
jp PrintText
CoinCaseNumCoinsText:
- TX_FAR _CoinCaseNumCoinsText
- db "@"
+ text_far _CoinCaseNumCoinsText
+ text_end
ItemUseOldRod:
call FishingInit
@@ -2101,12 +2055,12 @@ ItemUseGoodRod:
xor 1
jr RodResponse
-INCLUDE "data/good_rod.asm"
+INCLUDE "data/wild/good_rod.asm"
ItemUseSuperRod:
call FishingInit
jp c, ItemUseNotTime
- callab ReadSuperRodData
+ callfar ReadSuperRodData
ld c, e
ld b, d
ld a, $2
@@ -2142,7 +2096,7 @@ DoNotGenerateFishingEncounter:
push af
push hl
ld [hl], 0
- callba FishingAnim
+ farcall FishingAnim
pop hl
pop af
ld [hl], a
@@ -2189,7 +2143,7 @@ ItemUseItemfinder:
and a
jp nz, ItemUseNotTime
call ItemUseReloadOverworldData
- callba HiddenItemNear ; check for hidden items
+ farcall HiddenItemNear ; check for hidden items
ld hl, ItemfinderFoundNothingText
jr nc, .printText ; if no hidden items
ld c, 4
@@ -2205,12 +2159,12 @@ ItemUseItemfinder:
jp PrintText
ItemfinderFoundItemText:
- TX_FAR _ItemfinderFoundItemText
- db "@"
+ text_far _ItemfinderFoundItemText
+ text_end
ItemfinderFoundNothingText:
- TX_FAR _ItemfinderFoundNothingText
- db "@"
+ text_far _ItemfinderFoundNothingText
+ text_end
ItemUsePPUp:
ld a, [wIsInBattle]
@@ -2261,7 +2215,7 @@ ItemUsePPRestore:
call PrintText
xor a
ld [wPlayerMoveListIndex], a
- callab MoveSelectionMenu ; move selection menu
+ callfar MoveSelectionMenu ; move selection menu
ld a, 0
ld [wPlayerMoveListIndex], a
jr nz, .chooseMon
@@ -2418,24 +2372,24 @@ ItemUsePPRestore:
ret
RaisePPWhichTechniqueText:
- TX_FAR _RaisePPWhichTechniqueText
- db "@"
+ text_far _RaisePPWhichTechniqueText
+ text_end
RestorePPWhichTechniqueText:
- TX_FAR _RestorePPWhichTechniqueText
- db "@"
+ text_far _RestorePPWhichTechniqueText
+ text_end
PPMaxedOutText:
- TX_FAR _PPMaxedOutText
- db "@"
+ text_far _PPMaxedOutText
+ text_end
PPIncreasedText:
- TX_FAR _PPIncreasedText
- db "@"
+ text_far _PPIncreasedText
+ text_end
PPRestoredText:
- TX_FAR _PPRestoredText
- db "@"
+ text_far _PPRestoredText
+ text_end
; for items that can't be used from the Item menu
UnusableItem:
@@ -2446,10 +2400,10 @@ ItemUseTMHM:
and a
jp nz, ItemUseNotTime
ld a, [wcf91]
- sub TM_01
+ sub TM01 ; underflows below 0 for HM items (before TM items)
push af
jr nc, .skipAdding
- add 55 ; if item is an HM, add 55
+ add NUM_TMS + NUM_HMS ; adjust HM IDs to come after TM IDs
.skipAdding
inc a
ld [wd11e], a
@@ -2466,7 +2420,7 @@ ItemUseTMHM:
call PrintText
ld hl, TeachMachineMoveText
call PrintText
- coord hl, 14, 7
+ hlcoord 14, 7
lb bc, 8, 15
ld a, TWO_OPTION_MENU
ld [wTextBoxID], a
@@ -2525,7 +2479,7 @@ ItemUseTMHM:
jr .chooseMon
.checkIfAlreadyLearnedMove
- callab CheckIfMoveIsKnown ; check if the pokemon already knows the move
+ callfar CheckIfMoveIsKnown ; check if the pokemon already knows the move
jr c, .chooseMon
predef LearnMove ; teach move
ld a, [wWhichPokemon]
@@ -2543,12 +2497,12 @@ ItemUseTMHM:
ld a, d
ld [wWhichPokemon], a
callabd_ModifyPikachuHappiness PIKAHAPPY_USEDTMHM
- callab IsThisPartymonStarterPikachu_Party
+ callfar IsThisPartymonStarterPikachu_Party
jr nc, .notTeachingThunderboltOrThunderToPikachu
ld a, [wcf91]
- cp TM_24 ; are we teaching thunderbolt to the player pikachu?
+ cp TM_THUNDERBOLT ; are we teaching thunderbolt to the player pikachu?
jr z, .teachingThunderboltOrThunderToPlayerPikachu
- cp TM_25 ; are we teaching thunder then?
+ cp TM_THUNDER ; are we teaching thunder then?
jr nz, .notTeachingThunderboltOrThunderToPikachu
.teachingThunderboltOrThunderToPlayerPikachu
ld a, $5
@@ -2565,20 +2519,20 @@ ItemUseTMHM:
jp RemoveUsedItem
BootedUpTMText:
- TX_FAR _BootedUpTMText
- db "@"
+ text_far _BootedUpTMText
+ text_end
BootedUpHMText:
- TX_FAR _BootedUpHMText
- db "@"
+ text_far _BootedUpHMText
+ text_end
TeachMachineMoveText:
- TX_FAR _TeachMachineMoveText
- db "@"
+ text_far _TeachMachineMoveText
+ text_end
MonCannotLearnMachineMoveText:
- TX_FAR _MonCannotLearnMachineMoveText
- db "@"
+ text_far _MonCannotLearnMachineMoveText
+ text_end
PrintItemUseTextAndRemoveItem:
ld hl, ItemUseText00
@@ -2641,58 +2595,58 @@ ItemUseFailed:
jp PrintText
ItemUseNotTimeText:
- TX_FAR _ItemUseNotTimeText
- db "@"
+ text_far _ItemUseNotTimeText
+ text_end
ItemUseNotYoursToUseText:
- TX_FAR _ItemUseNotYoursToUseText
- db "@"
+ text_far _ItemUseNotYoursToUseText
+ text_end
ItemUseNoEffectText:
- TX_FAR _ItemUseNoEffectText
- db "@"
+ text_far _ItemUseNoEffectText
+ text_end
ThrowBallAtTrainerMonText1:
- TX_FAR _ThrowBallAtTrainerMonText1
- db "@"
+ text_far _ThrowBallAtTrainerMonText1
+ text_end
ThrowBallAtTrainerMonText2:
- TX_FAR _ThrowBallAtTrainerMonText2
- db "@"
+ text_far _ThrowBallAtTrainerMonText2
+ text_end
NoCyclingAllowedHereText:
- TX_FAR _NoCyclingAllowedHereText
- db "@"
+ text_far _NoCyclingAllowedHereText
+ text_end
NoSurfingHereText:
- TX_FAR _NoSurfingHereText
- db "@"
+ text_far _NoSurfingHereText
+ text_end
BoxFullCannotThrowBallText:
- TX_FAR _BoxFullCannotThrowBallText
- db "@"
+ text_far _BoxFullCannotThrowBallText
+ text_end
DontHavePokemonText:
- TX_FAR _DontHavePokemonText
- db "@"
+ text_far _DontHavePokemonText
+ text_end
ItemUseText00:
- TX_FAR _ItemUseText001
- TX_LINE
- TX_FAR _ItemUseText002
- db "@"
+ text_far _ItemUseText001
+ text_low
+ text_far _ItemUseText002
+ text_end
GotOnBicycleText:
- TX_FAR _GotOnBicycleText1
- TX_LINE
- TX_FAR _GotOnBicycleText2
- db "@"
+ text_far _GotOnBicycleText1
+ text_low
+ text_far _GotOnBicycleText2
+ text_end
GotOffBicycleText:
- TX_FAR _GotOffBicycleText1
- TX_LINE
- TX_FAR _GotOffBicycleText2
- db "@"
+ text_far _GotOffBicycleText1
+ text_low
+ text_far _GotOffBicycleText2
+ text_end
; 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
@@ -2744,13 +2698,13 @@ RestoreBonusPP:
AddBonusPP:
push bc
ld a, [de] ; normal max PP of move
- ld [H_DIVIDEND + 3], a
+ ldh [hDividend + 3], a
xor a
- ld [H_DIVIDEND], a
- ld [H_DIVIDEND + 1], a
- ld [H_DIVIDEND + 2], a
+ ldh [hDividend], a
+ ldh [hDividend + 1], a
+ ldh [hDividend + 2], a
ld a, 5
- ld [H_DIVISOR], a
+ ldh [hDivisor], a
ld b, 4
call Divide
ld a, [hl] ; move PP
@@ -2761,7 +2715,7 @@ AddBonusPP:
srl a
ld c, a ; c = number of PP Ups used
.loop
- ld a, [H_QUOTIENT + 3]
+ ldh a, [hQuotient + 3]
cp 8 ; is the amount greater than or equal to 8?
jr c, .addAmount
ld a, 7 ; cap the amount at 7
@@ -2870,7 +2824,7 @@ GetSelectedMoveOffset2:
; [wItemQuantity] = quantity to toss
; OUTPUT:
; clears carry flag if the item is tossed, sets carry flag if not
-TossItem_:
+TossItem_::
push hl
ld a, [wcf91]
call IsItemHM
@@ -2889,7 +2843,7 @@ TossItem_:
call CopyStringToCF4B ; copy name to wcf4b
ld hl, IsItOKToTossItemText
call PrintText
- coord hl, 14, 7
+ hlcoord 14, 7
lb bc, 8, 15
ld a, TWO_OPTION_MENU
ld [wTextBoxID], a
@@ -2922,16 +2876,16 @@ TossItem_:
ret
ThrewAwayItemText:
- TX_FAR _ThrewAwayItemText
- db "@"
+ text_far _ThrewAwayItemText
+ text_end
IsItOKToTossItemText:
- TX_FAR _IsItOKToTossItemText
- db "@"
+ text_far _IsItOKToTossItemText
+ text_end
TooImportantToTossText:
- TX_FAR _TooImportantToTossText
- db "@"
+ text_far _TooImportantToTossText
+ text_end
; checks if an item is a key item
; INPUT:
@@ -2940,11 +2894,11 @@ TooImportantToTossText:
; [wIsKeyItem] = result
; 00: item is not key item
; 01: item is key item
-IsKeyItem_:
+IsKeyItem_::
ld a, $01
ld [wIsKeyItem], a
ld a, [wcf91]
- cp HM_01 ; is the item an HM or TM?
+ cp HM01 ; is the item an HM or TM?
jr nc, .checkIfItemIsHM
; if the item is not an HM or TM
push af
@@ -2969,7 +2923,7 @@ IsKeyItem_:
ld [wIsKeyItem], a
ret
-INCLUDE "data/key_items.asm"
+INCLUDE "data/items/key_items.asm"
SendNewMonToBox:
ld de, wNumInBox
@@ -3103,15 +3057,15 @@ SendNewMonToBox:
push de
ld a, [wCurEnemyLVL]
ld d, a
- callab CalcExperience
+ callfar CalcExperience
pop de
- ld a, [hExperience]
+ ldh a, [hExperience]
ld [de], a
inc de
- ld a, [hExperience + 1]
+ ldh a, [hExperience + 1]
ld [de], a
inc de
- ld a, [hExperience + 2]
+ ldh a, [hExperience + 2]
ld [de], a
inc de
xor a
@@ -3146,7 +3100,7 @@ SendNewMonToBox:
; 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:
+IsNextTileShoreOrWater::
ld a, [wCurMapTileset]
ld hl, WaterTilesets
ld de, 1
@@ -3167,10 +3121,7 @@ IsNextTileShoreOrWater:
call IsInArray
ret
-; tilesets with water
-WaterTilesets:
- db OVERWORLD, FOREST, DOJO, GYM, SHIP, SHIP_PORT, CAVERN, FACILITY, PLATEAU
- db $ff ; terminator
+INCLUDE "data/tilesets/water_tilesets.asm"
; shore tiles
ShoreTiles:
diff --git a/engine/items/subtract_paid_money.asm b/engine/items/subtract_paid_money.asm
new file mode 100644
index 00000000..fdefe3d6
--- /dev/null
+++ b/engine/items/subtract_paid_money.asm
@@ -0,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
diff --git a/engine/items/tm_prices.asm b/engine/items/tm_prices.asm
index 80e6bf3c..df9761bd 100755
--- a/engine/items/tm_prices.asm
+++ b/engine/items/tm_prices.asm
@@ -1,9 +1,9 @@
-GetMachinePrice:
+GetMachinePrice::
; Input: [wcf91] = Item Id of a TM
; Output: Stores the TM price at hItemPrice
ld a, [wcf91] ; a contains TM item id
- sub TM_01
- ret c
+ sub TM01 ; underflows below 0 for HM items (before TM items)
+ ret c ; HMs are priceless
ld d, a
ld hl, TechnicalMachinePrices
srl a
@@ -16,10 +16,10 @@ GetMachinePrice:
swap a
.highNybbleIsPrice
and $f0
- ld [hItemPrice + 1], a
+ ldh [hItemPrice + 1], a
xor a
- ld [hItemPrice], a
- ld [hItemPrice + 2], a
+ ldh [hItemPrice], a
+ ldh [hItemPrice + 2], a
ret
-INCLUDE "data/tm_prices.asm"
+INCLUDE "data/items/tm_prices.asm"
diff --git a/engine/items/tmhm.asm b/engine/items/tmhm.asm
index 7ccaa232..a11cd736 100755
--- a/engine/items/tmhm.asm
+++ b/engine/items/tmhm.asm
@@ -22,5 +22,5 @@ CheckIfMoveIsKnown:
ret
AlreadyKnowsText:
- TX_FAR _AlreadyKnowsText
- db "@"
+ text_far _AlreadyKnowsText
+ text_end
diff --git a/engine/items/tms.asm b/engine/items/tms.asm
index 84770747..dcf2665d 100755
--- a/engine/items/tms.asm
+++ b/engine/items/tms.asm
@@ -39,4 +39,4 @@ TMToMove:
ld [wd11e], a
ret
-INCLUDE "data/tms.asm"
+INCLUDE "data/moves/tmhm_moves.asm"
diff --git a/engine/items/town_map.asm b/engine/items/town_map.asm
new file mode 100755
index 00000000..c401d1c1
--- /dev/null
+++ b/engine/items/town_map.asm
@@ -0,0 +1,629 @@
+NOT_VISITED EQU $fe
+
+DisplayTownMap:
+ call LoadTownMap
+ ld hl, wUpdateSpritesEnabled
+ ld a, [hl]
+ push af
+ ld [hl], $ff
+ push hl
+ ld a, $1
+ ldh [hJoy7], a
+ ld a, [wCurMap]
+ push af
+ ld b, $0
+ call DrawPlayerOrBirdSprite ; player sprite
+ hlcoord 1, 0
+ ld de, wcd6d
+ call PlaceString
+ ld hl, wOAMBuffer
+ ld de, wTileMapBackup
+ ld bc, $10
+ call CopyData
+ ld hl, vSprites tile $04
+ ld de, TownMapCursor
+ lb bc, BANK(TownMapCursor), (TownMapCursorEnd - TownMapCursor) / $8
+ call CopyVideoDataDouble
+ xor a
+ ld [wWhichTownMapLocation], a
+ pop af
+ jr .enterLoop
+
+.townMapLoop
+ hlcoord 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
+ hlcoord 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
+ ldh 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
+ ldh [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
+
+.asm_70f87
+ ldh a, [hJoy5]
+ and D_DOWN | D_UP
+ ret z
+ callfar PlayPikachuSoundClip
+ ret
+
+INCLUDE "data/maps/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
+ hlcoord 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
+ ld a, $1
+ ldh [hJoy7], a
+ call LoadPlayerSpriteGraphics
+ call LoadFontTilePatterns
+ ld de, BirdSprite
+ ld b, BANK(BirdSprite)
+ ld c, $c
+ ld hl, vSprites tile $04
+ call CopyVideoData
+ ld de, TownMapUpArrow
+ ld hl, vChars1 tile $6d
+ lb bc, BANK(TownMapUpArrow), (TownMapUpArrowEnd - TownMapUpArrow) / $8
+ call CopyVideoDataDouble
+ call BuildFlyLocationsList
+ ld hl, wUpdateSpritesEnabled
+ ld a, [hl]
+ push af
+ ld [hl], $ff
+ push hl
+ hlcoord 0, 0
+ ld de, ToText
+ call PlaceString
+ ld a, [wCurMap]
+ ld b, $0
+ call DrawPlayerOrBirdSprite
+ ld hl, wFlyLocationsList
+ decoord 18, 0
+.townMapFlyLoop
+ ld a, " "
+ ld [de], a
+ push hl
+ push hl
+ hlcoord 3, 0
+ lb bc, 1, 15
+ call ClearScreenArea
+ pop hl
+ ld a, [hl]
+ ld b, $4
+ call DrawPlayerOrBirdSprite ; draw bird sprite
+ hlcoord 3, 0
+ ld de, wcd6d
+ call PlaceString
+ ld c, 15
+ call DelayFrames
+ hlcoord 18, 0
+ ld [hl], "▶"
+ hlcoord 19, 0
+ ld [hl], "▼"
+ pop hl
+.inputLoop
+ push hl
+ call DelayFrame
+ call JoypadLowSensitivity
+ ldh 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
+ ldh [hJoy7], a
+ call GBPalWhiteOutWithDelay3
+ pop hl
+ pop af
+ ld [hl], a
+ ret
+.pressedUp
+ decoord 18, 0
+ inc hl
+ ld a, [hl]
+ cp $ff
+ jr z, .wrapToStartOfList
+ cp NOT_VISITED
+ jr z, .pressedUp ; skip past unvisited towns
+ jp .townMapFlyLoop
+.wrapToStartOfList
+ ld hl, wFlyLocationsList
+ jp .townMapFlyLoop
+.pressedDown
+ decoord 19, 0
+ dec hl
+ ld a, [hl]
+ cp $ff
+ jr z, .wrapToEndOfList
+ cp NOT_VISITED
+ jr z, .pressedDown ; skip past unvisited towns
+ jp .townMapFlyLoop
+.wrapToEndOfList
+ ld hl, wFlyLocationsList + NUM_CITY_MAPS
+ 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
+ lb bc, 0, NUM_CITY_MAPS
+.loop
+ srl d
+ rr e
+ ld a, NOT_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
+ hlcoord 0, 0
+ lb bc, $12, $12
+ call TextBoxBorder
+ call DisableLCD
+ ld hl, WorldMapTileGraphics
+ ld de, vChars2 tile $60
+ ld bc, WorldMapTileGraphicsEnd - WorldMapTileGraphics
+ ld a, BANK(WorldMapTileGraphics)
+ call FarCopyData
+ ld hl, MonNestIcon
+ ld de, vSprites tile $04
+ ld bc, MonNestIconEnd - MonNestIcon
+ ld a, BANK(MonNestIcon)
+ call FarCopyDataDouble
+ hlcoord 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:
+ farcall 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
+ hlcoord 1, 7
+ lb bc, 2, 15
+ call TextBoxBorder
+ hlcoord 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 FIRST_INDOOR_MAP
+ 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/maps/town_map_entries.asm"
+
+INCLUDE "data/maps/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