pokered/engine/items/items.asm
Antonio Niño Díaz 9ea25bc8cd Replace deprecated mnemonics by the correct ones
The old mnemonics generate warnings with new versions of rgbds. This
patch replaces them by the correct ones.

Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
2017-06-09 22:54:09 +01:00

2989 lines
60 KiB
NASM
Executable file

UseItem_:
ld a,1
ld [wActionResultOrTookBattleTurn],a ; initialise to success value
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:
dw ItemUseBall ; MASTER_BALL
dw ItemUseBall ; ULTRA_BALL
dw ItemUseBall ; GREAT_BALL
dw ItemUseBall ; POKE_BALL
dw ItemUseTownMap ; TOWN_MAP
dw ItemUseBicycle ; BICYCLE
dw ItemUseSurfboard ; out-of-battle Surf effect
dw ItemUseBall ; SAFARI_BALL
dw ItemUsePokedex ; POKEDEX
dw ItemUseEvoStone ; MOON_STONE
dw ItemUseMedicine ; ANTIDOTE
dw ItemUseMedicine ; BURN_HEAL
dw ItemUseMedicine ; ICE_HEAL
dw ItemUseMedicine ; AWAKENING
dw ItemUseMedicine ; PARLYZ_HEAL
dw ItemUseMedicine ; FULL_RESTORE
dw ItemUseMedicine ; MAX_POTION
dw ItemUseMedicine ; HYPER_POTION
dw ItemUseMedicine ; SUPER_POTION
dw ItemUseMedicine ; POTION
dw ItemUseBait ; BOULDERBADGE
dw ItemUseRock ; CASCADEBADGE
dw UnusableItem ; THUNDERBADGE
dw UnusableItem ; RAINBOWBADGE
dw UnusableItem ; SOULBADGE
dw UnusableItem ; MARSHBADGE
dw UnusableItem ; VOLCANOBADGE
dw UnusableItem ; EARTHBADGE
dw ItemUseEscapeRope ; ESCAPE_ROPE
dw ItemUseRepel ; REPEL
dw UnusableItem ; OLD_AMBER
dw ItemUseEvoStone ; FIRE_STONE
dw ItemUseEvoStone ; THUNDER_STONE
dw ItemUseEvoStone ; WATER_STONE
dw ItemUseVitamin ; HP_UP
dw ItemUseVitamin ; PROTEIN
dw ItemUseVitamin ; IRON
dw ItemUseVitamin ; CARBOS
dw ItemUseVitamin ; CALCIUM
dw ItemUseVitamin ; RARE_CANDY
dw UnusableItem ; DOME_FOSSIL
dw UnusableItem ; HELIX_FOSSIL
dw UnusableItem ; SECRET_KEY
dw UnusableItem
dw UnusableItem ; BIKE_VOUCHER
dw ItemUseXAccuracy ; X_ACCURACY
dw ItemUseEvoStone ; LEAF_STONE
dw ItemUseCardKey ; CARD_KEY
dw UnusableItem ; NUGGET
dw UnusableItem ; ??? PP_UP
dw ItemUsePokedoll ; POKE_DOLL
dw ItemUseMedicine ; FULL_HEAL
dw ItemUseMedicine ; REVIVE
dw ItemUseMedicine ; MAX_REVIVE
dw ItemUseGuardSpec ; GUARD_SPEC
dw ItemUseSuperRepel ; SUPER_REPL
dw ItemUseMaxRepel ; MAX_REPEL
dw ItemUseDireHit ; DIRE_HIT
dw UnusableItem ; COIN
dw ItemUseMedicine ; FRESH_WATER
dw ItemUseMedicine ; SODA_POP
dw ItemUseMedicine ; LEMONADE
dw UnusableItem ; S_S_TICKET
dw UnusableItem ; GOLD_TEETH
dw ItemUseXStat ; X_ATTACK
dw ItemUseXStat ; X_DEFEND
dw ItemUseXStat ; X_SPEED
dw ItemUseXStat ; X_SPECIAL
dw ItemUseCoinCase ; COIN_CASE
dw ItemUseOaksParcel ; OAKS_PARCEL
dw ItemUseItemfinder ; ITEMFINDER
dw UnusableItem ; SILPH_SCOPE
dw ItemUsePokeflute ; POKE_FLUTE
dw UnusableItem ; LIFT_KEY
dw UnusableItem ; EXP_ALL
dw ItemUseOldRod ; OLD_ROD
dw ItemUseGoodRod ; GOOD_ROD
dw ItemUseSuperRod ; SUPER_ROD
dw ItemUsePPUp ; PP_UP (real one)
dw ItemUsePPRestore ; ETHER
dw ItemUsePPRestore ; MAX_ETHER
dw ItemUsePPRestore ; ELIXER
dw ItemUsePPRestore ; MAX_ELIXER
ItemUseBall:
; Balls can't be used out of battle.
ld a,[wIsInBattle]
and a
jp z,ItemUseNotTime
; Balls can't catch trainers' Pokémon.
dec a
jp nz,ThrowBallAtTrainerMon
; If this is for the old man battle, skip checking if the party & box are full.
ld a,[wBattleType]
dec a
jr z,.canUseBall
ld a,[wPartyCount] ; is party full?
cp a,PARTY_LENGTH
jr nz,.canUseBall
ld a,[wNumInBox] ; is box full?
cp a,MONS_PER_BOX
jp z,BoxFullCannotThrowBall
.canUseBall
xor a
ld [wCapturedMonSpecies],a
ld a,[wBattleType]
cp a,BATTLE_TYPE_SAFARI
jr nz,.skipSafariZoneCode
.safariZone
ld hl,wNumSafariBalls
dec [hl] ; remove a Safari Ball
.skipSafariZoneCode
call RunDefaultPaletteCommand
ld a,$43 ; successful capture value
ld [wPokeBallAnimData],a
call LoadScreenTilesFromBuffer1
ld hl,ItemUseText00
call PrintText
; If the player is fighting an unidentified ghost, set the value that indicates
; the Pokémon can't be caught and skip the capture calculations.
callab IsGhostBattle
ld b,$10 ; can't be caught value
jp z,.setAnimData
ld a,[wBattleType]
dec a
jr nz,.notOldManBattle
.oldManBattle
ld hl,wGrassRate
ld de,wPlayerName
ld bc,NAME_LENGTH
call CopyData ; save the player's name in the Wild Monster data (part of the Cinnabar Island Missingno. glitch)
jp .captured
.notOldManBattle
; If the player is fighting the ghost Marowak, set the value that indicates the
; Pokémon can't be caught and skip the capture calculations.
ld a,[wCurMap]
cp a,POKEMONTOWER_6
jr nz,.loop
ld a,[wEnemyMonSpecies2]
cp a,MAROWAK
ld b,$10 ; can't be caught value
jp z,.setAnimData
; Get the first random number. Let it be called Rand1.
; Rand1 must be within a certain range according the kind of ball being thrown.
; The ranges are as follows.
; Poké Ball: [0, 255]
; Great Ball: [0, 200]
; Ultra/Safari Ball: [0, 150]
; Loop until an acceptable number is found.
.loop
call Random
ld b,a
; Get the item ID.
ld hl,wcf91
ld a,[hl]
; The Master Ball always succeeds.
cp a,MASTER_BALL
jp z,.captured
; Anything will do for the basic Poké Ball.
cp a,POKE_BALL
jr z,.checkForAilments
; If it's a Great/Ultra/Safari Ball and Rand1 is greater than 200, try again.
ld a,200
cp b
jr c,.loop
; Less than or equal to 200 is good enough for a Great Ball.
ld a,[hl]
cp a,GREAT_BALL
jr z,.checkForAilments
; If it's an Ultra/Safari Ball and Rand1 is greater than 150, try again.
ld a,150
cp b
jr c,.loop
.checkForAilments
; Pokémon can be caught more easily with a status ailment.
; Depending on the status ailment, a certain value will be subtracted from
; Rand1. Let this value be called Status.
; The larger Status is, the more easily the Pokémon can be caught.
; no status ailment: Status = 0
; Burn/Paralysis/Poison: Status = 12
; Freeze/Sleep: Status = 25
; If Status is greater than Rand1, the Pokémon will be caught for sure.
ld a,[wEnemyMonStatus]
and a
jr z,.skipAilmentValueSubtraction ; no ailments
and a, 1 << FRZ | SLP
ld c,12
jr z,.notFrozenOrAsleep
ld c,25
.notFrozenOrAsleep
ld a,b
sub c
jp c,.captured
ld b,a
.skipAilmentValueSubtraction
push bc ; save (Rand1 - Status)
; Calculate MaxHP * 255.
xor a
ld [H_MULTIPLICAND],a
ld hl,wEnemyMonMaxHP
ld a,[hli]
ld [H_MULTIPLICAND + 1],a
ld a,[hl]
ld [H_MULTIPLICAND + 2],a
ld a,255
ld [H_MULTIPLIER],a
call Multiply
; Determine BallFactor. It's 8 for Great Balls and 12 for the others.
ld a,[wcf91]
cp a,GREAT_BALL
ld a,12
jr nz,.skip1
ld a,8
.skip1
; Note that the results of all division operations are floored.
; Calculate (MaxHP * 255) / BallFactor.
ld [H_DIVISOR],a
ld b,4 ; number of bytes in dividend
call Divide
; Divide the enemy's current HP by 4. HP is not supposed to exceed 999 so
; the result should fit in a. If the division results in a quotient of 0,
; change it to 1.
ld hl,wEnemyMonHP
ld a,[hli]
ld b,a
ld a,[hl]
srl b
rr a
srl b
rr a
and a
jr nz,.skip2
inc a
.skip2
; Let W = ((MaxHP * 255) / BallFactor) / max(HP / 4, 1). Calculate W.
ld [H_DIVISOR],a
ld b,4
call Divide
; If W > 255, store 255 in [H_QUOTIENT + 3].
; Let X = min(W, 255) = [H_QUOTIENT + 3].
ld a,[H_QUOTIENT + 2]
and a
jr z,.skip3
ld a,255
ld [H_QUOTIENT + 3],a
.skip3
pop bc ; b = Rand1 - Status
; If Rand1 - Status > CatchRate, the ball fails to capture the Pokémon.
ld a,[wEnemyMonCatchRate]
cp b
jr c,.failedToCapture
; If W > 255, the ball captures the Pokémon.
ld a,[H_QUOTIENT + 2]
and a
jr nz,.captured
call Random ; Let this random number be called Rand2.
; If Rand2 > X, the ball fails to capture the Pokémon.
ld b,a
ld a,[H_QUOTIENT + 3]
cp b
jr c,.failedToCapture
.captured
jr .skipShakeCalculations
.failedToCapture
ld a,[H_QUOTIENT + 3]
ld [wPokeBallCaptureCalcTemp],a ; Save X.
; Calculate CatchRate * 100.
xor a
ld [H_MULTIPLICAND],a
ld [H_MULTIPLICAND + 1],a
ld a,[wEnemyMonCatchRate]
ld [H_MULTIPLICAND + 2],a
ld a,100
ld [H_MULTIPLIER],a
call Multiply
; Determine BallFactor2.
; Poké Ball: BallFactor2 = 255
; Great Ball: BallFactor2 = 200
; Ultra/Safari Ball: BallFactor2 = 150
ld a,[wcf91]
ld b,255
cp a,POKE_BALL
jr z,.skip4
ld b,200
cp a,GREAT_BALL
jr z,.skip4
ld b,150
cp a,ULTRA_BALL
jr z,.skip4
.skip4
; Let Y = (CatchRate * 100) / BallFactor2. Calculate Y.
ld a,b
ld [H_DIVISOR],a
ld b,4
call Divide
; If Y > 255, there are 3 shakes.
; Note that this shouldn't be possible.
; The maximum value of Y is (255 * 100) / 150 = 170.
ld a,[H_QUOTIENT + 2]
and a
ld b,$63 ; 3 shakes
jr nz,.setAnimData
; Calculate X * Y.
ld a,[wPokeBallCaptureCalcTemp]
ld [H_MULTIPLIER],a
call Multiply
; Calculate (X * Y) / 255.
ld a,255
ld [H_DIVISOR],a
ld b,4
call Divide
; Determine Status2.
; no status ailment: Status2 = 0
; Burn/Paralysis/Poison: Status2 = 5
; Freeze/Sleep: Status2 = 10
ld a,[wEnemyMonStatus]
and a
jr z,.skip5
and a, 1 << FRZ | SLP
ld b,5
jr z,.addAilmentValue
ld b,10
.addAilmentValue
; If the Pokémon has a status ailment, add Status2.
ld a,[H_QUOTIENT + 3]
add b
ld [H_QUOTIENT + 3],a
.skip5
; Finally determine the number of shakes.
; Let Z = ((X * Y) / 255) + Status2 = [H_QUOTIENT + 3].
; The number of shakes depend on the range Z is in.
; 0 ≤ Z < 10: 0 shakes (the ball misses)
; 10 ≤ Z < 30: 1 shake
; 30 ≤ Z < 70: 2 shakes
; 70 ≤ Z: 3 shakes
ld a,[H_QUOTIENT + 3]
cp a,10
ld b,$20
jr c,.setAnimData
cp a,30
ld b,$61
jr c,.setAnimData
cp a,70
ld b,$62
jr c,.setAnimData
ld b,$63
.setAnimData
ld a,b
ld [wPokeBallAnimData],a
.skipShakeCalculations
ld c,20
call DelayFrames
; Do the animation.
ld a,TOSS_ANIM
ld [wAnimationID],a
xor a
ld [H_WHOSETURN],a
ld [wAnimationType],a
ld [wDamageMultipliers],a
ld a,[wWhichPokemon]
push af
ld a,[wcf91]
push af
predef MoveAnimation
pop af
ld [wcf91],a
pop af
ld [wWhichPokemon],a
; Determine the message to display from the animation.
ld a,[wPokeBallAnimData]
cp a,$10
ld hl,ItemUseBallText00
jp z,.printMessage
cp a,$20
ld hl,ItemUseBallText01
jp z,.printMessage
cp a,$61
ld hl,ItemUseBallText02
jp z,.printMessage
cp a,$62
ld hl,ItemUseBallText03
jp z,.printMessage
cp a,$63
ld hl,ItemUseBallText04
jp z,.printMessage
; Save current HP.
ld hl,wEnemyMonHP
ld a,[hli]
push af
ld a,[hli]
push af
; Save status ailment.
inc hl
ld a,[hl]
push af
push hl
; If the Pokémon is transformed, the Pokémon is assumed to be a Ditto.
; This is a bug because a wild Pokémon could have used Transform via
; Mirror Move even though the only wild Pokémon that knows Transform is Ditto.
ld hl,wEnemyBattleStatus3
bit Transformed,[hl]
jr z,.notTransformed
ld a,DITTO
ld [wEnemyMonSpecies2],a
jr .skip6
.notTransformed
; If the Pokémon is not transformed, set the transformed bit and copy the
; DVs to wTransformedEnemyMonOriginalDVs so that LoadEnemyMonData won't generate
; new DVs.
set Transformed,[hl]
ld hl,wTransformedEnemyMonOriginalDVs
ld a,[wEnemyMonDVs]
ld [hli],a
ld a,[wEnemyMonDVs + 1]
ld [hl],a
.skip6
ld a,[wcf91]
push af
ld a,[wEnemyMonSpecies2]
ld [wcf91],a
ld a,[wEnemyMonLevel]
ld [wCurEnemyLVL],a
callab LoadEnemyMonData
pop af
ld [wcf91],a
pop hl
pop af
ld [hld],a
dec hl
pop af
ld [hld],a
pop af
ld [hl],a
ld a,[wEnemyMonSpecies]
ld [wCapturedMonSpecies],a
ld [wcf91],a
ld [wd11e],a
ld a,[wBattleType]
dec a ; is this the old man battle?
jr z,.oldManCaughtMon ; if so, don't give the player the caught Pokémon
ld hl,ItemUseBallText05
call PrintText
; Add the caught Pokémon to the Pokédex.
predef IndexToPokedex
ld a,[wd11e]
dec a
ld c,a
ld b,FLAG_TEST
ld hl,wPokedexOwned
predef FlagActionPredef
ld a,c
push af
ld a,[wd11e]
dec a
ld c,a
ld b,FLAG_SET
predef FlagActionPredef
pop af
and a ; was the Pokémon already in the Pokédex?
jr nz,.skipShowingPokedexData ; if so, don't show the Pokédex data
ld hl,ItemUseBallText06
call PrintText
call ClearSprites
ld a,[wEnemyMonSpecies]
ld [wd11e],a
predef ShowPokedexData
.skipShowingPokedexData
ld a,[wPartyCount]
cp a,PARTY_LENGTH ; is party full?
jr z,.sendToBox
xor a ; PLAYER_PARTY_DATA
ld [wMonDataLocation],a
call ClearSprites
call AddPartyMon
jr .done
.sendToBox
call ClearSprites
call SendNewMonToBox
ld hl,ItemUseBallText07
CheckEvent EVENT_MET_BILL
jr nz,.printTransferredToPCText
ld hl,ItemUseBallText08
.printTransferredToPCText
call PrintText
jr .done
.oldManCaughtMon
ld hl,ItemUseBallText05
.printMessage
call PrintText
call ClearSprites
.done
ld a,[wBattleType]
and a ; is this the old man battle?
ret nz ; if so, don't remove a ball from the bag
; Remove a ball from the bag.
ld hl,wNumBagItems
inc a
ld [wItemQuantity],a
jp RemoveItemFromInventory
ItemUseBallText00:
;"It dodged the thrown ball!"
;"This pokemon can't be caught"
TX_FAR _ItemUseBallText00
db "@"
ItemUseBallText01:
;"You missed the pokemon!"
TX_FAR _ItemUseBallText01
db "@"
ItemUseBallText02:
;"Darn! The pokemon broke free!"
TX_FAR _ItemUseBallText02
db "@"
ItemUseBallText03:
;"Aww! It appeared to be caught!"
TX_FAR _ItemUseBallText03
db "@"
ItemUseBallText04:
;"Shoot! It was so close too!"
TX_FAR _ItemUseBallText04
db "@"
ItemUseBallText05:
;"All right! {MonName} was caught!"
;play sound
TX_FAR _ItemUseBallText05
TX_SFX_CAUGHT_MON
TX_BLINK
db "@"
ItemUseBallText07:
;"X was transferred to Bill's PC"
TX_FAR _ItemUseBallText07
db "@"
ItemUseBallText08:
;"X was transferred to someone's PC"
TX_FAR _ItemUseBallText08
db "@"
ItemUseBallText06:
;"New DEX data will be added..."
;play sound
TX_FAR _ItemUseBallText06
TX_SFX_DEX_PAGE_ADDED
TX_BLINK
db "@"
ItemUseTownMap:
ld a,[wIsInBattle]
and a
jp nz,ItemUseNotTime
jpba DisplayTownMap
ItemUseBicycle:
ld a,[wIsInBattle]
and a
jp nz,ItemUseNotTime
ld a,[wWalkBikeSurfState]
ld [wWalkBikeSurfStateCopy],a
cp 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:
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 [hSpriteIndexOrTextID],a
ld d,16 ; talking range in pixels (normal range)
call IsSpriteInFrontOfPlayer2
res 7,[hl]
ld a,[hSpriteIndexOrTextID]
and a ; is there a sprite in the way?
jr nz,.cannotStopSurfing
ld hl,TilePairCollisionsWater
call CheckForTilePairCollisions
jr c,.cannotStopSurfing
ld hl,wTilesetCollisionPtr ; pointer to list of passable tiles
ld a,[hli]
ld h,[hl]
ld l,a ; hl now points to passable tiles
ld a,[wTileInFrontOfPlayer] ; tile in front of the player
ld b,a
.passableTileLoop
ld a,[hli]
cp b
jr z,.stopSurfing
cp 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,[wPlayerDirection] ; direction the player is going
bit PLAYER_DIR_BIT_UP,a
ld b,D_UP
jr nz,.storeSimulatedButtonPress
bit PLAYER_DIR_BIT_DOWN,a
ld b,D_DOWN
jr nz,.storeSimulatedButtonPress
bit PLAYER_DIR_BIT_LEFT,a
ld b,D_LEFT
jr nz,.storeSimulatedButtonPress
ld b,D_RIGHT
.storeSimulatedButtonPress
ld a,b
ld [wSimulatedJoypadStatesEnd],a
xor a
ld [wWastedByteCD39],a
inc a
ld [wSimulatedJoypadStatesIndex],a
ret
SurfingGotOnText:
TX_FAR _SurfingGotOnText
db "@"
SurfingNoPlaceToGetOffText:
TX_FAR _SurfingNoPlaceToGetOffText
db "@"
ItemUsePokedex:
predef_jump ShowPokedexMenu
ItemUseEvoStone:
ld a,[wIsInBattle]
and a
jp nz,ItemUseNotTime
ld a,[wWhichPokemon]
push af
ld a,[wcf91]
ld [wEvoStoneItemID],a
push af
ld a,EVO_STONE_PARTY_MENU
ld [wPartyMenuTypeOrMessageID],a
ld a,$ff
ld [wUpdateSpritesEnabled],a
call DisplayPartyMenu
pop bc
jr c,.canceledItemUse
ld a,b
ld [wcf91],a
ld a,$01
ld [wForceEvolution],a
ld a,SFX_HEAL_AILMENT
call PlaySoundWaitForCurrent
call WaitForSoundToFinish
callab TryEvolvingMon ; try to evolve pokemon
ld a,[wEvolutionOccurred]
and a
jr z,.noEffect
pop af
ld [wWhichPokemon],a
ld hl,wNumBagItems
ld a,1 ; remove 1 stone
ld [wItemQuantity],a
jp RemoveItemFromInventory
.noEffect
call ItemUseNoEffect
.canceledItemUse
xor a
ld [wActionResultOrTookBattleTurn],a ; item not used
pop af
ret
ItemUseVitamin:
ld a,[wIsInBattle]
and a
jp nz,ItemUseNotTime
ItemUseMedicine:
ld a,[wPartyCount]
and a
jp z,.emptyParty
ld a,[wWhichPokemon]
push af
ld a,[wcf91]
push af
ld a,USE_ITEM_PARTY_MENU
ld [wPartyMenuTypeOrMessageID],a
ld a,$ff
ld [wUpdateSpritesEnabled],a
ld a,[wPseudoItemID]
and a ; using Softboiled?
jr z,.notUsingSoftboiled
; if using softboiled
call GoBackToPartyMenu
jr .getPartyMonDataAddress
.emptyParty
ld hl,.emptyPartyText
xor a
ld [wActionResultOrTookBattleTurn],a ; item use failed
jp PrintText
.emptyPartyText
text "You don't have"
line "any #MON!"
prompt
.notUsingSoftboiled
call DisplayPartyMenu
.getPartyMonDataAddress
jp c,.canceledItemUse
ld hl,wPartyMons
ld bc,wPartyMon2 - wPartyMon1
ld a,[wWhichPokemon]
call AddNTimes
ld a,[wWhichPokemon]
ld [wUsedItemOnWhichPokemon],a
ld d,a
ld a,[wcf91]
ld e,a
ld [wd0b5],a
pop af
ld [wcf91],a
pop af
ld [wWhichPokemon],a
ld a,[wPseudoItemID]
and a ; using Softboiled?
jr z,.checkItemType
; if using softboiled
ld a,[wWhichPokemon]
cp d ; is the pokemon trying to use softboiled on itself?
jr z,ItemUseMedicine ; if so, force another choice
.checkItemType
ld a,[wcf91]
cp 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,wPartyMon1Status - wPartyMon1
add hl,bc ; hl now points to status
ld a,[wcf91]
lb bc, ANTIDOTE_MSG, 1 << PSN
cp a,ANTIDOTE
jr z,.checkMonStatus
lb bc, BURN_HEAL_MSG, 1 << BRN
cp a,BURN_HEAL
jr z,.checkMonStatus
lb bc, ICE_HEAL_MSG, 1 << FRZ
cp a,ICE_HEAL
jr z,.checkMonStatus
lb bc, AWAKENING_MSG, SLP
cp a,AWAKENING
jr z,.checkMonStatus
lb bc, PARALYZ_HEAL_MSG, 1 << PAR
cp a,PARLYZ_HEAL
jr z,.checkMonStatus
lb bc, FULL_HEAL_MSG, $ff ; Full Heal
.checkMonStatus
ld a,[hl] ; pokemon's status
and c ; does the pokemon have a status ailment the item can cure?
jp z,.healingItemNoEffect
; if the pokemon has a status the item can heal
xor a
ld [hl],a ; remove the status ailment in the party data
ld a,b
ld [wPartyMenuTypeOrMessageID],a ; the message to display for the item used
ld a,[wPlayerMonNumber]
cp d ; is pokemon the item was used on active in battle?
jp nz,.doneHealing
; if it is active in battle
xor a
ld [wBattleMonStatus],a ; remove the status ailment in the in-battle pokemon data
push hl
ld hl,wPlayerBattleStatus3
res BadlyPoisoned,[hl] ; heal Toxic status
pop hl
ld bc,wPartyMon1Stats - wPartyMon1Status
add hl,bc ; hl now points to party stats
ld de,wBattleMonStats
ld bc,NUM_STATS * 2
call CopyData ; copy party stats to in-battle stat data
predef DoubleOrHalveSelectedStats
jp .doneHealing
.healHP
inc hl ; hl = address of current HP
ld a,[hli]
ld b,a
ld [wHPBarOldHP+1],a
ld a,[hl]
ld c,a
ld [wHPBarOldHP],a ; current HP stored at wHPBarOldHP (2 bytes, big-endian)
or b
jr nz,.notFainted
.fainted
ld a,[wcf91]
cp a,REVIVE
jr z,.updateInBattleFaintedData
cp a,MAX_REVIVE
jr z,.updateInBattleFaintedData
jp .healingItemNoEffect
.updateInBattleFaintedData
ld a,[wIsInBattle]
and a
jr z,.compareCurrentHPToMaxHP
push hl
push de
push bc
ld a,[wUsedItemOnWhichPokemon]
ld c,a
ld hl,wPartyFoughtCurrentEnemyFlags
ld b,FLAG_TEST
predef FlagActionPredef
ld a,c
and a
jr z,.next
ld a,[wUsedItemOnWhichPokemon]
ld c,a
ld hl,wPartyGainExpFlags
ld b,FLAG_SET
predef FlagActionPredef
.next
pop bc
pop de
pop hl
jr .compareCurrentHPToMaxHP
.notFainted
ld a,[wcf91]
cp a,REVIVE
jp z,.healingItemNoEffect
cp a,MAX_REVIVE
jp z,.healingItemNoEffect
.compareCurrentHPToMaxHP
push hl
push bc
ld bc,wPartyMon1MaxHP - (wPartyMon1HP + 1)
add hl,bc ; hl now points to max HP
pop bc
ld a,[hli]
cp b
jr nz,.skipComparingLSB ; no need to compare the LSB's if the MSB's don't match
ld a,[hl]
cp c
.skipComparingLSB
pop hl
jr nz,.notFullHP
.fullHP ; if the pokemon's current HP equals its max HP
ld a,[wcf91]
cp 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 [wChannelSoundIDs + Ch4],a
push hl
push de
ld bc,wPartyMon1MaxHP - (wPartyMon1HP + 1)
add hl,bc ; hl now points to max HP
ld a,[hli]
ld [wHPBarMaxHP+1],a
ld a,[hl]
ld [wHPBarMaxHP],a ; max HP stored at wHPBarMaxHP (2 bytes, big-endian)
ld a,[wPseudoItemID]
and a ; using Softboiled?
jp z,.notUsingSoftboiled2
; if using softboiled
ld hl,wHPBarMaxHP
ld a,[hli]
push af
ld a,[hli]
push af
ld a,[hli]
push af
ld a,[hl]
push af
ld hl,wPartyMon1MaxHP
ld a,[wWhichPokemon]
ld bc,wPartyMon2 - wPartyMon1
call AddNTimes
ld a,[hli]
ld [wHPBarMaxHP + 1],a
ld [H_DIVIDEND],a
ld a,[hl]
ld [wHPBarMaxHP],a
ld [H_DIVIDEND + 1],a
ld a,5
ld [H_DIVISOR],a
ld b,2 ; number of bytes
call Divide ; get 1/5 of max HP of pokemon that used Softboiled
ld bc,(wPartyMon1HP + 1) - (wPartyMon1MaxHP + 1)
add hl,bc ; hl now points to LSB of current HP of pokemon that used Softboiled
; subtract 1/5 of max HP from current HP of pokemon that used Softboiled
ld a,[H_QUOTIENT + 3]
push af
ld b,a
ld a,[hl]
ld [wHPBarOldHP],a
sub b
ld [hld],a
ld [wHPBarNewHP],a
ld a,[H_QUOTIENT + 2]
ld b,a
ld a,[hl]
ld [wHPBarOldHP+1],a
sbc b
ld [hl],a
ld [wHPBarNewHP+1],a
coord hl, 4, 1
ld a,[wWhichPokemon]
ld bc,2 * SCREEN_WIDTH
call AddNTimes ; calculate coordinates of HP bar of pokemon that used Softboiled
ld a,SFX_HEAL_HP
call PlaySoundWaitForCurrent
ld a,[hFlags_0xFFF6]
set 0,a
ld [hFlags_0xFFF6],a
ld a,$02
ld [wHPBarType],a
predef UpdateHPBar2 ; animate HP bar decrease of pokemon that used Softboiled
ld a,[hFlags_0xFFF6]
res 0,a
ld [hFlags_0xFFF6],a
pop af
ld b,a ; store heal amount (1/5 of max HP)
ld hl,wHPBarOldHP + 1
pop af
ld [hld],a
pop af
ld [hld],a
pop af
ld [hld],a
pop af
ld [hl],a
jr .addHealAmount
.notUsingSoftboiled2
ld a,[wcf91]
cp 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,(wPartyMon1MaxHP + 1) - (wPartyMon1HP + 1)
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,wPartyMon1Status - (wPartyMon1MaxHP + 1)
add hl,bc
xor a
ld [hl],a ; remove the status ailment in the party data
.updateInBattleData
ld h,d
ld l,e
pop de
ld a,[wPlayerMonNumber]
cp d ; is pokemon the item was used on active in battle?
jr nz,.calculateHPBarCoords
; copy party HP to in-battle HP
ld a,[hli]
ld [wBattleMonHP],a
ld a,[hld]
ld [wBattleMonHP + 1],a
ld a,[wcf91]
cp 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 * SCREEN_WIDTH
inc d
.calculateHPBarCoordsLoop
add hl,bc
dec d
jr nz,.calculateHPBarCoordsLoop
jr .doneHealing
.healingItemNoEffect
call ItemUseNoEffect
jp .done
.doneHealing
ld a,[wPseudoItemID]
and a ; using Softboiled?
jr nz,.skipRemovingItem ; no item to remove if using Softboiled
push hl
call RemoveUsedItem
pop hl
.skipRemovingItem
ld a,[wcf91]
cp a,FULL_RESTORE
jr c,.playStatusAilmentCuringSound
cp a,FULL_HEAL
jr z,.playStatusAilmentCuringSound
ld a,SFX_HEAL_HP
call PlaySoundWaitForCurrent
ld a,[hFlags_0xFFF6]
set 0,a
ld [hFlags_0xFFF6],a
ld a,$02
ld [wHPBarType],a
predef UpdateHPBar2 ; animate the HP bar lengthening
ld a,[hFlags_0xFFF6]
res 0,a
ld [hFlags_0xFFF6],a
ld a,REVIVE_MSG
ld [wPartyMenuTypeOrMessageID],a
ld a,[wcf91]
cp a,REVIVE
jr z,.showHealingItemMessage
cp a,MAX_REVIVE
jr z,.showHealingItemMessage
ld a,POTION_MSG
ld [wPartyMenuTypeOrMessageID],a
jr .showHealingItemMessage
.playStatusAilmentCuringSound
ld a,SFX_HEAL_AILMENT
call PlaySoundWaitForCurrent
.showHealingItemMessage
xor a
ld [H_AUTOBGTRANSFERENABLED],a
call ClearScreen
dec a
ld [wUpdateSpritesEnabled],a
call RedrawPartyMenu ; redraws the party menu and displays the message
ld a,1
ld [H_AUTOBGTRANSFERENABLED],a
ld c,50
call DelayFrames
call WaitForTextScrollButtonPress
jr .done
.canceledItemUse
xor a
ld [wActionResultOrTookBattleTurn],a ; item use failed
pop af
pop af
.done
ld a,[wPseudoItemID]
and a ; using Softboiled?
ret nz ; if so, return
call GBPalWhiteOut
call z,RunDefaultPaletteCommand
ld a,[wIsInBattle]
and a
ret nz
jp ReloadMapData
.useVitamin
push hl
ld a,[hl]
ld [wd0b5],a
ld [wd11e],a
ld bc,wPartyMon1Level - wPartyMon1
add hl,bc ; hl now points to level
ld a,[hl] ; a = level
ld [wCurEnemyLVL],a ; store level
call GetMonHeader
push de
ld a,d
ld hl,wPartyMonNicks
call GetPartyMonName
pop de
pop hl
ld a,[wcf91]
cp a,RARE_CANDY
jp z,.useRareCandy
push hl
sub a,HP_UP
add a
ld bc,wPartyMon1HPExp - wPartyMon1
add hl,bc
add l
ld l,a
jr nc,.noCarry2
inc h
.noCarry2
ld a,10
ld b,a
ld a,[hl] ; a = MSB of stat experience of the appropriate stat
cp 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_HEAL_AILMENT
call PlaySound
ld hl,VitaminStatRoseText
call PrintText
jp RemoveUsedItem
.vitaminNoEffect
pop hl
ld hl,VitaminNoEffectText
call PrintText
jp GBPalWhiteOut
.recalculateStats
ld bc,wPartyMon1Stats - wPartyMon1
add hl,bc
ld d,h
ld e,l ; de now points to stats
ld bc,(wPartyMon1Exp + 2) - wPartyMon1Stats
add hl,bc ; hl now points to LSB of experience
ld b,1
jp CalcStats ; recalculate stats
.useRareCandy
push hl
ld bc,wPartyMon1Level - wPartyMon1
add hl,bc ; hl now points to level
ld a,[hl] ; a = level
cp a, MAX_LEVEL
jr z,.vitaminNoEffect ; can't raise level above 100
inc a
ld [hl],a ; store incremented level
ld [wCurEnemyLVL],a
push hl
push de
ld d,a
callab CalcExperience ; calculate experience for next level and store it at $ff96
pop de
pop hl
ld bc,wPartyMon1Exp - wPartyMon1Level
add hl,bc ; hl now points to MSB of experience
; update experience to minimum for new level
ld a,[hExperience]
ld [hli],a
ld a,[hExperience + 1]
ld [hli],a
ld a,[hExperience + 2]
ld [hl],a
pop hl
ld a,[wWhichPokemon]
push af
ld a,[wcf91]
push af
push de
push hl
ld bc,wPartyMon1MaxHP - wPartyMon1
add hl,bc ; hl now points to MSB of max HP
ld a,[hli]
ld b,a
ld c,[hl]
pop hl
push bc
push hl
call .recalculateStats
pop hl
ld bc,(wPartyMon1MaxHP + 1) - wPartyMon1
add hl,bc ; hl now points to LSB of max HP
pop bc
ld a,[hld]
sub c
ld c,a
ld a,[hl]
sbc b
ld b,a ; bc = the amount of max HP gained from leveling up
; add the amount gained to the current HP
ld de,(wPartyMon1HP + 1) - wPartyMon1MaxHP
add hl,de ; hl now points to LSB of current HP
ld a,[hl]
add c
ld [hld],a
ld a,[hl]
adc b
ld [hl],a
ld a,RARE_CANDY_MSG
ld [wPartyMenuTypeOrMessageID],a
call RedrawPartyMenu
pop de
ld a,d
ld [wWhichPokemon],a
ld a,e
ld [wd11e],a
xor a ; PLAYER_PARTY_DATA
ld [wMonDataLocation],a
call LoadMonData
ld d,$01
callab PrintStatsBox ; display new stats text box
call WaitForTextScrollButtonPress ; wait for button press
xor a ; PLAYER_PARTY_DATA
ld [wMonDataLocation],a
predef LearnMoveFromLevelUp ; learn level up move, if any
xor a
ld [wForceEvolution],a
callab TryEvolvingMon ; evolve pokemon, if appropriate
ld a,$01
ld [wUpdateSpritesEnabled],a
pop af
ld [wcf91],a
pop af
ld [wWhichPokemon],a
jp RemoveUsedItem
VitaminStatRoseText:
TX_FAR _VitaminStatRoseText
db "@"
VitaminNoEffectText:
TX_FAR _VitaminNoEffectText
db "@"
VitaminText:
db "HEALTH@"
db "ATTACK@"
db "DEFENSE@"
db "SPEED@"
db "SPECIAL@"
ItemUseBait:
ld hl,ThrewBaitText
call PrintText
ld hl,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:
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:
ld [wAnimationID],a
xor a
ld [wAnimationType],a
ld [H_WHOSETURN],a
ld [de],a ; zero escape factor (for bait), zero bait factor (for rock)
.randomLoop ; loop until a random number less than 5 is generated
call Random
and 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:
TX_FAR _ThrewBaitText
db "@"
ThrewRockText:
TX_FAR _ThrewRockText
db "@"
; also used for Dig out-of-battle effect
ItemUseEscapeRope:
ld a,[wIsInBattle]
and a
jr nz,.notUsable
ld a,[wCurMap]
cp a,AGATHAS_ROOM
jr z,.notUsable
ld a,[wCurMapTileset]
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]
ResetEvent EVENT_IN_SAFARI_ZONE
xor a
ld [wNumSafariBalls],a
ld [wSafariZoneEntranceCurScript],a
inc a
ld [wEscapedFromBattle],a
ld [wActionResultOrTookBattleTurn],a ; item used
ld a,[wPseudoItemID]
and a ; using Dig?
ret nz ; if so, return
call ItemUseReloadOverworldData
ld c,30
call DelayFrames
jp RemoveUsedItem
.notUsable
jp ItemUseNotTime
EscapeRopeTilesets:
db FOREST, CEMETERY, CAVERN, FACILITY, INTERIOR
db $ff ; terminator
ItemUseRepel:
ld b,100
ItemUseRepelCommon:
ld a,[wIsInBattle]
and a
jp nz,ItemUseNotTime
ld a,b
ld [wRepelRemainingSteps],a
jp PrintItemUseTextAndRemoveItem
; handles X Accuracy item
ItemUseXAccuracy:
ld a,[wIsInBattle]
and a
jp z,ItemUseNotTime
ld hl,wPlayerBattleStatus2
set 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:
xor a
ld [wUnusedD71F],a
call GetTileAndCoordsInFrontOfPlayer
ld a,[GetTileAndCoordsInFrontOfPlayer]
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,[wCurMap]
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 [wUnusedD71F],a
jr .done
.nextEntry1
inc hl
.nextEntry2
inc hl
.nextEntry3
inc hl
jr .loop
.done
ld hl,ItemUseText00
call PrintText
ld hl,wd728
set 7,[hl]
ret
; These tables are probably supposed to be door locations in Silph Co.,
; but they are unused.
; The reason there are 3 tables is unknown.
; Format:
; 00: Map ID
; 01: Y
; 02: X
; 03: ID?
CardKeyTable1:
db SILPH_CO_2F,$04,$04,$00
db SILPH_CO_2F,$04,$05,$01
db SILPH_CO_4F,$0C,$04,$02
db SILPH_CO_4F,$0C,$05,$03
db SILPH_CO_7F,$06,$0A,$04
db SILPH_CO_7F,$06,$0B,$05
db SILPH_CO_9F,$04,$12,$06
db SILPH_CO_9F,$04,$13,$07
db SILPH_CO_10F,$08,$0A,$08
db SILPH_CO_10F,$08,$0B,$09
db $ff
CardKeyTable2:
db SILPH_CO_3F,$08,$09,$0A
db SILPH_CO_3F,$09,$09,$0B
db SILPH_CO_5F,$04,$07,$0C
db SILPH_CO_5F,$05,$07,$0D
db SILPH_CO_6F,$0C,$05,$0E
db SILPH_CO_6F,$0D,$05,$0F
db SILPH_CO_8F,$08,$07,$10
db SILPH_CO_8F,$09,$07,$11
db SILPH_CO_9F,$08,$03,$12
db SILPH_CO_9F,$09,$03,$13
db $ff
CardKeyTable3:
db SILPH_CO_11F,$08,$09,$14
db SILPH_CO_11F,$09,$09,$15
db $ff
ItemUsePokedoll:
ld a,[wIsInBattle]
dec a
jp nz,ItemUseNotTime
ld a,$01
ld [wEscapedFromBattle],a
jp PrintItemUseTextAndRemoveItem
ItemUseGuardSpec:
ld a,[wIsInBattle]
and a
jp z,ItemUseNotTime
ld hl,wPlayerBattleStatus2
set ProtectedByMist,[hl] ; Mist bit
jp PrintItemUseTextAndRemoveItem
ItemUseSuperRepel:
ld b,200
jp ItemUseRepelCommon
ItemUseMaxRepel:
ld b,250
jp ItemUseRepelCommon
ItemUseDireHit:
ld a,[wIsInBattle]
and a
jp z,ItemUseNotTime
ld hl,wPlayerBattleStatus2
set GettingPumped,[hl] ; Focus Energy bit
jp PrintItemUseTextAndRemoveItem
ItemUseXStat:
ld a,[wIsInBattle]
and a
jr nz,.inBattle
call ItemUseNotTime
ld a,2
ld [wActionResultOrTookBattleTurn],a ; item not used
ret
.inBattle
ld hl,wPlayerMoveNum
ld a,[hli]
push af ; save [wPlayerMoveNum]
ld a,[hl]
push af ; save [wPlayerMoveEffect]
push hl
ld a,[wcf91]
sub 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 [wPlayerMoveNum],a
call LoadScreenTilesFromBuffer1 ; restore saved screen
call Delay3
xor a
ld [H_WHOSETURN],a ; set turn to player's turn
callba StatModifierUpEffect ; do stat increase move
pop hl
pop af
ld [hld],a ; restore [wPlayerMoveEffect]
pop af
ld [hl],a ; restore [wPlayerMoveNum]
ret
ItemUsePokeflute:
ld a,[wIsInBattle]
and a
jr nz,.inBattle
; if not in battle
call ItemUseReloadOverworldData
ld a,[wCurMap]
cp a,ROUTE_12
jr nz,.notRoute12
CheckEvent EVENT_BEAT_ROUTE12_SNORLAX
jr nz,.noSnorlaxToWakeUp
; if the player hasn't beaten Route 12 Snorlax
ld hl,Route12SnorlaxFluteCoords
call ArePlayerCoordsInArray
jr nc,.noSnorlaxToWakeUp
ld hl,PlayedFluteHadEffectText
call PrintText
SetEvent EVENT_FIGHT_ROUTE12_SNORLAX
ret
.notRoute12
cp a,ROUTE_16
jr nz,.noSnorlaxToWakeUp
CheckEvent EVENT_BEAT_ROUTE16_SNORLAX
jr nz,.noSnorlaxToWakeUp
; if the player hasn't beaten Route 16 Snorlax
ld hl,Route16SnorlaxFluteCoords
call ArePlayerCoordsInArray
jr nc,.noSnorlaxToWakeUp
ld hl,PlayedFluteHadEffectText
call PrintText
SetEvent EVENT_FIGHT_ROUTE16_SNORLAX
ret
.noSnorlaxToWakeUp
ld hl,PlayedFluteNoEffectText
jp PrintText
.inBattle
xor a
ld [wWereAnyMonsAsleep],a
ld b,~SLP & $ff
ld hl,wPartyMon1Status
call WakeUpEntireParty
ld a,[wIsInBattle]
dec a ; is it a trainer battle?
jr z,.skipWakingUpEnemyParty
; if it's a trainer battle
ld hl,wEnemyMon1Status
call WakeUpEntireParty
.skipWakingUpEnemyParty
ld hl,wBattleMonStatus
ld a,[hl]
and b ; remove Sleep status
ld [hl],a
ld hl,wEnemyMonStatus
ld a,[hl]
and b ; remove Sleep status
ld [hl],a
call LoadScreenTilesFromBuffer2 ; restore saved screen
ld a,[wWereAnyMonsAsleep]
and a ; were any pokemon asleep before playing the flute?
ld hl,PlayedFluteNoEffectText
jp z,PrintText ; if no pokemon were asleep
; if some pokemon were asleep
ld hl,PlayedFluteHadEffectText
call PrintText
ld a,[wLowHealthAlarm]
and 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,[wChannelSoundIDs + Ch6]
and a ; music off?
jr nz,.musicWaitLoop
.skipMusic
ld hl,FluteWokeUpText
jp PrintText
; wakes up all party pokemon
; INPUT:
; hl must point to status of first pokemon in party (player's or enemy's)
; b must equal ~SLP
; [wWereAnyMonsAsleep] should be initialized to 0
; OUTPUT:
; [wWereAnyMonsAsleep]: set to 1 if any pokemon were asleep
WakeUpEntireParty:
ld de,44
ld c,6
.loop
ld a,[hl]
push af
and a,SLP ; is pokemon asleep?
jr z,.notAsleep
ld a,1
ld [wWereAnyMonsAsleep],a ; indicate that a pokemon had to be woken up
.notAsleep
pop af
and b ; remove Sleep status
ld [hl],a
add hl,de
dec c
jr nz,.loop
ret
; Format:
; 00: Y
; 01: X
Route12SnorlaxFluteCoords:
db 62,9 ; one space West of Snorlax
db 61,10 ; one space North of Snorlax
db 63,10 ; one space South of Snorlax
db 62,11 ; one space East of Snorlax
db $ff ; terminator
; Format:
; 00: Y
; 01: X
Route16SnorlaxFluteCoords:
db 10,27 ; one space East of Snorlax
db 10,25 ; one space West of Snorlax
db $ff ; terminator
PlayedFluteNoEffectText:
TX_FAR _PlayedFluteNoEffectText
db "@"
FluteWokeUpText:
TX_FAR _FluteWokeUpText
db "@"
PlayedFluteHadEffectText:
TX_FAR _PlayedFluteHadEffectText
TX_BLINK
TX_ASM
ld a,[wIsInBattle]
and a
jr nz,.done
; play out-of-battle pokeflute music
ld a,$ff
call PlaySound ; turn off music
ld a, SFX_POKEFLUTE
ld c, BANK(SFX_Pokeflute)
call PlayMusic
.musicWaitLoop ; wait for music to finish playing
ld a,[wChannelSoundIDs + Ch2]
cp a, SFX_POKEFLUTE
jr z,.musicWaitLoop
call PlayDefaultMusic ; start playing normal music again
.done
jp TextScriptEnd ; end text
ItemUseCoinCase:
ld a,[wIsInBattle]
and a
jp nz,ItemUseNotTime
ld hl,CoinCaseNumCoinsText
jp PrintText
CoinCaseNumCoinsText:
TX_FAR _CoinCaseNumCoinsText
db "@"
ItemUseOldRod:
call FishingInit
jp c, ItemUseNotTime
lb bc, 5, MAGIKARP
ld a, $1 ; set bite
jr RodResponse
ItemUseGoodRod:
call FishingInit
jp c,ItemUseNotTime
.RandomLoop
call Random
srl a
jr c, .SetBite
and %11
cp 2
jr nc, .RandomLoop
; choose which monster appears
ld hl,GoodRodMons
add a,a
ld c,a
ld b,0
add hl,bc
ld b,[hl]
inc hl
ld c,[hl]
and a
.SetBite
ld a,0
rla
xor 1
jr RodResponse
INCLUDE "data/good_rod.asm"
ItemUseSuperRod:
call FishingInit
jp c, ItemUseNotTime
call ReadSuperRodData
ld a, e
RodResponse:
ld [wRodResponse], a
dec a ; is there a bite?
jr nz, .next
; if yes, store level and species data
ld a, 1
ld [wMoveMissed], a
ld a, b ; level
ld [wCurEnemyLVL], a
ld a, c ; species
ld [wCurOpponent], a
.next
ld hl, wWalkBikeSurfState
ld a, [hl] ; store the value in a
push af
push hl
ld [hl], 0
callba FishingAnim
pop hl
pop af
ld [hl], a
ret
; checks if fishing is possible and if so, runs initialization code common to all rods
; unsets carry if fishing is possible, sets carry if not
FishingInit:
ld a,[wIsInBattle]
and a
jr z,.notInBattle
scf ; can't fish during battle
ret
.notInBattle
call IsNextTileShoreOrWater
ret c
ld a,[wWalkBikeSurfState]
cp a,2 ; Surfing?
jr z,.surfing
call ItemUseReloadOverworldData
ld hl,ItemUseText00
call PrintText
ld a,SFX_HEAL_AILMENT
call PlaySound
ld c,80
call DelayFrames
and a
ret
.surfing
scf ; can't fish when surfing
ret
ItemUseOaksParcel:
jp ItemUseNotYoursToUse
ItemUseItemfinder:
ld a,[wIsInBattle]
and a
jp nz,ItemUseNotTime
call ItemUseReloadOverworldData
callba HiddenItemNear ; check for hidden items
ld hl,ItemfinderFoundNothingText
jr nc,.printText ; if no hidden items
ld c,4
.loop
ld a,SFX_HEALING_MACHINE
call PlaySoundWaitForCurrent
ld a,SFX_PURCHASE
call PlaySoundWaitForCurrent
dec c
jr nz,.loop
ld hl,ItemfinderFoundItemText
.printText
jp PrintText
ItemfinderFoundItemText:
TX_FAR _ItemfinderFoundItemText
db "@"
ItemfinderFoundNothingText:
TX_FAR _ItemfinderFoundNothingText
db "@"
ItemUsePPUp:
ld a,[wIsInBattle]
and a
jp nz,ItemUseNotTime
ItemUsePPRestore:
ld a,[wWhichPokemon]
push af
ld a,[wcf91]
ld [wPPRestoreItem],a
.chooseMon
xor a
ld [wUpdateSpritesEnabled],a
ld a,USE_ITEM_PARTY_MENU
ld [wPartyMenuTypeOrMessageID],a
call DisplayPartyMenu
jr nc,.chooseMove
jp .itemNotUsed
.chooseMove
ld a,[wPPRestoreItem]
cp a,ELIXER
jp nc,.useElixir ; if Elixir or Max Elixir
ld a,$02
ld [wMoveMenuType],a
ld hl,RaisePPWhichTechniqueText
ld a,[wPPRestoreItem]
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, wPartyMon2 - wPartyMon1
call GetSelectedMoveOffset
push hl
ld a,[hl]
ld [wd11e],a
call GetMoveName
call CopyStringToCF4B ; copy name to wcf4b
pop hl
ld a,[wPPRestoreItem]
cp a,ETHER
jr nc,.useEther ; if Ether or Max Ether
.usePPUp
ld bc,wPartyMon1PP - wPartyMon1Moves
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 RunDefaultPaletteCommand
jp RemoveUsedItem
.afterRestoringPP ; after using a (Max) Ether/Elixir
ld a,[wWhichPokemon]
ld b,a
ld a,[wPlayerMonNumber]
cp b ; is the pokemon whose PP was restored active in battle?
jr nz,.skipUpdatingInBattleData
ld hl,wPartyMon1PP
ld bc, wPartyMon2 - wPartyMon1
call AddNTimes
ld de,wBattleMonPP
ld bc,4
call CopyData ; copy party data to in-battle data
.skipUpdatingInBattleData
ld a,SFX_HEAL_AILMENT
call PlaySound
ld hl,PPRestoredText
call PrintText
jr .done
.useEther
call .restorePP
jr nz,.afterRestoringPP
jp .noEffect
; unsets zero flag if PP was restored, sets zero flag if not
; however, this is bugged for Max Ethers and Max Elixirs (see below)
.restorePP
xor a ; PLAYER_PARTY_DATA
ld [wMonDataLocation],a
call GetMaxPP
ld hl,wPartyMon1Moves
ld bc, wPartyMon2 - wPartyMon1
call GetSelectedMoveOffset
ld bc, wPartyMon1PP - wPartyMon1Moves
add hl,bc ; hl now points to move's PP
ld a,[wMaxPP]
ld b,a
ld a,[wPPRestoreItem]
cp 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,wPPRestoreItem
dec [hl]
dec [hl]
xor a
ld hl,wCurrentMenuItem
ld [hli],a
ld [hl],a ; zero the counter for number of moves that had their PP restored
ld b,4
; loop through each move and restore PP
.elixirLoop
push bc
ld hl,wPartyMon1Moves
ld bc, wPartyMon2 - wPartyMon1
call GetSelectedMoveOffset
ld a,[hl]
and a ; does the current slot have a move?
jr z,.nextMove
call .restorePP
jr z,.nextMove
; if some PP was restored
ld hl,wTileBehindCursor ; counter for number of moves that had their PP restored
inc [hl]
.nextMove
ld hl,wCurrentMenuItem
inc [hl]
pop bc
dec b
jr nz,.elixirLoop
ld a,[wTileBehindCursor]
and a ; did any moves have their PP restored?
jp nz,.afterRestoringPP
.noEffect
call ItemUseNoEffect
.itemNotUsed
call GBPalWhiteOut
call RunDefaultPaletteCommand
pop af
xor a
ld [wActionResultOrTookBattleTurn],a ; item use failed
ret
RaisePPWhichTechniqueText:
TX_FAR _RaisePPWhichTechniqueText
db "@"
RestorePPWhichTechniqueText:
TX_FAR _RestorePPWhichTechniqueText
db "@"
PPMaxedOutText:
TX_FAR _PPMaxedOutText
db "@"
PPIncreasedText:
TX_FAR _PPIncreasedText
db "@"
PPRestoredText:
TX_FAR _PPRestoredText
db "@"
; for items that can't be used from the Item menu
UnusableItem:
jp ItemUseNotTime
ItemUseTMHM:
ld a,[wIsInBattle]
and a
jp nz,ItemUseNotTime
ld a,[wcf91]
sub 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
coord hl, 14, 7
lb bc, 8, 15
ld a,TWO_OPTION_MENU
ld [wTextBoxID],a
call DisplayTextBoxID ; yes/no menu
ld a,[wCurrentMenuItem]
and a
jr z,.useMachine
ld a,2
ld [wActionResultOrTookBattleTurn],a ; item not used
ret
.useMachine
ld a,[wWhichPokemon]
push af
ld a,[wcf91]
push af
.chooseMon
ld hl,wcf4b
ld de,wTempMoveNameBuffer
ld bc,14
call CopyData ; save the move name because DisplayPartyMenu will overwrite it
ld a,$ff
ld [wUpdateSpritesEnabled],a
ld a,TMHM_PARTY_MENU
ld [wPartyMenuTypeOrMessageID],a
call DisplayPartyMenu
push af
ld hl,wTempMoveNameBuffer
ld de,wcf4b
ld bc,14
call CopyData
pop af
jr nc,.checkIfAbleToLearnMove
; if the player canceled teaching the move
pop af
pop af
call GBPalWhiteOutWithDelay3
call ClearSprites
call RunDefaultPaletteCommand
jp LoadScreenTilesFromBuffer1 ; restore saved screen
.checkIfAbleToLearnMove
predef CanLearnTM ; check if the pokemon can learn the move
push bc
ld a,[wWhichPokemon]
ld hl,wPartyMonNicks
call GetPartyMonName
pop bc
ld a,c
and a ; can the pokemon learn the move?
jr nz,.checkIfAlreadyLearnedMove
; if the pokemon can't learn the move
ld a,SFX_DENIED
call PlaySoundWaitForCurrent
ld hl,MonCannotLearnMachineMoveText
call PrintText
jr .chooseMon
.checkIfAlreadyLearnedMove
callab CheckIfMoveIsKnown ; check if the pokemon already knows the move
jr c,.chooseMon
predef LearnMove ; teach move
pop af
ld [wcf91],a
pop af
ld [wWhichPokemon],a
ld a,b
and a
ret z
ld a,[wcf91]
call IsItemHM
ret c
jp RemoveUsedItem
BootedUpTMText:
TX_FAR _BootedUpTMText
db "@"
BootedUpHMText:
TX_FAR _BootedUpHMText
db "@"
TeachMachineMoveText:
TX_FAR _TeachMachineMoveText
db "@"
MonCannotLearnMachineMoveText:
TX_FAR _MonCannotLearnMachineMoveText
db "@"
PrintItemUseTextAndRemoveItem:
ld hl,ItemUseText00
call PrintText
ld a,SFX_HEAL_AILMENT
call PlaySound
call WaitForTextScrollButtonPress ; wait for button press
RemoveUsedItem:
ld hl,wNumBagItems
ld a,1 ; one item
ld [wItemQuantity],a
jp RemoveItemFromInventory
ItemUseNoEffect:
ld hl,ItemUseNoEffectText
jr ItemUseFailed
ItemUseNotTime:
ld hl,ItemUseNotTimeText
jr ItemUseFailed
ItemUseNotYoursToUse:
ld hl,ItemUseNotYoursToUseText
jr ItemUseFailed
ThrowBallAtTrainerMon:
call RunDefaultPaletteCommand
call LoadScreenTilesFromBuffer1 ; restore saved screen
call Delay3
ld a,TOSS_ANIM
ld [wAnimationID],a
predef MoveAnimation ; do animation
ld hl,ThrowBallAtTrainerMonText1
call PrintText
ld hl,ThrowBallAtTrainerMonText2
call PrintText
jr RemoveUsedItem
NoCyclingAllowedHere:
ld hl,NoCyclingAllowedHereText
jr ItemUseFailed
BoxFullCannotThrowBall:
ld hl,BoxFullCannotThrowBallText
jr ItemUseFailed
SurfingAttemptFailed:
ld hl,NoSurfingHereText
ItemUseFailed:
xor a
ld [wActionResultOrTookBattleTurn],a ; item use failed
jp PrintText
ItemUseNotTimeText:
TX_FAR _ItemUseNotTimeText
db "@"
ItemUseNotYoursToUseText:
TX_FAR _ItemUseNotYoursToUseText
db "@"
ItemUseNoEffectText:
TX_FAR _ItemUseNoEffectText
db "@"
ThrowBallAtTrainerMonText1:
TX_FAR _ThrowBallAtTrainerMonText1
db "@"
ThrowBallAtTrainerMonText2:
TX_FAR _ThrowBallAtTrainerMonText2
db "@"
NoCyclingAllowedHereText:
TX_FAR _NoCyclingAllowedHereText
db "@"
NoSurfingHereText:
TX_FAR _NoSurfingHereText
db "@"
BoxFullCannotThrowBallText:
TX_FAR _BoxFullCannotThrowBallText
db "@"
ItemUseText00:
TX_FAR _ItemUseText001
TX_LINE
TX_FAR _ItemUseText002
db "@"
GotOnBicycleText:
TX_FAR _GotOnBicycleText1
TX_LINE
TX_FAR _GotOnBicycleText2
db "@"
GotOffBicycleText:
TX_FAR _GotOffBicycleText1
TX_LINE
TX_FAR _GotOffBicycleText2
db "@"
; restores bonus PP (from PP Ups) when healing at a pokemon center
; also, when a PP Up is used, it increases the current PP by one PP Up bonus
; INPUT:
; [wWhichPokemon] = index of pokemon in party
; [wCurrentMenuItem] = index of move (when using a PP Up)
RestoreBonusPP:
ld hl,wPartyMon1Moves
ld bc, wPartyMon2 - wPartyMon1
ld a,[wWhichPokemon]
call AddNTimes
push hl
ld de,wNormalMaxPPList - 1
predef LoadMovePPs ; loads the normal max PP of each of the pokemon's moves to wNormalMaxPPList
pop hl
ld c, wPartyMon1PP - wPartyMon1Moves
ld b,0
add hl,bc ; hl now points to move 1 PP
ld de,wNormalMaxPPList
ld b,0 ; initialize move counter to zero
; loop through the pokemon's moves
.loop
inc b
ld a,b
cp a,5 ; reached the end of the pokemon's moves?
ret z ; if so, return
ld a,[wUsingPPUp]
dec a ; using a PP Up?
jr nz,.skipMenuItemIDCheck
; if using a PP Up, check if this is the move it's being used on
ld a,[wCurrentMenuItem]
inc a
cp b
jr nz,.nextMove
.skipMenuItemIDCheck
ld a,[hl]
and 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
AddBonusPP:
push bc
ld a,[de] ; normal max PP of move
ld [H_DIVIDEND + 3],a
xor a
ld [H_DIVIDEND],a
ld [H_DIVIDEND + 1],a
ld [H_DIVIDEND + 2],a
ld a,5
ld [H_DIVISOR],a
ld b,4
call Divide
ld a,[hl] ; move PP
ld b,a
swap a
and 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,[wUsingPPUp]
dec a ; is the player using a PP Up right now?
jr z,.done ; if so, only add the bonus once
dec c
jr nz,.loop
.done
ld [hl],b
pop bc
ret
; gets max PP of a pokemon's move (including PP from PP Ups)
; INPUT:
; [wWhichPokemon] = index of pokemon within party/box
; [wMonDataLocation] = pokemon source
; 00: player's party
; 01: enemy's party
; 02: current box
; 03: daycare
; 04: player's in-battle pokemon
; [wCurrentMenuItem] = move index
; OUTPUT:
; [wMaxPP] = max PP
GetMaxPP:
ld a,[wMonDataLocation]
and a
ld hl,wPartyMon1Moves
ld bc,wPartyMon2 - wPartyMon1
jr z,.sourceWithMultipleMon
ld hl,wEnemyMon1Moves
dec a
jr z,.sourceWithMultipleMon
ld hl,wBoxMon1Moves
ld bc,wBoxMon2 - wBoxMon1
dec a
jr z,.sourceWithMultipleMon
ld hl,wDayCareMonMoves
dec a
jr z,.sourceWithOneMon
ld hl,wBattleMonMoves ; player's in-battle pokemon
.sourceWithOneMon
call GetSelectedMoveOffset2
jr .next
.sourceWithMultipleMon
call GetSelectedMoveOffset
.next
ld a,[hl]
dec a
push hl
ld hl,Moves
ld bc,MoveEnd - Moves
call AddNTimes
ld de,wcd6d
ld a,BANK(Moves)
call FarCopyData
ld de,wcd6d + 5 ; PP is byte 5 of move data
ld a,[de]
ld b,a ; b = normal max PP
pop hl
push bc
ld bc,wPartyMon1PP - wPartyMon1Moves ; PP offset if not player's in-battle pokemon data
ld a,[wMonDataLocation]
cp a,4 ; player's in-battle pokemon?
jr nz,.addPPOffset
ld bc,wBattleMonPP - wBattleMonMoves ; PP offset if player's in-battle pokemon data
.addPPOffset
add hl,bc
ld a,[hl] ; a = current PP
and 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 ; add the bonus for the existing PP Up count
ld [wUsingPPUp],a
call AddBonusPP ; add bonus PP from PP Ups
ld a,[hl]
and a,%00111111 ; mask out the PP Up count
ld [wMaxPP],a ; store max PP
ret
GetSelectedMoveOffset:
ld a,[wWhichPokemon]
call AddNTimes
GetSelectedMoveOffset2:
ld a,[wCurrentMenuItem]
ld c,a
ld b,0
add hl,bc
ret
; confirms the item toss and then tosses the item
; INPUT:
; hl = address of inventory (either wNumBagItems or wNumBoxItems)
; [wcf91] = item ID
; [wWhichPokemon] = index of item within inventory
; [wItemQuantity] = quantity to toss
; OUTPUT:
; clears carry flag if the item is tossed, sets carry flag if not
TossItem_:
push hl
ld a,[wcf91]
call IsItemHM
pop hl
jr c,.tooImportantToToss
push hl
call IsKeyItem_
ld a,[wIsKeyItem]
pop hl
and a
jr nz,.tooImportantToToss
push hl
ld a,[wcf91]
ld [wd11e],a
call GetItemName
call CopyStringToCF4B ; copy name to wcf4b
ld hl,IsItOKToTossItemText
call PrintText
coord hl, 14, 7
lb bc, 8, 15
ld a,TWO_OPTION_MENU
ld [wTextBoxID],a
call DisplayTextBoxID ; yes/no menu
ld a,[wMenuExitMethod]
cp a,CHOSE_SECOND_ITEM
pop hl
scf
ret z ; return if the player chose No
; if the player chose Yes
push hl
ld a,[wWhichPokemon]
call RemoveItemFromInventory
ld a,[wcf91]
ld [wd11e],a
call GetItemName
call CopyStringToCF4B ; copy name to wcf4b
ld hl,ThrewAwayItemText
call PrintText
pop hl
and a
ret
.tooImportantToToss
push hl
ld hl,TooImportantToTossText
call PrintText
pop hl
scf
ret
ThrewAwayItemText:
TX_FAR _ThrewAwayItemText
db "@"
IsItOKToTossItemText:
TX_FAR _IsItOKToTossItemText
db "@"
TooImportantToTossText:
TX_FAR _TooImportantToTossText
db "@"
; checks if an item is a key item
; INPUT:
; [wcf91] = item ID
; OUTPUT:
; [wIsKeyItem] = result
; 00: item is not key item
; 01: item is key item
IsKeyItem_:
ld a,$01
ld [wIsKeyItem],a
ld a,[wcf91]
cp 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,wBuffer
ld bc,15 ; only 11 bytes are actually used
call CopyData
pop af
dec a
ld c,a
ld hl,wBuffer
ld b,FLAG_TEST
predef FlagActionPredef
ld a,c
and a
ret nz
.checkIfItemIsHM
ld a,[wcf91]
call IsItemHM
ret c
xor a
ld [wIsKeyItem],a
ret
INCLUDE "data/key_items.asm"
SendNewMonToBox:
ld de, wNumInBox
ld a, [de]
inc a
ld [de], a
ld a, [wcf91]
ld [wd0b5], a
ld c, a
.asm_e7b1
inc de
ld a, [de]
ld b, a
ld a, c
ld c, b
ld [de], a
cp $ff
jr nz, .asm_e7b1
call GetMonHeader
ld hl, wBoxMonOT
ld bc, NAME_LENGTH
ld a, [wNumInBox]
dec a
jr z, .asm_e7ee
dec a
call AddNTimes
push hl
ld bc, NAME_LENGTH
add hl, bc
ld d, h
ld e, l
pop hl
ld a, [wNumInBox]
dec a
ld b, a
.asm_e7db
push bc
push hl
ld bc, NAME_LENGTH
call CopyData
pop hl
ld d, h
ld e, l
ld bc, -NAME_LENGTH
add hl, bc
pop bc
dec b
jr nz, .asm_e7db
.asm_e7ee
ld hl, wPlayerName
ld de, wBoxMonOT
ld bc, NAME_LENGTH
call CopyData
ld a, [wNumInBox]
dec a
jr z, .asm_e82a
ld hl, wBoxMonNicks
ld bc, NAME_LENGTH
dec a
call AddNTimes
push hl
ld bc, NAME_LENGTH
add hl, bc
ld d, h
ld e, l
pop hl
ld a, [wNumInBox]
dec a
ld b, a
.asm_e817
push bc
push hl
ld bc, NAME_LENGTH
call CopyData
pop hl
ld d, h
ld e, l
ld bc, -NAME_LENGTH
add hl, bc
pop bc
dec b
jr nz, .asm_e817
.asm_e82a
ld hl, wBoxMonNicks
ld a, NAME_MON_SCREEN
ld [wNamingScreenType], a
predef AskName
ld a, [wNumInBox]
dec a
jr z, .asm_e867
ld hl, wBoxMons
ld bc, wBoxMon2 - wBoxMon1
dec a
call AddNTimes
push hl
ld bc, wBoxMon2 - wBoxMon1
add hl, bc
ld d, h
ld e, l
pop hl
ld a, [wNumInBox]
dec a
ld b, a
.asm_e854
push bc
push hl
ld bc, wBoxMon2 - wBoxMon1
call CopyData
pop hl
ld d, h
ld e, l
ld bc, wBoxMon1 - wBoxMon2
add hl, bc
pop bc
dec b
jr nz, .asm_e854
.asm_e867
ld a, [wEnemyMonLevel]
ld [wEnemyMonBoxLevel], a
ld hl, wEnemyMon
ld de, wBoxMon1
ld bc, wEnemyMonDVs - wEnemyMon
call CopyData
ld hl, wPlayerID
ld a, [hli]
ld [de], a
inc de
ld a, [hl]
ld [de], a
inc de
push de
ld a, [wCurEnemyLVL]
ld d, a
callab CalcExperience
pop de
ld a, [hExperience]
ld [de], a
inc de
ld a, [hExperience + 1]
ld [de], a
inc de
ld a, [hExperience + 2]
ld [de], a
inc de
xor a
ld b, NUM_STATS * 2
.asm_e89f
ld [de], a
inc de
dec b
jr nz, .asm_e89f
ld hl, wEnemyMonDVs
ld a, [hli]
ld [de], a
inc de
ld a, [hli]
ld [de], a
ld hl, wEnemyMonPP
ld b, NUM_MOVES
.asm_e8b1
ld a, [hli]
inc de
ld [de], a
dec b
jr nz, .asm_e8b1
ret
; checks if the tile in front of the player is a shore or water tile
; used for surfing and fishing
; unsets carry if it is, sets carry if not
IsNextTileShoreOrWater:
ld a, [wCurMapTileset]
ld hl, WaterTilesets
ld de,1
call IsInArray
jr nc, .notShoreOrWater
ld a, [wCurMapTileset]
cp SHIP_PORT ; Vermilion Dock tileset
ld a, [wTileInFrontOfPlayer] ; tile in front of player
jr z, .skipShoreTiles ; if it's the Vermilion Dock tileset
cp $48 ; eastern shore tile in Safari Zone
jr z, .shoreOrWater
cp $32 ; usual eastern shore tile
jr z, .shoreOrWater
.skipShoreTiles
cp $14 ; water tile
jr z, .shoreOrWater
.notShoreOrWater
scf
ret
.shoreOrWater
and a
ret
; tilesets with water
WaterTilesets:
db OVERWORLD, FOREST, DOJO, GYM, SHIP, SHIP_PORT, CAVERN, FACILITY, PLATEAU
db $ff ; terminator
ReadSuperRodData:
; return e = 2 if no fish on this map
; return e = 1 if a bite, bc = level,species
; return e = 0 if no bite
ld a, [wCurMap]
ld de, 3 ; each fishing group is three bytes wide
ld hl, SuperRodData
call IsInArray
jr c, .ReadFishingGroup
ld e, $2 ; $2 if no fishing groups found
ret
.ReadFishingGroup
; hl points to the fishing group entry in the index
inc hl ; skip map id
; read fishing group address
ld a, [hli]
ld h, [hl]
ld l, a
ld b, [hl] ; how many mons in group
inc hl ; point to data
ld e, $0 ; no bite yet
.RandomLoop
call Random
srl a
ret c ; 50% chance of no battle
and %11 ; 2-bit random number
cp b
jr nc, .RandomLoop ; if a is greater than the number of mons, regenerate
; get the mon
add a
ld c, a
ld b, $0
add hl, bc
ld b, [hl] ; level
inc hl
ld c, [hl] ; species
ld e, $1 ; $1 if there's a bite
ret
INCLUDE "data/super_rod.asm"
; reloads map view and processes sprite data
; for items that cause the overworld to be displayed
ItemUseReloadOverworldData:
call LoadCurrentMapView
jp UpdateSprites
; creates a list at wBuffer of maps where the mon in [wd11e] can be found.
; this is used by the pokedex to display locations the mon can be found on the map.
FindWildLocationsOfMon:
ld hl, WildDataPointers
ld de, wBuffer
ld c, $0
.loop
inc hl
ld a, [hld]
inc a
jr z, .done
push hl
ld a, [hli]
ld h, [hl]
ld l, a
ld a, [hli]
and a
call nz, CheckMapForMon ; land
ld a, [hli]
and a
call nz, CheckMapForMon ; water
pop hl
inc hl
inc hl
inc c
jr .loop
.done
ld a, $ff ; list terminator
ld [de], a
ret
CheckMapForMon:
inc hl
ld b, $a
.loop
ld a, [wd11e]
cp [hl]
jr nz, .nextEntry
ld a, c
ld [de], a
inc de
.nextEntry
inc hl
inc hl
dec b
jr nz, .loop
dec hl
ret