From f558d784a87d7b56b2cacfc2f543f63237ad8183 Mon Sep 17 00:00:00 2001 From: "U-Daniel-PC\\Daniel" Date: Thu, 4 Jun 2015 23:15:09 -0500 Subject: EOL Windows->UNIX --- engine/items/items.asm | 5744 +++++++++++++++++++------------------- engine/overworld/map_sprites.asm | 880 +++--- 2 files changed, 3312 insertions(+), 3312 deletions(-) (limited to 'engine') diff --git a/engine/items/items.asm b/engine/items/items.asm index beb85cde..c6f098dc 100755 --- a/engine/items/items.asm +++ b/engine/items/items.asm @@ -1,2872 +1,2872 @@ -UseItem_: ; d5c7 (3:55c7) - ld a,1 - ld [wcd6a],a - ld a,[wcf91] ;contains item_ID - cp a,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: ; d5e1 (3:55e1) - 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 OldRodCode ; OLD_ROD - dw GoodRodCode ; GOOD_ROD - dw SuperRodCode ; SUPER_ROD - dw ItemUsePPUp ; PP_UP (real one) - dw ItemUsePPRestore ; ETHER - dw ItemUsePPRestore ; MAX_ETHER - dw ItemUsePPRestore ; ELIXER - dw ItemUsePPRestore ; MAX_ELIXER - -ItemUseBall: ; d687 (3:5687) - ld a,[W_ISINBATTLE] - and a - jp z,ItemUseNotTime ; not in battle - dec a - jp nz,ThrowBallAtTrainerMon - ld a,[W_BATTLETYPE] - dec a - jr z,.UseBall - ld a,[wPartyCount] ;is Party full? - cp a,PARTY_LENGTH - jr nz,.UseBall - ld a,[W_NUMINBOX] ;is Box full? - cp a,MONS_PER_BOX - jp z,BoxFullCannotThrowBall -.UseBall ;$56a7 -;ok, you can use a ball - xor a - ld [wd11c],a - ld a,[W_BATTLETYPE] - cp a,2 ;SafariBattle - jr nz,.skipSafariZoneCode -.safariZone - ; remove a Safari Ball from inventory - ld hl,W_NUMSAFARIBALLS - dec [hl] -.skipSafariZoneCode ;$56b6 - call GoPAL_SET_CF1C - ld a,$43 - ld [wd11e],a - call LoadScreenTilesFromBuffer1 ;restore screenBuffer from Backup - ld hl,ItemUseText00 - call PrintText - callab IsGhostBattle - ld b,$10 - jp z,.next12 - ld a,[W_BATTLETYPE] - dec a - jr nz,.notOldManBattle -.oldManBattle - ld hl,W_GRASSRATE - ld de,wPlayerName - ld bc,11 - call CopyData ; save the player's name in the Wild Monster data (part of the Cinnabar Island Missingno glitch) - jp .BallSuccess ;$578b -.notOldManBattle ;$56e9 - ld a,[W_CURMAP] - cp a,POKEMONTOWER_6 - jr nz,.loop - ld a,[wEnemyMonSpecies2] - cp a,MAROWAK - ld b,$10 - jp z,.next12 -; if not fighting ghost Marowak, loop until a random number in the current -; pokeball's allowed range is found -.loop ;$56fa - call Random - ld b,a - ld hl,wcf91 - ld a,[hl] - cp a,MASTER_BALL - jp z,.BallSuccess ;$578b - cp a,POKE_BALL - jr z,.checkForAilments - ld a,200 - cp b - jr c,.loop ;get only numbers <= 200 for Great Ball - ld a,[hl] - cp a,GREAT_BALL - jr z,.checkForAilments - ld a,150 ;get only numbers <= 150 for Ultra Ball - cp b - jr c,.loop -.checkForAilments ;$571a -; pokemon can be caught more easily with any (primary) status ailment -; Frozen/Asleep pokemon are relatively even easier to catch -; for Frozen/Asleep pokemon, any random number from 0-24 ensures a catch. -; for the others, a random number from 0-11 ensures a catch. - ld a,[wEnemyMonStatus] ;status ailments - and a - jr z,.noAilments - and a, 1 << FRZ | SLP ;is frozen and/or asleep? - ld c,12 - jr z,.notFrozenOrAsleep - ld c,25 -.notFrozenOrAsleep ;$5728 - ld a,b - sub c - jp c,.BallSuccess ;$578b - ld b,a -.noAilments ;$572e - push bc ;save RANDOM number - 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 ; MaxHP * 255 - ld a,[wcf91] - cp a,GREAT_BALL - ld a,12 ;any other BallFactor - jr nz,.next7 - ld a,8 -.next7 ;$574d - ld [H_DIVISOR],a - ld b,4 ; number of bytes in dividend - call Divide - ld hl,wEnemyMonHP - ld a,[hli] - ld b,a - ld a,[hl] - -; explanation: we have a 16-bit value equal to [b << 8 | a]. -; This number is divided by 4. The result is 8 bit (reg. a). -; Always bigger than zero. - srl b - rr a - srl b - rr a ; a = current HP / 4 - and a - jr nz,.next8 - inc a -.next8 ;$5766 - ld [H_DIVISOR],a - ld b,4 - call Divide ; ((MaxHP * 255) / BallFactor) / (CurHP / 4) - ld a,[H_QUOTIENT + 2] - and a - jr z,.next9 - ld a,255 - ld [H_QUOTIENT + 3],a -.next9 ;$5776 - pop bc - ld a,[wEnemyMonCatchRate] ;enemy: Catch Rate - cp b - jr c,.next10 - ld a,[H_QUOTIENT + 2] - and a - jr nz,.BallSuccess ; if ((MaxHP * 255) / BallFactor) / (CurHP / 4) > 0x255, automatic success - call Random - ld b,a - ld a,[H_QUOTIENT + 3] - cp b - jr c,.next10 -.BallSuccess ;$578b - jr .BallSuccess2 -.next10 ;$578d - ld a,[H_QUOTIENT + 3] - ld [wd11e],a - xor a - ld [H_MULTIPLICAND],a - ld [H_MULTIPLICAND + 1],a - ld a,[wEnemyMonCatchRate] ;enemy: Catch Rate - ld [H_MULTIPLICAND + 2],a - ld a,100 - ld [H_MULTIPLIER],a - call Multiply ; CatchRate * 100 - ld a,[wcf91] - ld b,255 - cp a,POKE_BALL - jr z,.next11 - ld b,200 - cp a,GREAT_BALL - jr z,.next11 - ld b,150 - cp a,ULTRA_BALL - jr z,.next11 -.next11 ;$57b8 - ld a,b - ld [H_DIVISOR],a - ld b,4 - call Divide - ld a,[H_QUOTIENT + 2] - and a - ld b,$63 - jr nz,.next12 - ld a,[wd11e] - ld [H_MULTIPLIER],a - call Multiply - ld a,255 - ld [H_DIVISOR],a - ld b,4 - call Divide - ld a,[wEnemyMonStatus] ;status ailments - and a - jr z,.next13 - and a, 1 << FRZ | SLP - ld b,5 - jr z,.next14 - ld b,10 -.next14 ;$57e6 - ld a,[H_QUOTIENT + 3] - add b - ld [H_QUOTIENT + 3],a -.next13 ;$57eb - ld a,[H_QUOTIENT + 3] - cp a,10 - ld b,$20 - jr c,.next12 - cp a,30 - ld b,$61 - jr c,.next12 - cp a,70 - ld b,$62 - jr c,.next12 - ld b,$63 -.next12 ;$5801 - ld a,b - ld [wd11e],a -.BallSuccess2 ;$5805 - ld c,20 - call DelayFrames - ld a,TOSS_ANIM - ld [W_ANIMATIONID],a - xor a - ld [$fff3],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 - ld a,[wd11e] - cp a,$10 - ld hl,ItemUseBallText00 - jp z,.printText0 - cp a,$20 - ld hl,ItemUseBallText01 - jp z,.printText0 - cp a,$61 - ld hl,ItemUseBallText02 - jp z,.printText0 - cp a,$62 - ld hl,ItemUseBallText03 - jp z,.printText0 - cp a,$63 - ld hl,ItemUseBallText04 - jp z,.printText0 - ld hl,wEnemyMonHP ;current HP - ld a,[hli] - push af - ld a,[hli] - push af ;backup currentHP... - inc hl - ld a,[hl] - push af ;...and status ailments - push hl - ld hl,W_ENEMYBATTSTATUS3 - bit Transformed,[hl] - jr z,.next15 - ld a,$4c - ld [wEnemyMonSpecies2],a - jr .next16 -.next15 ;$5871 - set Transformed,[hl] - ld hl,wcceb - ld a,[wEnemyMonDVs] - ld [hli],a - ld a,[wEnemyMonDVs + 1] - ld [hl],a -.next16 ;$587e - ld a,[wcf91] - push af - ld a,[wEnemyMonSpecies2] - ld [wcf91],a - ld a,[wEnemyMonLevel] - ld [W_CURENEMYLVL],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] ;enemy - ld [wd11c],a - ld [wcf91],a - ld [wd11e],a - ld a,[W_BATTLETYPE] - dec a - jr z,.printText1 - ld hl,ItemUseBallText05 - call PrintText - predef IndexToPokedex - ld a,[wd11e] - dec a - ld c,a - ld b,2 - ld hl,wPokedexOwned ;Dex_own_flags (pokemon) - predef FlagActionPredef - ld a,c - push af - ld a,[wd11e] - dec a - ld c,a - ld b,1 - predef FlagActionPredef - pop af - and a - jr nz,.checkParty - ld hl,ItemUseBallText06 - call PrintText - call ClearSprites - ld a,[wEnemyMonSpecies] ;caught mon_ID - ld [wd11e],a - predef ShowPokedexData -.checkParty ;$58f4 - ld a,[wPartyCount] - cp a,PARTY_LENGTH ;is party full? - jr z,.sendToBox - xor a - ld [wcc49],a - call ClearSprites - call AddPartyMon ;add mon to Party - jr .End -.sendToBox ;$5907 - call ClearSprites - call SendNewMonToBox - ld hl,ItemUseBallText07 - ld a,[wd7f1] - bit 0,a ;already met Bill? - jr nz,.sendToBox2 - ld hl,ItemUseBallText08 -.sendToBox2 ;$591a - call PrintText - jr .End -.printText1 ;$591f - ld hl,ItemUseBallText05 -.printText0 ;$5922 - call PrintText - call ClearSprites -.End ;$5928 - ld a,[W_BATTLETYPE] - and a - ret nz - ld hl,wNumBagItems - inc a - ld [wcf96],a - jp RemoveItemFromInventory ;remove ITEM (XXX) -ItemUseBallText00: ; d937 (3:5937) -;"It dodged the thrown ball!" -;"This pokemon can't be caught" - TX_FAR _ItemUseBallText00 - db "@" -ItemUseBallText01: ; d93c (3:593c) -;"You missed the pokemon!" - TX_FAR _ItemUseBallText01 - db "@" -ItemUseBallText02: ; d941 (3:5941) -;"Darn! The pokemon broke free!" - TX_FAR _ItemUseBallText02 - db "@" -ItemUseBallText03: ; d946 (3:5946) -;"Aww! It appeared to be caught!" - TX_FAR _ItemUseBallText03 - db "@" -ItemUseBallText04: ; d94b (3:594b) -;"Shoot! It was so close too!" - TX_FAR _ItemUseBallText04 - db "@" -ItemUseBallText05: ; d950 (3:5950) -;"All right! {MonName} was caught!" -;play sound - TX_FAR _ItemUseBallText05 - db $12,$06 - db "@" -ItemUseBallText07: ; d957 (3:5957) -;"X was transferred to Bill's PC" - TX_FAR _ItemUseBallText07 - db "@" -ItemUseBallText08: ; d95c (3:595c) -;"X was transferred to someone's PC" - TX_FAR _ItemUseBallText08 - db "@" - -ItemUseBallText06: ; d961 (3:5961) -;"New DEX data will be added..." -;play sound - TX_FAR _ItemUseBallText06 - db $13,$06 - db "@" - -ItemUseTownMap: ; d968 (3:5968) - ld a,[W_ISINBATTLE] - and a - jp nz,ItemUseNotTime - ld b, BANK(DisplayTownMap) - ld hl, DisplayTownMap - jp Bankswitch ; display Town Map - -ItemUseBicycle: ; d977 (3:5977) - ld a,[W_ISINBATTLE] - and a - jp nz,ItemUseNotTime - ld a,[wWalkBikeSurfState] - ld [wWalkBikeSurfStateCopy],a - cp a,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: ; d9b4 (3:59b4) - ld a,[wWalkBikeSurfState] - ld [wWalkBikeSurfStateCopy],a - cp a,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 [$ff8c],a - ld d,16 ; talking range in pixels (normal range) - call IsSpriteInFrontOfPlayer2 - res 7,[hl] - ld a,[$ff8c] - and a ; is there a sprite in the way? - jr nz,.cannotStopSurfing - ld hl,TilePairCollisionsWater - call CheckForTilePairCollisions - jr c,.cannotStopSurfing - ld hl,W_TILESETCOLLISIONPTR ; pointer to list of passable tiles - ld a,[hli] - ld h,[hl] - ld l,a ; hl now points to passable tiles - ld a,[wTileInFrontOfPlayer] ; tile in front of the player - ld b,a -.passableTileLoop - ld a,[hli] - cp b - jr z,.stopSurfing - cp a,$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,[wd52a] ; direction the player is going - bit 3,a - ld b,D_UP - jr nz,.storeSimulatedButtonPress - bit 2,a - ld b,D_DOWN - jr nz,.storeSimulatedButtonPress - bit 1,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: ; da4c (3:5a4c) - TX_FAR _SurfingGotOnText - db "@" - -SurfingNoPlaceToGetOffText: ; da51 (3:5a51) - TX_FAR _SurfingNoPlaceToGetOffText - db "@" - -ItemUsePokedex: ; da56 (3:5a56) - predef_jump ShowPokedexMenu - -ItemUseEvoStone: ; da5b (3:5a5b) - ld a,[W_ISINBATTLE] - and a - jp nz,ItemUseNotTime - ld a,[wWhichPokemon] - push af - ld a,[wcf91] - ld [wd156],a - push af - ld a,$05 ; evolution stone party menu - ld [wd07d],a - ld a,$ff - ld [wUpdateSpritesEnabled],a - call DisplayPartyMenu - pop bc - jr c,.canceledItemUse - ld a,b - ld [wcf91],a - ld a,$01 - ld [wccd4],a - ld a,(SFX_02_3e - SFX_Headers_02) / 3 - call PlaySoundWaitForCurrent ; play sound - call WaitForSoundToFinish ; wait for sound to end - callab TryEvolvingMon ; try to evolve pokemon - ld a,[wd121] - and a - jr z,.noEffect - pop af - ld [wWhichPokemon],a - ld hl,wNumBagItems - ld a,1 ; remove 1 stone - ld [wcf96],a - jp RemoveItemFromInventory -.noEffect - call ItemUseNoEffect -.canceledItemUse - xor a - ld [wcd6a],a - pop af - ret - -ItemUseVitamin: ; dab4 (3:5ab4) - ld a,[W_ISINBATTLE] - and a - jp nz,ItemUseNotTime - -ItemUseMedicine: ; dabb (3:5abb) - ld a,[wPartyCount] - and a - jp z,.emptyParty - ld a,[wWhichPokemon] - push af - ld a,[wcf91] - push af - ld a,$01 - ld [wd07d],a ; item use party menu - ld a,$ff - ld [wUpdateSpritesEnabled],a - ld a,[wd152] - and a ; using Softboiled? - jr z,.notUsingSoftboiled -; if using softboiled - call GoBackToPartyMenu - jr .getPartyMonDataAddress -.emptyParty - ld hl,.emptyPartyText - xor a - ld [wcd6a],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 [wcf06],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,[wd152] - 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 a,REVIVE - jr nc,.healHP ; if it's a Revive or Max Revive - cp a,FULL_HEAL - jr z,.cureStatusAilment ; if it's a Full Heal - cp a,HP_UP - jp nc,.useVitamin ; if it's a vitamin or Rare Candy - cp a,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-specifc healing items -.cureStatusAilment - ld bc,4 - add hl,bc ; hl now points to status - ld a,[wcf91] - ld bc,$f008 - cp a,ANTIDOTE - jr z,.checkMonStatus - ld bc,$f110 - cp a,BURN_HEAL - jr z,.checkMonStatus - ld bc,$f220 - cp a,ICE_HEAL - jr z,.checkMonStatus - ld bc,$f307 - cp a,AWAKENING - jr z,.checkMonStatus - ld bc,$f440 - cp a,PARLYZ_HEAL - jr z,.checkMonStatus - ld bc,$f6ff ; 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 [wd07d],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,W_PLAYERBATTSTATUS3 - res BadlyPoisoned,[hl] ; heal Toxic status - pop hl - ld bc,30 - add hl,bc ; hl now points to party stats - ld de,wBattleMonMaxHP - ld bc,10 - 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 a,REVIVE - jr z,.updateInBattleFaintedData - cp a,MAX_REVIVE - jr z,.updateInBattleFaintedData - jp .healingItemNoEffect -.updateInBattleFaintedData - ld a,[W_ISINBATTLE] - and a - jr z,.compareCurrentHPToMaxHP - push hl - push de - push bc - ld a,[wcf06] - ld c,a - ld hl,wPartyFoughtCurrentEnemyFlags - ld b,$02 - predef FlagActionPredef - ld a,c - and a - jr z,.next - ld a,[wcf06] - ld c,a - ld hl,wPartyGainExpFlags - ld b,$01 - predef FlagActionPredef -.next - pop bc - pop de - pop hl - jr .compareCurrentHPToMaxHP -.notFainted - ld a,[wcf91] - cp a,REVIVE - jp z,.healingItemNoEffect - cp a,MAX_REVIVE - jp z,.healingItemNoEffect -.compareCurrentHPToMaxHP - push hl - push bc - ld bc,32 - 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 a,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 [wc02a],a - push hl - push de - ld bc,32 - 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,[wd152] - 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 - wPartyMon1MaxHP - 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 - hlCoord 4, 1 - ld a,[wWhichPokemon] - ld bc,2 * 20 - call AddNTimes ; calculate coordinates of HP bar of pokemon that used Softboiled - ld a,(SFX_02_3d - SFX_Headers_02) / 3 - call PlaySoundWaitForCurrent ; play sound - 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 a,SODA_POP - ld b,60 ; Soda Pop heal amount - jr z,.addHealAmount - ld b,80 ; Lemonade heal amount - jr nc,.addHealAmount - cp a,FRESH_WATER - ld b,50 ; Fresh Water heal amount - jr z,.addHealAmount - cp a,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,33 - add hl,de ; hl now points to max HP - ld a,[wcf91] - cp a,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 a,HYPER_POTION - jr c,.setCurrentHPToMaxHp ; if using a Full Restore or Max Potion - cp a,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 a,FULL_RESTORE - jr nz,.updateInBattleData - ld bc,-31 - 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 a,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 * 20 - inc d -.calculateHPBarCoordsLoop - add hl,bc - dec d - jr nz,.calculateHPBarCoordsLoop - jr .doneHealing -.healingItemNoEffect - call ItemUseNoEffect - jp .done -.doneHealing - ld a,[wd152] - 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 a,FULL_RESTORE - jr c,.playStatusAilmentCuringSound - cp a,FULL_HEAL - jr z,.playStatusAilmentCuringSound - ld a,(SFX_02_3d - SFX_Headers_02) / 3 ; HP healing sound - call PlaySoundWaitForCurrent ; play sound - 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,$f7 ; revived message - ld [wd07d],a - ld a,[wcf91] - cp a,REVIVE - jr z,.showHealingItemMessage - cp a,MAX_REVIVE - jr z,.showHealingItemMessage - ld a,$f5 ; standard HP healed message - ld [wd07d],a - jr .showHealingItemMessage -.playStatusAilmentCuringSound - ld a,(SFX_02_3e - SFX_Headers_02) / 3 ; status ailment curing sound - 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 [wcd6a],a ; item use failed - pop af - pop af -.done - ld a,[wd152] - and a ; using Softboiled? - ret nz ; if so, return - call GBPalWhiteOut - call z,GoPAL_SET_CF1C - ld a,[W_ISINBATTLE] - and a - ret nz - jp ReloadMapData -.useVitamin - push hl - ld a,[hl] - ld [wd0b5],a - ld [wd11e],a - ld bc,33 - add hl,bc ; hl now points to level - ld a,[hl] ; a = level - ld [W_CURENEMYLVL],a ; store level - call GetMonHeader - push de - ld a,d - ld hl,wPartyMonNicks - call GetPartyMonName - pop de - pop hl - ld a,[wcf91] - cp a,RARE_CANDY - jp z,.useRareCandy - push hl - sub a,HP_UP - add a - ld bc,17 - 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 a,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 a,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_02_3e - SFX_Headers_02) / 3 - call PlaySound ; play sound - ld hl,VitaminStatRoseText - call PrintText - jp RemoveUsedItem -.vitaminNoEffect - pop hl - ld hl,VitaminNoEffectText - call PrintText - jp GBPalWhiteOut -.recalculateStats - ld bc,34 - add hl,bc - ld d,h - ld e,l ; de now points to stats - ld bc,-18 - add hl,bc ; hl now points to byte 3 of experience - ld b,1 - jp CalcStats ; recalculate stats -.useRareCandy - push hl - ld bc,33 - add hl,bc ; hl now points to level - ld a,[hl] ; a = level - cp a, MAX_LEVEL - jr z,.vitaminNoEffect ; can't raise level above 100 - inc a - ld [hl],a ; store incremented level - ld [W_CURENEMYLVL],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,-19 - add hl,bc ; hl now points to experience -; update experience to minimum for new level - ld a,[$ff96] - ld [hli],a - ld a,[$ff97] - ld [hli],a - ld a,[$ff98] - ld [hl],a - pop hl - ld a,[wWhichPokemon] - push af - ld a,[wcf91] - push af - push de - push hl - ld bc,34 - 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,35 ; hl now points to LSB of max HP - add hl,bc - 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,-32 - add hl,de ; hl now points to MSB of current HP - ld a,[hl] - add c - ld [hld],a - ld a,[hl] - adc b - ld [hl],a - ld a,$f8 ; level up message - ld [wd07d],a - call RedrawPartyMenu - pop de - ld a,d - ld [wWhichPokemon],a - ld a,e - ld [wd11e],a - xor a - ld [wcc49],a ; load from player's party - call LoadMonData - ld d,$01 - callab PrintStatsBox ; display new stats text box - call WaitForTextScrollButtonPress ; wait for button press - xor a - ld [wcc49],a - predef LearnMoveFromLevelUp ; learn level up move, if any - xor a - ld [wccd4],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: ; df24 (3:5f24) - TX_FAR _VitaminStatRoseText - db "@" - -VitaminNoEffectText: ; df29 (3:5f29) - TX_FAR _VitaminNoEffectText - db "@" - -VitaminText: ; df2e (3:5f2e) - db "HEALTH@" - db "ATTACK@" - db "DEFENSE@" - db "SPEED@" - db "SPECIAL@" - -ItemUseBait: ; df52 (3:5f52) - ld hl,ThrewBaitText - call PrintText - ld hl,wEnemyMonCatchRate ; catch rate - srl [hl] ; halve catch rate - ld a,BAIT_ANIM - ld hl,wSafariBaitFactor ; bait factor - ld de,wSafariEscapeFactor ; escape factor - jr BaitRockCommon - -ItemUseRock: ; df67 (3:5f67) - ld hl,ThrewRockText - call PrintText - ld hl,wEnemyMonCatchRate ; 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: ; df7f (3:5f7f) - ld [W_ANIMATIONID],a - xor a - ld [wcc5b],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 a,7 - cp a,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: ; dfa5 (3:5fa5) - TX_FAR _ThrewBaitText - db "@" - -ThrewRockText: ; dfaa (3:5faa) - TX_FAR _ThrewRockText - db "@" - -; also used for Dig out-of-battle effect -ItemUseEscapeRope: ; dfaf (3:5faf) - ld a,[W_ISINBATTLE] - and a - jr nz,.notUsable - ld a,[W_CURMAP] - cp a,AGATHAS_ROOM - jr z,.notUsable - ld a,[W_CURMAPTILESET] - ld b,a - ld hl,EscapeRopeTilesets -.loop - ld a,[hli] - cp a,$ff - jr z,.notUsable - cp b - jr nz,.loop - ld hl,wd732 - set 3,[hl] - set 6,[hl] - ld hl,wd72e - res 4,[hl] - ld hl,wd790 - res 7,[hl] ; unset Safari Zone bit - xor a - ld [W_NUMSAFARIBALLS],a - ld [W_SAFARIZONEENTRANCECURSCRIPT],a - inc a - ld [wEscapedFromBattle],a - ld [wcd6a],a ; item used - ld a,[wd152] - and a ; using Dig? - ret nz ; if so, return - call ItemUseReloadOverworldData - ld c,30 - call DelayFrames - jp RemoveUsedItem -.notUsable - jp ItemUseNotTime - -EscapeRopeTilesets: ; dffd (3:5ffd) - db FOREST, CEMETERY, CAVERN, FACILITY, INTERIOR - db $ff ; terminator - -ItemUseRepel: ; e003 (3:6003) - ld b,100 - -ItemUseRepelCommon: ; e005 (3:6005) - ld a,[W_ISINBATTLE] - and a - jp nz,ItemUseNotTime - ld a,b - ld [wRepelRemainingSteps],a - jp PrintItemUseTextAndRemoveItem - -; handles X Accuracy item -ItemUseXAccuracy: ; e013 (3:6013) - ld a,[W_ISINBATTLE] - and a - jp z,ItemUseNotTime - ld hl,W_PLAYERBATTSTATUS2 - set UsingXAccuracy,[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: ; e022 (3:6022) - xor a - ld [wd71f],a - call GetTileAndCoordsInFrontOfPlayer - ld a,[GetTileAndCoordsInFrontOfPlayer] ; $4586 - cp a,$18 - jr nz,.next0 - ld hl,CardKeyTable1 - jr .next1 -.next0 - cp a,$24 - jr nz,.next2 - ld hl,CardKeyTable2 - jr .next1 -.next2 - cp a,$5e - jp nz,ItemUseNotTime - ld hl,CardKeyTable3 -.next1 - ld a,[W_CURMAP] - ld b,a -.loop - ld a,[hli] - cp a,$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 [wd71f],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: ; e072 (3:6072) - 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: ; e09b (3:609b) - 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: ; e0c4 (3:60c4) - db SILPH_CO_11F,$08,$09,$14 - db SILPH_CO_11F,$09,$09,$15 - db $ff - -ItemUsePokedoll: ; e0cd (3:60cd) - ld a,[W_ISINBATTLE] - dec a - jp nz,ItemUseNotTime - ld a,$01 - ld [wEscapedFromBattle],a - jp PrintItemUseTextAndRemoveItem - -ItemUseGuardSpec: ; e0dc (3:60dc) - ld a,[W_ISINBATTLE] - and a - jp z,ItemUseNotTime - ld hl,W_PLAYERBATTSTATUS2 - set ProtectedByMist,[hl] ; Mist bit - jp PrintItemUseTextAndRemoveItem - -ItemUseSuperRepel: ; e0eb (3:60eb) - ld b,200 - jp ItemUseRepelCommon - -ItemUseMaxRepel: ; e0f0 (3:60f0) - ld b,250 - jp ItemUseRepelCommon - -ItemUseDireHit: ; e0f5 (3:60f5) - ld a,[W_ISINBATTLE] - and a - jp z,ItemUseNotTime - ld hl,W_PLAYERBATTSTATUS2 - set GettingPumped,[hl] ; Focus Energy bit - jp PrintItemUseTextAndRemoveItem - -ItemUseXStat: ; e104 (3:6104) - ld a,[W_ISINBATTLE] - and a - jr nz,.inBattle - call ItemUseNotTime - ld a,2 - ld [wcd6a],a ; item not used - ret -.inBattle - ld hl,W_PLAYERMOVENUM - ld a,[hli] - push af ; save [W_PLAYERMOVENUM] - ld a,[hl] - push af ; save [W_PLAYERMOVEEFFECT] - push hl - ld a,[wcf91] - sub a,X_ATTACK - ATTACK_UP1_EFFECT - ld [hl],a ; store player move effect - call PrintItemUseTextAndRemoveItem - ld a,XSTATITEM_ANIM ; X stat item animation ID - ld [W_PLAYERMOVENUM],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 [W_PLAYERMOVEEFFECT] - pop af - ld [hl],a ; restore [W_PLAYERMOVENUM] - ret - -ItemUsePokeflute: ; e140 (3:6140) - ld a,[W_ISINBATTLE] - and a - jr nz,.inBattle -; if not in battle - call ItemUseReloadOverworldData - ld a,[W_CURMAP] - cp a,ROUTE_12 - jr nz,.notRoute12 - ld a,[wd7d8] - bit 7,a ; has the player beaten Route 12 Snorlax yet? - 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 - ld hl,wd7d8 - set 6,[hl] ; trigger Snorlax fight (handled by map script) - ret -.notRoute12 - cp a,ROUTE_16 - jr nz,.noSnorlaxToWakeUp - ld a,[wd7e0] - bit 1,a ; has the player beaten Route 16 Snorlax yet? - 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 - ld hl,wd7e0 - set 0,[hl] ; trigger Snorlax fight (handled by map script) - ret -.noSnorlaxToWakeUp - ld hl,PlayedFluteNoEffectText - jp PrintText -.inBattle - xor a - ld [wWhichTrade],a ; initialize variable that indicates if any pokemon were woken up to zero - ld b,~SLP & $FF - ld hl,wPartyMon1Status - call WakeUpEntireParty - ld a,[W_ISINBATTLE] - 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,[wWhichTrade] - 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 a,$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,[wc02c] - 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 -; [wWhichTrade] should be initialized to 0 -; OUTPUT: -; [wWhichTrade]: set to 1 if any pokemon were asleep -WakeUpEntireParty: ; e1e5 (3:61e5) - ld de,44 - ld c,6 -.loop - ld a,[hl] - push af - and a,SLP ; is pokemon asleep? - jr z,.notAsleep - ld a,1 - ld [wWhichTrade],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: ; e1fd (3:61fd) - 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: ; e206 (3:6206) - db 10,27 ; one space East of Snorlax - db 10,25 ; one space West of Snorlax - db $ff ; terminator - -PlayedFluteNoEffectText: ; e20b (3:620b) - TX_FAR _PlayedFluteNoEffectText - db "@" - -FluteWokeUpText: ; e210 (3:6210) - TX_FAR _FluteWokeUpText - db "@" - -PlayedFluteHadEffectText: ; e215 (3:6215) - TX_FAR _PlayedFluteHadEffectText - db $06 - db $08 - ld a,[W_ISINBATTLE] - and a - jr nz,.done -; play out-of-battle pokeflute music - ld a,$ff - call PlaySound ; turn off music - ld a, (SFX_02_5e - SFX_Headers_02) / 3 - ld c, BANK(SFX_02_5e) - call PlayMusic ; play music -.musicWaitLoop ; wait for music to finish playing - ld a,[wc028] - cp a,$b8 - jr z,.musicWaitLoop - call PlayDefaultMusic ; start playing normal music again -.done - jp TextScriptEnd ; end text - -ItemUseCoinCase: ; e23a (3:623a) - ld a,[W_ISINBATTLE] - and a - jp nz,ItemUseNotTime - ld hl,CoinCaseNumCoinsText - jp PrintText - -CoinCaseNumCoinsText: ; e247 (3:6247) - TX_FAR _CoinCaseNumCoinsText - db "@" - -OldRodCode: ; e24c (3:624c) - call FishingInit - jp c, ItemUseNotTime - ld bc, (5 << 8) | MAGIKARP - ld a, $1 ; set bite - jr RodResponse ; 0xe257 $34 - -GoodRodCode: ; e259 (3:6259) - 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,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" - -SuperRodCode: ; e283 (3:6283) - call FishingInit - jp c, ItemUseNotTime - call ReadSuperRodData ; 0xe8ea - ld a, e -RodResponse: ; e28d (3:628d) - ld [wWhichTrade], a - - dec a ; is there a bite? - jr nz, .next - ; if yes, store level and species data - ld a, 1 - ld [W_MOVEMISSED], a - ld a, b ; level - ld [W_CURENEMYLVL], a - ld a, c ; species - ld [W_CUROPPONENT], a - -.next - ld hl, wWalkBikeSurfState - ld a, [hl] ; store the value in a - push af - push hl - ld [hl], 0 - callba Func_707b6 - 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: ; e2b4 (3:62b4) - ld a,[W_ISINBATTLE] - and a - jr z,.notInBattle - scf ; can't fish during battle - ret -.notInBattle - call IsNextTileShoreOrWater - ret c - ld a,[wWalkBikeSurfState] - cp a,2 ; Surfing? - jr z,.surfing - call ItemUseReloadOverworldData - ld hl,ItemUseText00 - call PrintText - ld a,(SFX_02_3e - SFX_Headers_02) / 3 - call PlaySound ; play sound - ld c,80 - call DelayFrames - and a - ret -.surfing - scf ; can't fish when surfing - ret - -ItemUseOaksParcel: ; e2de (3:62de) - jp ItemUseNotYoursToUse - -ItemUseItemfinder: ; e2e1 (3:62e1) - ld a,[W_ISINBATTLE] - 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_02_4a - SFX_Headers_02) / 3 - call PlaySoundWaitForCurrent ; play sound - ld a,(SFX_02_5a - SFX_Headers_02) / 3 - call PlaySoundWaitForCurrent ; play sound - dec c - jr nz,.loop - ld hl,ItemfinderFoundItemText -.printText - jp PrintText - -ItemfinderFoundItemText: ; e30d (3:630d) - TX_FAR _ItemfinderFoundItemText - db "@" - -ItemfinderFoundNothingText: ; e312 (3:6312) - TX_FAR _ItemfinderFoundNothingText - db "@" - -ItemUsePPUp: ; e317 (3:6317) - ld a,[W_ISINBATTLE] - and a - jp nz,ItemUseNotTime - -ItemUsePPRestore: ; e31e (3:631e) - ld a,[wWhichPokemon] - push af - ld a,[wcf91] - ld [wWhichTrade],a -.chooseMon - xor a - ld [wUpdateSpritesEnabled],a - ld a,$01 ; item use party menu - ld [wd07d],a - call DisplayPartyMenu - jr nc,.chooseMove - jp .itemNotUsed -.chooseMove - ld a,[wWhichTrade] - cp a,ELIXER - jp nc,.useElixir ; if Elixir or Max Elixir - ld a,$02 - ld [wMoveMenuType],a - ld hl,RaisePPWhichTechniqueText - ld a,[wWhichTrade] - cp a,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,44 - call GetSelectedMoveOffset - push hl - ld a,[hl] - ld [wd11e],a - call GetMoveName - call CopyStringToCF4B ; copy name to wcf4b - pop hl - ld a,[wWhichTrade] - cp a,ETHER - jr nc,.useEther ; if Ether or Max Ether -.usePPUp - ld bc,21 - add hl,bc - ld a,[hl] ; move PP - cp a,3 << 6 ; have 3 PP Ups already been used? - jr c,.PPNotMaxedOut - ld hl,PPMaxedOutText - call PrintText - jr .chooseMove -.PPNotMaxedOut - ld a,[hl] - add a,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 GoPAL_SET_CF1C - 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,44 - call AddNTimes - ld de,wBattleMonPP - ld bc,4 - call CopyData ; copy party data to in-battle data -.skipUpdatingInBattleData - ld a,(SFX_02_3e - SFX_Headers_02) / 3 - 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 - ld [wcc49],a ; party pokemon - call GetMaxPP - ld hl,wPartyMon1Moves - ld bc,44 - call GetSelectedMoveOffset - ld bc,21 - add hl,bc ; hl now points to move's PP - ld a,[wd11e] - ld b,a ; b = max PP - ld a,[wWhichTrade] - cp a,MAX_ETHER - jr z,.fullyRestorePP - ld a,[hl] ; move PP - and a,%00111111 ; lower 6 bit bits store current PP - cp b ; does current PP equal max PP? - ret z ; if so, return - add a,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 a,%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,wWhichTrade - 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,44 - 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 GoPAL_SET_CF1C - pop af - xor a - ld [wcd6a],a ; item use failed - ret - -RaisePPWhichTechniqueText: ; e45d (3:645d) - TX_FAR _RaisePPWhichTechniqueText - db "@" - -RestorePPWhichTechniqueText: ; e462 (3:6462) - TX_FAR _RestorePPWhichTechniqueText - db "@" - -PPMaxedOutText: ; e467 (3:6467) - TX_FAR _PPMaxedOutText - db "@" - -PPIncreasedText: ; e46c (3:646c) - TX_FAR _PPIncreasedText - db "@" - -PPRestoredText: ; e471 (3:6471) - TX_FAR _PPRestoredText - db "@" - -; for items that can't be used from the Item menu -UnusableItem: ; e476 (3:6476) - jp ItemUseNotTime - -ItemUseTMHM: ; e479 (3:6479) - ld a,[W_ISINBATTLE] - and a - jp nz,ItemUseNotTime - ld a,[wcf91] - sub a,TM_01 - push af - jr nc,.skipAdding - add a,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 - hlCoord 14, 7 - ld bc,$080f - 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 [wcd6a],a ; item not used - ret -.useMachine - ld a,[wWhichPokemon] - push af - ld a,[wcf91] - push af -.chooseMon - ld hl,wcf4b - ld de,wd036 - ld bc,14 - call CopyData - ld a,$ff - ld [wUpdateSpritesEnabled],a - ld a,$03 ; teach TM/HM party menu - ld [wd07d],a - call DisplayPartyMenu - push af - ld hl,wd036 - 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 GoPAL_SET_CF1C - 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_02_51 - SFX_Headers_02) / 3 - call PlaySoundWaitForCurrent ; play sound - 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: ; e54f (3:654f) - TX_FAR _BootedUpTMText - db "@" - -BootedUpHMText: ; e554 (3:6554) - TX_FAR _BootedUpHMText - db "@" - -TeachMachineMoveText: ; e559 (3:6559) - TX_FAR _TeachMachineMoveText - db "@" - -MonCannotLearnMachineMoveText: ; e55e (3:655e) - TX_FAR _MonCannotLearnMachineMoveText - db "@" - -PrintItemUseTextAndRemoveItem: ; e563 (3:6563) - ld hl,ItemUseText00 - call PrintText - ld a,(SFX_02_3e - SFX_Headers_02) / 3 - call PlaySound ; play sound - call WaitForTextScrollButtonPress ; wait for button press - -RemoveUsedItem: ; e571 (3:6571) - ld hl,wNumBagItems - ld a,1 ; one item - ld [wcf96],a ; store quantity - jp RemoveItemFromInventory - -ItemUseNoEffect: ; e57c (3:657c) - ld hl,ItemUseNoEffectText - jr ItemUseFailed - -ItemUseNotTime: ; e581 (3:6581) - ld hl,ItemUseNotTimeText - jr ItemUseFailed - -ItemUseNotYoursToUse: ; e586 (3:6586) - ld hl,ItemUseNotYoursToUseText - jr ItemUseFailed - -ThrowBallAtTrainerMon: ; e58b (3:658b) - call GoPAL_SET_CF1C - call LoadScreenTilesFromBuffer1 ; restore saved screen - call Delay3 - ld a,TOSS_ANIM - ld [W_ANIMATIONID],a - predef MoveAnimation ; do animation - ld hl,ThrowBallAtTrainerMonText1 - call PrintText - ld hl,ThrowBallAtTrainerMonText2 - call PrintText - jr RemoveUsedItem - -NoCyclingAllowedHere: ; e5ac (3:65ac) - ld hl,NoCyclingAllowedHereText - jr ItemUseFailed - -BoxFullCannotThrowBall: ; e5b1 (3:65b1) - ld hl,BoxFullCannotThrowBallText - jr ItemUseFailed - -SurfingAttemptFailed: ; e5b6 (3:65b6) - ld hl,NoSurfingHereText - -ItemUseFailed: ; e5b9 (3:65b9) - xor a - ld [wcd6a],a ; item use failed - jp PrintText - -ItemUseNotTimeText: ; e5c0 (3:65c0) - TX_FAR _ItemUseNotTimeText - db "@" - -ItemUseNotYoursToUseText: ; e5c5 (3:65c5) - TX_FAR _ItemUseNotYoursToUseText - db "@" - -ItemUseNoEffectText: ; e5ca (3:65ca) - TX_FAR _ItemUseNoEffectText - db "@" - -ThrowBallAtTrainerMonText1: ; e5cf (3:65cf) - TX_FAR _ThrowBallAtTrainerMonText1 - db "@" - -ThrowBallAtTrainerMonText2: ; e5d4 (3:65d4) - TX_FAR _ThrowBallAtTrainerMonText2 - db "@" - -NoCyclingAllowedHereText: ; e5d9 (3:65d9) - TX_FAR _NoCyclingAllowedHereText - db "@" - -NoSurfingHereText: ; e5de (3:65de) - TX_FAR _NoSurfingHereText - db "@" - -BoxFullCannotThrowBallText: ; e5e3 (3:65e3) - TX_FAR _BoxFullCannotThrowBallText - db "@" - -ItemUseText00: ; e5e8 (3:65e8) - TX_FAR _ItemUseText001 - db $05 - TX_FAR _ItemUseText002 - db "@" - -GotOnBicycleText: ; e5f2 (3:65f2) - TX_FAR _GotOnBicycleText1 - db $05 - TX_FAR _GotOnBicycleText2 - db "@" - -GotOffBicycleText: ; e5fc (3:65fc) - TX_FAR _GotOffBicycleText1 - db $05 - 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 -; [wd11e] = mode -; 0: Pokemon Center healing -; 1: using a PP Up -; [wCurrentMenuItem] = index of move (when using a PP Up) -RestoreBonusPP: ; e606 (3:6606) - ld hl,wPartyMon1Moves - ld bc,44 - ld a,[wWhichPokemon] - call AddNTimes - push hl - ld de,wcd78 - 1 - predef LoadMovePPs ; loads the normal max PP of each of the pokemon's moves to wcd78 - pop hl - ld c,21 - ld b,0 - add hl,bc ; hl now points to move 1 PP - ld de,wcd78 - ld b,0 ; initialize move counter to zero -; loop through the pokemon's moves -.loop - inc b - ld a,b - cp a,5 ; reached the end of the pokemon's moves? - ret z ; if so, return - ld a,[wd11e] - 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 a,%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 -; [wd11e] = max number of times to add bonus -; set to 1 when using a PP Up, set to 255 otherwise -AddBonusPP: ; e642 (3:6642) - 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 a,%00001111 - srl a - srl a - ld c,a ; c = number of PP Ups used -.loop - ld a,[H_QUOTIENT + 3] - cp a,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,[wd11e] - dec a - jr z,.done - 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 -; [wcc49] = 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: -; [wd11e] = max PP -GetMaxPP: ; e677 (3:6677) - ld a,[wcc49] - 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,6 - call AddNTimes - ld de,wcd6d - ld a,BANK(Moves) - call FarCopyData - ld de,wcd72 - ld a,[de] - ld b,a ; b = normal max PP - pop hl - push bc - ld bc,21 ; PP offset if not player's in-battle pokemon data - ld a,[wcc49] - cp a,4 ; player's in-battle pokemon? - jr nz,.addPPOffset - ld bc,17 ; PP offset if player's in-battle pokemon data -.addPPOffset - add hl,bc - ld a,[hl] ; a = current PP - and a,%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 - ld [wd11e],a ; no limit on PP Up amount - call AddBonusPP ; add bonus PP from PP Ups - ld a,[hl] - and a,%00111111 ; mask out the PP Up count - ld [wd11e],a ; store max PP - ret - -GetSelectedMoveOffset: ; e6e3 (3:66e3) - ld a,[wWhichPokemon] - call AddNTimes - -GetSelectedMoveOffset2: ; e6e9 (3:66e9) - 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 -; [wcf96] = quantity to toss -; OUTPUT: -; clears carry flag if the item is tossed, sets carry flag if not -TossItem_: ; e6f1 (3:66f1) - push hl - ld a,[wcf91] - call IsItemHM - pop hl - jr c,.tooImportantToToss - push hl - call IsKeyItem_ - ld a,[wd124] - 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 - hlCoord 14, 7 - ld bc,$080f - ld a,TWO_OPTION_MENU - ld [wTextBoxID],a - call DisplayTextBoxID ; yes/no menu - ld a,[wd12e] - cp a,2 - pop hl - scf - ret z -; 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: ; e755 (3:6755) - TX_FAR _ThrewAwayItemText - db "@" - -IsItOKToTossItemText: ; e75a (3:675a) - TX_FAR _IsItOKToTossItemText - db "@" - -TooImportantToTossText: ; e75f (3:675f) - TX_FAR _TooImportantToTossText - db "@" - -; checks if an item is a key item -; INPUT: -; [wcf91] = item ID -; OUTPUT: -; [wd124] = result -; 00: item is not key item -; 01: item is key item -IsKeyItem_: ; e764 (3:6764) - ld a,$01 - ld [wd124],a - ld a,[wcf91] - cp a,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,wHPBarMaxHP - ld bc,15 ; only 11 bytes are actually used - call CopyData - pop af - dec a - ld c,a - ld hl,wHPBarMaxHP - ld b,$02 ; test bit - predef FlagActionPredef ; bitfield operation function - ld a,c - and a - ret nz -.checkIfItemIsHM - ld a,[wcf91] - call IsItemHM - ret c - xor a - ld [wd124],a - ret - -INCLUDE "data/key_items.asm" - -SendNewMonToBox: ; e7a4 (3:67a4) - ld de, W_NUMINBOX ; wda80 - 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, $b - ld a, [W_NUMINBOX] ; wda80 - dec a - jr z, .asm_e7ee - dec a - call AddNTimes - push hl - ld bc, $b - add hl, bc - ld d, h - ld e, l - pop hl - ld a, [W_NUMINBOX] ; wda80 - dec a - ld b, a -.asm_e7db - push bc - push hl - ld bc, $b - call CopyData - pop hl - ld d, h - ld e, l - ld bc, $fff5 - add hl, bc - pop bc - dec b - jr nz, .asm_e7db -.asm_e7ee - ld hl, wPlayerName ; wd158 - ld de, wBoxMonOT - ld bc, $b - call CopyData - ld a, [W_NUMINBOX] ; wda80 - dec a - jr z, .asm_e82a - ld hl, wBoxMonNicks - ld bc, $b - dec a - call AddNTimes - push hl - ld bc, $b - add hl, bc - ld d, h - ld e, l - pop hl - ld a, [W_NUMINBOX] ; wda80 - dec a - ld b, a -.asm_e817 - push bc - push hl - ld bc, $b - call CopyData - pop hl - ld d, h - ld e, l - ld bc, $fff5 - add hl, bc - pop bc - dec b - jr nz, .asm_e817 -.asm_e82a - ld hl, wBoxMonNicks - ld a, $2 - ld [wd07d], a - predef AskName - ld a, [W_NUMINBOX] ; wda80 - 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, [W_NUMINBOX] ; wda80 - 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, $ffdf - add hl, bc - pop bc - dec b - jr nz, .asm_e854 -.asm_e867 - ld a, [wEnemyMonLevel] ; wEnemyMonLevel - ld [wEnemyMonBoxLevel], a - ld hl, wEnemyMon - ld de, wBoxMon1 - ld bc, $c - call CopyData - ld hl, wPlayerID ; wPlayerID - ld a, [hli] - ld [de], a - inc de - ld a, [hl] - ld [de], a - inc de - push de - ld a, [W_CURENEMYLVL] ; W_CURENEMYLVL - ld d, a - callab CalcExperience - pop de - ld a, [H_NUMTOPRINT] ; $ff96 (aliases: H_MULTIPLICAND) - ld [de], a - inc de - ld a, [$ff97] - ld [de], a - inc de - ld a, [$ff98] - ld [de], a - inc de - xor a - ld b, $a -.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 ; wcffe - ld b, $4 -.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: ; e8b8 (3:68b8) - ld a, [W_CURMAPTILESET] - ld hl, WaterTilesets - ld de,1 - call IsInArray ; does the current map allow surfing? - ret nc ; if not, return - ld hl,WaterTile - ld a, [W_CURMAPTILESET] - cp SHIP_PORT ; Vermilion Dock tileset - jr z, .skipShoreTiles ; if it's the Vermilion Dock tileset - cp GYM ; eastern shore tile in Safari Zone - jr z, .skipShoreTiles - cp DOJO ; usual eastern shore tile - jr z, .skipShoreTiles - ld hl,ShoreTiles -.skipShoreTiles - ld a,[wTileInFrontOfPlayer] - ld de,$1 - call IsInArray - ret - -; tilesets with water -WaterTilesets: ; e834 (3:6834) - db OVERWORLD, FOREST, DOJO, GYM, SHIP, SHIP_PORT, CAVERN, FACILITY, PLATEAU - db $ff ; terminator - -; shore tiles -ShoreTiles: ; e83e (3:683e) - db $48, $32 -WaterTile: ; e840 (3:6840) - db $14 - db $ff ; terminator - -ReadSuperRodData: ; e8ea (3:68ea) -; 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, [W_CURMAP] - 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 ; 0xe8f6 -; 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 ; 0xe90c - 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: ; e9c5 (3:69c5) - 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: ; e9cb (3:69cb) - 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: ; e9f0 (3:69f0) - 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 +UseItem_: ; d5c7 (3:55c7) + ld a,1 + ld [wcd6a],a + ld a,[wcf91] ;contains item_ID + cp a,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: ; d5e1 (3:55e1) + 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 OldRodCode ; OLD_ROD + dw GoodRodCode ; GOOD_ROD + dw SuperRodCode ; SUPER_ROD + dw ItemUsePPUp ; PP_UP (real one) + dw ItemUsePPRestore ; ETHER + dw ItemUsePPRestore ; MAX_ETHER + dw ItemUsePPRestore ; ELIXER + dw ItemUsePPRestore ; MAX_ELIXER + +ItemUseBall: ; d687 (3:5687) + ld a,[W_ISINBATTLE] + and a + jp z,ItemUseNotTime ; not in battle + dec a + jp nz,ThrowBallAtTrainerMon + ld a,[W_BATTLETYPE] + dec a + jr z,.UseBall + ld a,[wPartyCount] ;is Party full? + cp a,PARTY_LENGTH + jr nz,.UseBall + ld a,[W_NUMINBOX] ;is Box full? + cp a,MONS_PER_BOX + jp z,BoxFullCannotThrowBall +.UseBall ;$56a7 +;ok, you can use a ball + xor a + ld [wd11c],a + ld a,[W_BATTLETYPE] + cp a,2 ;SafariBattle + jr nz,.skipSafariZoneCode +.safariZone + ; remove a Safari Ball from inventory + ld hl,W_NUMSAFARIBALLS + dec [hl] +.skipSafariZoneCode ;$56b6 + call GoPAL_SET_CF1C + ld a,$43 + ld [wd11e],a + call LoadScreenTilesFromBuffer1 ;restore screenBuffer from Backup + ld hl,ItemUseText00 + call PrintText + callab IsGhostBattle + ld b,$10 + jp z,.next12 + ld a,[W_BATTLETYPE] + dec a + jr nz,.notOldManBattle +.oldManBattle + ld hl,W_GRASSRATE + ld de,wPlayerName + ld bc,11 + call CopyData ; save the player's name in the Wild Monster data (part of the Cinnabar Island Missingno glitch) + jp .BallSuccess ;$578b +.notOldManBattle ;$56e9 + ld a,[W_CURMAP] + cp a,POKEMONTOWER_6 + jr nz,.loop + ld a,[wEnemyMonSpecies2] + cp a,MAROWAK + ld b,$10 + jp z,.next12 +; if not fighting ghost Marowak, loop until a random number in the current +; pokeball's allowed range is found +.loop ;$56fa + call Random + ld b,a + ld hl,wcf91 + ld a,[hl] + cp a,MASTER_BALL + jp z,.BallSuccess ;$578b + cp a,POKE_BALL + jr z,.checkForAilments + ld a,200 + cp b + jr c,.loop ;get only numbers <= 200 for Great Ball + ld a,[hl] + cp a,GREAT_BALL + jr z,.checkForAilments + ld a,150 ;get only numbers <= 150 for Ultra Ball + cp b + jr c,.loop +.checkForAilments ;$571a +; pokemon can be caught more easily with any (primary) status ailment +; Frozen/Asleep pokemon are relatively even easier to catch +; for Frozen/Asleep pokemon, any random number from 0-24 ensures a catch. +; for the others, a random number from 0-11 ensures a catch. + ld a,[wEnemyMonStatus] ;status ailments + and a + jr z,.noAilments + and a, 1 << FRZ | SLP ;is frozen and/or asleep? + ld c,12 + jr z,.notFrozenOrAsleep + ld c,25 +.notFrozenOrAsleep ;$5728 + ld a,b + sub c + jp c,.BallSuccess ;$578b + ld b,a +.noAilments ;$572e + push bc ;save RANDOM number + 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 ; MaxHP * 255 + ld a,[wcf91] + cp a,GREAT_BALL + ld a,12 ;any other BallFactor + jr nz,.next7 + ld a,8 +.next7 ;$574d + ld [H_DIVISOR],a + ld b,4 ; number of bytes in dividend + call Divide + ld hl,wEnemyMonHP + ld a,[hli] + ld b,a + ld a,[hl] + +; explanation: we have a 16-bit value equal to [b << 8 | a]. +; This number is divided by 4. The result is 8 bit (reg. a). +; Always bigger than zero. + srl b + rr a + srl b + rr a ; a = current HP / 4 + and a + jr nz,.next8 + inc a +.next8 ;$5766 + ld [H_DIVISOR],a + ld b,4 + call Divide ; ((MaxHP * 255) / BallFactor) / (CurHP / 4) + ld a,[H_QUOTIENT + 2] + and a + jr z,.next9 + ld a,255 + ld [H_QUOTIENT + 3],a +.next9 ;$5776 + pop bc + ld a,[wEnemyMonCatchRate] ;enemy: Catch Rate + cp b + jr c,.next10 + ld a,[H_QUOTIENT + 2] + and a + jr nz,.BallSuccess ; if ((MaxHP * 255) / BallFactor) / (CurHP / 4) > 0x255, automatic success + call Random + ld b,a + ld a,[H_QUOTIENT + 3] + cp b + jr c,.next10 +.BallSuccess ;$578b + jr .BallSuccess2 +.next10 ;$578d + ld a,[H_QUOTIENT + 3] + ld [wd11e],a + xor a + ld [H_MULTIPLICAND],a + ld [H_MULTIPLICAND + 1],a + ld a,[wEnemyMonCatchRate] ;enemy: Catch Rate + ld [H_MULTIPLICAND + 2],a + ld a,100 + ld [H_MULTIPLIER],a + call Multiply ; CatchRate * 100 + ld a,[wcf91] + ld b,255 + cp a,POKE_BALL + jr z,.next11 + ld b,200 + cp a,GREAT_BALL + jr z,.next11 + ld b,150 + cp a,ULTRA_BALL + jr z,.next11 +.next11 ;$57b8 + ld a,b + ld [H_DIVISOR],a + ld b,4 + call Divide + ld a,[H_QUOTIENT + 2] + and a + ld b,$63 + jr nz,.next12 + ld a,[wd11e] + ld [H_MULTIPLIER],a + call Multiply + ld a,255 + ld [H_DIVISOR],a + ld b,4 + call Divide + ld a,[wEnemyMonStatus] ;status ailments + and a + jr z,.next13 + and a, 1 << FRZ | SLP + ld b,5 + jr z,.next14 + ld b,10 +.next14 ;$57e6 + ld a,[H_QUOTIENT + 3] + add b + ld [H_QUOTIENT + 3],a +.next13 ;$57eb + ld a,[H_QUOTIENT + 3] + cp a,10 + ld b,$20 + jr c,.next12 + cp a,30 + ld b,$61 + jr c,.next12 + cp a,70 + ld b,$62 + jr c,.next12 + ld b,$63 +.next12 ;$5801 + ld a,b + ld [wd11e],a +.BallSuccess2 ;$5805 + ld c,20 + call DelayFrames + ld a,TOSS_ANIM + ld [W_ANIMATIONID],a + xor a + ld [$fff3],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 + ld a,[wd11e] + cp a,$10 + ld hl,ItemUseBallText00 + jp z,.printText0 + cp a,$20 + ld hl,ItemUseBallText01 + jp z,.printText0 + cp a,$61 + ld hl,ItemUseBallText02 + jp z,.printText0 + cp a,$62 + ld hl,ItemUseBallText03 + jp z,.printText0 + cp a,$63 + ld hl,ItemUseBallText04 + jp z,.printText0 + ld hl,wEnemyMonHP ;current HP + ld a,[hli] + push af + ld a,[hli] + push af ;backup currentHP... + inc hl + ld a,[hl] + push af ;...and status ailments + push hl + ld hl,W_ENEMYBATTSTATUS3 + bit Transformed,[hl] + jr z,.next15 + ld a,$4c + ld [wEnemyMonSpecies2],a + jr .next16 +.next15 ;$5871 + set Transformed,[hl] + ld hl,wcceb + ld a,[wEnemyMonDVs] + ld [hli],a + ld a,[wEnemyMonDVs + 1] + ld [hl],a +.next16 ;$587e + ld a,[wcf91] + push af + ld a,[wEnemyMonSpecies2] + ld [wcf91],a + ld a,[wEnemyMonLevel] + ld [W_CURENEMYLVL],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] ;enemy + ld [wd11c],a + ld [wcf91],a + ld [wd11e],a + ld a,[W_BATTLETYPE] + dec a + jr z,.printText1 + ld hl,ItemUseBallText05 + call PrintText + predef IndexToPokedex + ld a,[wd11e] + dec a + ld c,a + ld b,2 + ld hl,wPokedexOwned ;Dex_own_flags (pokemon) + predef FlagActionPredef + ld a,c + push af + ld a,[wd11e] + dec a + ld c,a + ld b,1 + predef FlagActionPredef + pop af + and a + jr nz,.checkParty + ld hl,ItemUseBallText06 + call PrintText + call ClearSprites + ld a,[wEnemyMonSpecies] ;caught mon_ID + ld [wd11e],a + predef ShowPokedexData +.checkParty ;$58f4 + ld a,[wPartyCount] + cp a,PARTY_LENGTH ;is party full? + jr z,.sendToBox + xor a + ld [wcc49],a + call ClearSprites + call AddPartyMon ;add mon to Party + jr .End +.sendToBox ;$5907 + call ClearSprites + call SendNewMonToBox + ld hl,ItemUseBallText07 + ld a,[wd7f1] + bit 0,a ;already met Bill? + jr nz,.sendToBox2 + ld hl,ItemUseBallText08 +.sendToBox2 ;$591a + call PrintText + jr .End +.printText1 ;$591f + ld hl,ItemUseBallText05 +.printText0 ;$5922 + call PrintText + call ClearSprites +.End ;$5928 + ld a,[W_BATTLETYPE] + and a + ret nz + ld hl,wNumBagItems + inc a + ld [wcf96],a + jp RemoveItemFromInventory ;remove ITEM (XXX) +ItemUseBallText00: ; d937 (3:5937) +;"It dodged the thrown ball!" +;"This pokemon can't be caught" + TX_FAR _ItemUseBallText00 + db "@" +ItemUseBallText01: ; d93c (3:593c) +;"You missed the pokemon!" + TX_FAR _ItemUseBallText01 + db "@" +ItemUseBallText02: ; d941 (3:5941) +;"Darn! The pokemon broke free!" + TX_FAR _ItemUseBallText02 + db "@" +ItemUseBallText03: ; d946 (3:5946) +;"Aww! It appeared to be caught!" + TX_FAR _ItemUseBallText03 + db "@" +ItemUseBallText04: ; d94b (3:594b) +;"Shoot! It was so close too!" + TX_FAR _ItemUseBallText04 + db "@" +ItemUseBallText05: ; d950 (3:5950) +;"All right! {MonName} was caught!" +;play sound + TX_FAR _ItemUseBallText05 + db $12,$06 + db "@" +ItemUseBallText07: ; d957 (3:5957) +;"X was transferred to Bill's PC" + TX_FAR _ItemUseBallText07 + db "@" +ItemUseBallText08: ; d95c (3:595c) +;"X was transferred to someone's PC" + TX_FAR _ItemUseBallText08 + db "@" + +ItemUseBallText06: ; d961 (3:5961) +;"New DEX data will be added..." +;play sound + TX_FAR _ItemUseBallText06 + db $13,$06 + db "@" + +ItemUseTownMap: ; d968 (3:5968) + ld a,[W_ISINBATTLE] + and a + jp nz,ItemUseNotTime + ld b, BANK(DisplayTownMap) + ld hl, DisplayTownMap + jp Bankswitch ; display Town Map + +ItemUseBicycle: ; d977 (3:5977) + ld a,[W_ISINBATTLE] + and a + jp nz,ItemUseNotTime + ld a,[wWalkBikeSurfState] + ld [wWalkBikeSurfStateCopy],a + cp a,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: ; d9b4 (3:59b4) + ld a,[wWalkBikeSurfState] + ld [wWalkBikeSurfStateCopy],a + cp a,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 [$ff8c],a + ld d,16 ; talking range in pixels (normal range) + call IsSpriteInFrontOfPlayer2 + res 7,[hl] + ld a,[$ff8c] + and a ; is there a sprite in the way? + jr nz,.cannotStopSurfing + ld hl,TilePairCollisionsWater + call CheckForTilePairCollisions + jr c,.cannotStopSurfing + ld hl,W_TILESETCOLLISIONPTR ; pointer to list of passable tiles + ld a,[hli] + ld h,[hl] + ld l,a ; hl now points to passable tiles + ld a,[wTileInFrontOfPlayer] ; tile in front of the player + ld b,a +.passableTileLoop + ld a,[hli] + cp b + jr z,.stopSurfing + cp a,$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,[wd52a] ; direction the player is going + bit 3,a + ld b,D_UP + jr nz,.storeSimulatedButtonPress + bit 2,a + ld b,D_DOWN + jr nz,.storeSimulatedButtonPress + bit 1,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: ; da4c (3:5a4c) + TX_FAR _SurfingGotOnText + db "@" + +SurfingNoPlaceToGetOffText: ; da51 (3:5a51) + TX_FAR _SurfingNoPlaceToGetOffText + db "@" + +ItemUsePokedex: ; da56 (3:5a56) + predef_jump ShowPokedexMenu + +ItemUseEvoStone: ; da5b (3:5a5b) + ld a,[W_ISINBATTLE] + and a + jp nz,ItemUseNotTime + ld a,[wWhichPokemon] + push af + ld a,[wcf91] + ld [wd156],a + push af + ld a,$05 ; evolution stone party menu + ld [wd07d],a + ld a,$ff + ld [wUpdateSpritesEnabled],a + call DisplayPartyMenu + pop bc + jr c,.canceledItemUse + ld a,b + ld [wcf91],a + ld a,$01 + ld [wccd4],a + ld a,(SFX_02_3e - SFX_Headers_02) / 3 + call PlaySoundWaitForCurrent ; play sound + call WaitForSoundToFinish ; wait for sound to end + callab TryEvolvingMon ; try to evolve pokemon + ld a,[wd121] + and a + jr z,.noEffect + pop af + ld [wWhichPokemon],a + ld hl,wNumBagItems + ld a,1 ; remove 1 stone + ld [wcf96],a + jp RemoveItemFromInventory +.noEffect + call ItemUseNoEffect +.canceledItemUse + xor a + ld [wcd6a],a + pop af + ret + +ItemUseVitamin: ; dab4 (3:5ab4) + ld a,[W_ISINBATTLE] + and a + jp nz,ItemUseNotTime + +ItemUseMedicine: ; dabb (3:5abb) + ld a,[wPartyCount] + and a + jp z,.emptyParty + ld a,[wWhichPokemon] + push af + ld a,[wcf91] + push af + ld a,$01 + ld [wd07d],a ; item use party menu + ld a,$ff + ld [wUpdateSpritesEnabled],a + ld a,[wd152] + and a ; using Softboiled? + jr z,.notUsingSoftboiled +; if using softboiled + call GoBackToPartyMenu + jr .getPartyMonDataAddress +.emptyParty + ld hl,.emptyPartyText + xor a + ld [wcd6a],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 [wcf06],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,[wd152] + 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 a,REVIVE + jr nc,.healHP ; if it's a Revive or Max Revive + cp a,FULL_HEAL + jr z,.cureStatusAilment ; if it's a Full Heal + cp a,HP_UP + jp nc,.useVitamin ; if it's a vitamin or Rare Candy + cp a,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-specifc healing items +.cureStatusAilment + ld bc,4 + add hl,bc ; hl now points to status + ld a,[wcf91] + ld bc,$f008 + cp a,ANTIDOTE + jr z,.checkMonStatus + ld bc,$f110 + cp a,BURN_HEAL + jr z,.checkMonStatus + ld bc,$f220 + cp a,ICE_HEAL + jr z,.checkMonStatus + ld bc,$f307 + cp a,AWAKENING + jr z,.checkMonStatus + ld bc,$f440 + cp a,PARLYZ_HEAL + jr z,.checkMonStatus + ld bc,$f6ff ; 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 [wd07d],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,W_PLAYERBATTSTATUS3 + res BadlyPoisoned,[hl] ; heal Toxic status + pop hl + ld bc,30 + add hl,bc ; hl now points to party stats + ld de,wBattleMonMaxHP + ld bc,10 + 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 a,REVIVE + jr z,.updateInBattleFaintedData + cp a,MAX_REVIVE + jr z,.updateInBattleFaintedData + jp .healingItemNoEffect +.updateInBattleFaintedData + ld a,[W_ISINBATTLE] + and a + jr z,.compareCurrentHPToMaxHP + push hl + push de + push bc + ld a,[wcf06] + ld c,a + ld hl,wPartyFoughtCurrentEnemyFlags + ld b,$02 + predef FlagActionPredef + ld a,c + and a + jr z,.next + ld a,[wcf06] + ld c,a + ld hl,wPartyGainExpFlags + ld b,$01 + predef FlagActionPredef +.next + pop bc + pop de + pop hl + jr .compareCurrentHPToMaxHP +.notFainted + ld a,[wcf91] + cp a,REVIVE + jp z,.healingItemNoEffect + cp a,MAX_REVIVE + jp z,.healingItemNoEffect +.compareCurrentHPToMaxHP + push hl + push bc + ld bc,32 + 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 a,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 [wc02a],a + push hl + push de + ld bc,32 + 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,[wd152] + 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 - wPartyMon1MaxHP + 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 + hlCoord 4, 1 + ld a,[wWhichPokemon] + ld bc,2 * 20 + call AddNTimes ; calculate coordinates of HP bar of pokemon that used Softboiled + ld a,(SFX_02_3d - SFX_Headers_02) / 3 + call PlaySoundWaitForCurrent ; play sound + 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 a,SODA_POP + ld b,60 ; Soda Pop heal amount + jr z,.addHealAmount + ld b,80 ; Lemonade heal amount + jr nc,.addHealAmount + cp a,FRESH_WATER + ld b,50 ; Fresh Water heal amount + jr z,.addHealAmount + cp a,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,33 + add hl,de ; hl now points to max HP + ld a,[wcf91] + cp a,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 a,HYPER_POTION + jr c,.setCurrentHPToMaxHp ; if using a Full Restore or Max Potion + cp a,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 a,FULL_RESTORE + jr nz,.updateInBattleData + ld bc,-31 + 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 a,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 * 20 + inc d +.calculateHPBarCoordsLoop + add hl,bc + dec d + jr nz,.calculateHPBarCoordsLoop + jr .doneHealing +.healingItemNoEffect + call ItemUseNoEffect + jp .done +.doneHealing + ld a,[wd152] + 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 a,FULL_RESTORE + jr c,.playStatusAilmentCuringSound + cp a,FULL_HEAL + jr z,.playStatusAilmentCuringSound + ld a,(SFX_02_3d - SFX_Headers_02) / 3 ; HP healing sound + call PlaySoundWaitForCurrent ; play sound + 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,$f7 ; revived message + ld [wd07d],a + ld a,[wcf91] + cp a,REVIVE + jr z,.showHealingItemMessage + cp a,MAX_REVIVE + jr z,.showHealingItemMessage + ld a,$f5 ; standard HP healed message + ld [wd07d],a + jr .showHealingItemMessage +.playStatusAilmentCuringSound + ld a,(SFX_02_3e - SFX_Headers_02) / 3 ; status ailment curing sound + 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 [wcd6a],a ; item use failed + pop af + pop af +.done + ld a,[wd152] + and a ; using Softboiled? + ret nz ; if so, return + call GBPalWhiteOut + call z,GoPAL_SET_CF1C + ld a,[W_ISINBATTLE] + and a + ret nz + jp ReloadMapData +.useVitamin + push hl + ld a,[hl] + ld [wd0b5],a + ld [wd11e],a + ld bc,33 + add hl,bc ; hl now points to level + ld a,[hl] ; a = level + ld [W_CURENEMYLVL],a ; store level + call GetMonHeader + push de + ld a,d + ld hl,wPartyMonNicks + call GetPartyMonName + pop de + pop hl + ld a,[wcf91] + cp a,RARE_CANDY + jp z,.useRareCandy + push hl + sub a,HP_UP + add a + ld bc,17 + 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 a,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 a,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_02_3e - SFX_Headers_02) / 3 + call PlaySound ; play sound + ld hl,VitaminStatRoseText + call PrintText + jp RemoveUsedItem +.vitaminNoEffect + pop hl + ld hl,VitaminNoEffectText + call PrintText + jp GBPalWhiteOut +.recalculateStats + ld bc,34 + add hl,bc + ld d,h + ld e,l ; de now points to stats + ld bc,-18 + add hl,bc ; hl now points to byte 3 of experience + ld b,1 + jp CalcStats ; recalculate stats +.useRareCandy + push hl + ld bc,33 + add hl,bc ; hl now points to level + ld a,[hl] ; a = level + cp a, MAX_LEVEL + jr z,.vitaminNoEffect ; can't raise level above 100 + inc a + ld [hl],a ; store incremented level + ld [W_CURENEMYLVL],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,-19 + add hl,bc ; hl now points to experience +; update experience to minimum for new level + ld a,[$ff96] + ld [hli],a + ld a,[$ff97] + ld [hli],a + ld a,[$ff98] + ld [hl],a + pop hl + ld a,[wWhichPokemon] + push af + ld a,[wcf91] + push af + push de + push hl + ld bc,34 + 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,35 ; hl now points to LSB of max HP + add hl,bc + 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,-32 + add hl,de ; hl now points to MSB of current HP + ld a,[hl] + add c + ld [hld],a + ld a,[hl] + adc b + ld [hl],a + ld a,$f8 ; level up message + ld [wd07d],a + call RedrawPartyMenu + pop de + ld a,d + ld [wWhichPokemon],a + ld a,e + ld [wd11e],a + xor a + ld [wcc49],a ; load from player's party + call LoadMonData + ld d,$01 + callab PrintStatsBox ; display new stats text box + call WaitForTextScrollButtonPress ; wait for button press + xor a + ld [wcc49],a + predef LearnMoveFromLevelUp ; learn level up move, if any + xor a + ld [wccd4],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: ; df24 (3:5f24) + TX_FAR _VitaminStatRoseText + db "@" + +VitaminNoEffectText: ; df29 (3:5f29) + TX_FAR _VitaminNoEffectText + db "@" + +VitaminText: ; df2e (3:5f2e) + db "HEALTH@" + db "ATTACK@" + db "DEFENSE@" + db "SPEED@" + db "SPECIAL@" + +ItemUseBait: ; df52 (3:5f52) + ld hl,ThrewBaitText + call PrintText + ld hl,wEnemyMonCatchRate ; catch rate + srl [hl] ; halve catch rate + ld a,BAIT_ANIM + ld hl,wSafariBaitFactor ; bait factor + ld de,wSafariEscapeFactor ; escape factor + jr BaitRockCommon + +ItemUseRock: ; df67 (3:5f67) + ld hl,ThrewRockText + call PrintText + ld hl,wEnemyMonCatchRate ; 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: ; df7f (3:5f7f) + ld [W_ANIMATIONID],a + xor a + ld [wcc5b],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 a,7 + cp a,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: ; dfa5 (3:5fa5) + TX_FAR _ThrewBaitText + db "@" + +ThrewRockText: ; dfaa (3:5faa) + TX_FAR _ThrewRockText + db "@" + +; also used for Dig out-of-battle effect +ItemUseEscapeRope: ; dfaf (3:5faf) + ld a,[W_ISINBATTLE] + and a + jr nz,.notUsable + ld a,[W_CURMAP] + cp a,AGATHAS_ROOM + jr z,.notUsable + ld a,[W_CURMAPTILESET] + ld b,a + ld hl,EscapeRopeTilesets +.loop + ld a,[hli] + cp a,$ff + jr z,.notUsable + cp b + jr nz,.loop + ld hl,wd732 + set 3,[hl] + set 6,[hl] + ld hl,wd72e + res 4,[hl] + ld hl,wd790 + res 7,[hl] ; unset Safari Zone bit + xor a + ld [W_NUMSAFARIBALLS],a + ld [W_SAFARIZONEENTRANCECURSCRIPT],a + inc a + ld [wEscapedFromBattle],a + ld [wcd6a],a ; item used + ld a,[wd152] + and a ; using Dig? + ret nz ; if so, return + call ItemUseReloadOverworldData + ld c,30 + call DelayFrames + jp RemoveUsedItem +.notUsable + jp ItemUseNotTime + +EscapeRopeTilesets: ; dffd (3:5ffd) + db FOREST, CEMETERY, CAVERN, FACILITY, INTERIOR + db $ff ; terminator + +ItemUseRepel: ; e003 (3:6003) + ld b,100 + +ItemUseRepelCommon: ; e005 (3:6005) + ld a,[W_ISINBATTLE] + and a + jp nz,ItemUseNotTime + ld a,b + ld [wRepelRemainingSteps],a + jp PrintItemUseTextAndRemoveItem + +; handles X Accuracy item +ItemUseXAccuracy: ; e013 (3:6013) + ld a,[W_ISINBATTLE] + and a + jp z,ItemUseNotTime + ld hl,W_PLAYERBATTSTATUS2 + set UsingXAccuracy,[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: ; e022 (3:6022) + xor a + ld [wd71f],a + call GetTileAndCoordsInFrontOfPlayer + ld a,[GetTileAndCoordsInFrontOfPlayer] ; $4586 + cp a,$18 + jr nz,.next0 + ld hl,CardKeyTable1 + jr .next1 +.next0 + cp a,$24 + jr nz,.next2 + ld hl,CardKeyTable2 + jr .next1 +.next2 + cp a,$5e + jp nz,ItemUseNotTime + ld hl,CardKeyTable3 +.next1 + ld a,[W_CURMAP] + ld b,a +.loop + ld a,[hli] + cp a,$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 [wd71f],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: ; e072 (3:6072) + 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: ; e09b (3:609b) + 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: ; e0c4 (3:60c4) + db SILPH_CO_11F,$08,$09,$14 + db SILPH_CO_11F,$09,$09,$15 + db $ff + +ItemUsePokedoll: ; e0cd (3:60cd) + ld a,[W_ISINBATTLE] + dec a + jp nz,ItemUseNotTime + ld a,$01 + ld [wEscapedFromBattle],a + jp PrintItemUseTextAndRemoveItem + +ItemUseGuardSpec: ; e0dc (3:60dc) + ld a,[W_ISINBATTLE] + and a + jp z,ItemUseNotTime + ld hl,W_PLAYERBATTSTATUS2 + set ProtectedByMist,[hl] ; Mist bit + jp PrintItemUseTextAndRemoveItem + +ItemUseSuperRepel: ; e0eb (3:60eb) + ld b,200 + jp ItemUseRepelCommon + +ItemUseMaxRepel: ; e0f0 (3:60f0) + ld b,250 + jp ItemUseRepelCommon + +ItemUseDireHit: ; e0f5 (3:60f5) + ld a,[W_ISINBATTLE] + and a + jp z,ItemUseNotTime + ld hl,W_PLAYERBATTSTATUS2 + set GettingPumped,[hl] ; Focus Energy bit + jp PrintItemUseTextAndRemoveItem + +ItemUseXStat: ; e104 (3:6104) + ld a,[W_ISINBATTLE] + and a + jr nz,.inBattle + call ItemUseNotTime + ld a,2 + ld [wcd6a],a ; item not used + ret +.inBattle + ld hl,W_PLAYERMOVENUM + ld a,[hli] + push af ; save [W_PLAYERMOVENUM] + ld a,[hl] + push af ; save [W_PLAYERMOVEEFFECT] + push hl + ld a,[wcf91] + sub a,X_ATTACK - ATTACK_UP1_EFFECT + ld [hl],a ; store player move effect + call PrintItemUseTextAndRemoveItem + ld a,XSTATITEM_ANIM ; X stat item animation ID + ld [W_PLAYERMOVENUM],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 [W_PLAYERMOVEEFFECT] + pop af + ld [hl],a ; restore [W_PLAYERMOVENUM] + ret + +ItemUsePokeflute: ; e140 (3:6140) + ld a,[W_ISINBATTLE] + and a + jr nz,.inBattle +; if not in battle + call ItemUseReloadOverworldData + ld a,[W_CURMAP] + cp a,ROUTE_12 + jr nz,.notRoute12 + ld a,[wd7d8] + bit 7,a ; has the player beaten Route 12 Snorlax yet? + 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 + ld hl,wd7d8 + set 6,[hl] ; trigger Snorlax fight (handled by map script) + ret +.notRoute12 + cp a,ROUTE_16 + jr nz,.noSnorlaxToWakeUp + ld a,[wd7e0] + bit 1,a ; has the player beaten Route 16 Snorlax yet? + 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 + ld hl,wd7e0 + set 0,[hl] ; trigger Snorlax fight (handled by map script) + ret +.noSnorlaxToWakeUp + ld hl,PlayedFluteNoEffectText + jp PrintText +.inBattle + xor a + ld [wWhichTrade],a ; initialize variable that indicates if any pokemon were woken up to zero + ld b,~SLP & $FF + ld hl,wPartyMon1Status + call WakeUpEntireParty + ld a,[W_ISINBATTLE] + 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,[wWhichTrade] + 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 a,$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,[wc02c] + 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 +; [wWhichTrade] should be initialized to 0 +; OUTPUT: +; [wWhichTrade]: set to 1 if any pokemon were asleep +WakeUpEntireParty: ; e1e5 (3:61e5) + ld de,44 + ld c,6 +.loop + ld a,[hl] + push af + and a,SLP ; is pokemon asleep? + jr z,.notAsleep + ld a,1 + ld [wWhichTrade],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: ; e1fd (3:61fd) + 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: ; e206 (3:6206) + db 10,27 ; one space East of Snorlax + db 10,25 ; one space West of Snorlax + db $ff ; terminator + +PlayedFluteNoEffectText: ; e20b (3:620b) + TX_FAR _PlayedFluteNoEffectText + db "@" + +FluteWokeUpText: ; e210 (3:6210) + TX_FAR _FluteWokeUpText + db "@" + +PlayedFluteHadEffectText: ; e215 (3:6215) + TX_FAR _PlayedFluteHadEffectText + db $06 + db $08 + ld a,[W_ISINBATTLE] + and a + jr nz,.done +; play out-of-battle pokeflute music + ld a,$ff + call PlaySound ; turn off music + ld a, (SFX_02_5e - SFX_Headers_02) / 3 + ld c, BANK(SFX_02_5e) + call PlayMusic ; play music +.musicWaitLoop ; wait for music to finish playing + ld a,[wc028] + cp a,$b8 + jr z,.musicWaitLoop + call PlayDefaultMusic ; start playing normal music again +.done + jp TextScriptEnd ; end text + +ItemUseCoinCase: ; e23a (3:623a) + ld a,[W_ISINBATTLE] + and a + jp nz,ItemUseNotTime + ld hl,CoinCaseNumCoinsText + jp PrintText + +CoinCaseNumCoinsText: ; e247 (3:6247) + TX_FAR _CoinCaseNumCoinsText + db "@" + +OldRodCode: ; e24c (3:624c) + call FishingInit + jp c, ItemUseNotTime + ld bc, (5 << 8) | MAGIKARP + ld a, $1 ; set bite + jr RodResponse ; 0xe257 $34 + +GoodRodCode: ; e259 (3:6259) + 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,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" + +SuperRodCode: ; e283 (3:6283) + call FishingInit + jp c, ItemUseNotTime + call ReadSuperRodData ; 0xe8ea + ld a, e +RodResponse: ; e28d (3:628d) + ld [wWhichTrade], a + + dec a ; is there a bite? + jr nz, .next + ; if yes, store level and species data + ld a, 1 + ld [W_MOVEMISSED], a + ld a, b ; level + ld [W_CURENEMYLVL], a + ld a, c ; species + ld [W_CUROPPONENT], a + +.next + ld hl, wWalkBikeSurfState + ld a, [hl] ; store the value in a + push af + push hl + ld [hl], 0 + callba Func_707b6 + 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: ; e2b4 (3:62b4) + ld a,[W_ISINBATTLE] + and a + jr z,.notInBattle + scf ; can't fish during battle + ret +.notInBattle + call IsNextTileShoreOrWater + ret c + ld a,[wWalkBikeSurfState] + cp a,2 ; Surfing? + jr z,.surfing + call ItemUseReloadOverworldData + ld hl,ItemUseText00 + call PrintText + ld a,(SFX_02_3e - SFX_Headers_02) / 3 + call PlaySound ; play sound + ld c,80 + call DelayFrames + and a + ret +.surfing + scf ; can't fish when surfing + ret + +ItemUseOaksParcel: ; e2de (3:62de) + jp ItemUseNotYoursToUse + +ItemUseItemfinder: ; e2e1 (3:62e1) + ld a,[W_ISINBATTLE] + 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_02_4a - SFX_Headers_02) / 3 + call PlaySoundWaitForCurrent ; play sound + ld a,(SFX_02_5a - SFX_Headers_02) / 3 + call PlaySoundWaitForCurrent ; play sound + dec c + jr nz,.loop + ld hl,ItemfinderFoundItemText +.printText + jp PrintText + +ItemfinderFoundItemText: ; e30d (3:630d) + TX_FAR _ItemfinderFoundItemText + db "@" + +ItemfinderFoundNothingText: ; e312 (3:6312) + TX_FAR _ItemfinderFoundNothingText + db "@" + +ItemUsePPUp: ; e317 (3:6317) + ld a,[W_ISINBATTLE] + and a + jp nz,ItemUseNotTime + +ItemUsePPRestore: ; e31e (3:631e) + ld a,[wWhichPokemon] + push af + ld a,[wcf91] + ld [wWhichTrade],a +.chooseMon + xor a + ld [wUpdateSpritesEnabled],a + ld a,$01 ; item use party menu + ld [wd07d],a + call DisplayPartyMenu + jr nc,.chooseMove + jp .itemNotUsed +.chooseMove + ld a,[wWhichTrade] + cp a,ELIXER + jp nc,.useElixir ; if Elixir or Max Elixir + ld a,$02 + ld [wMoveMenuType],a + ld hl,RaisePPWhichTechniqueText + ld a,[wWhichTrade] + cp a,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,44 + call GetSelectedMoveOffset + push hl + ld a,[hl] + ld [wd11e],a + call GetMoveName + call CopyStringToCF4B ; copy name to wcf4b + pop hl + ld a,[wWhichTrade] + cp a,ETHER + jr nc,.useEther ; if Ether or Max Ether +.usePPUp + ld bc,21 + add hl,bc + ld a,[hl] ; move PP + cp a,3 << 6 ; have 3 PP Ups already been used? + jr c,.PPNotMaxedOut + ld hl,PPMaxedOutText + call PrintText + jr .chooseMove +.PPNotMaxedOut + ld a,[hl] + add a,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 GoPAL_SET_CF1C + 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,44 + call AddNTimes + ld de,wBattleMonPP + ld bc,4 + call CopyData ; copy party data to in-battle data +.skipUpdatingInBattleData + ld a,(SFX_02_3e - SFX_Headers_02) / 3 + 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 + ld [wcc49],a ; party pokemon + call GetMaxPP + ld hl,wPartyMon1Moves + ld bc,44 + call GetSelectedMoveOffset + ld bc,21 + add hl,bc ; hl now points to move's PP + ld a,[wd11e] + ld b,a ; b = max PP + ld a,[wWhichTrade] + cp a,MAX_ETHER + jr z,.fullyRestorePP + ld a,[hl] ; move PP + and a,%00111111 ; lower 6 bit bits store current PP + cp b ; does current PP equal max PP? + ret z ; if so, return + add a,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 a,%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,wWhichTrade + 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,44 + 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 GoPAL_SET_CF1C + pop af + xor a + ld [wcd6a],a ; item use failed + ret + +RaisePPWhichTechniqueText: ; e45d (3:645d) + TX_FAR _RaisePPWhichTechniqueText + db "@" + +RestorePPWhichTechniqueText: ; e462 (3:6462) + TX_FAR _RestorePPWhichTechniqueText + db "@" + +PPMaxedOutText: ; e467 (3:6467) + TX_FAR _PPMaxedOutText + db "@" + +PPIncreasedText: ; e46c (3:646c) + TX_FAR _PPIncreasedText + db "@" + +PPRestoredText: ; e471 (3:6471) + TX_FAR _PPRestoredText + db "@" + +; for items that can't be used from the Item menu +UnusableItem: ; e476 (3:6476) + jp ItemUseNotTime + +ItemUseTMHM: ; e479 (3:6479) + ld a,[W_ISINBATTLE] + and a + jp nz,ItemUseNotTime + ld a,[wcf91] + sub a,TM_01 + push af + jr nc,.skipAdding + add a,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 + hlCoord 14, 7 + ld bc,$080f + 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 [wcd6a],a ; item not used + ret +.useMachine + ld a,[wWhichPokemon] + push af + ld a,[wcf91] + push af +.chooseMon + ld hl,wcf4b + ld de,wd036 + ld bc,14 + call CopyData + ld a,$ff + ld [wUpdateSpritesEnabled],a + ld a,$03 ; teach TM/HM party menu + ld [wd07d],a + call DisplayPartyMenu + push af + ld hl,wd036 + 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 GoPAL_SET_CF1C + 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_02_51 - SFX_Headers_02) / 3 + call PlaySoundWaitForCurrent ; play sound + 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: ; e54f (3:654f) + TX_FAR _BootedUpTMText + db "@" + +BootedUpHMText: ; e554 (3:6554) + TX_FAR _BootedUpHMText + db "@" + +TeachMachineMoveText: ; e559 (3:6559) + TX_FAR _TeachMachineMoveText + db "@" + +MonCannotLearnMachineMoveText: ; e55e (3:655e) + TX_FAR _MonCannotLearnMachineMoveText + db "@" + +PrintItemUseTextAndRemoveItem: ; e563 (3:6563) + ld hl,ItemUseText00 + call PrintText + ld a,(SFX_02_3e - SFX_Headers_02) / 3 + call PlaySound ; play sound + call WaitForTextScrollButtonPress ; wait for button press + +RemoveUsedItem: ; e571 (3:6571) + ld hl,wNumBagItems + ld a,1 ; one item + ld [wcf96],a ; store quantity + jp RemoveItemFromInventory + +ItemUseNoEffect: ; e57c (3:657c) + ld hl,ItemUseNoEffectText + jr ItemUseFailed + +ItemUseNotTime: ; e581 (3:6581) + ld hl,ItemUseNotTimeText + jr ItemUseFailed + +ItemUseNotYoursToUse: ; e586 (3:6586) + ld hl,ItemUseNotYoursToUseText + jr ItemUseFailed + +ThrowBallAtTrainerMon: ; e58b (3:658b) + call GoPAL_SET_CF1C + call LoadScreenTilesFromBuffer1 ; restore saved screen + call Delay3 + ld a,TOSS_ANIM + ld [W_ANIMATIONID],a + predef MoveAnimation ; do animation + ld hl,ThrowBallAtTrainerMonText1 + call PrintText + ld hl,ThrowBallAtTrainerMonText2 + call PrintText + jr RemoveUsedItem + +NoCyclingAllowedHere: ; e5ac (3:65ac) + ld hl,NoCyclingAllowedHereText + jr ItemUseFailed + +BoxFullCannotThrowBall: ; e5b1 (3:65b1) + ld hl,BoxFullCannotThrowBallText + jr ItemUseFailed + +SurfingAttemptFailed: ; e5b6 (3:65b6) + ld hl,NoSurfingHereText + +ItemUseFailed: ; e5b9 (3:65b9) + xor a + ld [wcd6a],a ; item use failed + jp PrintText + +ItemUseNotTimeText: ; e5c0 (3:65c0) + TX_FAR _ItemUseNotTimeText + db "@" + +ItemUseNotYoursToUseText: ; e5c5 (3:65c5) + TX_FAR _ItemUseNotYoursToUseText + db "@" + +ItemUseNoEffectText: ; e5ca (3:65ca) + TX_FAR _ItemUseNoEffectText + db "@" + +ThrowBallAtTrainerMonText1: ; e5cf (3:65cf) + TX_FAR _ThrowBallAtTrainerMonText1 + db "@" + +ThrowBallAtTrainerMonText2: ; e5d4 (3:65d4) + TX_FAR _ThrowBallAtTrainerMonText2 + db "@" + +NoCyclingAllowedHereText: ; e5d9 (3:65d9) + TX_FAR _NoCyclingAllowedHereText + db "@" + +NoSurfingHereText: ; e5de (3:65de) + TX_FAR _NoSurfingHereText + db "@" + +BoxFullCannotThrowBallText: ; e5e3 (3:65e3) + TX_FAR _BoxFullCannotThrowBallText + db "@" + +ItemUseText00: ; e5e8 (3:65e8) + TX_FAR _ItemUseText001 + db $05 + TX_FAR _ItemUseText002 + db "@" + +GotOnBicycleText: ; e5f2 (3:65f2) + TX_FAR _GotOnBicycleText1 + db $05 + TX_FAR _GotOnBicycleText2 + db "@" + +GotOffBicycleText: ; e5fc (3:65fc) + TX_FAR _GotOffBicycleText1 + db $05 + 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 +; [wd11e] = mode +; 0: Pokemon Center healing +; 1: using a PP Up +; [wCurrentMenuItem] = index of move (when using a PP Up) +RestoreBonusPP: ; e606 (3:6606) + ld hl,wPartyMon1Moves + ld bc,44 + ld a,[wWhichPokemon] + call AddNTimes + push hl + ld de,wcd78 - 1 + predef LoadMovePPs ; loads the normal max PP of each of the pokemon's moves to wcd78 + pop hl + ld c,21 + ld b,0 + add hl,bc ; hl now points to move 1 PP + ld de,wcd78 + ld b,0 ; initialize move counter to zero +; loop through the pokemon's moves +.loop + inc b + ld a,b + cp a,5 ; reached the end of the pokemon's moves? + ret z ; if so, return + ld a,[wd11e] + 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 a,%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 +; [wd11e] = max number of times to add bonus +; set to 1 when using a PP Up, set to 255 otherwise +AddBonusPP: ; e642 (3:6642) + 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 a,%00001111 + srl a + srl a + ld c,a ; c = number of PP Ups used +.loop + ld a,[H_QUOTIENT + 3] + cp a,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,[wd11e] + dec a + jr z,.done + 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 +; [wcc49] = 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: +; [wd11e] = max PP +GetMaxPP: ; e677 (3:6677) + ld a,[wcc49] + 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,6 + call AddNTimes + ld de,wcd6d + ld a,BANK(Moves) + call FarCopyData + ld de,wcd72 + ld a,[de] + ld b,a ; b = normal max PP + pop hl + push bc + ld bc,21 ; PP offset if not player's in-battle pokemon data + ld a,[wcc49] + cp a,4 ; player's in-battle pokemon? + jr nz,.addPPOffset + ld bc,17 ; PP offset if player's in-battle pokemon data +.addPPOffset + add hl,bc + ld a,[hl] ; a = current PP + and a,%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 + ld [wd11e],a ; no limit on PP Up amount + call AddBonusPP ; add bonus PP from PP Ups + ld a,[hl] + and a,%00111111 ; mask out the PP Up count + ld [wd11e],a ; store max PP + ret + +GetSelectedMoveOffset: ; e6e3 (3:66e3) + ld a,[wWhichPokemon] + call AddNTimes + +GetSelectedMoveOffset2: ; e6e9 (3:66e9) + 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 +; [wcf96] = quantity to toss +; OUTPUT: +; clears carry flag if the item is tossed, sets carry flag if not +TossItem_: ; e6f1 (3:66f1) + push hl + ld a,[wcf91] + call IsItemHM + pop hl + jr c,.tooImportantToToss + push hl + call IsKeyItem_ + ld a,[wd124] + 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 + hlCoord 14, 7 + ld bc,$080f + ld a,TWO_OPTION_MENU + ld [wTextBoxID],a + call DisplayTextBoxID ; yes/no menu + ld a,[wd12e] + cp a,2 + pop hl + scf + ret z +; 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: ; e755 (3:6755) + TX_FAR _ThrewAwayItemText + db "@" + +IsItOKToTossItemText: ; e75a (3:675a) + TX_FAR _IsItOKToTossItemText + db "@" + +TooImportantToTossText: ; e75f (3:675f) + TX_FAR _TooImportantToTossText + db "@" + +; checks if an item is a key item +; INPUT: +; [wcf91] = item ID +; OUTPUT: +; [wd124] = result +; 00: item is not key item +; 01: item is key item +IsKeyItem_: ; e764 (3:6764) + ld a,$01 + ld [wd124],a + ld a,[wcf91] + cp a,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,wHPBarMaxHP + ld bc,15 ; only 11 bytes are actually used + call CopyData + pop af + dec a + ld c,a + ld hl,wHPBarMaxHP + ld b,$02 ; test bit + predef FlagActionPredef ; bitfield operation function + ld a,c + and a + ret nz +.checkIfItemIsHM + ld a,[wcf91] + call IsItemHM + ret c + xor a + ld [wd124],a + ret + +INCLUDE "data/key_items.asm" + +SendNewMonToBox: ; e7a4 (3:67a4) + ld de, W_NUMINBOX ; wda80 + 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, $b + ld a, [W_NUMINBOX] ; wda80 + dec a + jr z, .asm_e7ee + dec a + call AddNTimes + push hl + ld bc, $b + add hl, bc + ld d, h + ld e, l + pop hl + ld a, [W_NUMINBOX] ; wda80 + dec a + ld b, a +.asm_e7db + push bc + push hl + ld bc, $b + call CopyData + pop hl + ld d, h + ld e, l + ld bc, $fff5 + add hl, bc + pop bc + dec b + jr nz, .asm_e7db +.asm_e7ee + ld hl, wPlayerName ; wd158 + ld de, wBoxMonOT + ld bc, $b + call CopyData + ld a, [W_NUMINBOX] ; wda80 + dec a + jr z, .asm_e82a + ld hl, wBoxMonNicks + ld bc, $b + dec a + call AddNTimes + push hl + ld bc, $b + add hl, bc + ld d, h + ld e, l + pop hl + ld a, [W_NUMINBOX] ; wda80 + dec a + ld b, a +.asm_e817 + push bc + push hl + ld bc, $b + call CopyData + pop hl + ld d, h + ld e, l + ld bc, $fff5 + add hl, bc + pop bc + dec b + jr nz, .asm_e817 +.asm_e82a + ld hl, wBoxMonNicks + ld a, $2 + ld [wd07d], a + predef AskName + ld a, [W_NUMINBOX] ; wda80 + 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, [W_NUMINBOX] ; wda80 + 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, $ffdf + add hl, bc + pop bc + dec b + jr nz, .asm_e854 +.asm_e867 + ld a, [wEnemyMonLevel] ; wEnemyMonLevel + ld [wEnemyMonBoxLevel], a + ld hl, wEnemyMon + ld de, wBoxMon1 + ld bc, $c + call CopyData + ld hl, wPlayerID ; wPlayerID + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + ld [de], a + inc de + push de + ld a, [W_CURENEMYLVL] ; W_CURENEMYLVL + ld d, a + callab CalcExperience + pop de + ld a, [H_NUMTOPRINT] ; $ff96 (aliases: H_MULTIPLICAND) + ld [de], a + inc de + ld a, [$ff97] + ld [de], a + inc de + ld a, [$ff98] + ld [de], a + inc de + xor a + ld b, $a +.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 ; wcffe + ld b, $4 +.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: ; e8b8 (3:68b8) + ld a, [W_CURMAPTILESET] + ld hl, WaterTilesets + ld de,1 + call IsInArray ; does the current map allow surfing? + ret nc ; if not, return + ld hl,WaterTile + ld a, [W_CURMAPTILESET] + cp SHIP_PORT ; Vermilion Dock tileset + jr z, .skipShoreTiles ; if it's the Vermilion Dock tileset + cp GYM ; eastern shore tile in Safari Zone + jr z, .skipShoreTiles + cp DOJO ; usual eastern shore tile + jr z, .skipShoreTiles + ld hl,ShoreTiles +.skipShoreTiles + ld a,[wTileInFrontOfPlayer] + ld de,$1 + call IsInArray + ret + +; tilesets with water +WaterTilesets: ; e834 (3:6834) + db OVERWORLD, FOREST, DOJO, GYM, SHIP, SHIP_PORT, CAVERN, FACILITY, PLATEAU + db $ff ; terminator + +; shore tiles +ShoreTiles: ; e83e (3:683e) + db $48, $32 +WaterTile: ; e840 (3:6840) + db $14 + db $ff ; terminator + +ReadSuperRodData: ; e8ea (3:68ea) +; 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, [W_CURMAP] + 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 ; 0xe8f6 +; 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 ; 0xe90c + 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: ; e9c5 (3:69c5) + 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: ; e9cb (3:69cb) + 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: ; e9f0 (3:69f0) + 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 diff --git a/engine/overworld/map_sprites.asm b/engine/overworld/map_sprites.asm index 54312c6f..747a0a45 100755 --- a/engine/overworld/map_sprites.asm +++ b/engine/overworld/map_sprites.asm @@ -1,440 +1,440 @@ -; Loads tile patterns for map's sprites. -; For outside maps, it loads one of several fixed sets of sprites. -; For inside maps, it loads each sprite picture ID used in the map header. -; This is also called after displaying text because loading -; text tile patterns overwrites half of the sprite tile pattern data. -; Note on notation: -; $C1X* and $C2X* are used to denote wSpriteStateData1-wSpriteStateData1 + $ff and wSpriteStateData2 + $00-wSpriteStateData2 + $ff sprite slot -; fields, respectively, within loops. The X is the loop index. -; If there is an inner loop, Y is the inner loop index, i.e. $C1Y* and $C2Y* -; denote fields of the sprite slots interated over in the inner loop. -_InitMapSprites: ; 1785b (5:785b) - call InitOutsideMapSprites - ret c ; return if the map is an outside map (already handled by above call) -; if the map is an inside map (i.e. mapID >= $25) - ld hl,wSpriteStateData1 - ld de,wSpriteStateData2 + $0d -; Loop to copy picture ID's from $C1X0 to $C2XD for LoadMapSpriteTilePatterns. -.copyPictureIDLoop - ld a,[hl] ; $C1X0 (picture ID) - ld [de],a ; $C2XD - ld a,$10 - add e - ld e,a - ld a,$10 - add l - ld l,a - jr nz,.copyPictureIDLoop - -; This is used for both inside and outside maps, since it is called by -; InitOutsideMapSprites. -; Loads tile pattern data for sprites into VRAM. -LoadMapSpriteTilePatterns: ; 17871 (5:7871) - ld a,[W_NUMSPRITES] - and a ; are there any sprites? - jr nz,.spritesExist - ret -.spritesExist - ld c,a ; c = [W_NUMSPRITES] - ld b,$10 ; number of sprite slots - ld hl,wSpriteStateData2 + $0d - xor a - ld [$ff8e],a ; 4-tile sprite counter -.copyPictureIDLoop ; loop to copy picture ID from $C2XD to $C2XE - ld a,[hli] ; $C2XD (sprite picture ID) - ld [hld],a ; $C2XE - ld a,l - add a,$10 - ld l,a - dec b - jr nz,.copyPictureIDLoop - ld hl,wSpriteStateData2 + $1e -.loadTilePatternLoop - ld de,wSpriteStateData2 + $1d -; Check if the current picture ID has already had its tile patterns loaded. -; This done by looping through the previous sprite slots and seeing if any of -; their picture ID's match that of the current sprite slot. -.checkIfAlreadyLoadedLoop - ld a,e - and a,$f0 - ld b,a ; b = offset of the wSpriteStateData2 sprite slot being checked against - ld a,l - and a,$f0 ; a = offset of current wSpriteStateData2 sprite slot - cp b ; done checking all previous sprite slots? - jr z,.notAlreadyLoaded - ld a,[de] ; picture ID of the wSpriteStateData2 sprite slot being checked against - cp [hl] ; do the picture ID's match? - jp z,.alreadyLoaded - ld a,e - add a,$10 - ld e,a - jr .checkIfAlreadyLoadedLoop -.notAlreadyLoaded - ld de,wSpriteStateData2 + $0e - ld b,$01 -; loop to find the highest tile pattern VRAM slot (among the first 10 slots) used by a previous sprite slot -; this is done in order to find the first free VRAM slot available -.findNextVRAMSlotLoop - ld a,e - add a,$10 - ld e,a - ld a,l - cp e ; reached current slot? - jr z,.foundNextVRAMSlot - ld a,[de] ; $C2YE (VRAM slot) - cp a,11 ; is it one of the first 10 slots? - jr nc,.findNextVRAMSlotLoop - cp b ; compare the slot being checked to the current max - jr c,.findNextVRAMSlotLoop ; if the slot being checked is less than the current max -; if the slot being checked is greater than or equal to the current max - ld b,a ; store new max VRAM slot - jr .findNextVRAMSlotLoop -.foundNextVRAMSlot - inc b ; increment previous max value to get next VRAM tile pattern slot - ld a,b ; a = next VRAM tile pattern slot - push af - ld a,[hl] ; $C2XE (sprite picture ID) - ld b,a ; b = current sprite picture ID - cp a,SPRITE_BALL ; is it a 4-tile sprite? - jr c,.notFourTileSprite - pop af - ld a,[$ff8e] ; 4-tile sprite counter - add a,11 - jr .storeVRAMSlot -.notFourTileSprite - pop af -.storeVRAMSlot - ld [hl],a ; store VRAM slot at $C2XE - ld [$ff8d],a ; used to determine if it's 4-tile sprite later - ld a,b ; a = current sprite picture ID - dec a - add a - add a - push bc - push hl - ld hl,SpriteSheetPointerTable - jr nc,.noCarry - inc h -.noCarry - add l - ld l,a - jr nc,.noCarry2 - inc h -.noCarry2 - push hl - call ReadSpriteSheetData - push af - push de - push bc - ld hl,vNPCSprites ; VRAM base address - ld bc,$c0 ; number of bytes per VRAM slot - ld a,[$ff8d] - cp a,11 ; is it a 4-tile sprite? - jr nc,.fourTileSpriteVRAMAddr - ld d,a - dec d -; Equivalent to multiplying $C0 (number of bytes in 12 tiles) times the VRAM -; slot and adding the result to $8000 (the VRAM base address). -.calculateVRAMAddrLoop - add hl,bc - dec d - jr nz,.calculateVRAMAddrLoop - jr .loadStillTilePattern -.fourTileSpriteVRAMAddr - ld hl,vSprites + $7c0 ; address for second 4-tile sprite - ld a,[$ff8e] ; 4-tile sprite counter - and a ; is it the first 4-tile sprite? - jr nz,.loadStillTilePattern -; if it's the first 4-tile sprite - ld hl,vSprites + $780 ; address for first 4-tile sprite - inc a - ld [$ff8e],a ; 4-tile sprite counter -.loadStillTilePattern - pop bc - pop de - pop af - push hl - push hl - ld h,d - ld l,e - pop de - ld b,a - ld a,[wFontLoaded] - bit 0,a ; reloading upper half of tile patterns after displaying text? - jr nz,.skipFirstLoad ; if so, skip loading data into the lower half - ld a,b - ld b,0 - call FarCopyData2 ; load tile pattern data for sprite when standing still -.skipFirstLoad - pop de - pop hl - ld a,[$ff8d] - cp a,11 ; is it a 4-tile sprite? - jr nc,.skipSecondLoad ; if so, there is no second block - push de - call ReadSpriteSheetData - push af - ld a,$c0 - add e - ld e,a - jr nc,.noCarry3 - inc d -.noCarry3 - ld a,[wFontLoaded] - bit 0,a ; reloading upper half of tile patterns after displaying text? - jr nz,.loadWhileLCDOn - pop af - pop hl - set 3,h ; add $800 to hl - push hl - ld h,d - ld l,e - pop de - call FarCopyData2 ; load tile pattern data for sprite when walking - jr .skipSecondLoad -; When reloading the upper half of tile patterns after diplaying text, the LCD -; will be on, so CopyVideoData (which writes to VRAM only during V-blank) must -; be used instead of FarCopyData2. -.loadWhileLCDOn - pop af - pop hl - set 3,h ; add $800 to hl - ld b,a - swap c - call CopyVideoData ; load tile pattern data for sprite when walking -.skipSecondLoad - pop hl - pop bc - jr .nextSpriteSlot -.alreadyLoaded ; if the current picture ID has already had its tile patterns loaded - inc de - ld a,[de] ; a = VRAM slot for the current picture ID (from $C2YE) - ld [hl],a ; store VRAM slot in current wSpriteStateData2 sprite slot (at $C2XE) -.nextSpriteSlot - ld a,l - add a,$10 - ld l,a - dec c - jp nz,.loadTilePatternLoop - ld hl,wSpriteStateData2 + $0d - ld b,$10 -; the pictures ID's stored at $C2XD are no longer needed, so zero them -.zeroStoredPictureIDLoop - xor a - ld [hl],a ; $C2XD - ld a,$10 - add l - ld l,a - dec b - jr nz,.zeroStoredPictureIDLoop - ret - -; reads data from SpriteSheetPointerTable -; INPUT: -; hl = address of sprite sheet entry -; OUTPUT: -; de = pointer to sprite sheet -; bc = length in bytes -; a = ROM bank -ReadSpriteSheetData: ; 17971 (5:7971) - ld a,[hli] - ld e,a - ld a,[hli] - ld d,a - ld a,[hli] - ld c,a - xor a - ld b,a - ld a,[hli] - ret - -; Loads sprite set for outside maps (cities and routes) and sets VRAM slots. -; sets carry if the map is a city or route, unsets carry if not -InitOutsideMapSprites: ; 1797b (5:797b) - ld a,[W_CURMAP] - cp a,REDS_HOUSE_1F ; is the map a city or a route (map ID less than $25)? - ret nc ; if not, return - ld hl,MapSpriteSets - add l - ld l,a - jr nc,.noCarry - inc h -.noCarry - ld a,[hl] ; a = spriteSetID - cp a,$f0 ; does the map have 2 sprite sets? - call nc,GetSplitMapSpriteSetID ; if so, choose the appropriate one - ld b,a ; b = spriteSetID - ld a,[wFontLoaded] - bit 0,a ; reloading upper half of tile patterns after displaying text? - jr nz,.loadSpriteSet ; if so, forcibly reload the sprite set - ld a,[W_SPRITESETID] - cp b ; has the sprite set ID changed? - jr z,.skipLoadingSpriteSet ; if not, don't load it again -.loadSpriteSet - ld a,b - ld [W_SPRITESETID],a - dec a - ld b,a - sla a - ld c,a - sla a - sla a - add c - add b ; a = (spriteSetID - 1) * 11 - ld de,SpriteSets -; add a to de to get offset of sprite set - add e - ld e,a - jr nc,.noCarry2 - inc d -.noCarry2 - ld hl,wSpriteStateData2 + $0d - ld a,SPRITE_RED - ld [hl],a - ld bc,W_SPRITESET -; Load the sprite set into RAM. -; This loop also fills $C2XD (sprite picture ID) where X is from $0 to $A -; with picture ID's. This is done so that LoadMapSpriteTilePatterns will -; load tile patterns for all sprite pictures in the sprite set. -.loadSpriteSetLoop - ld a,$10 - add l - ld l,a - ld a,[de] ; sprite picture ID from sprite set - ld [hl],a ; $C2XD (sprite picture ID) - ld [bc],a - inc de - inc bc - ld a,l - cp a,$bd ; reached 11th sprite slot? - jr nz,.loadSpriteSetLoop - ld b,4 ; 4 remaining sprite slots -.zeroRemainingSlotsLoop ; loop to zero the picture ID's of the remaining sprite slots - ld a,$10 - add l - ld l,a - xor a - ld [hl],a ; $C2XD (sprite picture ID) - dec b - jr nz,.zeroRemainingSlotsLoop - ld a,[W_NUMSPRITES] - push af ; save number of sprites - ld a,11 ; 11 sprites in sprite set - ld [W_NUMSPRITES],a - call LoadMapSpriteTilePatterns - pop af - ld [W_NUMSPRITES],a ; restore number of sprites - ld hl,wSpriteStateData2 + $1e - ld b,$0f -; The VRAM tile pattern slots that LoadMapSpriteTilePatterns set are in the -; order of the map's sprite set, not the order of the actual sprites loaded -; for the current map. So, they are not needed and are zeroed by this loop. -.zeroVRAMSlotsLoop - xor a - ld [hl],a ; $C2XE (VRAM slot) - ld a,$10 - add l - ld l,a - dec b - jr nz,.zeroVRAMSlotsLoop -.skipLoadingSpriteSet - ld hl,wSpriteStateData1 + $10 -; This loop stores the correct VRAM tile pattern slots according the sprite -; data from the map's header. Since the VRAM tile pattern slots are filled in -; the order of the sprite set, in order to find the VRAM tile pattern slot -; for a sprite slot, the picture ID for the sprite is looked up within the -; sprite set. The index of the picture ID within the sprite set plus one -; (since the Red sprite always has the first VRAM tile pattern slot) is the -; VRAM tile pattern slot. -.storeVRAMSlotsLoop - ld c,0 - ld a,[hl] ; $C1X0 (picture ID) (zero if sprite slot is not used) - and a ; is the sprite slot used? - jr z,.skipGettingPictureIndex ; if the sprite slot is not used - ld b,a ; b = picture ID - ld de,W_SPRITESET -; Loop to find the index of the sprite's picture ID within the sprite set. -.getPictureIndexLoop - inc c - ld a,[de] - inc de - cp b ; does the picture ID match? - jr nz,.getPictureIndexLoop - inc c -.skipGettingPictureIndex - push hl - inc h - ld a,$0e - add l - ld l,a - ld a,c ; a = VRAM slot (zero if sprite slot is not used) - ld [hl],a ; $C2XE (VRAM slot) - pop hl - ld a,$10 - add l - ld l,a - and a - jr nz,.storeVRAMSlotsLoop - scf - ret - -; Chooses the correct sprite set ID depending on the player's position within -; the map for maps with two sprite sets. -GetSplitMapSpriteSetID: ; 17a1a (5:7a1a) - cp a,$f8 - jr z,.route20 - ld hl,SplitMapSpriteSets - and a,$0f - dec a - sla a - sla a - add l - ld l,a - jr nc,.noCarry - inc h -.noCarry - ld a,[hli] ; determines whether the map is split East/West or North/South - cp a,$01 - ld a,[hli] ; position of dividing line - ld b,a - jr z,.eastWestDivide -.northSouthDivide - ld a,[W_YCOORD] - jr .compareCoord -.eastWestDivide - ld a,[W_XCOORD] -.compareCoord - cp b - jr c,.loadSpriteSetID -; if in the East side or South side - inc hl -.loadSpriteSetID - ld a,[hl] - ret -; Uses sprite set $01 for West side and $0A for East side. -; Route 20 is a special case because the two map sections have a more complex -; shape instead of the map simply being split horizontally or vertically. -.route20 - ld hl,W_XCOORD - ld a,[hl] - cp a,$2b - ld a,$01 - ret c - ld a,[hl] - cp a,$3e - ld a,$0a - ret nc - ld a,[hl] - cp a,$37 - ld b,$08 - jr nc,.next - ld b,$0d -.next - ld a,[W_YCOORD] - cp b - ld a,$0a - ret c - ld a,$01 - ret - -INCLUDE "data/sprite_sets.asm" +; Loads tile patterns for map's sprites. +; For outside maps, it loads one of several fixed sets of sprites. +; For inside maps, it loads each sprite picture ID used in the map header. +; This is also called after displaying text because loading +; text tile patterns overwrites half of the sprite tile pattern data. +; Note on notation: +; $C1X* and $C2X* are used to denote wSpriteStateData1-wSpriteStateData1 + $ff and wSpriteStateData2 + $00-wSpriteStateData2 + $ff sprite slot +; fields, respectively, within loops. The X is the loop index. +; If there is an inner loop, Y is the inner loop index, i.e. $C1Y* and $C2Y* +; denote fields of the sprite slots interated over in the inner loop. +_InitMapSprites: ; 1785b (5:785b) + call InitOutsideMapSprites + ret c ; return if the map is an outside map (already handled by above call) +; if the map is an inside map (i.e. mapID >= $25) + ld hl,wSpriteStateData1 + ld de,wSpriteStateData2 + $0d +; Loop to copy picture ID's from $C1X0 to $C2XD for LoadMapSpriteTilePatterns. +.copyPictureIDLoop + ld a,[hl] ; $C1X0 (picture ID) + ld [de],a ; $C2XD + ld a,$10 + add e + ld e,a + ld a,$10 + add l + ld l,a + jr nz,.copyPictureIDLoop + +; This is used for both inside and outside maps, since it is called by +; InitOutsideMapSprites. +; Loads tile pattern data for sprites into VRAM. +LoadMapSpriteTilePatterns: ; 17871 (5:7871) + ld a,[W_NUMSPRITES] + and a ; are there any sprites? + jr nz,.spritesExist + ret +.spritesExist + ld c,a ; c = [W_NUMSPRITES] + ld b,$10 ; number of sprite slots + ld hl,wSpriteStateData2 + $0d + xor a + ld [$ff8e],a ; 4-tile sprite counter +.copyPictureIDLoop ; loop to copy picture ID from $C2XD to $C2XE + ld a,[hli] ; $C2XD (sprite picture ID) + ld [hld],a ; $C2XE + ld a,l + add a,$10 + ld l,a + dec b + jr nz,.copyPictureIDLoop + ld hl,wSpriteStateData2 + $1e +.loadTilePatternLoop + ld de,wSpriteStateData2 + $1d +; Check if the current picture ID has already had its tile patterns loaded. +; This done by looping through the previous sprite slots and seeing if any of +; their picture ID's match that of the current sprite slot. +.checkIfAlreadyLoadedLoop + ld a,e + and a,$f0 + ld b,a ; b = offset of the wSpriteStateData2 sprite slot being checked against + ld a,l + and a,$f0 ; a = offset of current wSpriteStateData2 sprite slot + cp b ; done checking all previous sprite slots? + jr z,.notAlreadyLoaded + ld a,[de] ; picture ID of the wSpriteStateData2 sprite slot being checked against + cp [hl] ; do the picture ID's match? + jp z,.alreadyLoaded + ld a,e + add a,$10 + ld e,a + jr .checkIfAlreadyLoadedLoop +.notAlreadyLoaded + ld de,wSpriteStateData2 + $0e + ld b,$01 +; loop to find the highest tile pattern VRAM slot (among the first 10 slots) used by a previous sprite slot +; this is done in order to find the first free VRAM slot available +.findNextVRAMSlotLoop + ld a,e + add a,$10 + ld e,a + ld a,l + cp e ; reached current slot? + jr z,.foundNextVRAMSlot + ld a,[de] ; $C2YE (VRAM slot) + cp a,11 ; is it one of the first 10 slots? + jr nc,.findNextVRAMSlotLoop + cp b ; compare the slot being checked to the current max + jr c,.findNextVRAMSlotLoop ; if the slot being checked is less than the current max +; if the slot being checked is greater than or equal to the current max + ld b,a ; store new max VRAM slot + jr .findNextVRAMSlotLoop +.foundNextVRAMSlot + inc b ; increment previous max value to get next VRAM tile pattern slot + ld a,b ; a = next VRAM tile pattern slot + push af + ld a,[hl] ; $C2XE (sprite picture ID) + ld b,a ; b = current sprite picture ID + cp a,SPRITE_BALL ; is it a 4-tile sprite? + jr c,.notFourTileSprite + pop af + ld a,[$ff8e] ; 4-tile sprite counter + add a,11 + jr .storeVRAMSlot +.notFourTileSprite + pop af +.storeVRAMSlot + ld [hl],a ; store VRAM slot at $C2XE + ld [$ff8d],a ; used to determine if it's 4-tile sprite later + ld a,b ; a = current sprite picture ID + dec a + add a + add a + push bc + push hl + ld hl,SpriteSheetPointerTable + jr nc,.noCarry + inc h +.noCarry + add l + ld l,a + jr nc,.noCarry2 + inc h +.noCarry2 + push hl + call ReadSpriteSheetData + push af + push de + push bc + ld hl,vNPCSprites ; VRAM base address + ld bc,$c0 ; number of bytes per VRAM slot + ld a,[$ff8d] + cp a,11 ; is it a 4-tile sprite? + jr nc,.fourTileSpriteVRAMAddr + ld d,a + dec d +; Equivalent to multiplying $C0 (number of bytes in 12 tiles) times the VRAM +; slot and adding the result to $8000 (the VRAM base address). +.calculateVRAMAddrLoop + add hl,bc + dec d + jr nz,.calculateVRAMAddrLoop + jr .loadStillTilePattern +.fourTileSpriteVRAMAddr + ld hl,vSprites + $7c0 ; address for second 4-tile sprite + ld a,[$ff8e] ; 4-tile sprite counter + and a ; is it the first 4-tile sprite? + jr nz,.loadStillTilePattern +; if it's the first 4-tile sprite + ld hl,vSprites + $780 ; address for first 4-tile sprite + inc a + ld [$ff8e],a ; 4-tile sprite counter +.loadStillTilePattern + pop bc + pop de + pop af + push hl + push hl + ld h,d + ld l,e + pop de + ld b,a + ld a,[wFontLoaded] + bit 0,a ; reloading upper half of tile patterns after displaying text? + jr nz,.skipFirstLoad ; if so, skip loading data into the lower half + ld a,b + ld b,0 + call FarCopyData2 ; load tile pattern data for sprite when standing still +.skipFirstLoad + pop de + pop hl + ld a,[$ff8d] + cp a,11 ; is it a 4-tile sprite? + jr nc,.skipSecondLoad ; if so, there is no second block + push de + call ReadSpriteSheetData + push af + ld a,$c0 + add e + ld e,a + jr nc,.noCarry3 + inc d +.noCarry3 + ld a,[wFontLoaded] + bit 0,a ; reloading upper half of tile patterns after displaying text? + jr nz,.loadWhileLCDOn + pop af + pop hl + set 3,h ; add $800 to hl + push hl + ld h,d + ld l,e + pop de + call FarCopyData2 ; load tile pattern data for sprite when walking + jr .skipSecondLoad +; When reloading the upper half of tile patterns after diplaying text, the LCD +; will be on, so CopyVideoData (which writes to VRAM only during V-blank) must +; be used instead of FarCopyData2. +.loadWhileLCDOn + pop af + pop hl + set 3,h ; add $800 to hl + ld b,a + swap c + call CopyVideoData ; load tile pattern data for sprite when walking +.skipSecondLoad + pop hl + pop bc + jr .nextSpriteSlot +.alreadyLoaded ; if the current picture ID has already had its tile patterns loaded + inc de + ld a,[de] ; a = VRAM slot for the current picture ID (from $C2YE) + ld [hl],a ; store VRAM slot in current wSpriteStateData2 sprite slot (at $C2XE) +.nextSpriteSlot + ld a,l + add a,$10 + ld l,a + dec c + jp nz,.loadTilePatternLoop + ld hl,wSpriteStateData2 + $0d + ld b,$10 +; the pictures ID's stored at $C2XD are no longer needed, so zero them +.zeroStoredPictureIDLoop + xor a + ld [hl],a ; $C2XD + ld a,$10 + add l + ld l,a + dec b + jr nz,.zeroStoredPictureIDLoop + ret + +; reads data from SpriteSheetPointerTable +; INPUT: +; hl = address of sprite sheet entry +; OUTPUT: +; de = pointer to sprite sheet +; bc = length in bytes +; a = ROM bank +ReadSpriteSheetData: ; 17971 (5:7971) + ld a,[hli] + ld e,a + ld a,[hli] + ld d,a + ld a,[hli] + ld c,a + xor a + ld b,a + ld a,[hli] + ret + +; Loads sprite set for outside maps (cities and routes) and sets VRAM slots. +; sets carry if the map is a city or route, unsets carry if not +InitOutsideMapSprites: ; 1797b (5:797b) + ld a,[W_CURMAP] + cp a,REDS_HOUSE_1F ; is the map a city or a route (map ID less than $25)? + ret nc ; if not, return + ld hl,MapSpriteSets + add l + ld l,a + jr nc,.noCarry + inc h +.noCarry + ld a,[hl] ; a = spriteSetID + cp a,$f0 ; does the map have 2 sprite sets? + call nc,GetSplitMapSpriteSetID ; if so, choose the appropriate one + ld b,a ; b = spriteSetID + ld a,[wFontLoaded] + bit 0,a ; reloading upper half of tile patterns after displaying text? + jr nz,.loadSpriteSet ; if so, forcibly reload the sprite set + ld a,[W_SPRITESETID] + cp b ; has the sprite set ID changed? + jr z,.skipLoadingSpriteSet ; if not, don't load it again +.loadSpriteSet + ld a,b + ld [W_SPRITESETID],a + dec a + ld b,a + sla a + ld c,a + sla a + sla a + add c + add b ; a = (spriteSetID - 1) * 11 + ld de,SpriteSets +; add a to de to get offset of sprite set + add e + ld e,a + jr nc,.noCarry2 + inc d +.noCarry2 + ld hl,wSpriteStateData2 + $0d + ld a,SPRITE_RED + ld [hl],a + ld bc,W_SPRITESET +; Load the sprite set into RAM. +; This loop also fills $C2XD (sprite picture ID) where X is from $0 to $A +; with picture ID's. This is done so that LoadMapSpriteTilePatterns will +; load tile patterns for all sprite pictures in the sprite set. +.loadSpriteSetLoop + ld a,$10 + add l + ld l,a + ld a,[de] ; sprite picture ID from sprite set + ld [hl],a ; $C2XD (sprite picture ID) + ld [bc],a + inc de + inc bc + ld a,l + cp a,$bd ; reached 11th sprite slot? + jr nz,.loadSpriteSetLoop + ld b,4 ; 4 remaining sprite slots +.zeroRemainingSlotsLoop ; loop to zero the picture ID's of the remaining sprite slots + ld a,$10 + add l + ld l,a + xor a + ld [hl],a ; $C2XD (sprite picture ID) + dec b + jr nz,.zeroRemainingSlotsLoop + ld a,[W_NUMSPRITES] + push af ; save number of sprites + ld a,11 ; 11 sprites in sprite set + ld [W_NUMSPRITES],a + call LoadMapSpriteTilePatterns + pop af + ld [W_NUMSPRITES],a ; restore number of sprites + ld hl,wSpriteStateData2 + $1e + ld b,$0f +; The VRAM tile pattern slots that LoadMapSpriteTilePatterns set are in the +; order of the map's sprite set, not the order of the actual sprites loaded +; for the current map. So, they are not needed and are zeroed by this loop. +.zeroVRAMSlotsLoop + xor a + ld [hl],a ; $C2XE (VRAM slot) + ld a,$10 + add l + ld l,a + dec b + jr nz,.zeroVRAMSlotsLoop +.skipLoadingSpriteSet + ld hl,wSpriteStateData1 + $10 +; This loop stores the correct VRAM tile pattern slots according the sprite +; data from the map's header. Since the VRAM tile pattern slots are filled in +; the order of the sprite set, in order to find the VRAM tile pattern slot +; for a sprite slot, the picture ID for the sprite is looked up within the +; sprite set. The index of the picture ID within the sprite set plus one +; (since the Red sprite always has the first VRAM tile pattern slot) is the +; VRAM tile pattern slot. +.storeVRAMSlotsLoop + ld c,0 + ld a,[hl] ; $C1X0 (picture ID) (zero if sprite slot is not used) + and a ; is the sprite slot used? + jr z,.skipGettingPictureIndex ; if the sprite slot is not used + ld b,a ; b = picture ID + ld de,W_SPRITESET +; Loop to find the index of the sprite's picture ID within the sprite set. +.getPictureIndexLoop + inc c + ld a,[de] + inc de + cp b ; does the picture ID match? + jr nz,.getPictureIndexLoop + inc c +.skipGettingPictureIndex + push hl + inc h + ld a,$0e + add l + ld l,a + ld a,c ; a = VRAM slot (zero if sprite slot is not used) + ld [hl],a ; $C2XE (VRAM slot) + pop hl + ld a,$10 + add l + ld l,a + and a + jr nz,.storeVRAMSlotsLoop + scf + ret + +; Chooses the correct sprite set ID depending on the player's position within +; the map for maps with two sprite sets. +GetSplitMapSpriteSetID: ; 17a1a (5:7a1a) + cp a,$f8 + jr z,.route20 + ld hl,SplitMapSpriteSets + and a,$0f + dec a + sla a + sla a + add l + ld l,a + jr nc,.noCarry + inc h +.noCarry + ld a,[hli] ; determines whether the map is split East/West or North/South + cp a,$01 + ld a,[hli] ; position of dividing line + ld b,a + jr z,.eastWestDivide +.northSouthDivide + ld a,[W_YCOORD] + jr .compareCoord +.eastWestDivide + ld a,[W_XCOORD] +.compareCoord + cp b + jr c,.loadSpriteSetID +; if in the East side or South side + inc hl +.loadSpriteSetID + ld a,[hl] + ret +; Uses sprite set $01 for West side and $0A for East side. +; Route 20 is a special case because the two map sections have a more complex +; shape instead of the map simply being split horizontally or vertically. +.route20 + ld hl,W_XCOORD + ld a,[hl] + cp a,$2b + ld a,$01 + ret c + ld a,[hl] + cp a,$3e + ld a,$0a + ret nc + ld a,[hl] + cp a,$37 + ld b,$08 + jr nc,.next + ld b,$0d +.next + ld a,[W_YCOORD] + cp b + ld a,$0a + ret c + ld a,$01 + ret + +INCLUDE "data/sprite_sets.asm" -- cgit v1.2.3