diff options
Diffstat (limited to 'engine')
-rw-r--r-- | engine/battle/core.asm | 4106 | ||||
-rw-r--r-- | engine/battle/sliding_intro.asm | 57 | ||||
-rwxr-xr-x | engine/events/specials.asm | 2 | ||||
-rwxr-xr-x | engine/items/item_effects.asm | 8 | ||||
-rwxr-xr-x | engine/items/pack.asm | 92 | ||||
-rw-r--r-- | engine/pokemon/correct_nick_errors.asm | 2 | ||||
-rw-r--r-- | engine/pokemon/learn.asm | 2 |
7 files changed, 4216 insertions, 53 deletions
diff --git a/engine/battle/core.asm b/engine/battle/core.asm index 04769f46..734d151b 100644 --- a/engine/battle/core.asm +++ b/engine/battle/core.asm @@ -4621,3 +4621,4109 @@ UpdateHPPal: ret_3df99: ret + +BattleMenu: + xor a + ldh [hBGMapMode], a + call LoadTempTilemapToTilemap + + ld a, [wBattleType] + cp BATTLETYPE_DEBUG + jr z, .ok + cp BATTLETYPE_TUTORIAL + jr z, .ok + call UpdateBattleHuds + call EmptyBattleTextbox + call LoadTilemapToTempTilemap +.ok + +.loop + ld a, [wBattleType] + cp BATTLETYPE_CONTEST + jr nz, .not_contest + callfar ContestBattleMenu + jr .next +.not_contest + + ; Auto input: choose "ITEM" + ld a, [wInputType] + or a + jr z, .skip_dude_pack_select + farcall _DudeAutoInput_DownA +.skip_dude_pack_select + callfar LoadBattleMenu + +.next + ld a, $1 + ldh [hBGMapMode], a + ld a, [wBattleMenuCursorBuffer] + cp $1 + jp z, BattleMenu_Fight + cp $3 + jp z, BattleMenu_Pack + cp $2 + jp z, BattleMenu_PKMN + cp $4 + jp z, BattleMenu_Run + jr .loop + +BattleMenu_Fight: + xor a + ld [wNumFleeAttempts], a + call SafeLoadTempTilemapToTilemap + and a + ret + +BattleMenu_Pack: + ld a, [wLinkMode] + and a + jp nz, .ItemsCantBeUsed + + call LoadStandardMenuHeader + + ld a, [wBattleType] + cp BATTLETYPE_TUTORIAL + jr z, .tutorial + cp BATTLETYPE_CONTEST + jr z, .contest + + farcall BattlePack + ld a, [wBattlePlayerAction] + and a ; BATTLEPLAYERACTION_USEMOVE? + jr z, .didnt_use_item + jr .got_item + +.tutorial + farcall TutorialPack + ld a, POKE_BALL + ld [wCurItem], a + call DoItemEffect + jr .got_item + +.contest + ld a, PARK_BALL + ld [wCurItem], a + call DoItemEffect + +.got_item + call .UseItem + ret + +.didnt_use_item + call ClearPalettes + call DelayFrame + call _LoadBattleFontsHPBar + call GetBattleMonBackpic + call GetEnemyMonFrontpic + call ExitMenu + call WaitBGMap + call FinishBattleAnim + call LoadTilemapToTempTilemap + jp BattleMenu + +.ItemsCantBeUsed: + ld hl, BattleText_ItemsCantBeUsedHere + call StdBattleTextbox + jp BattleMenu + +.UseItem: + ld a, [wWildMon] + and a + jr nz, .run + callfar CheckItemPocket + ld a, [wItemAttributeParamBuffer] + cp BALL + jr z, .ball + call ClearBGPalettes + +.ball + xor a + ldh [hBGMapMode], a + call _LoadBattleFontsHPBar + call ClearSprites + ld a, [wBattleType] + cp BATTLETYPE_TUTORIAL + jr z, .tutorial2 + call GetBattleMonBackpic + +.tutorial2 + call GetEnemyMonFrontpic + ld a, $1 + ld [wMenuCursorY], a + call ExitMenu + call UpdateBattleHUDs + call WaitBGMap + call LoadTilemapToTempTilemap + call ClearWindowData + call FinishBattleAnim + and a + ret + +.run + xor a + ld [wWildMon], a + ld a, [wBattleResult] + and BATTLERESULT_BITMASK + ld [wBattleResult], a ; WIN + call ClearWindowData + call SetPalettes + scf + ret + +BattleMenu_PKMN: + call LoadStandardMenuHeader +BattleMenuPKMN_ReturnFromStats: + call ExitMenu + call LoadStandardMenuHeader + call ClearBGPalettes +BattleMenuPKMN_Loop: + farcall LoadPartyMenuGFX + farcall InitPartyMenuWithCancel + farcall InitPartyMenuGFX + xor a + ld [wPartyMenuActionText], a + farcall WritePartyMenuTilemap + farcall PrintPartyMenuText + call WaitBGMap + call SetPalettes + call DelayFrame + farcall PartyMenuSelect + jr c, .Cancel +.loop + callfar FreezeMonIcons + callfar GetMenu + jr c, BattleMenuPKMN_Loop + call PlaceHollowCursor + ld a, [wMenuCursorY] + cp $1 ; SWITCH + jp z, TryPlayerSwitch + cp $2 ; STATS + jr z, .Stats + cp $3 ; CANCEL + jr z, .Cancel + jr .loop + +.Stats: + call Battle_StatsScreen + jp BattleMenuPKMN_ReturnFromStats + +.Cancel: + call ClearSprites + call ClearPalettes + call DelayFrame + call _LoadHPBar + call CloseWindow + call LoadTilemapToTempTilemap + call GetMemSGBLayout + call SetPalettes + jp BattleMenu + +Battle_StatsScreen: + call DisableLCD + + ld hl, vTiles2 tile $31 + ld de, vTiles0 + ld bc, $11 tiles + call CopyBytes + + ld hl, vTiles2 + ld de, vTiles0 tile $11 + ld bc, $31 tiles + call CopyBytes + + call EnableLCD + + call ClearSprites + call LowVolume + xor a ; PARTYMON + ld [wMonType], a + ld hl, wPartyMons + predef StatsScreenInit + call MaxVolume + + call DisableLCD + + ld hl, vTiles0 + ld de, vTiles2 tile $31 + ld bc, $11 tiles + call CopyBytes + + ld hl, vTiles0 tile $11 + ld de, vTiles2 + ld bc, $31 tiles + call CopyBytes + + call EnableLCD + ret + +TryPlayerSwitch: + ld a, [wCurBattleMon] + ld d, a + ld a, [wCurPartyMon] + cp d + jr nz, .check_trapped + ld hl, BattleText_MonIsAlreadyOut + call StdBattleTextbox + jp BattleMenuPKMN_Loop + +.check_trapped + ld a, [wPlayerWrapCount] + and a + jr nz, .trapped + ld a, [wEnemySubStatus5] + bit SUBSTATUS_CANT_RUN, a + jr z, .try_switch + +.trapped + ld hl, BattleText_MonCantBeRecalled + call StdBattleTextbox + jp BattleMenuPKMN_Loop + +.try_switch + call CheckIfCurPartyMonIsFitToFight + jp z, BattleMenuPKMN_Loop + ld a, [wCurBattleMon] + ld [wLastPlayerMon], a + ld a, BATTLEPLAYERACTION_SWITCH + ld [wBattlePlayerAction], a + call ClearPalettes + call DelayFrame + call ClearSprites + call _LoadHPBar + call CloseWindow + call GetMemSGBLayout + call SetPalettes + ld a, [wCurPartyMon] + ld [wCurBattleMon], a +PlayerSwitch: + ld a, 1 + ld [wPlayerIsSwitching], a + ld a, [wLinkMode] + and a + jr z, .not_linked + call LoadStandardMenuHeader + call LinkBattleSendReceiveAction + call CloseWindow + +.not_linked + call ParseEnemyAction + ld a, [wLinkMode] + and a + jr nz, .linked + +.switch + call BattleMonEntrance + and a + ret + +.linked + ld a, [wBattleAction] + cp BATTLEACTION_STRUGGLE + jp z, .switch + cp BATTLEACTION_SKIPTURN + jp z, .switch + cp BATTLEACTION_SWITCH1 + jp c, .switch + cp BATTLEACTION_FORFEIT + jr nz, .dont_run + call WildFled_EnemyFled_LinkBattleCanceled + ret + +.dont_run + ldh a, [hSerialConnectionStatus] + cp USING_EXTERNAL_CLOCK + jr z, .player_1 + call BattleMonEntrance + call EnemyMonEntrance + and a + ret + +.player_1 + call EnemyMonEntrance + call BattleMonEntrance + and a + ret + +EnemyMonEntrance: + callfar AI_Switch + call SetEnemyTurn + jp SpikesDamage + +BattleMonEntrance: + call WithdrawMonText + + ld c, 50 + call DelayFrames + + ld hl, wPlayerSubStatus4 + res SUBSTATUS_RAGE, [hl] + + call SetEnemyTurn + call PursuitSwitch + jr c, .ok + call RecallPlayerMon +.ok + + hlcoord 9, 7 + lb bc, 5, 11 + call ClearBox + + ld a, [wCurBattleMon] + ld [wCurPartyMon], a + call AddBattleParticipant + call InitBattleMon + call ResetPlayerStatLevels + call SendOutMonText + call NewBattleMonStatus + call BreakAttraction + call SendOutPlayerMon + call EmptyBattleTextbox + call LoadTilemapToTempTilemap + call SetPlayerTurn + call SpikesDamage + ld a, $2 + ld [wMenuCursorY], a + ret + +PassedBattleMonEntrance: + ld c, 50 + call DelayFrames + + hlcoord 9, 7 + lb bc, 5, 11 + call ClearBox + + ld a, [wCurPartyMon] + ld [wCurBattleMon], a + call AddBattleParticipant + call InitBattleMon + xor a ; FALSE + ld [wApplyStatLevelMultipliersToEnemy], a + call ApplyStatLevelMultiplierOnAllStats + call SendOutPlayerMon + call EmptyBattleTextbox + call LoadTilemapToTempTilemap + call SetPlayerTurn + jp SpikesDamage + +BattleMenu_Run: + call SafeLoadTempTilemapToTilemap + ld a, $3 + ld [wMenuCursorY], a + ld hl, wBattleMonSpeed + ld de, wEnemyMonSpeed + call TryToRunAwayFromBattle + ld a, FALSE + ld [wFailedToFlee], a + ret c + ld a, [wBattlePlayerAction] + and a ; BATTLEPLAYERACTION_USEMOVE? + ret nz + jp BattleMenu + +CheckAmuletCoin: + ld a, [wBattleMonItem] + ld b, a + callfar GetItemHeldEffect + ld a, b + cp HELD_AMULET_COIN + ret nz + ld a, 1 + ld [wAmuletCoin], a + ret + +MoveSelectionScreen: + ld hl, wEnemyMonMoves + ld a, [wMoveSelectionMenuType] + dec a + jr z, .got_menu_type + dec a + jr z, .ether_elixer_menu + call .CheckPlayerHasUsableMoves + ret z ; use Struggle + ld hl, wBattleMonMoves + jr .got_menu_type + +.ether_elixer_menu + ld a, MON_MOVES + call GetPartyParamLocation + +.got_menu_type + ld de, wListMoves_MoveIndicesBuffer + ld bc, NUM_MOVES + call CopyBytes + xor a + ldh [hBGMapMode], a + + hlcoord 4, 17 - NUM_MOVES - 1 + ld b, 4 + ld c, 14 + ld a, [wMoveSelectionMenuType] + cp $2 + jr nz, .got_dims + hlcoord 4, 17 - NUM_MOVES - 1 - 4 + ld b, 4 + ld c, 14 +.got_dims + call Textbox + + hlcoord 6, 17 - NUM_MOVES + ld a, [wMoveSelectionMenuType] + cp $2 + jr nz, .got_start_coord + hlcoord 6, 17 - NUM_MOVES - 4 +.got_start_coord + ld a, SCREEN_WIDTH + ld [wBuffer1], a + predef ListMoves + + ld b, 5 + ld a, [wMoveSelectionMenuType] + cp $2 + ld a, 17 - NUM_MOVES + jr nz, .got_default_coord + ld b, 5 + ld a, 17 - NUM_MOVES - 4 + +.got_default_coord + ld [w2DMenuCursorInitY], a + ld a, b + ld [w2DMenuCursorInitX], a + ld a, [wMoveSelectionMenuType] + cp $1 + jr z, .skip_inc + ld a, [wCurMoveNum] + inc a + +.skip_inc + ld [wMenuCursorY], a + ld a, 1 + ld [wMenuCursorX], a + ld a, [wNumMoves] + inc a + ld [w2DMenuNumRows], a + ld a, 1 + ld [w2DMenuNumCols], a + ld c, STATICMENU_ENABLE_LEFT_RIGHT | STATICMENU_ENABLE_START | STATICMENU_WRAP + ld a, [wMoveSelectionMenuType] + dec a + ld b, D_DOWN | D_UP | A_BUTTON + jr z, .okay + dec a + ld b, D_DOWN | D_UP | A_BUTTON | B_BUTTON + jr z, .okay + ld a, [wLinkMode] + cp LINK_COLOSSEUM + jr z, .okay + ld b, D_DOWN | D_UP | A_BUTTON | B_BUTTON | SELECT + +.okay + ld a, b + ld [wMenuJoypadFilter], a + ld a, c + ld [w2DMenuFlags1], a + xor a + ld [w2DMenuFlags2], a + ld a, $10 + ld [w2DMenuCursorOffsets], a +.menu_loop + ld a, [wMoveSelectionMenuType] + and a + jr z, .battle_player_moves + dec a + jr nz, .interpret_joypad + hlcoord 11, 14 + ld de, .string_3e61c + call PlaceString + jr .interpret_joypad + +.battle_player_moves + call MoveInfoBox + ld a, [wMoveSwapBuffer] + and a + jr z, .interpret_joypad + hlcoord 5, 13 + ld bc, SCREEN_WIDTH + dec a + call AddNTimes + ld [hl], "▷" + +.interpret_joypad + ld a, $1 + ldh [hBGMapMode], a + call ScrollingMenuJoypad + bit D_UP_F, a + jp nz, .pressed_up + bit D_DOWN_F, a + jp nz, .pressed_down + bit SELECT_F, a + jp nz, .pressed_select + bit B_BUTTON_F, a + ; A button + push af + + xor a + ld [wMoveSwapBuffer], a + ld a, [wMenuCursorY] + dec a + ld [wMenuCursorY], a + ld b, a + ld a, [wMoveSelectionMenuType] + dec a + jr nz, .not_enemy_moves_process_b + + pop af + ret + +.not_enemy_moves_process_b + dec a + ld a, b + ld [wCurMoveNum], a + jr nz, .use_move + + pop af + ret + +.use_move + pop af + ret nz + + ld hl, wBattleMonPP + ld a, [wMenuCursorY] + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + and PP_MASK + jr z, .no_pp_left + ld a, [wPlayerDisableCount] + swap a + and $f + dec a + cp c + jr z, .move_disabled + ld a, [wUnusedPlayerLockedMove] + and a + jr nz, .skip2 + ld a, [wMenuCursorY] + ld hl, wBattleMonMoves + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + +.skip2 + ld [wCurPlayerMove], a + xor a + ret + +.move_disabled + ld hl, BattleText_TheMoveIsDisabled + jr .place_textbox_start_over + +.no_pp_left + ld hl, BattleText_TheresNoPPLeftForThisMove + +.place_textbox_start_over + call StdBattleTextbox + call SafeLoadTempTilemapToTilemap + jp MoveSelectionScreen + +.string_3e61c + db "@" + +.pressed_up + ld a, [wMenuCursorY] + and a + jp nz, .menu_loop + ld a, [wNumMoves] + inc a + ld [wMenuCursorY], a + jp .menu_loop + +.pressed_down + ld a, [wMenuCursorY] + ld b, a + ld a, [wNumMoves] + inc a + inc a + cp b + jp nz, .menu_loop + ld a, $1 + ld [wMenuCursorY], a + jp .menu_loop + +.CheckPlayerHasUsableMoves: + ld a, STRUGGLE + ld [wCurPlayerMove], a + ld a, [wPlayerDisableCount] + and a + ld hl, wBattleMonPP + jr nz, .disabled + + ld a, [hli] + or [hl] + inc hl + or [hl] + inc hl + or [hl] + and PP_MASK + ret nz + jr .force_struggle + +.disabled + swap a + and $f + ld b, a + ld d, NUM_MOVES + 1 + xor a +.loop + dec d + jr z, .done + ld c, [hl] + inc hl + dec b + jr z, .loop + or c + jr .loop + +.done + ; Bug: this will result in a move with PP Up confusing the game. + and a ; should be "and PP_MASK" + ret nz + +.force_struggle + ld hl, BattleText_MonHasNoMovesLeft + call StdBattleTextbox + ld c, 60 + call DelayFrames + xor a + ret + +.pressed_select + ld a, [wMoveSwapBuffer] + and a + jr z, .start_swap + ld hl, wBattleMonMoves + call .swap_bytes + ld hl, wBattleMonPP + call .swap_bytes + ld hl, wPlayerDisableCount + ld a, [hl] + swap a + and $f + ld b, a + ld a, [wMenuCursorY] + cp b + jr nz, .not_swapping_disabled_move + ld a, [hl] + and $f + ld b, a + ld a, [wMoveSwapBuffer] + swap a + add b + ld [hl], a + jr .swap_moves_in_party_struct + +.not_swapping_disabled_move + ld a, [wMoveSwapBuffer] + cp b + jr nz, .swap_moves_in_party_struct + ld a, [hl] + and $f + ld b, a + ld a, [wMenuCursorY] + swap a + add b + ld [hl], a + +.swap_moves_in_party_struct +; Fixes the COOLTRAINER glitch + ld a, [wPlayerSubStatus5] + bit SUBSTATUS_TRANSFORMED, a + jr nz, .transformed + ld hl, wPartyMon1Moves + ld a, [wCurBattleMon] + call GetPartyLocation + push hl + call .swap_bytes + pop hl + ld bc, MON_PP - MON_MOVES + add hl, bc + call .swap_bytes + +.transformed + xor a + ld [wMoveSwapBuffer], a + jp MoveSelectionScreen + +.swap_bytes + push hl + ld a, [wMoveSwapBuffer] + dec a + ld c, a + ld b, 0 + add hl, bc + ld d, h + ld e, l + pop hl + ld a, [wMenuCursorY] + dec a + ld c, a + ld b, 0 + add hl, bc + ld a, [de] + ld b, [hl] + ld [hl], a + ld a, b + ld [de], a + ret + +.start_swap + ld a, [wMenuCursorY] + ld [wMoveSwapBuffer], a + jp MoveSelectionScreen + +MoveInfoBox: + xor a + ldh [hBGMapMode], a + + hlcoord 0, 8 + ld b, 3 + ld c, 9 + call Textbox + + ld a, [wPlayerDisableCount] + and a + jr z, .not_disabled + + swap a + and $f + ld b, a + ld a, [wMenuCursorY] + cp b + jr nz, .not_disabled + + hlcoord 1, 10 + ld de, .Disabled + call PlaceString + jr .done + +.not_disabled + ld hl, wMenuCursorY + dec [hl] + call SetPlayerTurn + ld hl, wBattleMonMoves + ld a, [wMenuCursorY] + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + ld [wCurPlayerMove], a + + ld a, [wCurBattleMon] + ld [wCurPartyMon], a + ld a, WILDMON + ld [wMonType], a + callfar GetMaxPPOfMove + + ld hl, wMenuCursorY + ld c, [hl] + inc [hl] + ld b, 0 + ld hl, wBattleMonPP + add hl, bc + ld a, [hl] + and PP_MASK + ld [wStringBuffer1], a + hlcoord 1, 9 + ld de, .Type + call PlaceString + + hlcoord 7, 11 + ld [hl], "/" + hlcoord 5, 11 + ld de, wStringBuffer1 + lb bc, 1, 2 + call PrintNum + + hlcoord 8, 11 + ld de, wNamedObjectIndexBuffer + lb bc, 1, 2 + call PrintNum + + callfar UpdateMoveData + ld a, [wPlayerMoveStruct + MOVE_ANIM] + ld b, a + hlcoord 2, 10 + predef PrintMoveType + +.done + ret + +.Disabled: + db "Disabled!@" +.Type: + db "TYPE/@" + +ParseEnemyAction: + ld a, [wEnemyIsSwitching] + and a + ret nz + ld a, [wLinkMode] + and a + jr z, .not_linked + call EmptyBattleTextbox + call LoadTilemapToTempTilemap + ld a, [wBattlePlayerAction] + and a ; BATTLEPLAYERACTION_USEMOVE? + call z, LinkBattleSendReceiveAction + call SafeLoadTempTilemapToTilemap + ld a, [wBattleAction] + cp BATTLEACTION_STRUGGLE + jp z, .struggle + cp BATTLEACTION_SKIPTURN + jp z, .skip_turn + cp BATTLEACTION_SWITCH1 + jp nc, ResetVarsForSubstatusRage + ld [wCurEnemyMoveNum], a + ld c, a + ld a, [wEnemySubStatus1] + bit SUBSTATUS_ROLLOUT, a + jp nz, .skip_load + ld a, [wEnemySubStatus3] + and 1 << SUBSTATUS_CHARGED | 1 << SUBSTATUS_RAMPAGE | 1 << SUBSTATUS_BIDE + jp nz, .skip_load + + ld hl, wEnemySubStatus5 + bit SUBSTATUS_ENCORED, [hl] + ld a, [wLastEnemyMove] + jp nz, .finish + ld hl, wEnemyMonMoves + ld b, 0 + add hl, bc + ld a, [hl] + jp .finish + +.not_linked + ld hl, wEnemySubStatus5 + bit SUBSTATUS_ENCORED, [hl] + jr z, .skip_encore + ld a, [wLastEnemyMove] + jp .finish + +.skip_encore + call CheckEnemyLockedIn + jp nz, ResetVarsForSubstatusRage + jr .continue + +.skip_turn + ld a, $ff + jr .finish + +.continue + ld hl, wEnemyMonMoves + ld de, wEnemyMonPP + ld b, NUM_MOVES +.loop + ld a, [hl] + and a + jp z, .struggle + ld a, [wEnemyDisabledMove] + cp [hl] + jr z, .disabled + ld a, [de] + and PP_MASK + jr nz, .enough_pp + +.disabled + inc hl + inc de + dec b + jr nz, .loop + jr .struggle + +.enough_pp + ld a, [wBattleMode] + dec a + jr nz, .skip_load +; wild +.loop2 + ld hl, wEnemyMonMoves + call BattleRandom + maskbits NUM_MOVES + ld c, a + ld b, 0 + add hl, bc + ld a, [wEnemyDisableCount] + swap a + and $f + dec a + cp c + jr z, .loop2 + ld a, [hl] + and a + jr z, .loop2 + ld hl, wEnemyMonPP + add hl, bc + ld b, a + ld a, [hl] + and PP_MASK + jr z, .loop2 + ld a, c + ld [wCurEnemyMoveNum], a + ld a, b + +.finish + ld [wCurEnemyMove], a + +.skip_load + call SetEnemyTurn + callfar UpdateMoveData + call CheckEnemyLockedIn + jr nz, .raging + xor a + ld [wEnemyCharging], a + +.raging + ld a, [wEnemyMoveStruct + MOVE_EFFECT] + cp EFFECT_FURY_CUTTER + jr z, .fury_cutter + xor a + ld [wEnemyFuryCutterCount], a + +.fury_cutter + ld a, [wEnemyMoveStruct + MOVE_EFFECT] + cp EFFECT_RAGE + jr z, .no_rage + ld hl, wEnemySubStatus4 + res SUBSTATUS_RAGE, [hl] + xor a + ld [wEnemyRageCounter], a + +.no_rage + ld a, [wEnemyMoveStruct + MOVE_EFFECT] + cp EFFECT_PROTECT + ret z + cp EFFECT_ENDURE + ret z + xor a + ld [wEnemyProtectCount], a + ret + +.struggle + ld a, STRUGGLE + jr .finish + +ResetVarsForSubstatusRage: + xor a + ld [wEnemyFuryCutterCount], a + ld [wEnemyProtectCount], a + ld [wEnemyRageCounter], a + ld hl, wEnemySubStatus4 + res SUBSTATUS_RAGE, [hl] + ret + +CheckEnemyLockedIn: + ld a, [wEnemySubStatus4] + and 1 << SUBSTATUS_RECHARGE + ret nz + + ld hl, wEnemySubStatus3 + ld a, [hl] + and 1 << SUBSTATUS_CHARGED | 1 << SUBSTATUS_RAMPAGE | 1 << SUBSTATUS_BIDE + ret nz + + ld hl, wEnemySubStatus1 + bit SUBSTATUS_ROLLOUT, [hl] + ret + +LinkBattleSendReceiveAction: + ld a, $ff + ld [wOtherPlayerLinkAction], a + ld a, [wBattlePlayerAction] + and a ; BATTLEPLAYERACTION_USEMOVE? + jr nz, .switch + ld a, [wCurPlayerMove] + cp STRUGGLE + ld b, BATTLEACTION_STRUGGLE + jr z, .struggle + dec b + inc a + jr z, .struggle + ld a, [wCurMoveNum] + jr .use_move + +.switch + ld a, [wCurPartyMon] + add BATTLEACTION_SWITCH1 + ld b, a + +.struggle + ld a, b + +.use_move + ld [wPlayerLinkAction], a + callfar PlaceWaitingText + +.waiting + call LinkTransfer + call DelayFrame + ld a, [wOtherPlayerLinkAction] + inc a + jr z, .waiting + + ld b, 10 +.receive + call DelayFrame + call LinkTransfer + dec b + jr nz, .receive + + ld b, 10 +.acknowledge + call DelayFrame + call LinkDataReceived + dec b + jr nz, .acknowledge + + ret + +LoadEnemyMon: +; Initialize enemy monster parameters +; To do this we pull the species from wTempEnemyMonSpecies + +; Notes: +; BattleRandom is used to ensure sync between Game Boys + +; Clear the whole enemy mon struct (wEnemyMon) + xor a + ld hl, wEnemyMonSpecies + ld bc, wEnemyMonEnd - wEnemyMon + call ByteFill + +; We don't need to be here if we're in a link battle + ld a, [wLinkMode] + and a + jp nz, InitEnemyMon + +; Make sure everything knows what species we're working with + ld a, [wTempEnemyMonSpecies] + ld [wEnemyMonSpecies], a + ld [wCurSpecies], a + ld [wCurPartySpecies], a + +; Grab the BaseData for this species + call GetBaseData + +; Let's get the item: + +; Is the item predetermined? + ld a, [wBattleMode] + dec a + jr z, .WildItem + +; If we're in a trainer battle, the item is in the party struct + ld a, [wCurPartyMon] + ld hl, wOTPartyMon1Item + call GetPartyLocation ; bc = PartyMon[wCurPartyMon] - wPartyMons + ld a, [hl] + jr .UpdateItem + +.WildItem: +; In a wild battle, we pull from the item slots in BaseData + +; Force Item1 +; Used for Ho-Oh, Lugia and Snorlax encounters + ld a, [wBattleType] + cp BATTLETYPE_FORCEITEM + ld a, [wBaseItem1] + jr z, .UpdateItem + +; Failing that, it's all up to chance +; Effective chances: +; 75% None +; 23% Item1 +; 2% Item2 + +; 25% chance of getting an item + call BattleRandom + cp 75 percent + 1 + ld a, NO_ITEM + jr c, .UpdateItem + +; From there, an 8% chance for Item2 + call BattleRandom + cp 8 percent ; 8% of 25% = 2% Item2 + ld a, [wBaseItem1] + jr nc, .UpdateItem + ld a, [wBaseItem2] + +.UpdateItem: + ld [wEnemyMonItem], a + +; Initialize DVs + +; If we're in a trainer battle, DVs are predetermined + ld a, [wBattleMode] + and a + jr z, .InitDVs + + ld a, [wEnemySubStatus5] + bit SUBSTATUS_TRANSFORMED, a + jr z, .InitDVs + +; Unknown + ld hl, wEnemyBackupDVs + ld de, wEnemyMonDVs + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + ld [de], a + jp .Happiness + +.InitDVs: +; Trainer DVs + +; All trainers have preset DVs, determined by class +; See GetTrainerDVs for more on that + farcall GetTrainerDVs +; These are the DVs we'll use if we're actually in a trainer battle + ld a, [wBattleMode] + dec a + jr nz, .UpdateDVs + +; Wild DVs +; Here's where the fun starts + +; Roaming monsters (Entei, Raikou, Suicune) work differently +; They have their own structs, which are shorter than normal + ld a, [wBattleType] + cp BATTLETYPE_ROAMING + jr nz, .NotRoaming + +; Grab HP + call GetRoamMonHP + ld a, [hl] +; Check if the HP has been initialized + and a +; We'll do something with the result in a minute + push af + +; Grab DVs + call GetRoamMonDVs + inc hl + ld a, [hld] + ld c, a + ld b, [hl] + +; Get back the result of our check + pop af +; If the RoamMon struct has already been initialized, we're done + jr nz, .UpdateDVs + +; If it hasn't, we need to initialize the DVs +; (HP is initialized at the end of the battle) + call GetRoamMonDVs + inc hl + call BattleRandom + ld [hld], a + ld c, a + call BattleRandom + ld [hl], a + ld b, a +; We're done with DVs + jr .UpdateDVs + +.NotRoaming: +; Register a contains wBattleType + +; Forced shiny battle type +; Used by Red Gyarados at Lake of Rage + cp BATTLETYPE_SHINY + jr nz, .GenerateDVs + + ld b, ATKDEFDV_SHINY ; $ea + ld c, SPDSPCDV_SHINY ; $aa + jr .UpdateDVs + +.GenerateDVs: +; Generate new random DVs + call BattleRandom + ld b, a + call BattleRandom + ld c, a + +.UpdateDVs: +; Input DVs in register bc + ld hl, wEnemyMonDVs + ld a, b + ld [hli], a + ld [hl], c + +; We've still got more to do if we're dealing with a wild monster + ld a, [wBattleMode] + dec a + jr nz, .Happiness + +; Species-specfic: + +; Unown + ld a, [wTempEnemyMonSpecies] + cp UNOWN + jr nz, .Magikarp + +; Get letter based on DVs + ld hl, wEnemyMonDVs + predef GetUnownLetter +; Can't use any letters that haven't been unlocked +; If combined with forced shiny battletype, causes an infinite loop + call CheckUnownLetter + jr c, .GenerateDVs ; try again + +.Magikarp: +; These filters are untranslated. +; They expect at wMagikarpLength a 2-byte value in mm, +; but the value is in feet and inches (one byte each). + +; The first filter is supposed to make very large Magikarp even rarer, +; by targeting those 1600 mm (= 5'3") or larger. +; After the conversion to feet, it is unable to target any, +; since the largest possible Magikarp is 5'3", and $0503 = 1283 mm. + ld a, [wTempEnemyMonSpecies] + cp MAGIKARP + jr nz, .Happiness + +; Get Magikarp's length + ld de, wEnemyMonDVs + ld bc, wPlayerID + callfar CalcMagikarpLength + +; No reason to keep going if length > 1536 mm (i.e. if HIGH(length) > 6 feet) + ld a, [wMagikarpLength] + cp HIGH(1536) ; should be "cp 5", since 1536 mm = 5'0", but HIGH(1536) = 6 + jr nz, .CheckMagikarpArea + +; 5% chance of skipping both size checks + call Random + cp 5 percent + jr c, .CheckMagikarpArea +; Try again if length >= 1616 mm (i.e. if LOW(length) >= 4 inches) + ld a, [wMagikarpLength + 1] + cp LOW(1616) ; should be "cp 4", since 1616 mm = 5'4", but LOW(1616) = 80 + jr nc, .GenerateDVs + +; 20% chance of skipping this check + call Random + cp 20 percent - 1 + jr c, .CheckMagikarpArea +; Try again if length >= 1600 mm (i.e. if LOW(length) >= 3 inches) + ld a, [wMagikarpLength + 1] + cp LOW(1600) ; should be "cp 3", since 1600 mm = 5'3", but LOW(1600) = 64 + jr nc, .GenerateDVs + +.CheckMagikarpArea: +; The "jr z" checks are supposed to be "jr nz". + +; Instead, all maps in GROUP_LAKE_OF_RAGE (Mahogany area) +; and Routes 20 and 44 are treated as Lake of Rage. + +; This also means Lake of Rage Magikarp can be smaller than ones +; caught elsewhere rather than the other way around. + +; Intended behavior enforces a minimum size at Lake of Rage. +; The real behavior prevents a minimum size in the Lake of Rage area. + +; Moreover, due to the check not being translated to feet+inches, all Magikarp +; smaller than 4'0" may be caught by the filter, a lot more than intended. + ld a, [wMapGroup] + cp GROUP_LAKE_OF_RAGE + jr z, .Happiness + ld a, [wMapNumber] + cp MAP_LAKE_OF_RAGE + jr z, .Happiness +; 40% chance of not flooring + call Random + cp 40 percent - 2 + jr c, .Happiness +; Try again if length < 1024 mm (i.e. if HIGH(length) < 3 feet) + ld a, [wMagikarpLength] + cp HIGH(1024) ; should be "cp 3", since 1024 mm = 3'4", but HIGH(1024) = 4 + jr c, .GenerateDVs ; try again + +; Finally done with DVs + +.Happiness: +; Set happiness + ld a, BASE_HAPPINESS + ld [wEnemyMonHappiness], a +; Set level + ld a, [wCurPartyLevel] + ld [wEnemyMonLevel], a +; Fill stats + ld de, wEnemyMonMaxHP + ld b, FALSE + ld hl, wEnemyMonDVs - (MON_DVS - MON_STAT_EXP + 1) ; wLinkBattleRNs + 7 ; ? + predef CalcMonStats + +; If we're in a trainer battle, +; get the rest of the parameters from the party struct + ld a, [wBattleMode] + cp TRAINER_BATTLE + jr z, .OpponentParty + +; If we're in a wild battle, check wild-specific stuff + and a + jr z, .TreeMon + + ld a, [wEnemySubStatus5] + bit SUBSTATUS_TRANSFORMED, a + jr nz, .Moves + +.TreeMon: +; If we're headbutting trees, some monsters enter battle asleep + ld a, [wTempEnemyMonSpecies] + +; Hoothoot/Noctowl are asleep if MORN/DAY + cp HOOTHOOT + jr z, .sleeping_if_not_nite + cp NOCTOWL + jr z, .sleeping_if_not_nite + +; Pidgey/Spearow are asleep if NITE + cp PIDGEY + jr z, .sleeping_if_nite + cp SPEAROW + jr z, .sleeping_if_nite + +; Other species are never asleep + jr .not_sleeping + +.sleeping_if_not_nite + ld a, [wTimeOfDay] + cp NITE_F + jr nz, .sleeping + jr .not_sleeping + +.sleeping_if_nite + ld a, [wTimeOfDay] + cp NITE_F + jr z, .sleeping + jr .not_sleeping + +.sleeping + ld a, TREEMON_SLEEP_TURNS + jr .UpdateStatus + +.not_sleeping + xor a + +.UpdateStatus: + ld hl, wEnemyMonStatus + ld [hli], a + +; Unused byte + xor a + ld [hli], a + +; Full HP.. + ld a, [wEnemyMonMaxHP] + ld [hli], a + ld a, [wEnemyMonMaxHP + 1] + ld [hl], a + +; ..unless it's a RoamMon + ld a, [wBattleType] + cp BATTLETYPE_ROAMING + jr nz, .Moves + +; Grab HP + call GetRoamMonHP + ld a, [hl] +; Check if it's been initialized again + and a + jr z, .InitRoamHP +; Update from the struct if it has + ld a, [hl] + ld [wEnemyMonHP + 1], a + jr .Moves + +.InitRoamHP: +; HP only uses the lo byte in the RoamMon struct since +; Raikou and Entei will have < 256 hp at level 40 + ld a, [wEnemyMonHP + 1] + ld [hl], a + jr .Moves + +.OpponentParty: +; Get HP from the party struct + ld hl, (wOTPartyMon1HP + 1) + ld a, [wCurPartyMon] + call GetPartyLocation + ld a, [hld] + ld [wEnemyMonHP + 1], a + ld a, [hld] + ld [wEnemyMonHP], a + +; Make sure everything knows which monster the opponent is using + ld a, [wCurPartyMon] + ld [wCurOTMon], a + +; Get status from the party struct + dec hl + ld a, [hl] ; OTPartyMonStatus + ld [wEnemyMonStatus], a + +.Moves: + ld hl, wBaseType1 + ld de, wEnemyMonType1 + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + ld [de], a + +; Get moves + ld de, wEnemyMonMoves +; Are we in a trainer battle? + ld a, [wBattleMode] + cp TRAINER_BATTLE + jr nz, .WildMoves +; Then copy moves from the party struct + ld hl, wOTPartyMon1Moves + ld a, [wCurPartyMon] + call GetPartyLocation + ld bc, NUM_MOVES + call CopyBytes + jr .PP + +.WildMoves: +; Clear wEnemyMonMoves + xor a + ld h, d + ld l, e + ld [hli], a + ld [hli], a + ld [hli], a + ld [hl], a +; Make sure the predef knows this isn't a partymon + ld [wEvolutionOldSpecies], a +; Fill moves based on level + predef FillMoves + +.PP: +; Trainer battle? + ld a, [wBattleMode] + cp TRAINER_BATTLE + jr z, .TrainerPP + +; Fill wild PP + ld hl, wEnemyMonMoves + ld de, wEnemyMonPP + predef FillPP + jr .Finish + +.TrainerPP: +; Copy PP from the party struct + ld hl, wOTPartyMon1PP + ld a, [wCurPartyMon] + call GetPartyLocation + ld de, wEnemyMonPP + ld bc, NUM_MOVES + call CopyBytes + +.Finish: +; Only the first five base stats are copied.. + ld hl, wBaseStats + ld de, wEnemyMonBaseStats + ld b, wBaseSpecialDefense - wBaseStats +.loop + ld a, [hli] + ld [de], a + inc de + dec b + jr nz, .loop + + ld a, [wBaseCatchRate] + ld [de], a + inc de + + ld a, [wBaseExp] + ld [de], a + + ld a, [wTempEnemyMonSpecies] + ld [wNamedObjectIndexBuffer], a + + call GetPokemonName + +; Did we catch it? + ld a, [wBattleMode] + and a + ret z + +; Update enemy nick + ld hl, wStringBuffer1 + ld de, wEnemyMonNick + ld bc, MON_NAME_LENGTH + call CopyBytes + +; Saw this mon + ld a, [wTempEnemyMonSpecies] + dec a + ld c, a + ld b, SET_FLAG + ld hl, wPokedexSeen + predef SmallFarFlagAction + + ld hl, wEnemyMonStats + ld de, wEnemyStats + ld bc, wEnemyMonStatsEnd - wEnemyMonStats + call CopyBytes + + ret + +CheckUnownLetter: +; Return carry if the Unown letter hasn't been unlocked yet + + ld a, [wUnlockedUnowns] + ld c, a + ld de, 0 + +.loop + +; Don't check this set unless it's been unlocked + srl c + jr nc, .next + +; Is our letter in the set? + ld hl, UnlockedUnownLetterSets + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + + push de + ld a, [wUnownLetter] + ld de, 1 + push bc + call IsInArray + pop bc + pop de + + jr c, .match + +.next +; Make sure we haven't gone past the end of the table + inc e + inc e + ld a, e + cp UnlockedUnownLetterSets.End - UnlockedUnownLetterSets + jr c, .loop + +; Hasn't been unlocked, or the letter is invalid + scf + ret + +.match +; Valid letter + and a + ret + +INCLUDE "data/wild/unlocked_unowns.asm" + +Unreferenced_SwapBattlerLevels: + push bc + ld a, [wBattleMonLevel] + ld b, a + ld a, [wEnemyMonLevel] + ld [wBattleMonLevel], a + ld a, b + ld [wEnemyMonLevel], a + pop bc + ret + +BattleWinSlideInEnemyTrainerFrontpic: + xor a + ld [wTempEnemyMonSpecies], a + call FinishBattleAnim + ld a, [wOtherTrainerClass] + ld [wTrainerClass], a + ld de, vTiles2 + callfar GetTrainerPic + hlcoord 19, 0 + ld c, 0 + +.outer_loop + inc c + ld a, c + cp 7 + ret z + xor a + ldh [hBGMapMode], a + ldh [hBGMapThird], a + ld d, $0 + push bc + push hl + +.inner_loop + call .CopyColumn + inc hl + ld a, 7 + add d + ld d, a + dec c + jr nz, .inner_loop + + ld a, $1 + ldh [hBGMapMode], a + ld c, 4 + call DelayFrames + pop hl + pop bc + dec hl + jr .outer_loop + +.CopyColumn: + push hl + push de + push bc + ld e, 7 + +.loop + ld [hl], d + ld bc, SCREEN_WIDTH + add hl, bc + inc d + dec e + jr nz, .loop + + pop bc + pop de + pop hl + ret + +ApplyStatusEffectOnPlayerStats: + ld a, 1 + jr ApplyStatusEffectOnStats + +ApplyStatusEffectOnEnemyStats: + xor a + +ApplyStatusEffectOnStats: + ldh [hBattleTurn], a + call ApplyPrzEffectOnSpeed + jp ApplyBrnEffectOnAttack + +ApplyPrzEffectOnSpeed: + ldh a, [hBattleTurn] + and a + jr z, .enemy + ld a, [wBattleMonStatus] + and 1 << PAR + ret z + ld hl, wBattleMonSpeed + 1 + ld a, [hld] + ld b, a + ld a, [hl] + srl a + rr b + srl a + rr b + ld [hli], a + or b + jr nz, .player_ok + ld b, $1 ; min speed + +.player_ok + ld [hl], b + ret + +.enemy + ld a, [wEnemyMonStatus] + and 1 << PAR + ret z + ld hl, wEnemyMonSpeed + 1 + ld a, [hld] + ld b, a + ld a, [hl] + srl a + rr b + srl a + rr b + ld [hli], a + or b + jr nz, .enemy_ok + ld b, $1 ; min speed + +.enemy_ok + ld [hl], b + ret + +ApplyBrnEffectOnAttack: + ldh a, [hBattleTurn] + and a + jr z, .enemy + ld a, [wBattleMonStatus] + and 1 << BRN + ret z + ld hl, wBattleMonAttack + 1 + ld a, [hld] + ld b, a + ld a, [hl] + srl a + rr b + ld [hli], a + or b + jr nz, .player_ok + ld b, $1 ; min attack + +.player_ok + ld [hl], b + ret + +.enemy + ld a, [wEnemyMonStatus] + and 1 << BRN + ret z + ld hl, wEnemyMonAttack + 1 + ld a, [hld] + ld b, a + ld a, [hl] + srl a + rr b + ld [hli], a + or b + jr nz, .enemy_ok + ld b, $1 ; min attack + +.enemy_ok + ld [hl], b + ret + +ApplyStatLevelMultiplierOnAllStats: +; Apply StatLevelMultipliers on all 5 Stats + ld c, 0 +.stat_loop + call ApplyStatLevelMultiplier + inc c + ld a, c + cp NUM_BATTLE_STATS + jr nz, .stat_loop + ret + +ApplyStatLevelMultiplier: + push bc + push bc + ld a, [wApplyStatLevelMultipliersToEnemy] + and a + ld a, c + ld hl, wBattleMonAttack + ld de, wPlayerStats + ld bc, wPlayerAtkLevel + jr z, .got_pointers + ld hl, wEnemyMonAttack + ld de, wEnemyStats + ld bc, wEnemyAtkLevel + +.got_pointers + add c + ld c, a + jr nc, .okay + inc b +.okay + ld a, [bc] + pop bc + ld b, a + push bc + sla c + ld b, 0 + add hl, bc + ld a, c + add e + ld e, a + jr nc, .okay2 + inc d +.okay2 + pop bc + push hl + ld hl, StatLevelMultipliers_Applied + dec b + sla b + ld c, b + ld b, 0 + add hl, bc + xor a + ldh [hMultiplicand + 0], a + ld a, [de] + ldh [hMultiplicand + 1], a + inc de + ld a, [de] + ldh [hMultiplicand + 2], a + ld a, [hli] + ldh [hMultiplier], a + call Multiply + ld a, [hl] + ldh [hDivisor], a + ld b, 4 + call Divide + pop hl + +; Cap at 999. + ldh a, [hQuotient + 3] + sub LOW(MAX_STAT_VALUE) + ldh a, [hQuotient + 2] + sbc HIGH(MAX_STAT_VALUE) + jp c, .okay3 + + ld a, HIGH(MAX_STAT_VALUE) + ldh [hQuotient + 2], a + ld a, LOW(MAX_STAT_VALUE) + ldh [hQuotient + 3], a + +.okay3 + ldh a, [hQuotient + 2] + ld [hli], a + ld b, a + ldh a, [hQuotient + 3] + ld [hl], a + or b + jr nz, .okay4 + inc [hl] + +.okay4 + pop bc + ret + +INCLUDE "data/battle/stat_multipliers_2.asm" + +BadgeStatBoosts: +; Raise the stats of the battle mon in wBattleMon +; depending on which badges have been obtained. + +; Every other badge boosts a stat, starting from the first. +; GlacierBadge also boosts Special Defense, although the relevant code is buggy (see below). + +; ZephyrBadge: Attack +; PlainBadge: Speed +; MineralBadge: Defense +; GlacierBadge: Special Attack and Special Defense + +; The boosted stats are in order, except PlainBadge and MineralBadge's boosts are swapped. + + ld a, [wLinkMode] + and a + ret nz + + ld a, [wJohtoBadges] + +; Swap badges 3 (PlainBadge) and 5 (MineralBadge). + ld d, a + and (1 << PLAINBADGE) + add a + add a + ld b, a + ld a, d + and (1 << MINERALBADGE) + rrca + rrca + ld c, a + ld a, d + and ((1 << ZEPHYRBADGE) | (1 << HIVEBADGE) | (1 << FOGBADGE) | (1 << STORMBADGE) | (1 << GLACIERBADGE) | (1 << RISINGBADGE)) + or b + or c + ld b, a + + ld hl, wBattleMonAttack + ld c, 4 +.CheckBadge: + ld a, b + srl b + call c, BoostStat + inc hl + inc hl +; Check every other badge. + srl b + dec c + jr nz, .CheckBadge +; Check GlacierBadge again for Special Defense. +; This check is buggy because it assumes that a is set by the "ld a, b" in the above loop, +; but it can actually be overwritten by the call to BoostStat. + srl a + call c, BoostStat + ret + +BoostStat: +; Raise stat at hl by 1/8. + + ld a, [hli] + ld d, a + ld e, [hl] + srl d + rr e + srl d + rr e + srl d + rr e + ld a, [hl] + add e + ld [hld], a + ld a, [hl] + adc d + ld [hli], a + +; Cap at 999. + ld a, [hld] + sub LOW(MAX_STAT_VALUE) + ld a, [hl] + sbc HIGH(MAX_STAT_VALUE) + ret c + ld a, HIGH(MAX_STAT_VALUE) + ld [hli], a + ld a, LOW(MAX_STAT_VALUE) + ld [hld], a + ret + +_LoadBattleFontsHPBar: + callfar LoadBattleFontsHPBar + ret + +_LoadHPBar: + callfar LoadHPBar + ret + +Unreferenced_LoadHPExpBarGFX: + ld de, EnemyHPBarBorderGFX + ld hl, vTiles2 tile $6c + lb bc, BANK(EnemyHPBarBorderGFX), 4 + call Get1bpp + ld de, HPExpBarBorderGFX + ld hl, vTiles2 tile $73 + lb bc, BANK(HPExpBarBorderGFX), 6 + call Get1bpp + ld de, ExpBarGFX + ld hl, vTiles2 tile $55 + lb bc, BANK(ExpBarGFX), 8 + jp Get2bpp + +EmptyBattleTextbox: + ld hl, .empty + jp PrintText + +.empty: + text_end + +_BattleRandom:: +; If the normal RNG is used in a link battle it'll desync. +; To circumvent this a shared PRNG is used instead. + +; But if we're in a non-link battle we're safe to use it + ld a, [wLinkMode] + and a + jp z, Random + +; The PRNG operates in streams of 10 values. + +; Which value are we trying to pull? + push hl + push bc + ld a, [wLinkBattleRNCount] + ld c, a + ld b, 0 + ld hl, wLinkBattleRNs + add hl, bc + inc a + ld [wLinkBattleRNCount], a + +; If we haven't hit the end yet, we're good + cp 10 - 1 ; Exclude last value. See the closing comment + ld a, [hl] + pop bc + pop hl + ret c + +; If we have, we have to generate new pseudorandom data +; Instead of having multiple PRNGs, ten seeds are used + push hl + push bc + push af + +; Reset count to 0 + xor a + ld [wLinkBattleRNCount], a + ld hl, wLinkBattleRNs + ld b, 10 ; number of seeds + +; Generate next number in the sequence for each seed +; a[n+1] = (a[n] * 5 + 1) % 256 +.loop + ; get last # + ld a, [hl] + + ; a * 5 + 1 + ld c, a + add a + add a + add c + inc a + + ; update # + ld [hli], a + dec b + jr nz, .loop + +; This has the side effect of pulling the last value first, +; then wrapping around. As a result, when we check to see if +; we've reached the end, we check the one before it. + + pop af + pop bc + pop hl + ret + +Call_PlayBattleAnim_OnlyIfVisible: + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVar + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + ret nz + +Call_PlayBattleAnim: + ld a, e + ld [wFXAnimID], a + ld a, d + ld [wFXAnimID + 1], a + call WaitBGMap + predef_jump PlayBattleAnim + +FinishBattleAnim: + push af + push bc + push de + push hl + ld b, SCGB_BATTLE_COLORS + call GetSGBLayout + call SetPalettes + call DelayFrame + pop hl + pop de + pop bc + pop af + ret + +GiveExperiencePoints: +; Give experience. +; Don't give experience if linked or in the Battle Tower. + ld a, [wLinkMode] + and a + ret nz + + call .EvenlyDivideExpAmongParticipants + xor a + ld [wCurPartyMon], a + ld bc, wPartyMon1Species + +.loop + ld hl, MON_HP + add hl, bc + ld a, [hli] + or [hl] + jp z, .next_mon ; fainted + + push bc + ld hl, wBattleParticipantsNotFainted + ld a, [wCurPartyMon] + ld c, a + ld b, CHECK_FLAG + ld d, 0 + predef SmallFarFlagAction + ld a, c + and a + pop bc + jp z, .next_mon + +; give stat exp + ld hl, MON_STAT_EXP + 1 + add hl, bc + ld d, h + ld e, l + ld hl, wEnemyMonBaseStats - 1 + push bc + ld c, NUM_EXP_STATS +.stat_exp_loop + inc hl + ld a, [de] + add [hl] + ld [de], a + jr nc, .no_carry_stat_exp + dec de + ld a, [de] + inc a + jr z, .stat_exp_maxed_out + ld [de], a + inc de + +.no_carry_stat_exp + push hl + push bc + ld a, MON_PKRUS + call GetPartyParamLocation + ld a, [hl] + and a + pop bc + pop hl + jr z, .stat_exp_awarded + ld a, [de] + add [hl] + ld [de], a + jr nc, .stat_exp_awarded + dec de + ld a, [de] + inc a + jr z, .stat_exp_maxed_out + ld [de], a + inc de + jr .stat_exp_awarded + +.stat_exp_maxed_out + ld a, $ff + ld [de], a + inc de + ld [de], a + +.stat_exp_awarded + inc de + inc de + dec c + jr nz, .stat_exp_loop + xor a + ldh [hMultiplicand + 0], a + ldh [hMultiplicand + 1], a + ld a, [wEnemyMonBaseExp] + ldh [hMultiplicand + 2], a + ld a, [wEnemyMonLevel] + ldh [hMultiplier], a + call Multiply + ld a, 7 + ldh [hDivisor], a + ld b, 4 + call Divide +; Boost Experience for traded Pokemon + pop bc + ld hl, MON_ID + add hl, bc + ld a, [wPlayerID] + cp [hl] + jr nz, .boosted + inc hl + ld a, [wPlayerID + 1] + cp [hl] + ld a, 0 + jr z, .no_boost + +.boosted + call BoostExp + ld a, 1 + +.no_boost +; Boost experience for a Trainer Battle + ld [wStringBuffer2 + 2], a + ld a, [wBattleMode] + dec a + call nz, BoostExp +; Boost experience for Lucky Egg + push bc + ld a, MON_ITEM + call GetPartyParamLocation + ld a, [hl] + cp LUCKY_EGG + call z, BoostExp + ldh a, [hQuotient + 3] + ld [wStringBuffer2 + 1], a + ldh a, [hQuotient + 2] + ld [wStringBuffer2], a + ld a, [wCurPartyMon] + ld hl, wPartyMonNicknames + call GetNick + ld hl, Text_MonGainedExpPoint + call PrintText + ld a, [wStringBuffer2 + 1] + ldh [hQuotient + 3], a + ld a, [wStringBuffer2] + ldh [hQuotient + 2], a + pop bc + call AnimateExpBar + push bc + call LoadTilemapToTempTilemap + pop bc + ld hl, MON_EXP + 2 + add hl, bc + ld d, [hl] + ldh a, [hQuotient + 3] + add d + ld [hld], a + ld d, [hl] + ldh a, [hQuotient + 2] + adc d + ld [hl], a + jr nc, .no_exp_overflow + dec hl + inc [hl] + +.no_exp_overflow + ld a, [wCurPartyMon] + ld e, a + ld d, 0 + ld hl, wPartySpecies + add hl, de + ld a, [hl] + ld [wCurSpecies], a + call GetBaseData + push bc + ld d, MAX_LEVEL + callfar CalcExpAtLevel + pop bc + ld hl, MON_EXP + 2 + add hl, bc + push bc + ldh a, [hQuotient + 1] + ld b, a + ldh a, [hQuotient + 2] + ld c, a + ldh a, [hQuotient + 3] + ld d, a + ld a, [hld] + sub d + ld a, [hld] + sbc c + ld a, [hl] + sbc b + jr c, .not_max_exp + ld a, b + ld [hli], a + ld a, c + ld [hli], a + ld a, d + ld [hld], a + +.not_max_exp +; Check if the mon leveled up + xor a ; PARTYMON + ld [wMonType], a + predef CopyMonToTempMon + callfar CalcLevel + pop bc + ld hl, MON_LEVEL + add hl, bc + ld a, [hl] + cp d + jp z, .next_mon +; <NICKNAME> grew to level ##! + ld [wTempLevel], a + ld a, [wCurPartyLevel] + push af + ld a, d + ld [wCurPartyLevel], a + ld [hl], a + ld hl, MON_SPECIES + add hl, bc + ld a, [hl] + ld [wCurSpecies], a + ld [wTempSpecies], a ; unused? + call GetBaseData + ld hl, MON_MAXHP + 1 + add hl, bc + ld a, [hld] + ld e, a + ld d, [hl] + push de + ld hl, MON_MAXHP + add hl, bc + ld d, h + ld e, l + ld hl, MON_STAT_EXP - 1 + add hl, bc + push bc + ld b, TRUE + predef CalcMonStats + pop bc + pop de + ld hl, MON_MAXHP + 1 + add hl, bc + ld a, [hld] + sub e + ld e, a + ld a, [hl] + sbc d + ld d, a + dec hl + ld a, [hl] + add e + ld [hld], a + ld a, [hl] + adc d + ld [hl], a + ld a, [wCurBattleMon] + ld d, a + ld a, [wCurPartyMon] + cp d + jr nz, .skip_active_mon_update + ld de, wBattleMonHP + ld a, [hli] + ld [de], a + inc de + ld a, [hli] + ld [de], a + ld de, wBattleMonMaxHP + push bc + ld bc, PARTYMON_STRUCT_LENGTH - MON_MAXHP + call CopyBytes + pop bc + ld hl, MON_LEVEL + add hl, bc + ld a, [hl] + ld [wBattleMonLevel], a + ld a, [wPlayerSubStatus5] + bit SUBSTATUS_TRANSFORMED, a + jr nz, .transformed + ld hl, MON_ATK + add hl, bc + ld de, wPlayerStats + ld bc, PARTYMON_STRUCT_LENGTH - MON_ATK + call CopyBytes + +.transformed + xor a ; FALSE + ld [wApplyStatLevelMultipliersToEnemy], a + call ApplyStatLevelMultiplierOnAllStats + callfar ApplyStatusEffectOnPlayerStats + callfar BadgeStatBoosts + callfar UpdatePlayerHUD + call EmptyBattleTextbox + call LoadTilemapToTempTilemap + ld a, $1 + ldh [hBGMapMode], a + +.skip_active_mon_update + ; level up happiness mod + ld c, 1 + callfar ChangeHappiness + ld a, [wCurBattleMon] + ld b, a + ld a, [wCurPartyMon] + cp b + jr z, .skip_exp_bar_animation + ld de, SFX_HIT_END_OF_EXP_BAR + call PlaySFX + call WaitSFX + ld hl, BattleText_StringBuffer1GrewToLevel + call StdBattleTextbox + call LoadTilemapToTempTilemap + +.skip_exp_bar_animation + xor a ; PARTYMON + ld [wMonType], a + predef CopyMonToTempMon + hlcoord 9, 0 + ld b, 10 + ld c, 9 + call Textbox + hlcoord 11, 1 + ld bc, 4 + predef PrintTempMonStats + ld c, 30 + call DelayFrames + call WaitPressAorB_BlinkCursor + call SafeLoadTempTilemapToTilemap + xor a ; PARTYMON + ld [wMonType], a + ld a, [wCurSpecies] + ld [wTempSpecies], a ; unused? + ld a, [wCurPartyLevel] + push af + ld c, a + ld a, [wTempLevel] + ld b, a + +.level_loop + inc b + ld a, b + ld [wCurPartyLevel], a + push bc + predef LearnLevelMoves + pop bc + ld a, b + cp c + jr nz, .level_loop + pop af + ld [wCurPartyLevel], a + ld hl, wEvolvableFlags + ld a, [wCurPartyMon] + ld c, a + ld b, SET_FLAG + predef SmallFarFlagAction + pop af + ld [wCurPartyLevel], a + +.next_mon + ld a, [wPartyCount] + ld b, a + ld a, [wCurPartyMon] + inc a + cp b + jr z, .done + ld [wCurPartyMon], a + ld a, MON_SPECIES + call GetPartyParamLocation + ld b, h + ld c, l + jp .loop + +.done + jp ResetBattleParticipants + +.EvenlyDivideExpAmongParticipants: +; count number of battle participants + ld a, [wBattleParticipantsNotFainted] + ld b, a + ld c, PARTY_LENGTH + ld d, 0 +.count_loop + xor a + srl b + adc d + ld d, a + dec c + jr nz, .count_loop + cp 2 + ret c + + ld [wTempByteValue], a + ld hl, wEnemyMonBaseStats + ld c, wEnemyMonEnd - wEnemyMonBaseStats +.base_stat_division_loop + xor a + ldh [hDividend + 0], a + ld a, [hl] + ldh [hDividend + 1], a + ld a, [wTempByteValue] + ldh [hDivisor], a + ld b, 2 + call Divide + ldh a, [hQuotient + 3] + ld [hli], a + dec c + jr nz, .base_stat_division_loop + ret + +BoostExp: +; Multiply experience by 1.5x + push bc +; load experience value + ldh a, [hProduct + 2] + ld b, a + ldh a, [hProduct + 3] + ld c, a +; halve it + srl b + rr c +; add it back to the whole exp value + add c + ldh [hProduct + 3], a + ldh a, [hProduct + 2] + adc b + ldh [hProduct + 2], a + pop bc + ret + +Text_MonGainedExpPoint: + text_far Text_Gained + text_asm + ld hl, ExpPointsText + ld a, [wStringBuffer2 + 2] ; IsTradedMon + and a + ret z + + ld hl, BoostedExpPointsText + ret + +BoostedExpPointsText: + text_far _BoostedExpPointsText + text_end + +ExpPointsText: + text_far _ExpPointsText + text_end + +AnimateExpBar: + push bc + + ld hl, wCurPartyMon + ld a, [wCurBattleMon] + cp [hl] + jp nz, .finish + + ld a, [wBattleMonLevel] + cp MAX_LEVEL + jp z, .finish + + ldh a, [hProduct + 3] + ld [wceef], a + push af + ldh a, [hProduct + 2] + ld [wceee], a + push af + xor a + ld [wceed], a + xor a ; PARTYMON + ld [wMonType], a + predef CopyMonToTempMon + ld a, [wTempMonLevel] + ld b, a + ld e, a + push de + ld de, wTempMonExp + 2 + call CalcExpBar + push bc + ld hl, wTempMonExp + 2 + ld a, [wceef] + add [hl] + ld [hld], a + ld a, [wceee] + adc [hl] + ld [hld], a + jr nc, .NoOverflow + inc [hl] + +.NoOverflow: + ld d, MAX_LEVEL + callfar CalcExpAtLevel + ldh a, [hProduct + 1] + ld b, a + ldh a, [hProduct + 2] + ld c, a + ldh a, [hProduct + 3] + ld d, a + ld hl, wTempMonExp + 2 + ld a, [hld] + sub d + ld a, [hld] + sbc c + ld a, [hl] + sbc b + jr c, .AlreadyAtMaxExp + ld a, b + ld [hli], a + ld a, c + ld [hli], a + ld a, d + ld [hld], a + +.AlreadyAtMaxExp: + callfar CalcLevel + ld a, d + pop bc + pop de + ld d, a + +.LoopLevels: + ld a, e + cp d + jr z, .FinishExpBar + inc a + ld [wTempMonLevel], a + ld [wCurPartyLevel], a + ld [wBattleMonLevel], a + push de + call .PlayExpBarSound + ld c, $40 + call .LoopBarAnimation + call PrintPlayerHUD + ld hl, wBattleMonNick + ld de, wStringBuffer1 + ld bc, MON_NAME_LENGTH + call CopyBytes + call TerminateExpBarSound + ld de, SFX_HIT_END_OF_EXP_BAR + call PlaySFX + farcall AnimateEndOfExpBar + call WaitSFX + ld hl, BattleText_StringBuffer1GrewToLevel + call StdBattleTextbox + pop de + inc e + ld b, $0 + jr .LoopLevels + +.FinishExpBar: + push bc + ld b, d + ld de, wTempMonExp + 2 + call CalcExpBar + ld a, b + pop bc + ld c, a + call .PlayExpBarSound + call .LoopBarAnimation + call TerminateExpBarSound + pop af + ldh [hProduct + 2], a + pop af + ldh [hProduct + 3], a + +.finish + pop bc + ret + +.PlayExpBarSound: + push bc + call WaitSFX + ld de, SFX_EXP_BAR + call PlaySFX + ld c, 10 + call DelayFrames + pop bc + ret + +.LoopBarAnimation: + ld d, 3 + dec b +.anim_loop + inc b + push bc + push de + hlcoord 17, 11 + call PlaceExpBar + pop de + ld a, $1 + ldh [hBGMapMode], a + ld c, d + call DelayFrames + xor a + ldh [hBGMapMode], a + pop bc + ld a, c + cp b + jr z, .end_animation + inc b + push bc + push de + hlcoord 17, 11 + call PlaceExpBar + pop de + ld a, $1 + ldh [hBGMapMode], a + ld c, d + call DelayFrames + xor a + ldh [hBGMapMode], a + dec d + jr nz, .min_number_of_frames + ld d, 1 +.min_number_of_frames + pop bc + ld a, c + cp b + jr nz, .anim_loop +.end_animation + ld a, $1 + ldh [hBGMapMode], a + ret + +SendOutMonText: + ld a, [wLinkMode] + and a + jr z, .not_linked + + ld hl, JumpText_GoMon ; If we're in a LinkBattle print just "Go <PlayerMon>" + + ld a, [wBattleHasJustStarted] ; unless this (unidentified) variable is set + and a + jr nz, .skip_to_textbox + +.not_linked +; Depending on the HP of the enemy mon, the game prints a different text + ld hl, wEnemyMonHP + ld a, [hli] + or [hl] + ld hl, JumpText_GoMon + jr z, .skip_to_textbox + + ; compute enemy helth remaining as a percentage + xor a + ldh [hMultiplicand + 0], a + ld hl, wEnemyMonHP + ld a, [hli] + ld [wEnemyHPAtTimeOfPlayerSwitch], a + ldh [hMultiplicand + 1], a + ld a, [hl] + ld [wEnemyHPAtTimeOfPlayerSwitch + 1], a + ldh [hMultiplicand + 2], a + ld a, 25 + ldh [hMultiplier], a + call Multiply + ld hl, wEnemyMonMaxHP + ld a, [hli] + ld b, [hl] + srl a + rr b + srl a + rr b + ld a, b + ld b, 4 + ldh [hDivisor], a + call Divide + + ldh a, [hQuotient + 3] + ld hl, JumpText_GoMon + cp 70 + jr nc, .skip_to_textbox + + ld hl, JumpText_DoItMon + cp 40 + jr nc, .skip_to_textbox + + ld hl, JumpText_GoForItMon + cp 10 + jr nc, .skip_to_textbox + + ld hl, JumpText_YourFoesWeakGetmMon +.skip_to_textbox + jp PrintText + +JumpText_GoMon: + text_far Text_GoMon + text_end + +JumpText_DoItMon: + text_far Text_DoItMon + text_end + +JumpText_GoForItMon: + text_far Text_GoForItMon + text_end + +JumpText_YourFoesWeakGetmMon: + text_far Text_YourFoesWeakGetmMon + text_end + +WithdrawMonText: + ld hl, .WithdrawMonText + jp PrintText + +.WithdrawMonText: + text_far Text_BattleMonNickComma + text_asm +; Print text to withdraw mon +; depending on HP the message is different + push de + push bc + ld hl, wEnemyMonHP + 1 + ld de, wEnemyHPAtTimeOfPlayerSwitch + 1 + ld b, [hl] + dec hl + ld a, [de] + sub b + ldh [hMultiplicand + 2], a + dec de + ld b, [hl] + ld a, [de] + sbc b + ldh [hMultiplicand + 1], a + ld a, 25 + ldh [hMultiplier], a + call Multiply + ld hl, wEnemyMonMaxHP + ld a, [hli] + ld b, [hl] + srl a + rr b + srl a + rr b + ld a, b + ld b, 4 + ldh [hDivisor], a + call Divide + pop bc + pop de + ldh a, [hQuotient + 3] + ld hl, ThatsEnoughComeBackText + and a + ret z + + ld hl, ComeBackText + cp 30 + ret c + + ld hl, OKComeBackText + cp 70 + ret c + + ld hl, GoodComeBackText + ret + +ThatsEnoughComeBackText: + text_far _ThatsEnoughComeBackText + text_end + +OKComeBackText: + text_far _OKComeBackText + text_end + +GoodComeBackText: + text_far _GoodComeBackText + text_end + +ComeBackText: + text_far _ComeBackText + text_end + +Unreferenced_HandleSafariAngerEatingStatus: + ld hl, wSafariMonEating + ld a, [hl] + and a + jr z, .angry + dec [hl] + ld hl, BattleText_WildMonIsEating + jr .finish + +.angry + dec hl ; wSafariMonAngerCount + ld a, [hl] + and a + ret z + dec [hl] + ld hl, BattleText_WildMonIsAngry + jr nz, .finish + push hl + ld a, [wEnemyMonSpecies] + ld [wCurSpecies], a + call GetBaseData + ld a, [wBaseCatchRate] + ld [wEnemyMonCatchRate], a + pop hl + +.finish + push hl + call SafeLoadTempTilemapToTilemap + pop hl + jp StdBattleTextbox + +FillInExpBar: + push hl + call CalcExpBar + pop hl + ld de, 7 + add hl, de + jp PlaceExpBar + +CalcExpBar: +; Calculate the percent exp between this level and the next +; Level in b + push de + ld d, b + push de + callfar CalcExpAtLevel + pop de +; exp at current level gets pushed to the stack + ld hl, hMultiplicand + ld a, [hli] + push af + ld a, [hli] + push af + ld a, [hl] + push af +; next level + inc d + callfar CalcExpAtLevel +; back up the next level exp, and subtract the two levels + ld hl, hMultiplicand + 2 + ld a, [hl] + ldh [hMathBuffer + 2], a + pop bc + sub b + ld [hld], a + ld a, [hl] + ldh [hMathBuffer + 1], a + pop bc + sbc b + ld [hld], a + ld a, [hl] + ldh [hMathBuffer], a + pop bc + sbc b + ld [hl], a + pop de + + ld hl, hMultiplicand + 1 + ld a, [hli] + push af + ld a, [hl] + push af + +; get the amount of exp remaining to the next level + ld a, [de] + dec de + ld c, a + ldh a, [hMathBuffer + 2] + sub c + ld [hld], a + ld a, [de] + dec de + ld b, a + ldh a, [hMathBuffer + 1] + sbc b + ld [hld], a + ld a, [de] + ld c, a + ldh a, [hMathBuffer] + sbc c + ld [hld], a + xor a + ld [hl], a + ld a, 64 + ldh [hMultiplier], a + call Multiply + pop af + ld c, a + pop af + ld b, a +.loop + ld a, b + and a + jr z, .done + srl b + rr c + ld hl, hProduct + srl [hl] + inc hl + rr [hl] + inc hl + rr [hl] + inc hl + rr [hl] + jr .loop + +.done + ld a, c + ldh [hDivisor], a + ld b, 4 + call Divide + ldh a, [hQuotient + 3] + ld b, a + ld a, $40 + sub b + ld b, a + ret + +PlaceExpBar: + ld c, $8 ; number of tiles +.loop1 + ld a, b + sub $8 + jr c, .next + ld b, a + ld a, $6a ; full bar + ld [hld], a + dec c + jr z, .finish + jr .loop1 + +.next + add $8 + jr z, .loop2 + add $54 ; tile to the left of small exp bar tile + jr .skip + +.loop2 + ld a, $62 ; empty bar + +.skip + ld [hld], a + ld a, $62 ; empty bar + dec c + jr nz, .loop2 + +.finish + ret + +GetBattleMonBackpic: + ld a, [wPlayerSubStatus4] + bit SUBSTATUS_SUBSTITUTE, a + ld hl, BattleAnimCmd_RaiseSub + jr nz, GetBattleMonBackpic_DoAnim ; substitute + +DropPlayerSub: + ld a, [wPlayerMinimized] + and a + ld hl, BattleAnimCmd_MinimizeOpp + jr nz, GetBattleMonBackpic_DoAnim + ld a, [wCurPartySpecies] + push af + ld a, [wBattleMonSpecies] + ld [wCurPartySpecies], a + ld hl, wBattleMonDVs + predef GetUnownLetter + ld de, vTiles2 tile $31 + predef GetMonBackpic + pop af + ld [wCurPartySpecies], a + ret + +GetBattleMonBackpic_DoAnim: + ldh a, [hBattleTurn] + push af + xor a + ldh [hBattleTurn], a + ld a, BANK("Move Animations") + rst FarCall + pop af + ldh [hBattleTurn], a + ret + +GetEnemyMonFrontpic: + ld a, [wEnemySubStatus4] + bit SUBSTATUS_SUBSTITUTE, a + ld hl, BattleAnimCmd_RaiseSub + jr nz, GetEnemyMonFrontpic_DoAnim + +DropEnemySub: + ld a, [wEnemyMinimized] + and a + ld hl, BattleAnimCmd_MinimizeOpp + jr nz, GetEnemyMonFrontpic_DoAnim + + ld a, [wCurPartySpecies] + push af + ld a, [wEnemyMonSpecies] + ld [wCurSpecies], a + ld [wCurPartySpecies], a + call GetBaseData + ld hl, wEnemyMonDVs + predef GetUnownLetter + ld de, vTiles2 + predef GetMonFrontpic + pop af + ld [wCurPartySpecies], a + ret + +GetEnemyMonFrontpic_DoAnim: + ldh a, [hBattleTurn] + push af + call SetEnemyTurn + ld a, BANK(BattleAnimCmd_MinimizeOpp) + rst FarCall + pop af + ldh [hBattleTurn], a + ret + +StartBattle: +; This check prevents you from entering a battle without any Pokemon. +; Those using walk-through-walls to bypass getting a Pokemon experience +; the effects of this check. + ld a, [wPartyCount] + and a + ret z + + ld a, [wOtherTrainerClass] + and a + jr nz, .battle_intro + + ld a, [wTempWildMonSpecies] + ld [wCurPartySpecies], a + +.battle_intro + ld [wTempEnemyMonSpecies], a + ld a, [wTimeOfDayPal] + push af + xor a + ldh [hMapAnims], a + xor a + ld [wTempBattleMonSpecies], a + ld [wBattleMenuCursorBuffer], a + farcall PlayBattleMusic + ld a, 0 + ld [wSpriteUpdatesEnabled], a + call ShowLinkBattleParticipants + farcall ClearBattleRAM + ld hl, rLCDC + res rLCDC_WINDOW_TILEMAP, [hl] ; select 9800-9BFF + ld a, [wOtherTrainerClass] + and a + jr nz, .trainer + + call InitEnemyWildmon + jr .back_up_bgmap2 + +.trainer + call InitEnemyTrainer + +.back_up_bgmap2 + ld b, 0 + call GetSGBLayout + ld hl, wVramState + res 0, [hl] + call InitBattleDisplay + call BattleStartMessage + xor a + ldh [hBGMapMode], a + ld hl, rLCDC + set rLCDC_WINDOW_TILEMAP, [hl] ; select 9C00-9FFF + call EmptyBattleTextbox + hlcoord 9, 7 + lb bc, 5, 11 + call ClearBox + hlcoord 1, 0 + lb bc, 4, 10 + call ClearBox + call ClearSprites + ld a, [wEnemyMonEnd] + cp WILD_BATTLE + call z, UpdateEnemyHUD + ld a, $1 + ldh [hBGMapMode], a + call DoBattle + call ExitBattle + pop af + ld [wTimeOfDayPal], a + scf + ret + +InitEnemyTrainer: + ld [wTrainerClass], a + xor a + ld [wTempEnemyMonSpecies], a + callfar GetTrainerAttributes + callfar ReadTrainerParty + + ; RIVAL1's first mon has no held item + ld a, [wTrainerClass] + cp RIVAL1 + jr nz, .ok + xor a + ld [wOTPartyMon1Item], a + +.ok: + ld de, vTiles2 + callfar GetTrainerPic + xor a + ldh [hGraphicStartTile], a + dec a + ld [wEnemyItemState], a + hlcoord 12, 0 + lb bc, 7, 7 + predef PlaceGraphic + ld a, -1 + ld [wCurOTMon], a + ld a, TRAINER_BATTLE + ld [wBattleMode], a + + call IsGymLeader + jr nc, .done + xor a + ld [wCurPartyMon], a + ld a, [wPartyCount] + ld b, a +.partyloop + push bc + ld a, MON_HP + call GetPartyParamLocation + ld a, [hli] + or [hl] + jr z, .skipfaintedmon + ld c, HAPPINESS_GYMBATTLE + callfar ChangeHappiness +.skipfaintedmon + pop bc + dec b + jr z, .done + ld hl, wCurPartyMon + inc [hl] + jr .partyloop +.done + ret + +InitEnemyWildmon: + ld a, WILD_BATTLE + ld [wBattleMode], a + call LoadEnemyMon + ld hl, wEnemyMonMoves + ld de, wWildMonMoves + ld bc, NUM_MOVES + call CopyBytes + ld hl, wEnemyMonPP + ld de, wWildMonPP + ld bc, NUM_MOVES + call CopyBytes + ld hl, wEnemyMonDVs + predef GetUnownLetter + ld a, [wCurPartySpecies] + cp UNOWN + jr nz, .skip_unown + ld a, [wFirstUnownSeen] + and a + jr nz, .skip_unown + ld a, [wUnownLetter] + ld [wFirstUnownSeen], a +.skip_unown + ld de, vTiles2 + predef GetMonFrontpic + xor a + ld [wTrainerClass], a + ldh [hGraphicStartTile], a + hlcoord 12, 0 + lb bc, 7, 7 + predef PlaceGraphic + ret + +Unreferenced_Function3f41a: + ld hl, wEnemyMonMoves + ld de, wListMoves_MoveIndicesBuffer + ld b, NUM_MOVES +.loop + ld a, [de] + inc de + ld [hli], a + and a + jr z, .clearpp + + push bc + push hl + + push hl + dec a + ld hl, Moves + MOVE_PP + ld bc, MOVE_LENGTH + call AddNTimes + ld a, BANK(Moves) + call GetFarByte + pop hl + + ld bc, wEnemyMonPP - (wEnemyMonMoves + 1) + add hl, bc + ld [hl], a + + pop hl + pop bc + + dec b + jr nz, .loop + ret + +.clear + xor a + ld [hli], a + +.clearpp + push bc + push hl + ld bc, wEnemyMonPP - (wEnemyMonMoves + 1) + add hl, bc + xor a + ld [hl], a + pop hl + pop bc + dec b + jr nz, .clear + ret + +ExitBattle: + call IsLinkBattle + jr nz, .handle_end_of_battle + call ShowLinkBattleParticipantsAfterEnd + jr .clean_up_battle_ram + +.handle_end_of_battle + ld a, [wBattleResult] + and $f + jr nz, .clean_up_battle_ram + ; WIN + call CheckPayDay + xor a + ld [wForceEvolution], a + predef EvolveAfterBattle + farcall GivePokerusAndConvertBerries + +.clean_up_battle_ram + call BattleEnd_HandleRoamMons + xor a + ld [wLowHealthAlarm], a + ld [wBattleMode], a + ld [wBattleType], a + ld [wAttackMissed], a + ld [wTempWildMonSpecies], a + ld [wOtherTrainerClass], a + ld [wFailedToFlee], a + ld [wNumFleeAttempts], a + ld [wForcedSwitch], a + ld [wPartyMenuCursor], a + ld [wKeyItemsPocketCursor], a + ld [wItemsPocketCursor], a + ld [wBattleMenuCursorBuffer], a + ld [wCurMoveNum], a + ld [wBallsPocketCursor], a + ld [wLastPocket], a + ld [wMenuScrollPosition], a + ld [wKeyItemsPocketScrollPosition], a + ld [wItemsPocketScrollPosition], a + ld [wBallsPocketScrollPosition], a + ld hl, wPlayerSubStatus1 + ld b, wEnemyFuryCutterCount - wPlayerSubStatus1 +.loop + ld [hli], a + dec b + jr nz, .loop + call WaitSFX + ret + +CheckPayDay: + ld hl, wPayDayMoney + ld a, [hli] + or [hl] + inc hl + or [hl] + ret z + ld a, [wAmuletCoin] + and a + jr z, .okay + ld hl, wPayDayMoney + 2 + sla [hl] + dec hl + rl [hl] + dec hl + rl [hl] + jr nc, .okay + ld a, $ff + ld [hli], a + ld [hli], a + ld [hl], a + +.okay + ld hl, wPayDayMoney + 2 + ld de, wMoney + 2 + call AddBattleMoneyToAccount + ld hl, BattleText_PlayerPickedUpPayDayMoney + call StdBattleTextbox + ret + +PlayerPickedUpPayDayMoney: + text_far _PlayerPickedUpPayDayMoney + text_end + +ShowLinkBattleParticipantsAfterEnd: + ld a, [wCurOTMon] + ld hl, wOTPartyMon1Status + call GetPartyLocation + ld a, [wEnemyMonStatus] + ld [hl], a + call ClearTilemap + farcall _ShowLinkBattleParticipants + ld a, [wBattleResult] + and $f + cp LOSE + ld de, .Win + jr c, .store_result + ld de, .Lose + jr z, .store_result + ; DRAW + ld de, .Draw + +.store_result + hlcoord 6, 8 + call PlaceString + ld c, 200 + call DelayFrames + + ld a, BANK(sLinkBattleStats) + call OpenSRAM + + call AddLastMobileBattleToLinkRecord + call ReadAndPrintLinkBattleRecord + + call CloseSRAM + + call WaitPressAorB_BlinkCursor + call ClearTilemap + ret + +.Win: + db "YOU WIN@" +.Lose: + db "YOU LOSE@" +.Draw: + db " DRAW@" + +_DisplayLinkRecord: + ld a, BANK(sLinkBattleStats) + call OpenSRAM + + call ReadAndPrintLinkBattleRecord + + call CloseSRAM + hlcoord 0, 0, wAttrmap + xor a + ld bc, SCREEN_WIDTH * SCREEN_HEIGHT + call ByteFill + call WaitBGMap2 + ld b, SCGB_DIPLOMA + call GetSGBLayout + call SetPalettes + ld c, 8 + call DelayFrames + call WaitPressAorB_BlinkCursor + ret + +ReadAndPrintLinkBattleRecord: + call ClearTilemap + call ClearSprites + call .PrintBattleRecord + hlcoord 0, 8 + ld b, 5 + ld de, sLinkBattleRecord + 2 +.loop + push bc + push hl + push de + ld a, [de] + and a + jr z, .PrintFormatString + ld a, [wSavedAtLeastOnce] + and a + jr z, .PrintFormatString + push hl + push hl + ld h, d + ld l, e + ld de, wceed + ld bc, 10 + call CopyBytes + ld a, "@" + ld [de], a + inc de + ld bc, 6 + call CopyBytes + ld de, wceed + pop hl + call PlaceString + pop hl + ld de, 26 + add hl, de + push hl + ld de, wcef8 + lb bc, 2, 4 + call PrintNum + pop hl + ld de, 5 + add hl, de + push hl + ld de, wcefa + lb bc, 2, 4 + call PrintNum + pop hl + ld de, 5 + add hl, de + ld de, wcefc + lb bc, 2, 4 + call PrintNum + jr .next + +.PrintFormatString: + ld de, .Format + call PlaceString +.next + pop hl + ld bc, 18 + add hl, bc + ld d, h + ld e, l + pop hl + ld bc, 2 * SCREEN_WIDTH + add hl, bc + pop bc + dec b + jr nz, .loop + ret + +.PrintBattleRecord: + hlcoord 1, 0 + ld de, .Record + call PlaceString + + hlcoord 0, 6 + ld de, .Result + call PlaceString + + hlcoord 0, 2 + ld de, .Total + call PlaceString + + hlcoord 6, 4 + ld de, sLinkBattleWins + call .PrintZerosIfNoSaveFileExists + + lb bc, 2, 4 + call PrintNum + + hlcoord 11, 4 + ld de, sLinkBattleLosses + call .PrintZerosIfNoSaveFileExists + + lb bc, 2, 4 + call PrintNum + + hlcoord 16, 4 + ld de, sLinkBattleDraws + call .PrintZerosIfNoSaveFileExists + + lb bc, 2, 4 + call PrintNum + +.quit + ret + +.PrintZerosIfNoSaveFileExists: + ld a, [wSavedAtLeastOnce] + and a + ret nz + ld de, .Scores + ret + +.Scores: + db "<NULL><NULL>" +.Format: + db " --- <LF>" + db " - - -@" +.Record: + db "<PLAYER>'s RECORD@" +.Result: + db "RESULT WIN LOSE DRAW@" +.Total: + db "TOTAL WIN LOSE DRAW@" + +BattleEnd_HandleRoamMons: + ld a, [wBattleType] + cp BATTLETYPE_ROAMING + jr nz, .not_roaming + ld a, [wBattleResult] + and $f + jr z, .caught_or_defeated_roam_mon ; WIN + call GetRoamMonHP + ld a, [wEnemyMonHP + 1] + ld [hl], a + jr .update_roam_mons + +.caught_or_defeated_roam_mon + call GetRoamMonHP + ld [hl], 0 + call GetRoamMonMapGroup + ld [hl], GROUP_N_A + call GetRoamMonMapNumber + ld [hl], MAP_N_A + call GetRoamMonSpecies + ld [hl], 0 + ret + +.not_roaming + call BattleRandom + and $f + ret nz + +.update_roam_mons + callfar UpdateRoamMons + ret + +GetRoamMonMapGroup: + ld a, [wTempEnemyMonSpecies] + ld b, a + ld a, [wRoamMon1Species] + cp b + ld hl, wRoamMon1MapGroup + ret z + ld a, [wRoamMon2Species] + cp b + ld hl, wRoamMon2MapGroup + ret z + ld hl, wRoamMon3MapGroup + ret + +GetRoamMonMapNumber: + ld a, [wTempEnemyMonSpecies] + ld b, a + ld a, [wRoamMon1Species] + cp b + ld hl, wRoamMon1MapNumber + ret z + ld a, [wRoamMon2Species] + cp b + ld hl, wRoamMon2MapNumber + ret z + ld hl, wRoamMon3MapNumber + ret + +GetRoamMonHP: +; output: hl = wRoamMonHP + ld a, [wTempEnemyMonSpecies] + ld b, a + ld a, [wRoamMon1Species] + cp b + ld hl, wRoamMon1HP + ret z + ld a, [wRoamMon2Species] + cp b + ld hl, wRoamMon2HP + ret z + ld hl, wRoamMon3HP + ret + +GetRoamMonDVs: +; output: hl = wRoamMonDVs + ld a, [wTempEnemyMonSpecies] + ld b, a + ld a, [wRoamMon1Species] + cp b + ld hl, wRoamMon1DVs + ret z + ld a, [wRoamMon2Species] + cp b + ld hl, wRoamMon2DVs + ret z + ld hl, wRoamMon3DVs + ret + +GetRoamMonSpecies: + ld a, [wTempEnemyMonSpecies] + ld hl, wRoamMon1Species + cp [hl] + ret z + ld hl, wRoamMon2Species + cp [hl] + ret z + ld hl, wRoamMon3Species + ret + +AddLastMobileBattleToLinkRecord: + ld hl, wOTPlayerID + ld de, wStringBuffer1 + ld bc, 2 + call CopyBytes + ld hl, wOTPlayerName + ld bc, NAME_LENGTH - 1 + call CopyBytes + ld hl, sLinkBattleStats - 12 + call .StoreResult + ld hl, sLinkBattleRecord + ld d, 5 +.loop + push hl + inc hl + inc hl + ld a, [hl] + dec hl + dec hl + and a + jr z, .copy + push de + ld bc, 12 + ld de, wStringBuffer1 + call CompareBytesLong + pop de + pop hl + jr c, .done + ld bc, 18 + add hl, bc + dec d + jr nz, .loop + ld bc, -18 + add hl, bc + push hl + +.copy + ld d, h + ld e, l + ld hl, wStringBuffer1 + ld bc, 12 + call CopyBytes + ld b, 6 + xor a +.loop2 + ld [de], a + inc de + dec b + jr nz, .loop2 + pop hl + +.done + call .StoreResult + call .FindOpponentAndAppendRecord + ret +.StoreResult: + ld a, [wBattleResult] + and $f + cp LOSE + ld bc, sLinkBattleWins + 1 - (sLinkBattleStats - 12) + jr c, .okay ; WIN + ld bc, sLinkBattleLosses + 1 - (sLinkBattleStats - 12) + jr z, .okay ; LOSE + ; DRAW + ld bc, sLinkBattleDraws + 1 - (sLinkBattleStats - 12) +.okay + add hl, bc + call .CheckOverflow + ret nc + inc [hl] + ret nz + dec hl + inc [hl] + ret + +.CheckOverflow: + dec hl + ld a, [hl] + inc hl + cp HIGH(MAX_LINK_RECORD) + ret c + ld a, [hl] + cp LOW(MAX_LINK_RECORD) + ret + +.FindOpponentAndAppendRecord: + ld b, 5 + ld hl, sLinkBattleRecord + 17 + ld de, wceed +.loop3 + push bc + push de + push hl + call .LoadPointer + pop hl + ld a, e + pop de + ld [de], a + inc de + ld a, b + ld [de], a + inc de + ld a, c + ld [de], a + inc de + ld bc, 18 + add hl, bc + pop bc + dec b + jr nz, .loop3 + ld b, $0 + ld c, $1 +.loop4 + ld a, b + add b + add b + ld e, a + ld d, $0 + ld hl, wceed + add hl, de + push hl + ld a, c + add c + add c + ld e, a + ld d, $0 + ld hl, wceed + add hl, de + ld d, h + ld e, l + pop hl + push bc + ld c, 3 + call CompareBytes + pop bc + jr z, .equal + jr nc, .done2 + +.equal + inc c + ld a, c + cp $5 + jr nz, .loop4 + inc b + ld c, b + inc c + ld a, b + cp $4 + jr nz, .loop4 + ret + +.done2 + push bc + ld a, b + ld bc, 18 + ld hl, sLinkBattleRecord + call AddNTimes + push hl + ld de, wceed + ld bc, 18 + call CopyBytes + pop hl + pop bc + push hl + ld a, c + ld bc, 18 + ld hl, sLinkBattleRecord + call AddNTimes + pop de + push hl + ld bc, 18 + call CopyBytes + ld hl, wceed + ld bc, 18 + pop de + call CopyBytes + ret + +.LoadPointer: + ld e, $0 + ld a, [hld] + ld c, a + ld a, [hld] + ld b, a + ld a, [hld] + add c + ld c, a + ld a, [hld] + adc b + ld b, a + jr nc, .okay2 + inc e + +.okay2 + ld a, [hld] + add c + ld c, a + ld a, [hl] + adc b + ld b, a + ret nc + inc e + ret + +InitBattleDisplay: + call InitBackPic + hlcoord 0, 12 + ld b, 4 + ld c, 18 + call Textbox + hlcoord 1, 5 + lb bc, 3, 7 + call ClearBox + call LoadStandardFont + call _LoadBattleFontsHPBar + call .BlankBGMap + xor a + ldh [hMapAnims], a + ldh [hSCY], a + ld a, $90 + ldh [hWY], a + ldh [rWY], a + call WaitBGMap + xor a + ldh [hBGMapMode], a + call BattleIntroSlidingPics + ld a, $1 + ldh [hBGMapMode], a + ld a, $31 + ldh [hGraphicStartTile], a + hlcoord 2, 6 + lb bc, 6, 6 + predef PlaceGraphic + xor a + ldh [hWY], a + ldh [rWY], a + call WaitBGMap + call HideSprites + ld b, SCGB_BATTLE_COLORS + call GetSGBLayout + call SetPalettes + ld a, $90 + ldh [hWY], a + xor a + ldh [hSCX], a + ret + +.BlankBGMap: + ld a, BANK(sDecompressScratch) + call OpenSRAM + + ld hl, sDecompressScratch + ld bc, sScratchAttrmap - sDecompressScratch + ld a, " " + call ByteFill + + ld de, sDecompressScratch + hlbgcoord 0, 0 + lb bc, BANK(.BlankBGMap), $40 + call Request2bpp + call CloseSRAM + ret + +INCLUDE "engine/battle/sliding_intro.asm" + +InitBackPic: + call GetTrainerBackpic + call CopyBackpic + ret + +GetTrainerBackpic: + ld hl, ChrisBackpic + ld a, [wBattleType] + cp BATTLETYPE_TUTORIAL + jr nz, .ok + ld hl, DudeBackpic + +.ok: + ld de, vTiles2 tile $31 + ld b, BANK(ChrisBackpic) + ld c, 7 * 7 + predef DecompressGet2bpp + ret + +CopyBackpic: + ld a, BANK(sDecompressBuffer) + call OpenSRAM + ld hl, vTiles3 + ld de, sDecompressBuffer + ldh a, [hROMBank] + ld b, a + ld c, 7 * 7 + call Request2bpp + call CloseSRAM + call .LoadTrainerBackpicAsOAM + ld a, 7 * 7 + ldh [hGraphicStartTile], a + hlcoord 2, 6 + lb bc, 6, 6 + predef PlaceGraphic + ret + +.LoadTrainerBackpicAsOAM: + ld hl, wVirtualOAMSprite00 + xor a + ldh [hMapObjectIndexBuffer], a + ld b, 6 + ld e, (SCREEN_WIDTH + 1) * TILE_WIDTH +.outer_loop + ld c, 3 + ld d, 8 * TILE_WIDTH +.inner_loop + ld [hl], d ; y + inc hl + ld [hl], e ; x + inc hl + ldh a, [hMapObjectIndexBuffer] + ld [hli], a ; tile id + inc a + ldh [hMapObjectIndexBuffer], a + ld a, PAL_BATTLE_OB_PLAYER + ld [hli], a ; attributes + ld a, d + add 1 * TILE_WIDTH + ld d, a + dec c + jr nz, .inner_loop + ldh a, [hMapObjectIndexBuffer] + add $3 + ldh [hMapObjectIndexBuffer], a + ld a, e + add 1 * TILE_WIDTH + ld e, a + dec b + jr nz, .outer_loop + ret + +ChrisBackpic: +INCBIN "gfx/player/chris_back.2bpp.lz" + +DudeBackpic: +INCBIN "gfx/battle/dude.2bpp.lz" + +BattleStartMessage: + ld a, [wBattleMode] + dec a + jr z, .wild + + ld de, SFX_SHINE + call PlaySFX + call WaitSFX + + ld c, 20 + call DelayFrames + + callfar Battle_GetTrainerName + + ld hl, WantsToBattleText + jr .PlaceBattleStartText + +.wild + call BattleCheckEnemyShininess + jr nc, .not_shiny + + xor a + ld [wNumHits], a + ld a, 1 + ldh [hBattleTurn], a + ld a, 1 + ld [wBattleAnimParam], a + ld de, ANIM_SEND_OUT_MON + call Call_PlayBattleAnim + +.not_shiny + ld a, $f + ld [wCryTracks], a + ld a, [wTempEnemyMonSpecies] + call PlayStereoCry + ld hl, HookedPokemonAttackedText + ld a, [wBattleType] + cp BATTLETYPE_FISH + jr z, .PlaceBattleStartText + ld hl, PokemonFellFromTreeText + cp BATTLETYPE_TREE + jr z, .PlaceBattleStartText + ld hl, WildPokemonAppearedText + +.PlaceBattleStartText: + push hl + farcall BattleStart_TrainerHuds + pop hl + call StdBattleTextbox + ret + +ShowLinkBattleParticipants: + call IsLinkBattle + jr nz, .ok + farcall _ShowLinkBattleParticipants + call ClearTilemap + call ClearSprites + +.ok + xor a + ldh [hMapAnims], a + call DelayFrame + predef DoBattleTransition + call _LoadBattleFontsHPBar + ld a, $1 + ldh [hBGMapMode], a + call ClearSprites + call ClearTilemap + xor a + ldh [hBGMapMode], a + ldh [hWY], a + ldh [rWY], a + ldh [hMapAnims], a + ret + +IsLinkBattle: + push bc + push af + ld a, [wLinkMode] + cp LINK_COLOSSEUM + pop bc + ld a, b + pop bc + ret diff --git a/engine/battle/sliding_intro.asm b/engine/battle/sliding_intro.asm new file mode 100644 index 00000000..f872a8de --- /dev/null +++ b/engine/battle/sliding_intro.asm @@ -0,0 +1,57 @@ +BattleIntroSlidingPics: + ld b, $70 + ld c, $90 + ld a, c + ldh [hSCX], a + call DelayFrame + ld a, %11100100 + call DmgToCgbBGPals + lb de, %11100100, %11100100 + call DmgToCgbObjPals + +.loop1 + push bc + ld h, b + ld l, $40 + call .subfunction2 + ld h, $00 + ld l, $60 + call .subfunction2 + call .subfunction1 + pop bc + ld a, c + ldh [hSCX], a + inc b + inc b + dec c + dec c + jr nz, .loop1 + ret + +.subfunction1 + push bc + ld hl, wVirtualOAMSprite00XCoord + ld c, $12 ; 18 + ld de, SPRITEOAMSTRUCT_LENGTH +.loop2 + dec [hl] + dec [hl] + add hl, de + dec c + jr nz, .loop2 + pop bc + ret + +.subfunction2 +.loop3 + ldh a, [rLY] + cp l + jr nz, .loop3 + ld a, h + ldh [rSCX], a + +.loop4 + ldh a, [rLY] + cp h + jr z, .loop4 + ret diff --git a/engine/events/specials.asm b/engine/events/specials.asm index 605346b4..e030f68a 100755 --- a/engine/events/specials.asm +++ b/engine/events/specials.asm @@ -241,7 +241,7 @@ UnownPrinter: ; c427 (3:4427) DisplayLinkRecord: ; c434 (3:4434) call FadeToMenu - farcall Function3f55d + farcall _DisplayLinkRecord call ExitAllMenus ret diff --git a/engine/items/item_effects.asm b/engine/items/item_effects.asm index 6735ec16..ac360409 100755 --- a/engine/items/item_effects.asm +++ b/engine/items/item_effects.asm @@ -1023,7 +1023,7 @@ WaterStone: ; ee63 cp EVERSTONE jr z, .failed ld a, $1 - ld [wd0d2], a + ld [wForceEvolution], a farcall EvolvePokemon ; 10:61db ld a, [wd154] and a @@ -1218,7 +1218,7 @@ RareCandy: ; ef68 (3:6f68) ld [wd151], a predef LearnLevelMoves xor a - ld [wd0d2], a + ld [wForceEvolution], a farcall EvolvePokemon jp Functionf7dc @@ -2307,7 +2307,7 @@ Functionf6f6: ; f6f6 (3:76f6) jr z, .asm_f715 call Functionf72f jr z, .asm_f715 - ld hl, wcee1 + ld hl, wMenuCursorX inc [hl] .asm_f715 ld hl, wMenuCursorY @@ -2315,7 +2315,7 @@ Functionf6f6: ; f6f6 (3:76f6) pop bc dec b jr nz, .asm_f6fe - ld a, [wcee1] + ld a, [wMenuCursorX] and a jp nz, asm_f699 Functionf724: ; f724 (3:7724) diff --git a/engine/items/pack.asm b/engine/items/pack.asm index 8edd2555..5225362a 100755 --- a/engine/items/pack.asm +++ b/engine/items/pack.asm @@ -13,7 +13,7 @@ Pack: .asm_1044a ld a, [wce65] - ld [wcfc8], a + ld [wLastPocket], a ld hl, wOptions res NO_TEXT_SCROLL, [hl] ret @@ -58,15 +58,15 @@ Pack_InitItemsPocket: Pack_ItemsPocketMenu: ld hl, ItemsPocketMenuDataHeader call CopyMenuHeader - ld a, [wcfca] + ld a, [wItemsPocketCursor] ld [wMenuCursorBuffer], a - ld a, [wcfcf] + ld a, [wItemsPocketScrollPosition] ld [wMenuScrollPosition], a call ScrollingMenu ld a, [wMenuScrollPosition] - ld [wcfcf], a + ld [wItemsPocketScrollPosition], a ld a, [wMenuCursorY] - ld [wcfca], a + ld [wItemsPocketCursor], a .asm_104b7 ld b, $7 ld c, $3 @@ -87,15 +87,15 @@ Pack_InitKeyItemsPocket: Pack_KeyItemsPocketMenu: ld hl, KeyItemsPocketMenuDataHeader ; $4e9a call CopyMenuHeader - ld a, [wcfcb] + ld a, [wKeyItemsPocketCursor] ld [wMenuCursorBuffer], a - ld a, [wcfd0] + ld a, [wKeyItemsPocketScrollPosition] ld [wMenuScrollPosition], a call ScrollingMenu ld a, [wMenuScrollPosition] - ld [wcfd0], a + ld [wKeyItemsPocketScrollPosition], a ld a, [wMenuCursorY] - ld [wcfcb], a + ld [wKeyItemsPocketCursor], a ld b, $3 ld c, $7 call Function10cef @@ -211,15 +211,15 @@ Pack_InitBallsPocket: Pack_BallsPocketMenu: ld hl, BallsPocketMenuDataHeader ; $4eca call CopyMenuHeader - ld a, [wcfcc] + ld a, [wBallsPocketCursor] ld [wMenuCursorBuffer], a - ld a, [wcfd1] + ld a, [wBallsPocketScrollPosition] ld [wMenuScrollPosition], a call ScrollingMenu ld a, [wMenuScrollPosition] - ld [wcfd1], a + ld [wBallsPocketScrollPosition], a ld a, [wMenuCursorY] - ld [wcfcc], a + ld [wBallsPocketCursor], a ld b, $1 ld c, $5 call Function10cef @@ -504,20 +504,20 @@ Function107cd: .asm_107da xor a - ld [wcfcc], a - ld [wcfd1], a + ld [wBallsPocketCursor], a + ld [wBallsPocketScrollPosition], a ret .asm_107e2 xor a - ld [wcfca], a - ld [wcfcf], a + ld [wItemsPocketCursor], a + ld [wItemsPocketScrollPosition], a ret .asm_107ea xor a - ld [wcfcb], a - ld [wcfd0], a + ld [wKeyItemsPocketCursor], a + ld [wKeyItemsPocketScrollPosition], a ret RegisterItem: @@ -630,7 +630,7 @@ BattlePack: .asm_108dd ld a, [wce65] - ld [wcfc8], a + ld [wLastPocket], a ld hl, wOptions res 4, [hl] ret @@ -675,15 +675,15 @@ BattlePack_InitItemsPocket: BattlePack_ItemsPocketMenu: ld hl, $4e6a call CopyMenuHeader - ld a, [wcfca] + ld a, [wItemsPocketCursor] ld [wMenuCursorBuffer], a - ld a, [wcfcf] + ld a, [wItemsPocketScrollPosition] ld [wMenuScrollPosition], a call ScrollingMenu ld a, [wMenuScrollPosition] - ld [wcfcf], a + ld [wItemsPocketScrollPosition], a ld a, [wMenuCursorY] - ld [wcfca], a + ld [wItemsPocketCursor], a ld b, $7 ld c, $3 call Function10cef @@ -703,15 +703,15 @@ BattlePack_InitKeyItemsPocket: BattlePack_KeyItemsPocketMenu: ld hl, $4e9a call CopyMenuHeader - ld a, [wcfcb] + ld a, [wKeyItemsPocketCursor] ld [wMenuCursorBuffer], a - ld a, [wcfd0] + ld a, [wKeyItemsPocketScrollPosition] ld [wMenuScrollPosition], a call ScrollingMenu ld a, [wMenuScrollPosition] - ld [wcfd0], a + ld [wKeyItemsPocketScrollPosition], a ld a, [wMenuCursorY] - ld [wcfcb], a + ld [wKeyItemsPocketCursor], a ld b, $3 ld c, $7 call Function10cef @@ -754,15 +754,15 @@ BattlePack_InitBallsPocket: BattlePack_BallsPocketMenu: ld hl, $4eca call CopyMenuHeader - ld a, [wcfcc] + ld a, [wBallsPocketCursor] ld [wMenuCursorBuffer], a - ld a, [wcfd1] + ld a, [wBallsPocketScrollPosition] ld [wMenuScrollPosition], a call ScrollingMenu ld a, [wMenuScrollPosition] - ld [wcfd1], a + ld [wBallsPocketScrollPosition], a ld a, [wMenuCursorY] - ld [wcfcc], a + ld [wBallsPocketCursor], a ld b, $1 ld c, $5 call Function10cef @@ -893,7 +893,7 @@ BattlePack_QuitSubmenu: Function10aba: ; 10aba (4:4aba) xor a ld [wce63], a - ld a, [wcfc8] + ld a, [wLastPocket] and $3 ld [wCurPocket], a inc a @@ -942,15 +942,15 @@ DepositOrSell_ItemPocket: call Function10b92 ld hl, PC_Mart_ItemsPocketMenuDataHeader ; $4e82 call CopyMenuHeader - ld a, [wcfca] + ld a, [wItemsPocketCursor] ld [wMenuCursorBuffer], a - ld a, [wcfcf] + ld a, [wItemsPocketScrollPosition] ld [wMenuScrollPosition], a call ScrollingMenu ld a, [wMenuScrollPosition] - ld [wcfcf], a + ld [wItemsPocketScrollPosition], a ld a, [wMenuCursorY] - ld [wcfca], a + ld [wItemsPocketCursor], a ret DepositOrSell_KeyItemsPocket: @@ -958,15 +958,15 @@ DepositOrSell_KeyItemsPocket: call Function10b92 ld hl, PC_Mart_KeyItemsPocketMenuDataHeader ; $4eb2 call CopyMenuHeader - ld a, [wcfcb] + ld a, [wKeyItemsPocketCursor] ld [wMenuCursorBuffer], a - ld a, [wcfd0] + ld a, [wKeyItemsPocketScrollPosition] ld [wMenuScrollPosition], a call ScrollingMenu ld a, [wMenuScrollPosition] - ld [wcfd0], a + ld [wKeyItemsPocketScrollPosition], a ld a, [wMenuCursorY] - ld [wcfcb], a + ld [wKeyItemsPocketCursor], a ret DepositOrSell_TMHMPocket: @@ -983,15 +983,15 @@ DepositOrSell_BallsPocket: call Function10b92 ld hl, PC_Mart_BallsPocketMenuDataHeader ; $4ee2 call CopyMenuHeader - ld a, [wcfcc] + ld a, [wBallsPocketCursor] ld [wMenuCursorBuffer], a - ld a, [wcfd1] + ld a, [wBallsPocketScrollPosition] ld [wMenuScrollPosition], a call ScrollingMenu ld a, [wMenuScrollPosition] - ld [wcfd1], a + ld [wBallsPocketScrollPosition], a ld a, [wMenuCursorY] - ld [wcfcc], a + ld [wBallsPocketCursor], a ret Function10b92: ; 10b92 (4:4b92) @@ -1059,7 +1059,7 @@ TutorialPack: ld a, [wInputType] or a jr z, .asm_10bfa - farcall DudeAutoInput_RightA ; 70:4dee + farcall _DudeAutoInput_RightA ; 70:4dee .asm_10bfa call Function10c07 call Function10b9f diff --git a/engine/pokemon/correct_nick_errors.asm b/engine/pokemon/correct_nick_errors.asm index 0f264a36..c8056251 100644 --- a/engine/pokemon/correct_nick_errors.asm +++ b/engine/pokemon/correct_nick_errors.asm @@ -43,7 +43,7 @@ CorrectNickErrors:: ; 677e (1:677e) ; table defining which characters are actually text commands ; format: ; ≥ < - db "<START>", $04 + 1 + db "<NULL>", $04 + 1 db "<PLAY_G>", $18 + 1 db $1d, "%" + 1 db $35, "<GREEN>" + 1 diff --git a/engine/pokemon/learn.asm b/engine/pokemon/learn.asm index 65816783..fe6ff121 100644 --- a/engine/pokemon/learn.asm +++ b/engine/pokemon/learn.asm @@ -136,7 +136,7 @@ LearnMove: ld a, $1 ld [w2DMenuNumCols], a ld [wMenuCursorY], a - ld [wcee1], a + ld [wMenuCursorX], a ld a, $3 ld [wMenuJoypadFilter], a ld a, $20 |