diff options
Diffstat (limited to 'engine/battle/core.asm')
-rw-r--r-- | engine/battle/core.asm | 9511 |
1 files changed, 9511 insertions, 0 deletions
diff --git a/engine/battle/core.asm b/engine/battle/core.asm new file mode 100644 index 000000000..a62b70d72 --- /dev/null +++ b/engine/battle/core.asm @@ -0,0 +1,9511 @@ +; Core components of the battle engine. +BattleCore: +DoBattle: ; 3c000 + xor a + ld [wBattleParticipantsNotFainted], a + ld [wBattleParticipantsIncludingFainted], a + ld [wPlayerAction], a + ld [BattleEnded], a + inc a + ld [wBattleHasJustStarted], a + ld hl, OTPartyMon1HP + ld bc, PARTYMON_STRUCT_LENGTH - 1 + ld d, BATTLEACTION_SWITCH1 - 1 +.loop + inc d + ld a, [hli] + or [hl] + jr nz, .alive + add hl, bc + jr .loop + +.alive + ld a, d + ld [wBattleAction], a + ld a, [wLinkMode] + and a + jr z, .not_linked + + ld a, [hLinkPlayerNumber] + cp $2 + jr z, .player_2 + +.not_linked + ld a, [wBattleMode] + dec a + jr z, .wild + xor a + ld [wEnemySwitchMonIndex], a + call NewEnemyMonStatus + call ResetEnemyStatLevels + call BreakAttraction + call EnemySwitch + +.wild + ld c, 40 + call DelayFrames + +.player_2 + call LoadTileMapToTempTileMap + call CheckPlayerPartyForFitPkmn + ld a, d + and a + jp z, LostBattle + call Call_LoadTempTileMapToTileMap + ld a, [BattleType] + cp BATTLETYPE_DEBUG + jp z, .tutorial_debug + cp BATTLETYPE_TUTORIAL + jp z, .tutorial_debug + xor a + ld [CurPartyMon], a +.loop2 + call CheckIfCurPartyMonIsFitToFight + jr nz, .alive2 + ld hl, CurPartyMon + inc [hl] + jr .loop2 + +.alive2 + ld a, [CurBattleMon] + ld [LastPlayerMon], a + ld a, [CurPartyMon] + ld [CurBattleMon], a + inc a + ld hl, PartySpecies - 1 + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + ld [CurPartySpecies], a + ld [TempBattleMonSpecies], a + hlcoord 1, 5 + ld a, 9 + call SlideBattlePicOut + call LoadTileMapToTempTileMap + call ResetBattleParticipants + call InitBattleMon + call ResetPlayerStatLevels + call SendOutPkmnText + call NewBattleMonStatus + call BreakAttraction + call SendOutPlayerMon + call EmptyBattleTextBox + call LoadTileMapToTempTileMap + call SetPlayerTurn + call SpikesDamage + ld a, [wLinkMode] + and a + jr z, .not_linked_2 + ld a, [hLinkPlayerNumber] + cp $2 + jr nz, .not_linked_2 + xor a + ld [wEnemySwitchMonIndex], a + call NewEnemyMonStatus + call ResetEnemyStatLevels + call BreakAttraction + call EnemySwitch + call SetEnemyTurn + call SpikesDamage + +.not_linked_2 + jp BattleTurn + +.tutorial_debug + jp BattleMenu +; 3c0e5 + +WildFled_EnemyFled_LinkBattleCanceled: ; 3c0e5 + call Call_LoadTempTileMapToTileMap + ld a, [wBattleResult] + and $c0 + add $2 + ld [wBattleResult], a + ld a, [wLinkMode] + and a + ld hl, BattleText_WildFled + jr z, .print_text + + ld a, [wBattleResult] + and $c0 + ld [wBattleResult], a + ld hl, BattleText_EnemyFled + call CheckMobileBattleError + jr nc, .print_text + + ld hl, wcd2a + bit 4, [hl] + jr nz, .skip_text + + ld hl, BattleText_LinkErrorBattleCanceled + +.print_text + call StdBattleTextBox + +.skip_text + call StopDangerSound + call CheckMobileBattleError + jr c, .skip_sfx + + ld de, SFX_RUN + call PlaySFX + +.skip_sfx + call SetPlayerTurn + ld a, 1 + ld [BattleEnded], a + ret +; 3c12f + +BattleTurn: ; 3c12f +.loop + call MobileFn_3c1bf + call CheckContestBattleOver + jp c, .quit + + xor a + ld [wPlayerIsSwitching], a + ld [wEnemyIsSwitching], a + ld [wBattleHasJustStarted], a + ld [wPlayerJustGotFrozen], a + ld [wEnemyJustGotFrozen], a + ld [CurDamage], a + ld [CurDamage + 1], a + + call HandleBerserkGene + call UpdateBattleMonInParty + farcall AIChooseMove + + call IsMobileBattle + jr nz, .not_disconnected + farcall Function100da5 + farcall StartMobileInactivityTimer + farcall Function100dd8 + jp c, .quit +.not_disconnected + + call CheckPlayerLockedIn + jr c, .skip_iteration +.loop1 + call BattleMenu + jr c, .quit + ld a, [BattleEnded] + and a + jr nz, .quit + ld a, [wForcedSwitch] ; roared/whirlwinded/teleported + and a + jr nz, .quit +.skip_iteration + call ParsePlayerAction + jr nz, .loop1 + + call EnemyTriesToFlee + jr c, .quit + + call DetermineMoveOrder + jr c, .false + call Battle_EnemyFirst + jr .proceed +.false + call Battle_PlayerFirst +.proceed + call CheckMobileBattleError + jr c, .quit + + ld a, [wForcedSwitch] + and a + jr nz, .quit + + ld a, [BattleEnded] + and a + jr nz, .quit + + call HandleBetweenTurnEffects + ld a, [BattleEnded] + and a + jr nz, .quit + jp .loop + +.quit + ret +; 3c1bf + +MobileFn_3c1bf: mobile + ld a, $5 + call GetSRAMBank + ld hl, $a89b ; s5_a89b + inc [hl] + jr nz, .finish + dec hl + inc [hl] + jr nz, .finish + dec [hl] + inc hl + dec [hl] + +.finish + call CloseSRAM + ret +; 3c1d6 + +HandleBetweenTurnEffects: ; 3c1d6 + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .CheckEnemyFirst + call CheckFaint_PlayerThenEnemy + ret c + call HandleFutureSight + call CheckFaint_PlayerThenEnemy + ret c + call HandleWeather + call CheckFaint_PlayerThenEnemy + ret c + call HandleWrap + call CheckFaint_PlayerThenEnemy + ret c + call HandlePerishSong + call CheckFaint_PlayerThenEnemy + ret c + jr .NoMoreFaintingConditions + +.CheckEnemyFirst: + call CheckFaint_EnemyThenPlayer + ret c + call HandleFutureSight + call CheckFaint_EnemyThenPlayer + ret c + call HandleWeather + call CheckFaint_EnemyThenPlayer + ret c + call HandleWrap + call CheckFaint_EnemyThenPlayer + ret c + call HandlePerishSong + call CheckFaint_EnemyThenPlayer + ret c + +.NoMoreFaintingConditions: + call HandleLeftovers + call HandleMysteryberry + call HanleDefrost + call HandleSafeguard + call HandleScreens + call HandleStatBoostingHeldItems + call HandleHealingItems + call UpdateBattleMonInParty + call LoadTileMapToTempTileMap + jp HandleEncore +; 3c23c + +CheckFaint_PlayerThenEnemy: ; 3c23c + call HasPlayerFainted + jr nz, .PlayerNotFainted + call HandlePlayerMonFaint + ld a, [BattleEnded] + and a + jr nz, .BattleIsOver + +.PlayerNotFainted: + call HasEnemyFainted + jr nz, .BattleContinues + call HandleEnemyMonFaint + ld a, [BattleEnded] + and a + jr nz, .BattleIsOver + +.BattleContinues: + and a + ret + +.BattleIsOver: + scf + ret +; 3c25c + +CheckFaint_EnemyThenPlayer: ; 3c25c + call HasEnemyFainted + jr nz, .EnemyNotFainted + call HandleEnemyMonFaint + ld a, [BattleEnded] + and a + jr nz, .BattleIsOver + +.EnemyNotFainted: + call HasPlayerFainted + jr nz, .BattleContinues + call HandlePlayerMonFaint + ld a, [BattleEnded] + and a + jr nz, .BattleIsOver + +.BattleContinues: + and a + ret + +.BattleIsOver: + scf + ret +; 3c27c + +HandleBerserkGene: ; 3c27c + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .reverse + + call .player + jr .enemy + +.reverse + call .enemy +; jr .player + +.player + call SetPlayerTurn + ld de, PartyMon1Item + ld a, [CurBattleMon] + ld b, a + jr .go + +.enemy + call SetEnemyTurn + ld de, OTPartyMon1Item + ld a, [CurOTMon] + ld b, a +; jr .go + +.go + push de + push bc + callfar GetUserItem + ld a, [hl] + ld [wd265], a + sub BERSERK_GENE + pop bc + pop de + ret nz + + ld [hl], a + + ld h, d + ld l, e + ld a, b + call GetPartyLocation + xor a + ld [hl], a + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVarAddr + push af + set SUBSTATUS_CONFUSED, [hl] + ld a, BATTLE_VARS_MOVE_ANIM + call GetBattleVarAddr + push hl + push af + xor a + ld [hl], a + ld [AttackMissed], a + ld [EffectFailed], a + farcall BattleCommand_AttackUp2 + pop af + pop hl + ld [hl], a + call GetItemName + ld hl, BattleText_UsersStringBuffer1Activated + call StdBattleTextBox + callfar BattleCommand_StatUpMessage + pop af + bit SUBSTATUS_CONFUSED, a + ret nz + xor a + ld [wNumHits], a + ld de, ANIM_CONFUSED + call Call_PlayBattleAnim_OnlyIfVisible + call SwitchTurnCore + ld hl, BecameConfusedText + jp StdBattleTextBox +; 3c300 + +EnemyTriesToFlee: ; 3c300 + ld a, [wLinkMode] + and a + jr z, .not_linked + ld a, [wBattleAction] + cp BATTLEACTION_FORFEIT + jr z, .forfeit + +.not_linked + and a + ret + +.forfeit + call WildFled_EnemyFled_LinkBattleCanceled + scf + ret +; 3c314 + +DetermineMoveOrder: ; 3c314 + ld a, [wLinkMode] + and a + jr z, .use_move + ld a, [wBattleAction] + cp BATTLEACTION_E + jr z, .use_move + cp BATTLEACTION_D + jr z, .use_move + sub BATTLEACTION_SWITCH1 + jr c, .use_move + ld a, [wPlayerAction] + cp $2 + jr nz, .switch + ld a, [hLinkPlayerNumber] + cp $2 + jr z, .player_2 + + call BattleRandom + cp 1 + (50 percent) + jp c, .player_first + jp .enemy_first + +.player_2 + call BattleRandom + cp 1 + (50 percent) + jp c, .enemy_first + jp .player_first + +.switch + callfar AI_Switch + call SetEnemyTurn + call SpikesDamage + jp .enemy_first + +.use_move + ld a, [wPlayerAction] + and a + jp nz, .player_first + call CompareMovePriority + jr z, .equal_priority + jp c, .player_first ; player goes first + jp .enemy_first + +.equal_priority + call SetPlayerTurn + callfar GetUserItem + push bc + callfar GetOpponentItem + pop de + ld a, d + cp HELD_QUICK_CLAW + jr nz, .player_no_quick_claw + ld a, b + cp HELD_QUICK_CLAW + jr z, .both_have_quick_claw + call BattleRandom + cp e + jr nc, .speed_check + jp .player_first + +.player_no_quick_claw + ld a, b + cp HELD_QUICK_CLAW + jr nz, .speed_check + call BattleRandom + cp c + jr nc, .speed_check + jp .enemy_first + +.both_have_quick_claw + ld a, [hLinkPlayerNumber] + cp $2 + jr z, .player_2b + call BattleRandom + cp c + jp c, .enemy_first + call BattleRandom + cp e + jp c, .player_first + jr .speed_check + +.player_2b + call BattleRandom + cp e + jp c, .player_first + call BattleRandom + cp c + jp c, .enemy_first + jr .speed_check + +.speed_check + ld de, BattleMonSpeed + ld hl, EnemyMonSpeed + ld c, 2 + call StringCmp + jr z, .speed_tie + jp nc, .player_first + jp .enemy_first + +.speed_tie + ld a, [hLinkPlayerNumber] + cp $2 + jr z, .player_2c + call BattleRandom + cp 1 + (50 percent) + jp c, .player_first + jp .enemy_first + +.player_2c + call BattleRandom + cp 1 + (50 percent) + jp c, .enemy_first +.player_first + scf + ret +; 3c3f3 + +.enemy_first ; 3c3f3 + and a + ret +; 3c3f5 + +CheckContestBattleOver: ; 3c3f5 + ld a, [BattleType] + cp BATTLETYPE_CONTEST + jr nz, .contest_not_over + ld a, [wParkBallsRemaining] + and a + jr nz, .contest_not_over + ld a, [wBattleResult] + and $c0 + add $2 + ld [wBattleResult], a + scf + ret + +.contest_not_over + and a + ret +; 3c410 + +CheckPlayerLockedIn: ; 3c410 + ld a, [PlayerSubStatus4] + and 1 << SUBSTATUS_RECHARGE + jp nz, .quit + + ld hl, EnemySubStatus3 + res SUBSTATUS_FLINCHED, [hl] + ld hl, PlayerSubStatus3 + res SUBSTATUS_FLINCHED, [hl] + + ld a, [hl] + and 1 << SUBSTATUS_CHARGED | 1 << SUBSTATUS_RAMPAGE + jp nz, .quit + + ld hl, PlayerSubStatus1 + bit SUBSTATUS_ROLLOUT, [hl] + jp nz, .quit + + and a + ret + +.quit + scf + ret +; 3c434 + +ParsePlayerAction: ; 3c434 + call CheckPlayerLockedIn + jp c, .locked_in + ld hl, PlayerSubStatus5 + bit SUBSTATUS_ENCORED, [hl] + jr z, .not_encored + ld a, [LastPlayerMove] + ld [CurPlayerMove], a + jr .encored + +.not_encored + ld a, [wPlayerAction] + cp $2 + jr z, .reset_rage + and a + jr nz, .reset_bide + ld a, [PlayerSubStatus3] + and 1 << SUBSTATUS_BIDE + jr nz, .locked_in + xor a + ld [wMoveSelectionMenuType], a + inc a ; POUND + ld [FXAnimID], a + call MoveSelectionScreen + push af + call Call_LoadTempTileMapToTileMap + call UpdateBattleHuds + ld a, [CurPlayerMove] + cp STRUGGLE + jr z, .struggle + call PlayClickSFX + +.struggle + ld a, $1 + ld [hBGMapMode], a + pop af + ret nz + +.encored + call SetPlayerTurn + callfar UpdateMoveData + xor a + ld [wPlayerCharging], a + ld a, [wPlayerMoveStruct + MOVE_EFFECT] + cp EFFECT_FURY_CUTTER + jr z, .continue_fury_cutter + xor a + ld [PlayerFuryCutterCount], a + +.continue_fury_cutter + ld a, [wPlayerMoveStruct + MOVE_EFFECT] + cp EFFECT_RAGE + jr z, .continue_rage + ld hl, PlayerSubStatus4 + res SUBSTATUS_RAGE, [hl] + xor a + ld [wPlayerRageCounter], a + +.continue_rage + ld a, [wPlayerMoveStruct + MOVE_EFFECT] + cp EFFECT_PROTECT + jr z, .continue_protect + cp EFFECT_ENDURE + jr z, .continue_protect + xor a + ld [PlayerProtectCount], a + jr .continue_protect + +.reset_bide + ld hl, PlayerSubStatus3 + res SUBSTATUS_BIDE, [hl] + +.locked_in + xor a + ld [PlayerFuryCutterCount], a + ld [PlayerProtectCount], a + ld [wPlayerRageCounter], a + ld hl, PlayerSubStatus4 + res SUBSTATUS_RAGE, [hl] + +.continue_protect + call ParseEnemyAction + xor a + ret + +.reset_rage + xor a + ld [PlayerFuryCutterCount], a + ld [PlayerProtectCount], a + ld [wPlayerRageCounter], a + ld hl, PlayerSubStatus4 + res SUBSTATUS_RAGE, [hl] + xor a + ret +; 3c4df + +HandleEncore: ; 3c4df + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .player_1 + call .do_player + jr .do_enemy + +.player_1 + call .do_enemy +.do_player + ld hl, PlayerSubStatus5 + bit SUBSTATUS_ENCORED, [hl] + ret z + ld a, [PlayerEncoreCount] + dec a + ld [PlayerEncoreCount], a + jr z, .end_player_encore + ld hl, BattleMonPP + ld a, [CurMoveNum] + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + and $3f + ret nz + +.end_player_encore + ld hl, PlayerSubStatus5 + res SUBSTATUS_ENCORED, [hl] + call SetEnemyTurn + ld hl, BattleText_TargetsEncoreEnded + jp StdBattleTextBox + +.do_enemy + ld hl, EnemySubStatus5 + bit SUBSTATUS_ENCORED, [hl] + ret z + ld a, [EnemyEncoreCount] + dec a + ld [EnemyEncoreCount], a + jr z, .end_enemy_encore + ld hl, EnemyMonPP + ld a, [CurEnemyMoveNum] + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + and $3f + ret nz + +.end_enemy_encore + ld hl, EnemySubStatus5 + res SUBSTATUS_ENCORED, [hl] + call SetPlayerTurn + ld hl, BattleText_TargetsEncoreEnded + jp StdBattleTextBox +; 3c543 + +TryEnemyFlee: ; 3c543 + ld a, [wBattleMode] + dec a + jr nz, .Stay + + ld a, [PlayerSubStatus5] + bit SUBSTATUS_CANT_RUN, a + jr nz, .Stay + + ld a, [wEnemyWrapCount] + and a + jr nz, .Stay + + ld a, [EnemyMonStatus] + and 1 << FRZ | SLP + jr nz, .Stay + + ld a, [TempEnemyMonSpecies] + ld de, 1 + ld hl, AlwaysFleeMons + call IsInArray + jr c, .Flee + + call BattleRandom + ld b, a + cp 1 + (50 percent) + jr nc, .Stay + + push bc + ld a, [TempEnemyMonSpecies] + ld de, 1 + ld hl, OftenFleeMons + call IsInArray + pop bc + jr c, .Flee + + ld a, b + cp 1 + (10 percent) + jr nc, .Stay + + ld a, [TempEnemyMonSpecies] + ld de, 1 + ld hl, SometimesFleeMons + call IsInArray + jr c, .Flee + +.Stay: + and a + ret + +.Flee: + scf + ret +; 3c59a + +INCLUDE "data/wild/flee_mons.asm" + +CompareMovePriority: ; 3c5b4 +; Compare the priority of the player and enemy's moves. +; Return carry if the player goes first, or z if they match. + + ld a, [CurPlayerMove] + call GetMovePriority + ld b, a + push bc + ld a, [CurEnemyMove] + call GetMovePriority + pop bc + cp b + ret +; 3c5c5 + +GetMovePriority: ; 3c5c5 +; Return the priority (0-3) of move a. + + ld b, a + + ; Vital Throw goes last. + cp VITAL_THROW + ld a, 0 + ret z + + call GetMoveEffect + ld hl, MoveEffectPriorities +.loop + ld a, [hli] + cp b + jr z, .done + inc hl + cp -1 + jr nz, .loop + + ld a, 1 + ret + +.done + ld a, [hl] + ret +; 3c5df + +MoveEffectPriorities: ; 3c5df + db EFFECT_PROTECT, 3 + db EFFECT_ENDURE, 3 + db EFFECT_PRIORITY_HIT, 2 + db EFFECT_FORCE_SWITCH, 0 + db EFFECT_COUNTER, 0 + db EFFECT_MIRROR_COAT, 0 + db -1 +; 3c5ec + +GetMoveEffect: ; 3c5ec + ld a, b + dec a + ld hl, Moves + MOVE_EFFECT + ld bc, MOVE_LENGTH + call AddNTimes + ld a, BANK(Moves) + call GetFarByte + ld b, a + ret +; 3c5fe + +Battle_EnemyFirst: ; 3c5fe + call LoadTileMapToTempTileMap + call TryEnemyFlee + jp c, WildFled_EnemyFled_LinkBattleCanceled + call SetEnemyTurn + ld a, $1 + ld [wEnemyGoesFirst], a + callfar AI_SwitchOrTryItem + jr c, .switch_item + call EnemyTurn_EndOpponentProtectEndureDestinyBond + call CheckMobileBattleError + ret c + ld a, [wForcedSwitch] + and a + ret nz + call HasPlayerFainted + jp z, HandlePlayerMonFaint + call HasEnemyFainted + jp z, HandleEnemyMonFaint + +.switch_item + call SetEnemyTurn + call ResidualDamage + jp z, HandleEnemyMonFaint + call RefreshBattleHuds + call PlayerTurn_EndOpponentProtectEndureDestinyBond + call CheckMobileBattleError + ret c + ld a, [wForcedSwitch] + and a + ret nz + call HasEnemyFainted + jp z, HandleEnemyMonFaint + call HasPlayerFainted + jp z, HandlePlayerMonFaint + call SetPlayerTurn + call ResidualDamage + jp z, HandlePlayerMonFaint + call RefreshBattleHuds + xor a + ld [wPlayerAction], a + ret +; 3c664 + +Battle_PlayerFirst: ; 3c664 + xor a + ld [wEnemyGoesFirst], a + call SetEnemyTurn + callfar AI_SwitchOrTryItem + push af + call PlayerTurn_EndOpponentProtectEndureDestinyBond + pop bc + ld a, [wForcedSwitch] + and a + ret nz + call CheckMobileBattleError + ret c + call HasEnemyFainted + jp z, HandleEnemyMonFaint + call HasPlayerFainted + jp z, HandlePlayerMonFaint + push bc + call SetPlayerTurn + call ResidualDamage + pop bc + jp z, HandlePlayerMonFaint + push bc + call RefreshBattleHuds + pop af + jr c, .switched_or_used_item + call LoadTileMapToTempTileMap + call TryEnemyFlee + jp c, WildFled_EnemyFled_LinkBattleCanceled + call EnemyTurn_EndOpponentProtectEndureDestinyBond + call CheckMobileBattleError + ret c + ld a, [wForcedSwitch] + and a + ret nz + call HasPlayerFainted + jp z, HandlePlayerMonFaint + call HasEnemyFainted + jp z, HandleEnemyMonFaint + +.switched_or_used_item + call SetEnemyTurn + call ResidualDamage + jp z, HandleEnemyMonFaint + call RefreshBattleHuds + xor a + ld [wPlayerAction], a + ret +; 3c6cf + +PlayerTurn_EndOpponentProtectEndureDestinyBond: ; 3c6cf + call SetPlayerTurn + call EndUserDestinyBond + callfar DoPlayerTurn + jp EndOpponentProtectEndureDestinyBond +; 3c6de + +EnemyTurn_EndOpponentProtectEndureDestinyBond: ; 3c6de + call SetEnemyTurn + call EndUserDestinyBond + callfar DoEnemyTurn + jp EndOpponentProtectEndureDestinyBond +; 3c6ed + +EndOpponentProtectEndureDestinyBond: ; 3c6ed + ld a, BATTLE_VARS_SUBSTATUS1_OPP + call GetBattleVarAddr + res SUBSTATUS_PROTECT, [hl] + res SUBSTATUS_ENDURE, [hl] + ld a, BATTLE_VARS_SUBSTATUS5_OPP + call GetBattleVarAddr + res SUBSTATUS_DESTINY_BOND, [hl] + ret +; 3c6fe + +EndUserDestinyBond: ; 3c6fe + ld a, BATTLE_VARS_SUBSTATUS5 + call GetBattleVarAddr + res SUBSTATUS_DESTINY_BOND, [hl] + ret +; 3c706 + +HasUserFainted: ; 3c706 + ld a, [hBattleTurn] + and a + jr z, HasPlayerFainted +HasEnemyFainted: ; 3c70b + ld hl, EnemyMonHP + jr CheckIfHPIsZero + +HasPlayerFainted: ; 3c710 + ld hl, BattleMonHP + +CheckIfHPIsZero: ; 3c713 + ld a, [hli] + or [hl] + ret +; 3c716 + +ResidualDamage: ; 3c716 +; Return z if the user fainted before +; or as a result of residual damage. +; For Sandstorm damage, see HandleWeather. + + call HasUserFainted + ret z + + ld a, BATTLE_VARS_STATUS + call GetBattleVar + and 1 << PSN | 1 << BRN + jr z, .did_psn_brn + + ld hl, HurtByPoisonText + ld de, ANIM_PSN + and 1 << BRN + jr z, .got_anim + ld hl, HurtByBurnText + ld de, ANIM_BRN +.got_anim + + push de + call StdBattleTextBox + pop de + + xor a + ld [wNumHits], a + call Call_PlayBattleAnim_OnlyIfVisible + call GetEighthMaxHP + ld de, PlayerToxicCount + ld a, [hBattleTurn] + and a + jr z, .check_toxic + ld de, EnemyToxicCount +.check_toxic + + ld a, BATTLE_VARS_SUBSTATUS5 + call GetBattleVar + bit SUBSTATUS_TOXIC, a + jr z, .did_toxic + call GetSixteenthMaxHP + ld a, [de] + inc a + ld [de], a + ld hl, 0 +.add + add hl, bc + dec a + jr nz, .add + ld b, h + ld c, l +.did_toxic + + call SubtractHPFromUser +.did_psn_brn + + call HasUserFainted + jp z, .fainted + + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVarAddr + bit SUBSTATUS_LEECH_SEED, [hl] + jr z, .not_seeded + + call SwitchTurnCore + xor a + ld [wNumHits], a + ld de, ANIM_SAP + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVar + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + call z, Call_PlayBattleAnim_OnlyIfVisible + call SwitchTurnCore + + call GetEighthMaxHP + call SubtractHPFromUser + ld a, $1 + ld [hBGMapMode], a + call RestoreHP + ld hl, LeechSeedSapsText + call StdBattleTextBox +.not_seeded + + call HasUserFainted + jr z, .fainted + + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVarAddr + bit SUBSTATUS_NIGHTMARE, [hl] + jr z, .not_nightmare + xor a + ld [wNumHits], a + ld de, ANIM_IN_NIGHTMARE + call Call_PlayBattleAnim_OnlyIfVisible + call GetQuarterMaxHP + call SubtractHPFromUser + ld hl, HasANightmareText + call StdBattleTextBox +.not_nightmare + + call HasUserFainted + jr z, .fainted + + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVarAddr + bit SUBSTATUS_CURSE, [hl] + jr z, .not_cursed + + xor a + ld [wNumHits], a + ld de, ANIM_IN_NIGHTMARE + call Call_PlayBattleAnim_OnlyIfVisible + call GetQuarterMaxHP + call SubtractHPFromUser + ld hl, HurtByCurseText + call StdBattleTextBox + +.not_cursed + ld hl, BattleMonHP + ld a, [hBattleTurn] + and a + jr z, .check_fainted + ld hl, EnemyMonHP + +.check_fainted + ld a, [hli] + or [hl] + ret nz + +.fainted + call RefreshBattleHuds + ld c, 20 + call DelayFrames + xor a + ret +; 3c801 + +HandlePerishSong: ; 3c801 + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .EnemyFirst + call SetPlayerTurn + call .do_it + call SetEnemyTurn + jp .do_it + +.EnemyFirst: + call SetEnemyTurn + call .do_it + call SetPlayerTurn + +.do_it + ld hl, PlayerPerishCount + ld a, [hBattleTurn] + and a + jr z, .got_count + ld hl, EnemyPerishCount + +.got_count + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVar + bit SUBSTATUS_PERISH, a + ret z + dec [hl] + ld a, [hl] + ld [wd265], a + push af + ld hl, PerishCountText + call StdBattleTextBox + pop af + ret nz + ld a, BATTLE_VARS_SUBSTATUS1 + call GetBattleVarAddr + res SUBSTATUS_PERISH, [hl] + ld a, [hBattleTurn] + and a + jr nz, .kill_enemy + ld hl, BattleMonHP + xor a + ld [hli], a + ld [hl], a + ld hl, PartyMon1HP + ld a, [CurBattleMon] + call GetPartyLocation + xor a + ld [hli], a + ld [hl], a + ret + +.kill_enemy + ld hl, EnemyMonHP + xor a + ld [hli], a + ld [hl], a + ld a, [wBattleMode] + dec a + ret z + ld hl, OTPartyMon1HP + ld a, [CurOTMon] + call GetPartyLocation + xor a + ld [hli], a + ld [hl], a + ret +; 3c874 + +HandleWrap: ; 3c874 + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .EnemyFirst + call SetPlayerTurn + call .do_it + call SetEnemyTurn + jp .do_it + +.EnemyFirst: + call SetEnemyTurn + call .do_it + call SetPlayerTurn + +.do_it + ld hl, wPlayerWrapCount + ld de, wPlayerTrappingMove + ld a, [hBattleTurn] + and a + jr z, .got_addrs + ld hl, wEnemyWrapCount + ld de, wEnemyTrappingMove + +.got_addrs + ld a, [hl] + and a + ret z + + ld a, BATTLE_VARS_SUBSTATUS4 + call GetBattleVar + bit SUBSTATUS_SUBSTITUTE, a + ret nz + + ld a, [de] + ld [wd265], a + ld [FXAnimID], a + call GetMoveName + dec [hl] + jr z, .release_from_bounds + + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVar + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + jr nz, .skip_anim + + call SwitchTurnCore + xor a + ld [wNumHits], a + ld [FXAnimID + 1], a + predef PlayBattleAnim + call SwitchTurnCore + +.skip_anim + call GetSixteenthMaxHP + call SubtractHPFromUser + ld hl, BattleText_UsersHurtByStringBuffer1 + jr .print_text + +.release_from_bounds + ld hl, BattleText_UserWasReleasedFromStringBuffer1 + +.print_text + jp StdBattleTextBox +; 3c8e4 + +SwitchTurnCore: ; 3c8e4 + ld a, [hBattleTurn] + xor 1 + ld [hBattleTurn], a + ret +; 3c8eb + +HandleLeftovers: ; 3c8eb + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .DoEnemyFirst + call SetPlayerTurn + call .do_it + call SetEnemyTurn + jp .do_it + +.DoEnemyFirst: + call SetEnemyTurn + call .do_it + call SetPlayerTurn +.do_it + + callfar GetUserItem + ld a, [hl] + ld [wd265], a + call GetItemName + ld a, b + cp HELD_LEFTOVERS + ret nz + + ld hl, BattleMonHP + ld a, [hBattleTurn] + and a + jr z, .got_hp + ld hl, EnemyMonHP + +.got_hp +; Don't restore if we're already at max HP + ld a, [hli] + ld b, a + ld a, [hli] + ld c, a + ld a, [hli] + cp b + jr nz, .restore + ld a, [hl] + cp c + ret z + +.restore + call GetSixteenthMaxHP + call SwitchTurnCore + call RestoreHP + ld hl, BattleText_TargetRecoveredWithItem + jp StdBattleTextBox +; 3c93c + +HandleMysteryberry: ; 3c93c + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .DoEnemyFirst + call SetPlayerTurn + call .do_it + call SetEnemyTurn + jp .do_it + +.DoEnemyFirst: + call SetEnemyTurn + call .do_it + call SetPlayerTurn + +.do_it + callfar GetUserItem + ld a, b + cp HELD_RESTORE_PP + jr nz, .quit + ld hl, PartyMon1PP + ld a, [CurBattleMon] + call GetPartyLocation + ld d, h + ld e, l + ld hl, PartyMon1Moves + ld a, [CurBattleMon] + call GetPartyLocation + ld a, [hBattleTurn] + and a + jr z, .wild + ld de, wWildMonPP + ld hl, wWildMonMoves + ld a, [wBattleMode] + dec a + jr z, .wild + ld hl, OTPartyMon1PP + ld a, [CurOTMon] + call GetPartyLocation + ld d, h + ld e, l + ld hl, OTPartyMon1Moves + ld a, [CurOTMon] + call GetPartyLocation + +.wild + ld c, $0 +.loop + ld a, [hl] + and a + jr z, .quit + ld a, [de] + and $3f + jr z, .restore + inc hl + inc de + inc c + ld a, c + cp NUM_MOVES + jr nz, .loop + +.quit + ret + +.restore + ; lousy hack + ld a, [hl] + cp SKETCH + ld b, 1 + jr z, .sketch + ld b, 5 +.sketch + ld a, [de] + add b + ld [de], a + push bc + push bc + ld a, [hl] + ld [wd265], a + ld de, BattleMonMoves - 1 + ld hl, BattleMonPP + ld a, [hBattleTurn] + and a + jr z, .player_pp + ld de, EnemyMonMoves - 1 + ld hl, EnemyMonPP +.player_pp + inc de + pop bc + ld b, 0 + add hl, bc + push hl + ld h, d + ld l, e + add hl, bc + pop de + pop bc + + ld a, [wd265] + cp [hl] + jr nz, .skip_checks + ld a, [hBattleTurn] + and a + ld a, [PlayerSubStatus5] + jr z, .check_transform + ld a, [EnemySubStatus5] +.check_transform + bit SUBSTATUS_TRANSFORMED, a + jr nz, .skip_checks + ld a, [de] + add b + ld [de], a +.skip_checks + callfar GetUserItem + ld a, [hl] + ld [wd265], a + xor a + ld [hl], a + call GetPartymonItem + ld a, [hBattleTurn] + and a + jr z, .consume_item + ld a, [wBattleMode] + dec a + jr z, .skip_consumption + call GetOTPartymonItem + +.consume_item + xor a + ld [hl], a + +.skip_consumption + call GetItemName + call SwitchTurnCore + call ItemRecoveryAnim + call SwitchTurnCore + ld hl, BattleText_UserRecoveredPPUsing + jp StdBattleTextBox +; 3ca26 + +HandleFutureSight: ; 3ca26 + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .enemy_first + call SetPlayerTurn + call .do_it + call SetEnemyTurn + jp .do_it + +.enemy_first + call SetEnemyTurn + call .do_it + call SetPlayerTurn + +.do_it + ld hl, wPlayerFutureSightCount + ld a, [hBattleTurn] + and a + jr z, .okay + ld hl, wEnemyFutureSightCount + +.okay + ld a, [hl] + and a + ret z + dec a + ld [hl], a + cp $1 + ret nz + + ld hl, BattleText_TargetWasHitByFutureSight + call StdBattleTextBox + + ld a, BATTLE_VARS_MOVE + call GetBattleVarAddr + push af + ld a, FUTURE_SIGHT + ld [hl], a + + callfar UpdateMoveData + xor a + ld [AttackMissed], a + ld [AlreadyDisobeyed], a + ld a, 10 + ld [TypeModifier], a + callfar DoMove + xor a + ld [CurDamage], a + ld [CurDamage + 1], a + + ld a, BATTLE_VARS_MOVE + call GetBattleVarAddr + pop af + ld [hl], a + + call UpdateBattleMonInParty + jp UpdateEnemyMonInParty +; 3ca8f + +HanleDefrost: ; 3ca8f + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .enemy_first + call .do_player_turn + jr .do_enemy_turn + +.enemy_first + call .do_enemy_turn +.do_player_turn + ld a, [BattleMonStatus] + bit FRZ, a + ret z + + ld a, [wPlayerJustGotFrozen] + and a + ret nz + + call BattleRandom + cp 10 percent + ret nc + xor a + ld [BattleMonStatus], a + ld a, [CurBattleMon] + ld hl, PartyMon1Status + call GetPartyLocation + ld [hl], 0 + call UpdateBattleHuds + call SetEnemyTurn + ld hl, DefrostedOpponentText + jp StdBattleTextBox + +.do_enemy_turn + ld a, [EnemyMonStatus] + bit FRZ, a + ret z + ld a, [wEnemyJustGotFrozen] + and a + ret nz + call BattleRandom + cp 10 percent + ret nc + xor a + ld [EnemyMonStatus], a + + ld a, [wBattleMode] + dec a + jr z, .wild + ld a, [CurOTMon] + ld hl, OTPartyMon1Status + call GetPartyLocation + ld [hl], 0 +.wild + + call UpdateBattleHuds + call SetPlayerTurn + ld hl, DefrostedOpponentText + jp StdBattleTextBox +; 3cafb + +HandleSafeguard: ; 3cafb + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .player1 + call .CheckPlayer + jr .CheckEnemy + +.player1 + call .CheckEnemy +.CheckPlayer: + ld a, [PlayerScreens] + bit SCREENS_SAFEGUARD, a + ret z + ld hl, PlayerSafeguardCount + dec [hl] + ret nz + res SCREENS_SAFEGUARD, a + ld [PlayerScreens], a + xor a + jr .print + +.CheckEnemy: + ld a, [EnemyScreens] + bit SCREENS_SAFEGUARD, a + ret z + ld hl, EnemySafeguardCount + dec [hl] + ret nz + res SCREENS_SAFEGUARD, a + ld [EnemyScreens], a + ld a, $1 + +.print + ld [hBattleTurn], a + ld hl, BattleText_SafeguardFaded + jp StdBattleTextBox + +HandleScreens: ; 3cb36 + ld a, [hLinkPlayerNumber] + cp 1 + jr z, .Both + call .CheckPlayer + jr .CheckEnemy + +.Both: + call .CheckEnemy + +.CheckPlayer: + call SetPlayerTurn + ld de, .Your + call .Copy + ld hl, PlayerScreens + ld de, PlayerLightScreenCount + jr .TickScreens + +.CheckEnemy: + call SetEnemyTurn + ld de, .Enemy + call .Copy + ld hl, EnemyScreens + ld de, EnemyLightScreenCount + +.TickScreens: + bit SCREENS_LIGHT_SCREEN, [hl] + call nz, .LightScreenTick + bit SCREENS_REFLECT, [hl] + call nz, .ReflectTick + ret + +.Copy: + ld hl, StringBuffer1 + jp CopyName2 +; 3cb75 + +.Your: + db "Your@" +.Enemy: + db "Enemy@" +; 3cb80 + +.LightScreenTick: ; 3cb80 + ld a, [de] + dec a + ld [de], a + ret nz + res SCREENS_LIGHT_SCREEN, [hl] + push hl + push de + ld hl, BattleText_PkmnLightScreenFell + call StdBattleTextBox + pop de + pop hl + ret +; 3cb91 + +.ReflectTick: ; 3cb91 + inc de + ld a, [de] + dec a + ld [de], a + ret nz + res SCREENS_REFLECT, [hl] + ld hl, BattleText_PkmnReflectFaded + jp StdBattleTextBox +; 3cb9e + +HandleWeather: ; 3cb9e + ld a, [Weather] + cp WEATHER_NONE + ret z + + ld hl, WeatherCount + dec [hl] + jr z, .ended + + ld hl, .WeatherMessages + call .PrintWeatherMessage + + ld a, [Weather] + cp WEATHER_SANDSTORM + ret nz + + ld a, [hLinkPlayerNumber] + cp 1 + jr z, .enemy_first + +.player_first + call SetPlayerTurn + call .SandstormDamage + call SetEnemyTurn + jr .SandstormDamage + +.enemy_first + call SetEnemyTurn + call .SandstormDamage + call SetPlayerTurn + +.SandstormDamage: + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVar + bit SUBSTATUS_UNDERGROUND, a + ret nz + + ld hl, BattleMonType1 + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, EnemyMonType1 +.ok + ld a, [hli] + cp ROCK + ret z + cp GROUND + ret z + cp STEEL + ret z + + ld a, [hl] + cp ROCK + ret z + cp GROUND + ret z + cp STEEL + ret z + + call SwitchTurnCore + xor a + ld [wNumHits], a + ld de, ANIM_IN_SANDSTORM + call Call_PlayBattleAnim + call SwitchTurnCore + call GetEighthMaxHP + call SubtractHPFromUser + + ld hl, SandstormHitsText + jp StdBattleTextBox + +.ended + ld hl, .WeatherEndedMessages + call .PrintWeatherMessage + xor a + ld [Weather], a + ret + +.PrintWeatherMessage: + ld a, [Weather] + dec a + ld c, a + ld b, 0 + add hl, bc + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + jp StdBattleTextBox +; 3cc2d + +.WeatherMessages: + dw BattleText_RainContinuesToFall + dw BattleText_TheSunlightIsStrong + dw BattleText_TheSandstormRages +.WeatherEndedMessages: + dw BattleText_TheRainStopped + dw BattleText_TheSunlightFaded + dw BattleText_TheSandstormSubsided +; 3cc39 + +SubtractHPFromTarget: ; 3cc39 + call SubtractHP + jp UpdateHPBar +; 3cc3f + +SubtractHPFromUser: ; 3cc3f +; Subtract HP from Pkmn + call SubtractHP + jp UpdateHPBarBattleHuds +; 3cc45 + +SubtractHP: ; 3cc45 + ld hl, BattleMonHP + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, EnemyMonHP +.ok + inc hl + ld a, [hl] + ld [Buffer3], a + sub c + ld [hld], a + ld [Buffer5], a + ld a, [hl] + ld [Buffer4], a + sbc b + ld [hl], a + ld [Buffer6], a + ret nc + + ld a, [Buffer3] + ld c, a + ld a, [Buffer4] + ld b, a + xor a + ld [hli], a + ld [hl], a + ld [Buffer5], a + ld [Buffer6], a + ret +; 3cc76 + +GetSixteenthMaxHP: ; 3cc76 + call GetQuarterMaxHP + ; quarter result + srl c + srl c + ; round up + ld a, c + and a + jr nz, .ok + inc c +.ok + ret +; 3cc83 + +GetEighthMaxHP: ; 3cc83 +; output: bc + call GetQuarterMaxHP +; assumes nothing can have 1024 or more hp +; halve result + srl c +; round up + ld a, c + and a + jr nz, .end + inc c +.end + ret +; 3cc8e + +GetQuarterMaxHP: ; 3cc8e +; output: bc + call GetMaxHP + +; quarter result + srl b + rr c + srl b + rr c + +; assumes nothing can have 1024 or more hp +; round up + ld a, c + and a + jr nz, .end + inc c +.end + ret +; 3cc9f + +GetHalfMaxHP: ; 3cc9f +; output: bc + call GetMaxHP + +; halve result + srl b + rr c + +; floor = 1 + ld a, c + or b + jr nz, .end + inc c +.end + ret +; 3ccac + +GetMaxHP: ; 3ccac +; output: bc, Buffer1-2 + + ld hl, BattleMonMaxHP + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, EnemyMonMaxHP +.ok + ld a, [hli] + ld [Buffer2], a + ld b, a + + ld a, [hl] + ld [Buffer1], a + ld c, a + ret +; 3ccc2 + +GetHalfHP: ; 3ccc2 +; unreferenced + ld hl, BattleMonHP + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, EnemyMonHP +.ok + ld a, [hli] + ld b, a + ld a, [hli] + ld c, a + srl b + rr c + ld a, [hli] + ld [Buffer2], a + ld a, [hl] + ld [Buffer1], a + ret +; 3ccde + +CheckUserHasEnoughHP: ; 3ccde + ld hl, BattleMonHP + 1 + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, EnemyMonHP + 1 +.ok + ld a, c + sub [hl] + dec hl + ld a, b + sbc [hl] + ret +; 3ccef + +RestoreHP ; 3ccef + ld hl, EnemyMonMaxHP + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, BattleMonMaxHP +.ok + ld a, [hli] + ld [Buffer2], a + ld a, [hld] + ld [Buffer1], a + dec hl + ld a, [hl] + ld [Buffer3], a + add c + ld [hld], a + ld [Buffer5], a + ld a, [hl] + ld [Buffer4], a + adc b + ld [hli], a + ld [Buffer6], a + + ld a, [Buffer1] + ld c, a + ld a, [hld] + sub c + ld a, [Buffer2] + ld b, a + ld a, [hl] + sbc b + jr c, .asm_3cd2d + ld a, b + ld [hli], a + ld [Buffer6], a + ld a, c + ld [hl], a + ld [Buffer5], a +.asm_3cd2d + + call SwitchTurnCore + call UpdateHPBarBattleHuds + jp SwitchTurnCore +; 3cd36 + +UpdateHPBarBattleHuds: ; 3cd36 + call UpdateHPBar + jp UpdateBattleHuds +; 3cd3c + +UpdateHPBar: ; 3cd3c + hlcoord 10, 9 + ld a, [hBattleTurn] + and a + ld a, 1 + jr z, .ok + hlcoord 2, 2 + xor a +.ok + push bc + ld [wWhichHPBar], a + predef AnimateHPBar + pop bc + ret +; 3cd55 + +HandleEnemyMonFaint: ; 3cd55 + call FaintEnemyPokemon + ld hl, BattleMonHP + ld a, [hli] + or [hl] + call z, FaintYourPokemon + xor a + ld [wWhichMonFaintedFirst], a + call UpdateBattleStateAndExperienceAfterEnemyFaint + call CheckPlayerPartyForFitPkmn + ld a, d + and a + jp z, LostBattle + + ld hl, BattleMonHP + ld a, [hli] + or [hl] + call nz, UpdatePlayerHUD + + ld a, $1 + ld [hBGMapMode], a + ld c, 60 + call DelayFrames + + ld a, [wBattleMode] + dec a + jr nz, .trainer + + ld a, 1 + ld [BattleEnded], a + ret + +.trainer + call CheckEnemyTrainerDefeated + jp z, WinTrainerBattle + + ld hl, BattleMonHP + ld a, [hli] + or [hl] + jr nz, .player_mon_not_fainted + + call AskUseNextPokemon + jr nc, .dont_flee + + ld a, 1 + ld [BattleEnded], a + ret + +.dont_flee + call ForcePlayerMonChoice + call CheckMobileBattleError + jp c, WildFled_EnemyFled_LinkBattleCanceled + + ld a, $1 + ld [wPlayerAction], a + call HandleEnemySwitch + jp z, WildFled_EnemyFled_LinkBattleCanceled + jr DoubleSwitch + +.player_mon_not_fainted + ld a, $1 + ld [wPlayerAction], a + call HandleEnemySwitch + jp z, WildFled_EnemyFled_LinkBattleCanceled + xor a + ld [wPlayerAction], a + ret +; 3cdca + +DoubleSwitch: ; 3cdca + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .player_1 + call ClearSprites + hlcoord 1, 0 + lb bc, 4, 10 + call ClearBox + call PlayerPartyMonEntrance + ld a, $1 + call EnemyPartyMonEntrance + jr .done + +.player_1 + ld a, [CurPartyMon] + push af + ld a, $1 + call EnemyPartyMonEntrance + call ClearSprites + call LoadTileMapToTempTileMap + pop af + ld [CurPartyMon], a + call PlayerPartyMonEntrance + +.done + xor a + ld [wPlayerAction], a + ret +; 3ce01 + +UpdateBattleStateAndExperienceAfterEnemyFaint: ; 3ce01 + call UpdateBattleMonInParty + ld a, [wBattleMode] + dec a + jr z, .wild + ld a, [CurOTMon] + ld hl, OTPartyMon1HP + call GetPartyLocation + xor a + ld [hli], a + ld [hl], a + +.wild + ld hl, PlayerSubStatus3 + res SUBSTATUS_IN_LOOP, [hl] + xor a + ld hl, EnemyDamageTaken + ld [hli], a + ld [hl], a + call NewEnemyMonStatus + call BreakAttraction + ld a, [wBattleMode] + dec a + jr z, .wild2 + jr .trainer + +.wild2 + call StopDangerSound + ld a, $1 + ld [wDanger], a + +.trainer + ld hl, BattleMonHP + ld a, [hli] + or [hl] + jr nz, .player_mon_did_not_faint + ld a, [wWhichMonFaintedFirst] + and a + jr nz, .player_mon_did_not_faint + call PlayerMonFaintHappinessMod + +.player_mon_did_not_faint + call CheckPlayerPartyForFitPkmn + ld a, d + and a + ret z + ld a, [wBattleMode] + dec a + call z, PlayVictoryMusic + call EmptyBattleTextBox + call LoadTileMapToTempTileMap + ld a, [wBattleResult] + and $c0 + ld [wBattleResult], a + call IsAnyMonHoldingExpShare + jr z, .skip_exp + ld hl, EnemyMonBaseStats + ld b, EnemyMonEnd - EnemyMonBaseStats +.loop + srl [hl] + inc hl + dec b + jr nz, .loop + +.skip_exp + ld hl, EnemyMonBaseStats + ld de, wBackupEnemyMonBaseStats + ld bc, EnemyMonEnd - EnemyMonBaseStats + call CopyBytes + xor a + ld [wGivingExperienceToExpShareHolders], a + call GiveExperiencePoints + call IsAnyMonHoldingExpShare + ret z + + ld a, [wBattleParticipantsNotFainted] + push af + ld a, d + ld [wBattleParticipantsNotFainted], a + ld hl, wBackupEnemyMonBaseStats + ld de, EnemyMonBaseStats + ld bc, EnemyMonEnd - EnemyMonBaseStats + call CopyBytes + ld a, $1 + ld [wGivingExperienceToExpShareHolders], a + call GiveExperiencePoints + pop af + ld [wBattleParticipantsNotFainted], a + ret +; 3ceaa + +IsAnyMonHoldingExpShare: ; 3ceaa + ld a, [PartyCount] + ld b, a + ld hl, PartyMon1 + ld c, 1 + ld d, 0 +.loop + push hl + push bc + ld bc, MON_HP + add hl, bc + ld a, [hli] + or [hl] + pop bc + pop hl + jr z, .next + + push hl + push bc + ld bc, MON_ITEM + add hl, bc + pop bc + ld a, [hl] + pop hl + + cp EXP_SHARE + jr nz, .next + ld a, d + or c + ld d, a + +.next + sla c + push de + ld de, PARTYMON_STRUCT_LENGTH + add hl, de + pop de + dec b + jr nz, .loop + + ld a, d + ld e, 0 + ld b, PARTY_LENGTH +.loop2 + srl a + jr nc, .okay + inc e + +.okay + dec b + jr nz, .loop2 + ld a, e + and a + ret +; 3ceec + +StopDangerSound: ; 3ceec + xor a + ld [Danger], a + ret +; 3cef1 + +FaintYourPokemon: ; 3cef1 + call StopDangerSound + call WaitSFX + ld a, $f0 + ld [CryTracks], a + ld a, [BattleMonSpecies] + call PlayStereoCry + call PlayerMonFaintedAnimation + hlcoord 9, 7 + lb bc, 5, 11 + call ClearBox + ld hl, BattleText_PkmnFainted + jp StdBattleTextBox +; 3cf14 + +FaintEnemyPokemon: ; 3cf14 + call WaitSFX + ld de, SFX_KINESIS + call PlaySFX + call EnemyMonFaintedAnimation + ld de, SFX_FAINT + call PlaySFX + hlcoord 1, 0 + lb bc, 4, 10 + call ClearBox + ld hl, BattleText_EnemyPkmnFainted + jp StdBattleTextBox +; 3cf35 + +CheckEnemyTrainerDefeated: ; 3cf35 + ld a, [OTPartyCount] + ld b, a + xor a + ld hl, OTPartyMon1HP + ld de, PARTYMON_STRUCT_LENGTH + +.loop + or [hl] + inc hl + or [hl] + dec hl + add hl, de + dec b + jr nz, .loop + + and a + ret +; 3cf4a + +HandleEnemySwitch: ; 3cf4a + ld hl, EnemyHPPal + ld e, HP_BAR_LENGTH_PX + call UpdateHPPal + call WaitBGMap + farcall EnemySwitch_TrainerHud + ld a, [wLinkMode] + and a + jr z, .not_linked + + call LinkBattleSendReceiveAction + ld a, [wBattleAction] + cp BATTLEACTION_FORFEIT + ret z + + call Call_LoadTempTileMapToTileMap + +.not_linked + ld hl, BattleMonHP + ld a, [hli] + or [hl] + ld a, $0 + jr nz, EnemyPartyMonEntrance + inc a + ret +; 3cf78 + +EnemyPartyMonEntrance: ; 3cf78 + push af + xor a + ld [wEnemySwitchMonIndex], a + call NewEnemyMonStatus + call ResetEnemyStatLevels + call BreakAttraction + pop af + and a + jr nz, .set + call EnemySwitch + jr .done_switch + +.set + call EnemySwitch_SetMode +.done_switch + call ResetBattleParticipants + call SetEnemyTurn + call SpikesDamage + xor a + ld [wEnemyMoveStruct + MOVE_ANIM], a + ld [wPlayerAction], a + inc a + ret +; 3cfa4 + +WinTrainerBattle: ; 3cfa4 +; Player won the battle + call StopDangerSound + ld a, $1 + ld [wDanger], a + ld [BattleEnded], a + ld a, [wLinkMode] + and a + ld a, b + call z, PlayVictoryMusic + callfar Battle_GetTrainerName + ld hl, BattleText_EnemyWasDefeated + call StdBattleTextBox + + call IsMobileBattle + jr z, .mobile + ld a, [wLinkMode] + and a + ret nz + + ld a, [InBattleTowerBattle] + bit 0, a + jr nz, .battle_tower + + call BattleWinSlideInEnemyTrainerFrontpic + ld c, 40 + call DelayFrames + ld a, [BattleType] + cp BATTLETYPE_CANLOSE + jr nz, .skip_heal + predef HealParty +.skip_heal + ld a, [wMonStatusFlags] + bit 0, a + jr nz, .skip_win_loss_text + call PrintWinLossText + +.skip_win_loss_text + jp .GiveMoney + +.mobile + call BattleWinSlideInEnemyTrainerFrontpic + ld c, 40 + call DelayFrames + ld c, $4 ; win + farcall Mobile_PrintOpponentBattleMessage + ret + +.battle_tower + call BattleWinSlideInEnemyTrainerFrontpic + ld c, 40 + call DelayFrames + call EmptyBattleTextBox + ld c, $3 + farcall BattleTowerText + call WaitPressAorB_BlinkCursor + ld hl, wPayDayMoney + ld a, [hli] + or [hl] + inc hl + or [hl] + ret nz + call ClearTileMap + call ClearBGPalettes + ret + +.GiveMoney: + ld a, [wAmuletCoin] + and a + call nz, .DoubleReward + call .CheckMaxedOutMomMoney + push af + ld a, $0 + jr nc, .okay + ld a, [wMomSavingMoney] + and $7 + cp $3 + jr nz, .okay + inc a + +.okay + ld b, a + ld c, $4 +.loop + ld a, b + and a + jr z, .loop2 + call .SendMoneyToMom + dec c + dec b + jr .loop + +.loop2 + ld a, c + and a + jr z, .done + call .AddMoneyToWallet + dec c + jr .loop2 + +.done + call .DoubleReward + call .DoubleReward + pop af + jr nc, .KeepItAll + ld a, [wMomSavingMoney] + and $7 + jr z, .KeepItAll + ld hl, .SentToMomTexts + dec a + ld c, a + ld b, 0 + add hl, bc + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + jp StdBattleTextBox + +.KeepItAll: + ld hl, GotMoneyForWinningText + jp StdBattleTextBox +; 3d081 + +.SendMoneyToMom: ; 3d081 + push bc + ld hl, wBattleReward + 2 + ld de, wMomsMoney + 2 + call AddBattleMoneyToAccount + pop bc + ret +; 3d08d + +.AddMoneyToWallet: ; 3d08d + push bc + ld hl, wBattleReward + 2 + ld de, Money + 2 + call AddBattleMoneyToAccount + pop bc + ret +; 3d099 + +.DoubleReward: ; 3d099 + ld hl, wBattleReward + 2 + sla [hl] + dec hl + rl [hl] + dec hl + rl [hl] + ret nc + ld a, $ff + ld [hli], a + ld [hli], a + ld [hl], a + ret +; 3d0ab + +.SentToMomTexts: ; 3d0ab + dw SentSomeToMomText + dw SentHalfToMomText + dw SentAllToMomText +; 3d0b1 + +.CheckMaxedOutMomMoney: ; 3d0b1 + ld hl, wMomsMoney + 2 + ld a, [hld] + cp LOW(MAX_MONEY) + ld a, [hld] + sbc HIGH(MAX_MONEY) ; mid + ld a, [hl] + sbc HIGH(MAX_MONEY >> 8) + ret +; 3d0be + +AddBattleMoneyToAccount: ; 3d0be + ld c, $3 + and a + push de + push hl + push bc + ld b, h + ld c, l + farcall TrainerRankings_AddToBattlePayouts + pop bc + pop hl +.loop + ld a, [de] + adc [hl] + ld [de], a + dec de + dec hl + dec c + jr nz, .loop + pop hl + ld a, [hld] + cp LOW(MAX_MONEY) + ld a, [hld] + sbc HIGH(MAX_MONEY) ; mid + ld a, [hl] + sbc HIGH(MAX_MONEY >> 8) + ret c + ld [hl], HIGH(MAX_MONEY >> 8) + inc hl + ld [hl], HIGH(MAX_MONEY) ; mid + inc hl + ld [hl], LOW(MAX_MONEY) + ret +; 3d0ea + +PlayVictoryMusic: ; 3d0ea + push de + ld de, MUSIC_NONE + call PlayMusic + call DelayFrame + ld de, MUSIC_WILD_VICTORY + ld a, [wBattleMode] + dec a + jr nz, .trainer_victory + push de + call IsAnyMonHoldingExpShare + pop de + jr nz, .play_music + ld hl, wPayDayMoney + ld a, [hli] + or [hl] + jr nz, .play_music + ld a, [wBattleParticipantsNotFainted] + and a + jr z, .lost + jr .play_music + +.trainer_victory + ld de, MUSIC_GYM_VICTORY + call IsJohtoGymLeader + jr c, .play_music + ld de, MUSIC_TRAINER_VICTORY + +.play_music + call PlayMusic + +.lost + pop de + ret +; 3d123 + +; These functions check if the current opponent is a gym leader or one of a +; few other special trainers. + +; Note: KantoGymLeaders is a subset of JohtoGymLeaders. If you wish to +; differentiate between the two, call IsKantoGymLeader first. + +; The Lance and Red entries are unused for music checks; those trainers are +; accounted for elsewhere. + +IsKantoGymLeader: ; 0x3d123 + ld hl, KantoGymLeaders + jr IsGymLeaderCommon + +IsJohtoGymLeader: ; 0x3d128 + ld hl, JohtoGymLeaders +IsGymLeaderCommon: + push de + ld a, [OtherTrainerClass] + ld de, $0001 + call IsInArray + pop de + ret +; 0x3d137 + +JohtoGymLeaders: + db FALKNER + db WHITNEY + db BUGSY + db MORTY + db PRYCE + db JASMINE + db CHUCK + db CLAIR + db WILL + db BRUNO + db KAREN + db KOGA +; fallthrough +; these two entries are unused + db CHAMPION + db RED +; fallthrough +KantoGymLeaders: + db BROCK + db MISTY + db LT_SURGE + db ERIKA + db JANINE + db SABRINA + db BLAINE + db BLUE + db -1 + +HandlePlayerMonFaint: ; 3d14e + call FaintYourPokemon + ld hl, EnemyMonHP + ld a, [hli] + or [hl] + call z, FaintEnemyPokemon + ld a, $1 + ld [wWhichMonFaintedFirst], a + call PlayerMonFaintHappinessMod + call CheckPlayerPartyForFitPkmn + ld a, d + and a + jp z, LostBattle + ld hl, EnemyMonHP + ld a, [hli] + or [hl] + jr nz, .notfainted + call UpdateBattleStateAndExperienceAfterEnemyFaint + ld a, [wBattleMode] + dec a + jr nz, .trainer + ld a, $1 + ld [BattleEnded], a + ret + +.trainer + call CheckEnemyTrainerDefeated + jp z, WinTrainerBattle + +.notfainted + call AskUseNextPokemon + jr nc, .switch + ld a, $1 + ld [BattleEnded], a + ret + +.switch + call ForcePlayerMonChoice + call CheckMobileBattleError + jp c, WildFled_EnemyFled_LinkBattleCanceled + ld a, c + and a + ret nz + ld a, $1 + ld [wPlayerAction], a + call HandleEnemySwitch + jp z, WildFled_EnemyFled_LinkBattleCanceled + jp DoubleSwitch +; 3d1aa + +PlayerMonFaintHappinessMod: ; 3d1aa + ld a, [CurBattleMon] + ld c, a + ld hl, wBattleParticipantsNotFainted + ld b, RESET_FLAG + predef FlagPredef + ld hl, EnemySubStatus3 + res SUBSTATUS_IN_LOOP, [hl] + xor a + ld [Danger], a + ld hl, PlayerDamageTaken + ld [hli], a + ld [hl], a + ld [BattleMonStatus], a + call UpdateBattleMonInParty + ld c, HAPPINESS_FAINTED + ; If TheirLevel > (YourLevel + 30), use a different parameter + ld a, [BattleMonLevel] + add 30 + ld b, a + ld a, [EnemyMonLevel] + cp b + jr c, .got_param + ld c, HAPPINESS_BEATENBYSTRONGFOE + +.got_param + ld a, [CurBattleMon] + ld [CurPartyMon], a + callfar ChangeHappiness + ld a, [wBattleResult] + and %11000000 + add $1 + ld [wBattleResult], a + ld a, [wWhichMonFaintedFirst] + and a + ret z + ret ; ?????????? +; 3d1f8 + +AskUseNextPokemon: ; 3d1f8 + call EmptyBattleTextBox + call LoadTileMapToTempTileMap +; We don't need to be here if we're in a Trainer battle, +; as that decision is made for us. + ld a, [wBattleMode] + and a + dec a + ret nz + + ld hl, BattleText_UseNextMon + call StdBattleTextBox +.loop + lb bc, 1, 7 + call PlaceYesNoBox + ld a, [wMenuCursorY] + jr c, .pressed_b + and a + ret + +.pressed_b + ld a, [wMenuCursorY] + cp $1 ; YES + jr z, .loop + ld hl, PartyMon1Speed + ld de, EnemyMonSpeed + jp TryToRunAwayFromBattle +; 3d227 + +ForcePlayerMonChoice: ; 3d227 + call EmptyBattleTextBox + call LoadStandardMenuDataHeader + call SetUpBattlePartyMenu_NoLoop + call ForcePickPartyMonInBattle + ld a, [wLinkMode] + and a + jr z, .skip_link + ld a, $1 + ld [wPlayerAction], a + call LinkBattleSendReceiveAction + +.skip_link + xor a + ld [wPlayerAction], a + call CheckMobileBattleError + jr c, .enemy_fainted_mobile_error + ld hl, EnemyMonHP + ld a, [hli] + or [hl] + jr nz, .send_out_pokemon + +.enemy_fainted_mobile_error + call ClearSprites + call ClearBGPalettes + call _LoadHPBar + call ExitMenu + call LoadTileMapToTempTileMap + call WaitBGMap + call GetMemSGBLayout + call SetPalettes + xor a + ld c, a + ret + +.send_out_pokemon + call ClearSprites + ld a, [CurBattleMon] + ld [LastPlayerMon], a + ld a, [CurPartyMon] + ld [CurBattleMon], a + call AddBattleParticipant + call InitBattleMon + call ResetPlayerStatLevels + call ClearPalettes + call DelayFrame + call _LoadHPBar + call CloseWindow + call GetMemSGBLayout + call SetPalettes + call SendOutPkmnText + call NewBattleMonStatus + call BreakAttraction + call SendOutPlayerMon + call EmptyBattleTextBox + call LoadTileMapToTempTileMap + call SetPlayerTurn + call SpikesDamage + ld a, $1 + and a + ld c, a + ret +; 3d2b3 + +PlayerPartyMonEntrance: ; 3d2b3 + ld a, [CurBattleMon] + ld [LastPlayerMon], a + ld a, [CurPartyMon] + ld [CurBattleMon], a + call AddBattleParticipant + call InitBattleMon + call ResetPlayerStatLevels + call SendOutPkmnText + call NewBattleMonStatus + call BreakAttraction + call SendOutPlayerMon + call EmptyBattleTextBox + call LoadTileMapToTempTileMap + call SetPlayerTurn + jp SpikesDamage +; 3d2e0 + +CheckMobileBattleError: ; 3d2e0 + ld a, [wLinkMode] + cp LINK_MOBILE + jr nz, .not_mobile ; It's not a mobile battle + + ld a, [wcd2b] + and a + jr z, .not_mobile + +; We have a mobile battle and something else happened + scf + ret + +.not_mobile + xor a + ret +; 3d2f1 + +IsMobileBattle: ; 3d2f1 + ld a, [wLinkMode] + cp LINK_MOBILE + ret +; 3d2f7 + +SetUpBattlePartyMenu_NoLoop: ; 3d2f7 + call ClearBGPalettes +SetUpBattlePartyMenu: ; switch to fullscreen menu? + farcall LoadPartyMenuGFX + farcall InitPartyMenuWithCancel + farcall InitPartyMenuBGPal7 + farcall InitPartyMenuGFX + ret +; 3d313 + +JumpToPartyMenuAndPrintText: ; 3d313 + farcall WritePartyMenuTilemap + farcall PrintPartyMenuText + call WaitBGMap + call SetPalettes + call DelayFrame + ret +; 3d329 + +SelectBattleMon: ; 3d329 + call IsMobileBattle + jr z, .mobile + farcall PartyMenuSelect + ret + +.mobile + farcall Mobile_PartyMenuSelect + ret +; 3d33c + +PickPartyMonInBattle: ; 3d33c +.loop + ld a, PARTYMENUACTION_SWITCH ; Which PKMN? + ld [PartyMenuActionText], a + call JumpToPartyMenuAndPrintText + call SelectBattleMon + ret c + call CheckIfCurPartyMonIsFitToFight + jr z, .loop + xor a + ret +; 3d34f + +SwitchMonAlreadyOut: ; 3d34f + ld hl, CurBattleMon + ld a, [CurPartyMon] + cp [hl] + jr nz, .notout + + ld hl, BattleText_PkmnIsAlreadyOut + call StdBattleTextBox + scf + ret + +.notout + xor a + ret +; 3d362 + +ForcePickPartyMonInBattle: ; 3d362 +; Can't back out. + +.pick + call PickPartyMonInBattle + ret nc + call CheckMobileBattleError + ret c + + ld de, SFX_WRONG + call PlaySFX + call WaitSFX + jr .pick +; 3d375 + +PickSwitchMonInBattle: ; 3d375 +.pick + call PickPartyMonInBattle + ret c + call SwitchMonAlreadyOut + jr c, .pick + xor a + ret +; 3d380 + +ForcePickSwitchMonInBattle: ; 3d380 +; Can't back out. + +.pick + call ForcePickPartyMonInBattle + call CheckMobileBattleError + ret c + call SwitchMonAlreadyOut + jr c, .pick + + xor a + ret +; 3d38e + +LostBattle: ; 3d38e + ld a, 1 + ld [BattleEnded], a + + ld a, [InBattleTowerBattle] + bit 0, a + jr nz, .battle_tower + + ld a, [BattleType] + cp BATTLETYPE_CANLOSE + jr nz, .not_canlose + +; Remove the enemy from the screen. + hlcoord 0, 0 + lb bc, 8, 21 + call ClearBox + call BattleWinSlideInEnemyTrainerFrontpic + + ld c, 40 + call DelayFrames + + ld a, [wMonStatusFlags] + bit 0, a + jr nz, .skip_win_loss_text + call PrintWinLossText +.skip_win_loss_text + ret + +.battle_tower +; Remove the enemy from the screen. + hlcoord 0, 0 + lb bc, 8, 21 + call ClearBox + call BattleWinSlideInEnemyTrainerFrontpic + + ld c, 40 + call DelayFrames + + call EmptyBattleTextBox + ld c, 2 + farcall BattleTowerText + call WaitPressAorB_BlinkCursor + call ClearTileMap + call ClearBGPalettes + ret + +.not_canlose + ld a, [wLinkMode] + and a + jr nz, .LostLinkBattle + +; Greyscale + ld b, SCGB_BATTLE_GRAYSCALE + call GetSGBLayout + call SetPalettes + jr .end + +.LostLinkBattle: + call UpdateEnemyMonInParty + call CheckEnemyTrainerDefeated + jr nz, .not_tied + ld hl, TiedAgainstText + ld a, [wBattleResult] + and $c0 + add 2 + ld [wBattleResult], a + jr .text + +.not_tied + ld hl, LostAgainstText + call IsMobileBattle + jr z, .mobile + +.text + call StdBattleTextBox + +.end + scf + ret + +.mobile +; Remove the enemy from the screen. + hlcoord 0, 0 + lb bc, 8, 21 + call ClearBox + call BattleWinSlideInEnemyTrainerFrontpic + + ld c, 40 + call DelayFrames + + ld c, $3 ; lost + farcall Mobile_PrintOpponentBattleMessage + scf + ret +; 3d432 + +EnemyMonFaintedAnimation: ; 3d432 + hlcoord 12, 5 + decoord 12, 6 + jp MonFaintedAnimation +; 3d43b + +PlayerMonFaintedAnimation: ; 3d43b + hlcoord 1, 10 + decoord 1, 11 + jp MonFaintedAnimation +; 3d444 + +MonFaintedAnimation: ; 3d444 + ld a, [wcfbe] + push af + set 6, a + ld [wcfbe], a + ld b, 7 + +.OuterLoop: + push bc + push de + push hl + ld b, 6 + +.InnerLoop: + push bc + push hl + push de + ld bc, 7 + call CopyBytes + pop de + pop hl + ld bc, -SCREEN_WIDTH + add hl, bc + push hl + ld h, d + ld l, e + add hl, bc + ld d, h + ld e, l + pop hl + pop bc + dec b + jr nz, .InnerLoop + + ld bc, 20 + add hl, bc + ld de, .Spaces + call PlaceString + ld c, 2 + call DelayFrames + pop hl + pop de + pop bc + dec b + jr nz, .OuterLoop + + pop af + ld [wcfbe], a + ret +; 3d488 + +.Spaces: + db " @" +; 3d490 + +SlideBattlePicOut: ; 3d490 + ld [hMapObjectIndexBuffer], a + ld c, a +.loop + push bc + push hl + ld b, $7 +.loop2 + push hl + call .DoFrame + pop hl + ld de, SCREEN_WIDTH + add hl, de + dec b + jr nz, .loop2 + ld c, 2 + call DelayFrames + pop hl + pop bc + dec c + jr nz, .loop + ret +; 3d4ae + +.DoFrame: ; 3d4ae + ld a, [hMapObjectIndexBuffer] + ld c, a + cp $8 + jr nz, .back +.forward + ld a, [hli] + ld [hld], a + dec hl + dec c + jr nz, .forward + ret + +.back + ld a, [hld] + ld [hli], a + inc hl + dec c + jr nz, .back + ret +; 3d4c3 + +ForceEnemySwitch: ; 3d4c3 + call ResetEnemyBattleVars + ld a, [wEnemySwitchMonIndex] + dec a + ld b, a + call LoadEnemyPkmnToSwitchTo + call ClearEnemyMonBox + call NewEnemyMonStatus + call ResetEnemyStatLevels + call Function_SetEnemyPkmnAndSendOutAnimation + call BreakAttraction + call ResetBattleParticipants + ret +; 3d4e1 + +EnemySwitch: ; 3d4e1 + call CheckWhetherToAskSwitch + jr nc, EnemySwitch_SetMode + ; Shift Mode + call ResetEnemyBattleVars + call CheckWhetherSwitchmonIsPredetermined + jr c, .skip + call FindPkmnInOTPartyToSwitchIntoBattle +.skip + ; 'b' contains the PartyNr of the Pkmn the AI will switch to + call LoadEnemyPkmnToSwitchTo + call OfferSwitch + push af + call ClearEnemyMonBox + call Function_BattleTextEnemySentOut + call Function_SetEnemyPkmnAndSendOutAnimation + pop af + ret c + ; If we're here, then we're switching too + xor a + ld [wBattleParticipantsNotFainted], a + ld [wBattleParticipantsIncludingFainted], a + ld [wPlayerAction], a + inc a + ld [wEnemyIsSwitching], a + call LoadTileMapToTempTileMap + jp PlayerSwitch +; 3d517 + +EnemySwitch_SetMode: ; 3d517 + call ResetEnemyBattleVars + call CheckWhetherSwitchmonIsPredetermined + jr c, .skip + call FindPkmnInOTPartyToSwitchIntoBattle +.skip + ; 'b' contains the PartyNr of the Pkmn the AI will switch to + call LoadEnemyPkmnToSwitchTo + ld a, 1 + ld [wEnemyIsSwitching], a + call ClearEnemyMonBox + call Function_BattleTextEnemySentOut + jp Function_SetEnemyPkmnAndSendOutAnimation +; 3d533 + +CheckWhetherSwitchmonIsPredetermined: ; 3d533 +; returns carry if: ??? + ld a, [wLinkMode] + and a + jr z, .not_linked + + ld a, [wBattleAction] + sub BATTLEACTION_SWITCH1 + ld b, a + jr .return_carry + +.not_linked + ld a, [wEnemySwitchMonIndex] + and a + jr z, .check_wBattleHasJustStarted + + dec a + ld b, a + jr .return_carry + +.check_wBattleHasJustStarted + ld a, [wBattleHasJustStarted] + and a + ld b, $0 + jr nz, .return_carry + + and a + ret + +.return_carry + scf + ret +; 3d557 + +ResetEnemyBattleVars: ; 3d557 +; and draw empty TextBox + xor a + ld [LastPlayerCounterMove], a + ld [LastEnemyCounterMove], a + ld [LastEnemyMove], a + ld [CurEnemyMove], a + dec a + ld [wEnemyItemState], a + xor a + ld [wPlayerWrapCount], a + hlcoord 18, 0 + ld a, 8 + call SlideBattlePicOut + call EmptyBattleTextBox + jp LoadStandardMenuDataHeader +; 3d57a + +ResetBattleParticipants: ; 3d57a + xor a + ld [wBattleParticipantsNotFainted], a + ld [wBattleParticipantsIncludingFainted], a +AddBattleParticipant: ; 3d581 + ld a, [CurBattleMon] + ld c, a + ld hl, wBattleParticipantsNotFainted + ld b, SET_FLAG + push bc + predef FlagPredef + pop bc + ld hl, wBattleParticipantsIncludingFainted + predef_jump FlagPredef +; 3d599 + +FindPkmnInOTPartyToSwitchIntoBattle: ; 3d599 + ld b, $ff + ld a, $1 + ld [Buffer1], a + ld [Buffer2], a +.loop + ld hl, Buffer1 + sla [hl] + inc hl + sla [hl] + inc b + ld a, [OTPartyCount] + cp b + jp z, ScoreMonTypeMatchups + ld a, [CurOTMon] + cp b + jr z, .discourage + ld hl, OTPartyMon1HP + push bc + ld a, b + call GetPartyLocation + ld a, [hli] + ld c, a + ld a, [hl] + or c + pop bc + jr z, .discourage + call LookUpTheEffectivenessOfEveryMove + call IsThePlayerPkmnTypesEffectiveAgainstOTPkmn + jr .loop + +.discourage + ld hl, Buffer2 + set 0, [hl] + jr .loop +; 3d5d7 + +LookUpTheEffectivenessOfEveryMove: ; 3d5d7 + push bc + ld hl, OTPartyMon1Moves + ld a, b + call GetPartyLocation + pop bc + ld e, NUM_MOVES + 1 +.loop + dec e + jr z, .done + ld a, [hli] + and a + jr z, .done + push hl + push de + push bc + dec a + ld hl, Moves + ld bc, MOVE_LENGTH + call AddNTimes + ld de, wEnemyMoveStruct + ld a, BANK(Moves) + call FarCopyBytes + call SetEnemyTurn + callfar BattleCheckTypeMatchup + pop bc + pop de + pop hl + ld a, [wd265] ; Get The Effectiveness Modifier + cp 10 + 1 ; 1.0 + 0.1 + jr c, .loop + ld hl, Buffer1 + set 0, [hl] + ret +.done + ret +; 3d618 + +IsThePlayerPkmnTypesEffectiveAgainstOTPkmn: ; 3d618 +; Calculates the effectiveness of the types of the PlayerPkmn +; against the OTPkmn + push bc + ld hl, OTPartyCount + ld a, b + inc a + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + dec a + ld hl, BaseData + BASE_TYPES + ld bc, BASE_DATA_SIZE + call AddNTimes + ld de, EnemyMonType + ld bc, BASE_CATCH_RATE - BASE_TYPES + ld a, BANK(BaseData) + call FarCopyBytes + ld a, [BattleMonType1] + ld [wPlayerMoveStruct + MOVE_TYPE], a + call SetPlayerTurn + callfar BattleCheckTypeMatchup + ld a, [wd265] + cp 10 + 1 ; 1.0 + 0.1 + jr nc, .super_effective + ld a, [BattleMonType2] + ld [wPlayerMoveStruct + MOVE_TYPE], a + callfar BattleCheckTypeMatchup + ld a, [wd265] + cp 10 + 1 ; 1.0 + 0.1 + jr nc, .super_effective + pop bc + ret + +.super_effective + pop bc + ld hl, Buffer1 + bit 0, [hl] + jr nz, .reset + inc hl + set 0, [hl] + ret + +.reset + res 0, [hl] + ret +; 3d672 + +ScoreMonTypeMatchups: ; 3d672 +.loop1 + ld hl, Buffer1 + sla [hl] + inc hl + sla [hl] + jr nc, .loop1 + ld a, [OTPartyCount] + ld b, a + ld c, [hl] +.loop2 + sla c + jr nc, .okay + dec b + jr z, .loop5 + jr .loop2 + +.okay + ld a, [Buffer1] + and a + jr z, .okay2 + ld b, $ff + ld c, a +.loop3 + inc b + sla c + jr nc, .loop3 + jr .quit + +.okay2 + ld b, $ff + ld a, [Buffer2] + ld c, a +.loop4 + inc b + sla c + jr c, .loop4 + jr .quit + +.loop5 + ld a, [OTPartyCount] + ld b, a + call BattleRandom + and $7 + cp b + jr nc, .loop5 + ld b, a + ld a, [CurOTMon] + cp b + jr z, .loop5 + ld hl, OTPartyMon1HP + push bc + ld a, b + call GetPartyLocation + pop bc + ld a, [hli] + ld c, a + ld a, [hl] + or c + jr z, .loop5 + +.quit + ret +; 3d6ca + +LoadEnemyPkmnToSwitchTo: ; 3d6ca + ; 'b' contains the PartyNr of the Pkmn the AI will switch to + ld a, b + ld [CurPartyMon], a + ld hl, OTPartyMon1Level + call GetPartyLocation + ld a, [hl] + ld [CurPartyLevel], a + ld a, [CurPartyMon] + inc a + ld hl, OTPartyCount + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + ld [TempEnemyMonSpecies], a + ld [CurPartySpecies], a + call LoadEnemyMon + + ld a, [CurPartySpecies] + cp UNOWN + jr nz, .skip_unown + ld a, [wFirstUnownSeen] + and a + jr nz, .skip_unown + ld hl, EnemyMonDVs + predef GetUnownLetter + ld a, [UnownLetter] + ld [wFirstUnownSeen], a +.skip_unown + + ld hl, EnemyMonHP + ld a, [hli] + ld [wEnemyHPAtTimeOfPlayerSwitch], a + ld a, [hl] + ld [wEnemyHPAtTimeOfPlayerSwitch + 1], a + ret +; 3d714 + +CheckWhetherToAskSwitch: ; 3d714 + ld a, [wBattleHasJustStarted] + dec a + jp z, .return_nc + ld a, [PartyCount] + dec a + jp z, .return_nc + ld a, [wLinkMode] + and a + jp nz, .return_nc + ld a, [Options] + bit BATTLE_SHIFT, a + jr nz, .return_nc + ld a, [CurPartyMon] + push af + ld a, [CurBattleMon] + ld [CurPartyMon], a + farcall CheckCurPartyMonFainted + pop bc + ld a, b + ld [CurPartyMon], a + jr c, .return_nc + scf + ret + +.return_nc + and a + ret +; 3d74b + +OfferSwitch: ; 3d74b + ld a, [CurPartyMon] + push af + callfar Battle_GetTrainerName + ld hl, BattleText_EnemyIsAboutToUseWillPlayerChangePkmn + call StdBattleTextBox + lb bc, 1, 7 + call PlaceYesNoBox + ld a, [wMenuCursorY] + dec a + jr nz, .said_no + call SetUpBattlePartyMenu_NoLoop + call PickSwitchMonInBattle + jr c, .canceled_switch + ld a, [CurBattleMon] + ld [LastPlayerMon], a + ld a, [CurPartyMon] + ld [CurBattleMon], a + call ClearPalettes + call DelayFrame + call _LoadHPBar + pop af + ld [CurPartyMon], a + xor a + ld [CurEnemyMove], a + ld [CurPlayerMove], a + and a + ret + +.canceled_switch + call ClearPalettes + call DelayFrame + call _LoadHPBar + +.said_no + pop af + ld [CurPartyMon], a + scf + ret +; 3d7a0 + +ClearEnemyMonBox: ; 3d7a0 + xor a + ld [hBGMapMode], a + call ExitMenu + call ClearSprites + hlcoord 1, 0 + lb bc, 4, 10 + call ClearBox + call WaitBGMap + jp FinishBattleAnim +; 3d7b8 + +Function_BattleTextEnemySentOut: ; 3d7b8 + callfar Battle_GetTrainerName + ld hl, BattleText_EnemySentOut + call StdBattleTextBox + jp WaitBGMap +; 3d7c7 + +Function_SetEnemyPkmnAndSendOutAnimation: ; 3d7c7 + ld a, [TempEnemyMonSpecies] + ld [CurPartySpecies], a + ld [CurSpecies], a + call GetBaseData + ld a, OTPARTYMON + ld [MonType], a + predef CopyPkmnToTempMon + call GetEnemyMonFrontpic + + xor a + ld [wNumHits], a + ld [wBattleAnimParam], a + call SetEnemyTurn + ld de, ANIM_SEND_OUT_MON + call Call_PlayBattleAnim + + call BattleCheckEnemyShininess + jr nc, .not_shiny + ld a, 1 ; shiny anim + ld [wBattleAnimParam], a + ld de, ANIM_SEND_OUT_MON + call Call_PlayBattleAnim +.not_shiny + + ld bc, TempMonSpecies + farcall CheckFaintedFrzSlp + jr c, .skip_cry + farcall CheckBattleScene + jr c, .cry_no_anim + hlcoord 12, 0 + ld d, $0 + ld e, ANIM_MON_SLOW + predef AnimateFrontpic + jr .skip_cry + +.cry_no_anim + ld a, $f + ld [CryTracks], a + ld a, [TempEnemyMonSpecies] + call PlayStereoCry + +.skip_cry + call UpdateEnemyHUD + ld a, $1 + ld [hBGMapMode], a + ret +; 3d834 + +NewEnemyMonStatus: ; 3d834 + xor a + ld [LastPlayerCounterMove], a + ld [LastEnemyCounterMove], a + ld [LastEnemyMove], a + ld hl, EnemySubStatus1 +rept 4 + ld [hli], a +endr + ld [hl], a + ld [EnemyDisableCount], a + ld [EnemyFuryCutterCount], a + ld [EnemyProtectCount], a + ld [wEnemyRageCounter], a + ld [EnemyDisabledMove], a + ld [wEnemyMinimized], a + ld [wPlayerWrapCount], a + ld [wEnemyWrapCount], a + ld [EnemyTurnsTaken], a + ld hl, PlayerSubStatus5 + res SUBSTATUS_CANT_RUN, [hl] + ret +; 3d867 + +ResetEnemyStatLevels: ; 3d867 + ld a, BASE_STAT_LEVEL + ld b, NUM_LEVEL_STATS + ld hl, EnemyStatLevels +.loop + ld [hli], a + dec b + jr nz, .loop + ret +; 3d873 + +CheckPlayerPartyForFitPkmn: ; 3d873 +; Has the player any Pkmn in his Party that can fight? + ld a, [PartyCount] + ld e, a + xor a + ld hl, PartyMon1HP + ld bc, PartyMon2 - (PartyMon1 + 1) +.loop + or [hl] + inc hl + or [hl] + add hl, bc + dec e + jr nz, .loop + ld d, a + ret +; 3d887 + +CheckIfCurPartyMonIsFitToFight: ; 3d887 + ld a, [CurPartyMon] + ld hl, PartyMon1HP + call GetPartyLocation + ld a, [hli] + or [hl] + ret nz + + ld a, [wBattleHasJustStarted] + and a + jr nz, .finish_fail + ld hl, PartySpecies + ld a, [CurPartyMon] + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + cp EGG + ld hl, BattleText_AnEGGCantBattle + jr z, .print_textbox + + ld hl, BattleText_TheresNoWillToBattle + +.print_textbox + call StdBattleTextBox + +.finish_fail + xor a + ret +; 3d8b3 + +TryToRunAwayFromBattle: ; 3d8b3 +; Run away from battle, with or without item + ld a, [BattleType] + cp BATTLETYPE_DEBUG + jp z, .can_escape + cp BATTLETYPE_CONTEST + jp z, .can_escape + cp BATTLETYPE_TRAP + jp z, .cant_escape + cp BATTLETYPE_CELEBI + jp z, .cant_escape + cp BATTLETYPE_SHINY + jp z, .cant_escape + cp BATTLETYPE_SUICUNE + jp z, .cant_escape + + ld a, [wLinkMode] + and a + jp nz, .can_escape + + ld a, [wBattleMode] + dec a + jp nz, .cant_run_from_trainer + + ld a, [EnemySubStatus5] + bit SUBSTATUS_CANT_RUN, a + jp nz, .cant_escape + + ld a, [wPlayerWrapCount] + and a + jp nz, .cant_escape + + push hl + push de + ld a, [BattleMonItem] + ld [wd265], a + ld b, a + callfar GetItemHeldEffect + ld a, b + cp HELD_ESCAPE + pop de + pop hl + jr nz, .no_flee_item + + call SetPlayerTurn + call GetItemName + ld hl, BattleText_UserFledUsingAStringBuffer1 + call StdBattleTextBox + jp .can_escape + +.no_flee_item + ld a, [wNumFleeAttempts] + inc a + ld [wNumFleeAttempts], a + ld a, [hli] + ld [hStringCmpString2 + 0], a + ld a, [hl] + ld [hStringCmpString2 + 1], a + ld a, [de] + inc de + ld [hStringCmpString1 + 0], a + ld a, [de] + ld [hStringCmpString1 + 1], a + call Call_LoadTempTileMapToTileMap + ld de, hStringCmpString2 + ld hl, hStringCmpString1 + ld c, $2 + call StringCmp + jr nc, .can_escape + + xor a + ld [hMultiplicand], a + ld a, $20 + ld [hMultiplier], a + call Multiply + ld a, [hProduct + 2] + ld [hDividend + 0], a + ld a, [hProduct + 3] + ld [hDividend + 1], a + ld a, [hStringCmpString1 + 0] + ld b, a + ld a, [hStringCmpString1 + 1] + srl b + rr a + srl b + rr a + and a + jr z, .can_escape + ld [hDivisor], a + ld b, 2 + call Divide + ld a, [hQuotient + 1] + and a + jr nz, .can_escape + ld a, [wNumFleeAttempts] + ld c, a +.loop + dec c + jr z, .cant_escape_2 + ld b, 30 + ld a, [hQuotient + 2] + add b + ld [hQuotient + 2], a + jr c, .can_escape + jr .loop + +.cant_escape_2 + call BattleRandom + ld b, a + ld a, [hQuotient + 2] + cp b + jr nc, .can_escape + ld a, $1 + ld [wPlayerAction], a + ld hl, BattleText_CantEscape2 + jr .print_inescapable_text + +.cant_escape + ld hl, BattleText_CantEscape + jr .print_inescapable_text + +.cant_run_from_trainer + ld hl, BattleText_TheresNoEscapeFromTrainerBattle + +.print_inescapable_text + call StdBattleTextBox + ld a, $1 + ld [wFailedToFlee], a + call LoadTileMapToTempTileMap + and a + ret + +.can_escape + ld a, [wLinkMode] + and a + ld a, DRAW + jr z, .fled + call LoadTileMapToTempTileMap + xor a + ld [wPlayerAction], a + ld a, $f + ld [CurMoveNum], a + xor a + ld [CurPlayerMove], a + call LinkBattleSendReceiveAction + call Call_LoadTempTileMapToTileMap + call CheckMobileBattleError + jr c, .mobile + + ; Got away safely + ld a, [wBattleAction] + cp BATTLEACTION_FORFEIT + ld a, DRAW + jr z, .fled + dec a +.fled + ld b, a + ld a, [wBattleResult] + and $c0 + add b + ld [wBattleResult], a + call StopDangerSound + push de + ld de, SFX_RUN + call WaitPlaySFX + pop de + call WaitSFX + ld hl, BattleText_GotAwaySafely + call StdBattleTextBox + call WaitSFX + call LoadTileMapToTempTileMap + scf + ret + +.mobile + call StopDangerSound + ld hl, wcd2a + bit 4, [hl] + jr nz, .skip_link_error + ld hl, BattleText_LinkErrorBattleCanceled + call StdBattleTextBox + +.skip_link_error + call WaitSFX + call LoadTileMapToTempTileMap + scf + ret +; 3da0d + +InitBattleMon: ; 3da0d + ld a, MON_SPECIES + call GetPartyParamLocation + ld de, BattleMonSpecies + ld bc, MON_ID + call CopyBytes + ld bc, MON_DVS - MON_ID + add hl, bc + ld de, BattleMonDVs + ld bc, MON_PKRUS - MON_DVS + call CopyBytes + inc hl + inc hl + inc hl + ld de, BattleMonLevel + ld bc, PARTYMON_STRUCT_LENGTH - MON_LEVEL + call CopyBytes + ld a, [BattleMonSpecies] + ld [TempBattleMonSpecies], a + ld [CurPartySpecies], a + ld [CurSpecies], a + call GetBaseData + ld a, [BaseType1] + ld [BattleMonType1], a + ld a, [BaseType2] + ld [BattleMonType2], a + ld hl, PartyMonNicknames + ld a, [CurBattleMon] + call SkipNames + ld de, BattleMonNick + ld bc, PKMN_NAME_LENGTH + call CopyBytes + ld hl, BattleMonAttack + ld de, PlayerStats + ld bc, PARTYMON_STRUCT_LENGTH - MON_ATK + call CopyBytes + call ApplyStatusEffectOnPlayerStats + call BadgeStatBoosts + ret +; 3da74 + +BattleCheckPlayerShininess: ; 3da74 + call GetPartyMonDVs + jr BattleCheckShininess + +BattleCheckEnemyShininess: ; 3da79 + call GetEnemyMonDVs + +BattleCheckShininess: ; 3da7c + ld b, h + ld c, l + callfar CheckShininess + ret +; 3da85 + +GetPartyMonDVs: ; 3da85 + ld hl, BattleMonDVs + ld a, [PlayerSubStatus5] + bit SUBSTATUS_TRANSFORMED, a + ret z + ld hl, PartyMon1DVs + ld a, [CurBattleMon] + jp GetPartyLocation +; 3da97 + +GetEnemyMonDVs: ; 3da97 + ld hl, EnemyMonDVs + ld a, [EnemySubStatus5] + bit SUBSTATUS_TRANSFORMED, a + ret z + ld hl, wEnemyBackupDVs + ld a, [wBattleMode] + dec a + ret z + ld hl, OTPartyMon1DVs + ld a, [CurOTMon] + jp GetPartyLocation +; 3dab1 + +ResetPlayerStatLevels: ; 3dab1 + ld a, BASE_STAT_LEVEL + ld b, NUM_LEVEL_STATS + ld hl, PlayerStatLevels +.loop + ld [hli], a + dec b + jr nz, .loop + ret +; 3dabd + +InitEnemyMon: ; 3dabd + ld a, [CurPartyMon] + ld hl, OTPartyMon1Species + call GetPartyLocation + ld de, EnemyMonSpecies + ld bc, MON_ID + call CopyBytes + ld bc, MON_DVS - MON_ID + add hl, bc + ld de, EnemyMonDVs + ld bc, MON_PKRUS - MON_DVS + call CopyBytes + inc hl + inc hl + inc hl + ld de, EnemyMonLevel + ld bc, PARTYMON_STRUCT_LENGTH - MON_LEVEL + call CopyBytes + ld a, [EnemyMonSpecies] + ld [CurSpecies], a + call GetBaseData + ld hl, OTPartyMonNicknames + ld a, [CurPartyMon] + call SkipNames + ld de, EnemyMonNick + ld bc, PKMN_NAME_LENGTH + call CopyBytes + ld hl, EnemyMonAttack + ld de, EnemyStats + ld bc, PARTYMON_STRUCT_LENGTH - MON_ATK + call CopyBytes + call ApplyStatusEffectOnEnemyStats + ld hl, BaseType1 + ld de, EnemyMonType1 + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + ld [de], a + ld hl, BaseStats + ld de, EnemyMonBaseStats + ld b, 5 +.loop + ld a, [hli] + ld [de], a + inc de + dec b + jr nz, .loop + ld a, [CurPartyMon] + ld [CurOTMon], a + ret +; 3db32 + +SwitchPlayerMon: ; 3db32 + call ClearSprites + ld a, [CurBattleMon] + ld [LastPlayerMon], a + ld a, [CurPartyMon] + ld [CurBattleMon], a + call AddBattleParticipant + call InitBattleMon + call ResetPlayerStatLevels + call NewBattleMonStatus + call BreakAttraction + call SendOutPlayerMon + call EmptyBattleTextBox + call LoadTileMapToTempTileMap + ld hl, EnemyMonHP + ld a, [hli] + or [hl] + ret +; 3db5f + +SendOutPlayerMon: ; 3db5f + ld hl, BattleMonDVs + predef GetUnownLetter + hlcoord 1, 5 + ld b, 7 + ld c, 8 + call ClearBox + call WaitBGMap + xor a + ld [hBGMapMode], a + call GetBattleMonBackpic + xor a + ld [hGraphicStartTile], a + ld [wBattleMenuCursorBuffer], a + ld [CurMoveNum], a + ld [TypeModifier], a + ld [wPlayerMoveStruct + MOVE_ANIM], a + ld [LastPlayerCounterMove], a + ld [LastEnemyCounterMove], a + ld [LastPlayerMove], a + call CheckAmuletCoin + call FinishBattleAnim + xor a + ld [wEnemyWrapCount], a + call SetPlayerTurn + xor a + ld [wNumHits], a + ld [wBattleAnimParam], a + ld de, ANIM_SEND_OUT_MON + call Call_PlayBattleAnim + call BattleCheckPlayerShininess + jr nc, .not_shiny + ld a, 1 + ld [wBattleAnimParam], a + ld de, ANIM_SEND_OUT_MON + call Call_PlayBattleAnim + +.not_shiny + ld a, MON_SPECIES + call GetPartyParamLocation + ld b, h + ld c, l + farcall CheckFaintedFrzSlp + jr c, .statused + ld a, $f0 + ld [CryTracks], a + ld a, [CurPartySpecies] + call PlayStereoCry + +.statused + call UpdatePlayerHUD + ld a, $1 + ld [hBGMapMode], a + ret +; 3dbde + +NewBattleMonStatus: ; 3dbde + xor a + ld [LastPlayerCounterMove], a + ld [LastEnemyCounterMove], a + ld [LastPlayerMove], a + ld hl, PlayerSubStatus1 +rept 4 + ld [hli], a +endr + ld [hl], a + ld hl, PlayerUsedMoves + ld [hli], a + ld [hli], a + ld [hli], a + ld [hl], a + ld [PlayerDisableCount], a + ld [PlayerFuryCutterCount], a + ld [PlayerProtectCount], a + ld [wPlayerRageCounter], a + ld [DisabledMove], a + ld [wPlayerMinimized], a + ld [wEnemyWrapCount], a + ld [wPlayerWrapCount], a + ld [PlayerTurnsTaken], a + ld hl, EnemySubStatus5 + res SUBSTATUS_CANT_RUN, [hl] + ret +; 3dc18 + +BreakAttraction: ; 3dc18 + ld hl, PlayerSubStatus1 + res SUBSTATUS_IN_LOVE, [hl] + ld hl, EnemySubStatus1 + res SUBSTATUS_IN_LOVE, [hl] + ret +; 3dc23 + +SpikesDamage: ; 3dc23 + ld hl, PlayerScreens + ld de, BattleMonType + ld bc, UpdatePlayerHUD + ld a, [hBattleTurn] + and a + jr z, .ok + ld hl, EnemyScreens + ld de, EnemyMonType + ld bc, UpdateEnemyHUD +.ok + + bit SCREENS_SPIKES, [hl] + ret z + + ; Flying-types aren't affected by Spikes. + ld a, [de] + cp FLYING + ret z + inc de + ld a, [de] + cp FLYING + ret z + + push bc + + ld hl, BattleText_UserHurtBySpikes ; "hurt by SPIKES!" + call StdBattleTextBox + + call GetEighthMaxHP + call SubtractHPFromTarget + + pop hl + call .hl + + jp WaitBGMap + +.hl + jp hl +; 3dc5b + +PursuitSwitch: ; 3dc5b + ld a, BATTLE_VARS_MOVE + call GetBattleVar + ld b, a + call GetMoveEffect + ld a, b + cp EFFECT_PURSUIT + jr nz, .done + + ld a, [CurBattleMon] + push af + + ld hl, DoPlayerTurn + ld a, [hBattleTurn] + and a + jr z, .do_turn + ld hl, DoEnemyTurn + ld a, [LastPlayerMon] + ld [CurBattleMon], a +.do_turn + ld a, BANK(DoPlayerTurn) + rst FarCall + + ld a, BATTLE_VARS_MOVE + call GetBattleVarAddr + ld a, $ff + ld [hl], a + + pop af + ld [CurBattleMon], a + + ld a, [hBattleTurn] + and a + jr z, .check_enemy_fainted + + ld a, [LastPlayerMon] + call UpdateBattleMon + ld hl, BattleMonHP + ld a, [hli] + or [hl] + jr nz, .done + + ld a, $f0 + ld [CryTracks], a + ld a, [BattleMonSpecies] + call PlayStereoCry + ld a, [LastPlayerMon] + ld c, a + ld hl, wBattleParticipantsNotFainted + ld b, RESET_FLAG + predef FlagPredef + call PlayerMonFaintedAnimation + ld hl, BattleText_PkmnFainted + jr .done_fainted + +.check_enemy_fainted + ld hl, EnemyMonHP + ld a, [hli] + or [hl] + jr nz, .done + + ld de, SFX_KINESIS + call PlaySFX + call WaitSFX + ld de, SFX_FAINT + call PlaySFX + call WaitSFX + call EnemyMonFaintedAnimation + ld hl, BattleText_EnemyPkmnFainted + +.done_fainted + call StdBattleTextBox + scf + ret + +.done + and a + ret +; 3dce6 + +RecallPlayerMon: ; 3dce6 + ld a, [hBattleTurn] + push af + xor a + ld [hBattleTurn], a + ld [wNumHits], a + ld de, ANIM_RETURN_MON + call Call_PlayBattleAnim + pop af + ld [hBattleTurn], a + ret +; 3dcf9 + +HandleHealingItems: ; 3dcf9 + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .player_1 + call SetPlayerTurn + call HandleHPHealingItem + call UseHeldStatusHealingItem + call UseConfusionHealingItem + call SetEnemyTurn + call HandleHPHealingItem + call UseHeldStatusHealingItem + jp UseConfusionHealingItem + +.player_1 + call SetEnemyTurn + call HandleHPHealingItem + call UseHeldStatusHealingItem + call UseConfusionHealingItem + call SetPlayerTurn + call HandleHPHealingItem + call UseHeldStatusHealingItem + jp UseConfusionHealingItem +; 3dd2f + +HandleHPHealingItem: ; 3dd2f + callfar GetOpponentItem + ld a, b + cp HELD_BERRY + ret nz + ld de, EnemyMonHP + 1 + ld hl, EnemyMonMaxHP + ld a, [hBattleTurn] + and a + jr z, .go + ld de, BattleMonHP + 1 + ld hl, BattleMonMaxHP + +.go +; If, and only if, Pokemon's HP is less than half max, use the item. +; Store current HP in Buffer 3/4 + push bc + ld a, [de] + ld [Buffer3], a + add a + ld c, a + dec de + ld a, [de] + inc de + ld [Buffer4], a + adc a + ld b, a + ld a, b + cp [hl] + ld a, c + pop bc + jr z, .equal + jr c, .less + ret + +.equal + inc hl + cp [hl] + dec hl + ret nc + +.less + call ItemRecoveryAnim + ; store max HP in Buffer1/2 + ld a, [hli] + ld [Buffer2], a + ld a, [hl] + ld [Buffer1], a + ld a, [de] + add c + ld [Buffer5], a + ld c, a + dec de + ld a, [de] + adc $0 + ld [Buffer6], a + ld b, a + ld a, [hld] + cp c + ld a, [hl] + sbc b + jr nc, .okay + ld a, [hli] + ld [Buffer6], a + ld a, [hl] + ld [Buffer5], a + +.okay + ld a, [Buffer6] + ld [de], a + inc de + ld a, [Buffer5] + ld [de], a + ld a, [hBattleTurn] + ld [wWhichHPBar], a + and a + hlcoord 2, 2 + jr z, .got_hp_bar_coords + hlcoord 10, 9 + +.got_hp_bar_coords + ld [wWhichHPBar], a + predef AnimateHPBar +UseOpponentItem: + call RefreshBattleHuds + callfar GetOpponentItem + ld a, [hl] + ld [wNamedObjectIndexBuffer], a + call GetItemName + callfar ConsumeHeldItem + ld hl, RecoveredUsingText + jp StdBattleTextBox +; 3ddc8 + +ItemRecoveryAnim: ; 3ddc8 + push hl + push de + push bc + call EmptyBattleTextBox + ld a, RECOVER + ld [FXAnimID], a + call SwitchTurnCore + xor a + ld [wNumHits], a + ld [FXAnimID + 1], a + predef PlayBattleAnim + call SwitchTurnCore + pop bc + pop de + pop hl + ret +; 3dde9 + +UseHeldStatusHealingItem: ; 3dde9 + callfar GetOpponentItem + ld hl, .Statuses +.loop + ld a, [hli] + cp $ff + ret z + inc hl + cp b + jr nz, .loop + dec hl + ld b, [hl] + ld a, BATTLE_VARS_STATUS_OPP + call GetBattleVarAddr + and b + ret z + xor a + ld [hl], a + push bc + call UpdateOpponentInParty + pop bc + ld a, BATTLE_VARS_SUBSTATUS5_OPP + call GetBattleVarAddr + and [hl] + res SUBSTATUS_TOXIC, [hl] + ld a, BATTLE_VARS_SUBSTATUS1_OPP + call GetBattleVarAddr + and [hl] + res SUBSTATUS_NIGHTMARE, [hl] + ld a, b + cp ALL_STATUS + jr nz, .skip_confuse + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVarAddr + res SUBSTATUS_CONFUSED, [hl] + +.skip_confuse + ld hl, CalcEnemyStats + ld a, [hBattleTurn] + and a + jr z, .got_pointer + ld hl, CalcPlayerStats + +.got_pointer + call SwitchTurnCore + ld a, BANK(CalcEnemyStats) + rst FarCall + call SwitchTurnCore + call ItemRecoveryAnim + call UseOpponentItem + ld a, $1 + and a + ret +; 3de44 + +.Statuses: ; 3de44 + db HELD_HEAL_POISON, 1 << PSN + db HELD_HEAL_FREEZE, 1 << FRZ + db HELD_HEAL_BURN, 1 << BRN + db HELD_HEAL_SLEEP, SLP + db HELD_HEAL_PARALYZE, 1 << PAR + db HELD_HEAL_STATUS, ALL_STATUS + db $ff +; 3de51 + +UseConfusionHealingItem: ; 3de51 + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVar + bit SUBSTATUS_CONFUSED, a + ret z + callfar GetOpponentItem + ld a, b + cp HELD_HEAL_CONFUSION + jr z, .heal_status + cp HELD_HEAL_STATUS + ret nz + +.heal_status + ld a, [hl] + ld [wd265], a + ld a, BATTLE_VARS_SUBSTATUS3_OPP + call GetBattleVarAddr + res SUBSTATUS_CONFUSED, [hl] + call GetItemName + call ItemRecoveryAnim + ld hl, BattleText_ItemHealedConfusion + call StdBattleTextBox + ld a, [hBattleTurn] + and a + jr nz, .do_partymon + call GetOTPartymonItem + xor a + ld [bc], a + ld a, [wBattleMode] + dec a + ret z + ld [hl], $0 + ret + +.do_partymon + call GetPartymonItem + xor a + ld [bc], a + ld [hl], a + ret +; 3de97 + +HandleStatBoostingHeldItems: ; 3de97 +; The effects handled here are not used in-game. + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .player_1 + call .DoPlayer + jp .DoEnemy + +.player_1 + call .DoEnemy + jp .DoPlayer +; 3dea9 + +.DoPlayer: ; 3dea9 + call GetPartymonItem + ld a, $0 + jp .HandleItem +; 3deb1 + +.DoEnemy: ; 3deb1 + call GetOTPartymonItem + ld a, $1 +.HandleItem: ; 3deb6 + ld [hBattleTurn], a + ld d, h + ld e, l + push de + push bc + ld a, [bc] + ld b, a + callfar GetItemHeldEffect + ld hl, .StatUpItems +.loop + ld a, [hli] + cp $ff + jr z, .finish + inc hl + inc hl + cp b + jr nz, .loop + pop bc + ld a, [bc] + ld [wd265], a + push bc + dec hl + dec hl + ld a, [hli] + ld h, [hl] + ld l, a + ld a, BANK(BattleCommand_AttackUp) + rst FarCall + pop bc + pop de + ld a, [FailedMessage] + and a + ret nz + xor a + ld [bc], a + ld [de], a + call GetItemName + ld hl, BattleText_UsersStringBuffer1Activated + call StdBattleTextBox + callfar BattleCommand_StatUpMessage + ret + +.finish + pop bc + pop de + ret +; 3defc + +.StatUpItems: + dbw HELD_ATTACK_UP, BattleCommand_AttackUp + dbw HELD_DEFENSE_UP, BattleCommand_DefenseUp + dbw HELD_SPEED_UP, BattleCommand_SpeedUp + dbw HELD_SP_ATTACK_UP, BattleCommand_SpecialAttackUp + dbw HELD_SP_DEFENSE_UP, BattleCommand_SpecialDefenseUp + dbw HELD_ACCURACY_UP, BattleCommand_AccuracyUp + dbw HELD_EVASION_UP, BattleCommand_EvasionUp + db $ff +; 3df12 + +GetPartymonItem: ; 3df12 + ld hl, PartyMon1Item + ld a, [CurBattleMon] + call GetPartyLocation + ld bc, BattleMonItem + ret +; 3df1f + +GetOTPartymonItem: ; 3df1f + ld hl, OTPartyMon1Item + ld a, [CurOTMon] + call GetPartyLocation + ld bc, EnemyMonItem + ret +; 3df2c + +UpdateBattleHUDs: ; 3df2c + push hl + push de + push bc + call DrawPlayerHUD + ld hl, PlayerHPPal + call SetHPPal + call CheckDanger + call DrawEnemyHUD + ld hl, EnemyHPPal + call SetHPPal + pop bc + pop de + pop hl + ret +; 3df48 + +UpdatePlayerHUD:: ; 3df48 + push hl + push de + push bc + call DrawPlayerHUD + call UpdatePlayerHPPal + call CheckDanger + pop bc + pop de + pop hl + ret +; 3df58 + +DrawPlayerHUD: ; 3df58 + xor a + ld [hBGMapMode], a + + ; Clear the area + hlcoord 9, 7 + lb bc, 5, 11 + call ClearBox + + farcall DrawPlayerHUDBorder + + hlcoord 18, 9 + ld [hl], $73 ; vertical bar + call PrintPlayerHUD + + ; HP bar + hlcoord 10, 9 + ld b, 1 + xor a ; PARTYMON + ld [MonType], a + predef DrawPlayerHP + + ; Exp bar + push de + ld a, [CurBattleMon] + ld hl, PartyMon1Exp + 2 + call GetPartyLocation + ld d, h + ld e, l + + hlcoord 10, 11 + ld a, [TempMonLevel] + ld b, a + call FillInExpBar + pop de + ret +; 3df98 + +UpdatePlayerHPPal: ; 3df98 + ld hl, PlayerHPPal + jp UpdateHPPal +; 3df9e + +CheckDanger: ; 3df9e + ld hl, BattleMonHP + ld a, [hli] + or [hl] + jr z, .no_danger + ld a, [wDanger] + and a + jr nz, .done + ld a, [PlayerHPPal] + cp HP_RED + jr z, .danger + +.no_danger + ld hl, Danger + res DANGER_ON_F, [hl] + jr .done + +.danger + ld hl, Danger + set DANGER_ON_F, [hl] + +.done + ret +; 3dfbf + +PrintPlayerHUD: ; 3dfbf + ld de, BattleMonNick + hlcoord 10, 7 + call ret_3e138 + call PlaceString + + push bc + + ld a, [CurBattleMon] + ld hl, PartyMon1DVs + call GetPartyLocation + ld de, TempMonDVs + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + ld [de], a + ld hl, BattleMonLevel + ld de, TempMonLevel + ld bc, $0011 + call CopyBytes + ld a, [CurBattleMon] + ld hl, PartyMon1Species + call GetPartyLocation + ld a, [hl] + ld [CurPartySpecies], a + ld [CurSpecies], a + call GetBaseData + + pop hl + dec hl + + ld a, TEMPMON + ld [MonType], a + callfar GetGender + ld a, " " + jr c, .got_gender_char + ld a, "♂" + jr nz, .got_gender_char + ld a, "♀" + +.got_gender_char + hlcoord 17, 8 + ld [hl], a + hlcoord 14, 8 + push af ; back up gender + push hl + ld de, BattleMonStatus + predef PlaceNonFaintStatus + pop hl + pop bc + ret nz + ld a, b + cp " " + jr nz, .copy_level ; male or female + dec hl ; genderless + +.copy_level + ld a, [BattleMonLevel] + ld [TempMonLevel], a + jp PrintLevel +; 3e036 + +UpdateEnemyHUD:: ; 3e036 + push hl + push de + push bc + call DrawEnemyHUD + call UpdateEnemyHPPal + pop bc + pop de + pop hl + ret +; 3e043 + +DrawEnemyHUD: ; 3e043 + xor a + ld [hBGMapMode], a + + hlcoord 1, 0 + lb bc, 4, 11 + call ClearBox + + farcall DrawEnemyHUDBorder + + ld a, [TempEnemyMonSpecies] + ld [CurSpecies], a + ld [CurPartySpecies], a + call GetBaseData + ld de, EnemyMonNick + hlcoord 1, 0 + call ret_3e138 + call PlaceString + ld h, b + ld l, c + dec hl + + ld hl, EnemyMonDVs + ld de, TempMonDVs + ld a, [EnemySubStatus5] + bit SUBSTATUS_TRANSFORMED, a + jr z, .ok + ld hl, wEnemyBackupDVs +.ok + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + ld [de], a + + ld a, TEMPMON + ld [MonType], a + callfar GetGender + ld a, " " + jr c, .got_gender + ld a, "♂" + jr nz, .got_gender + ld a, "♀" + +.got_gender + hlcoord 9, 1 + ld [hl], a + + hlcoord 6, 1 + push af + push hl + ld de, EnemyMonStatus + predef PlaceNonFaintStatus + pop hl + pop bc + jr nz, .skip_level + ld a, b + cp " " + jr nz, .print_level + dec hl +.print_level + ld a, [EnemyMonLevel] + ld [TempMonLevel], a + call PrintLevel +.skip_level + + ld hl, EnemyMonHP + ld a, [hli] + ld [hMultiplicand + 1], a + ld a, [hld] + ld [hMultiplicand + 2], a + or [hl] + jr nz, .not_fainted + + ld c, a + ld e, a + ld d, HP_BAR_LENGTH + jp .draw_bar + +.not_fainted + xor a + ld [hMultiplicand], a + ld a, HP_BAR_LENGTH_PX + ld [hMultiplier], a + call Multiply + ld hl, EnemyMonMaxHP + ld a, [hli] + ld b, a + ld a, [hl] + ld [hMultiplier], a + ld a, b + and a + jr z, .less_than_256_max + ld a, [hMultiplier] + srl b + rr a + srl b + rr a + ld [hDivisor], a + ld a, [hProduct + 2] + ld b, a + srl b + ld a, [hProduct + 3] + rr a + srl b + rr a + ld [hProduct + 3], a + ld a, b + ld [hProduct + 2], a + +.less_than_256_max + ld a, [hProduct + 2] + ld [hDividend + 0], a + ld a, [hProduct + 3] + ld [hDividend + 1], a + ld a, 2 + ld b, a + call Divide + ld a, [hQuotient + 2] + ld e, a + ld a, HP_BAR_LENGTH + ld d, a + ld c, a + +.draw_bar + xor a + ld [wWhichHPBar], a + hlcoord 2, 2 + ld b, 0 + call DrawBattleHPBar + ret +; 3e127 + +UpdateEnemyHPPal: ; 3e127 + ld hl, EnemyHPPal + call UpdateHPPal + ret +; 3e12e + +UpdateHPPal: ; 3e12e + ld b, [hl] + call SetHPPal + ld a, [hl] + cp b + ret z + jp FinishBattleAnim +; 3e138 + +ret_3e138: ; 3e138 + ret +; 3e139 + +BattleMenu: ; 3e139 + xor a + ld [hBGMapMode], a + call LoadTempTileMapToTileMap + + ld a, [BattleType] + cp BATTLETYPE_DEBUG + jr z, .ok + cp BATTLETYPE_TUTORIAL + jr z, .ok + call EmptyBattleTextBox + call UpdateBattleHuds + call EmptyBattleTextBox + call LoadTileMapToTempTileMap +.ok + +.loop + ld a, [BattleType] + cp BATTLETYPE_CONTEST + jr nz, .not_contest + farcall ContestBattleMenu + jr .next +.not_contest + + ; Auto input: choose "ITEM" + ld a, [InputType] + or a + jr z, .skip_dude_pack_select + farcall _DudeAutoInput_DownA +.skip_dude_pack_select + call LoadBattleMenu2 + ret c + +.next + ld a, $1 + ld [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 +; 3e192 + +BattleMenu_Fight: ; 3e192 + xor a + ld [wNumFleeAttempts], a + call Call_LoadTempTileMapToTileMap + and a + ret +; 3e19b + +LoadBattleMenu2: ; 3e19b + call IsMobileBattle + jr z, .mobile + + farcall LoadBattleMenu + and a + ret + +.mobile + farcall Function100b12 + ld a, [wcd2b] + and a + ret z + + ld hl, wcd2a + bit 4, [hl] + jr nz, .error + ld hl, BattleText_LinkErrorBattleCanceled + call StdBattleTextBox + ld c, 60 + call DelayFrames +.error + scf + ret +; 3e1c7 + +BattleMenu_Pack: ; 3e1c7 + ld a, [wLinkMode] + and a + jp nz, .ItemsCantBeUsed + + ld a, [InBattleTowerBattle] + and a + jp nz, .ItemsCantBeUsed + + call LoadStandardMenuDataHeader + + ld a, [BattleType] + cp BATTLETYPE_TUTORIAL + jr z, .tutorial + cp BATTLETYPE_CONTEST + jr z, .contest + + farcall BattlePack + ld a, [wPlayerAction] + and a + jr z, .didnt_use_item + jr .got_item + +.tutorial + farcall TutorialPack + ld a, POKE_BALL + ld [CurItem], a + call DoItemEffect + jr .got_item + +.contest + ld a, PARK_BALL + ld [CurItem], 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 +; 3e22b + +.ItemsCantBeUsed: ; 3e22b + ld hl, BattleText_ItemsCantBeUsedHere + call StdBattleTextBox + jp BattleMenu +; 3e234 + +.UseItem: ; 3e234 + ld a, [wWildMon] + and a + jr nz, .run + callfar CheckItemPocket + ld a, [wItemAttributeParamBuffer] + cp BALL + jr z, .ball + call ClearBGPalettes + +.ball + xor a + ld [hBGMapMode], a + call _LoadBattleFontsHPBar + call ClearSprites + ld a, [BattleType] + 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 $c0 + ld [wBattleResult], a + call ClearWindowData + call SetPalettes + scf + ret +; 3e28d + +BattleMenu_PKMN: ; 3e28d + call LoadStandardMenuDataHeader +BattleMenuPKMN_ReturnFromStats: + call ExitMenu + call LoadStandardMenuDataHeader + call ClearBGPalettes +BattleMenuPKMN_Loop: + call SetUpBattlePartyMenu + xor a + ld [PartyMenuActionText], a + call JumpToPartyMenuAndPrintText + call SelectBattleMon + jr c, .Cancel +.loop + farcall FreezeMonIcons + call .GetMenu + jr c, .PressedB + 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 + +.PressedB: + call CheckMobileBattleError + jr c, .Cancel + jr BattleMenuPKMN_Loop + +.Stats: + call Battle_StatsScreen + call CheckMobileBattleError + jr c, .Cancel + jp BattleMenuPKMN_ReturnFromStats + +.Cancel: + call ClearSprites + call ClearPalettes + call DelayFrame + call _LoadHPBar + call CloseWindow + call LoadTileMapToTempTileMap + call GetMemSGBLayout + call SetPalettes + jp BattleMenu +; 3e2f5 + +.GetMenu: ; 3e2f5 + call IsMobileBattle + jr z, .mobile + farcall BattleMonMenu + ret + +.mobile + farcall MobileBattleMonMenu + ret +; 3e308 + +Battle_StatsScreen: ; 3e308 + 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 [MonType], a + farcall BattleStatsScreenInit + 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 +; 3e358 + +TryPlayerSwitch: ; 3e358 + ld a, [CurBattleMon] + ld d, a + ld a, [CurPartyMon] + cp d + jr nz, .check_trapped + ld hl, BattleText_PkmnIsAlreadyOut + call StdBattleTextBox + jp BattleMenuPKMN_Loop + +.check_trapped + ld a, [wPlayerWrapCount] + and a + jr nz, .trapped + ld a, [EnemySubStatus5] + bit SUBSTATUS_CANT_RUN, a + jr z, .try_switch + +.trapped + ld hl, BattleText_PkmnCantBeRecalled + call StdBattleTextBox + jp BattleMenuPKMN_Loop + +.try_switch + call CheckIfCurPartyMonIsFitToFight + jp z, BattleMenuPKMN_Loop + ld a, [CurBattleMon] + ld [LastPlayerMon], a + ld a, $2 + ld [wPlayerAction], a + call ClearPalettes + call DelayFrame + call ClearSprites + call _LoadHPBar + call CloseWindow + call GetMemSGBLayout + call SetPalettes + ld a, [CurPartyMon] + ld [CurBattleMon], a +PlayerSwitch: ; 3e3ad + ld a, 1 + ld [wPlayerIsSwitching], a + ld a, [wLinkMode] + and a + jr z, .not_linked + call LoadStandardMenuDataHeader + 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_E + jp z, .switch + cp BATTLEACTION_D + jp z, .switch + cp BATTLEACTION_SWITCH1 + jp c, .switch + cp BATTLEACTION_FORFEIT + jr nz, .dont_run + call WildFled_EnemyFled_LinkBattleCanceled + ret + +.dont_run + ld a, [hLinkPlayerNumber] + cp $1 + jr z, .player_1 + call BattleMonEntrance + call EnemyMonEntrance + and a + ret + +.player_1 + call EnemyMonEntrance + call BattleMonEntrance + and a + ret +; 3e3ff + +EnemyMonEntrance: ; 3e3ff + callfar AI_Switch + call SetEnemyTurn + jp SpikesDamage +; 3e40b + +BattleMonEntrance: ; 3e40b + call WithdrawPkmnText + + ld c, 50 + call DelayFrames + + ld hl, PlayerSubStatus4 + 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, [CurBattleMon] + ld [CurPartyMon], a + call AddBattleParticipant + call InitBattleMon + call ResetPlayerStatLevels + call SendOutPkmnText + call NewBattleMonStatus + call BreakAttraction + call SendOutPlayerMon + call EmptyBattleTextBox + call LoadTileMapToTempTileMap + call SetPlayerTurn + call SpikesDamage + ld a, $2 + ld [wMenuCursorY], a + ret +; 3e459 + +PassedBattleMonEntrance: ; 3e459 + ld c, 50 + call DelayFrames + + hlcoord 9, 7 + lb bc, 5, 11 + call ClearBox + + ld a, [CurPartyMon] + ld [CurBattleMon], a + call AddBattleParticipant + call InitBattleMon + xor a + ld [wd265], a + call ApplyStatLevelMultiplierOnAllStats + call SendOutPlayerMon + call EmptyBattleTextBox + call LoadTileMapToTempTileMap + call SetPlayerTurn + jp SpikesDamage +; 3e489 + +BattleMenu_Run: ; 3e489 + call Call_LoadTempTileMapToTileMap + ld a, $3 + ld [wMenuCursorY], a + ld hl, BattleMonSpeed + ld de, EnemyMonSpeed + call TryToRunAwayFromBattle + ld a, $0 + ld [wFailedToFlee], a + ret c + ld a, [wPlayerAction] + and a + ret nz + jp BattleMenu +; 3e4a8 + +CheckAmuletCoin: ; 3e4a8 + ld a, [BattleMonItem] + ld b, a + callfar GetItemHeldEffect + ld a, b + cp HELD_AMULET_COIN + ret nz + ld a, 1 + ld [wAmuletCoin], a + ret +; 3e4bc + +MoveSelectionScreen: ; 3e4bc + call IsMobileBattle + jr nz, .not_mobile + farcall MobileMoveSelectionScreen + ret + +.not_mobile + ld hl, EnemyMonMoves + 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, BattleMonMoves + 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 + ld [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 [Buffer1], 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, [CurMoveNum] + 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, $2c + 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] + and a + jr nz, .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 + ld [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 [CurMoveNum], a + jr nz, .use_move + + pop af + ret + +.use_move + pop af + ret nz + + ld hl, BattleMonPP + ld a, [wMenuCursorY] + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + and $3f + jr z, .no_pp_left + ld a, [PlayerDisableCount] + 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, BattleMonMoves + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + +.skip2 + ld [CurPlayerMove], 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 Call_LoadTempTileMapToTileMap + jp MoveSelectionScreen +; 3e61c + +.string_3e61c ; 3e61c + db "@" +; 3e61d + +.pressed_up + ld a, [wMenuCursorY] + and a + jp nz, .menu_loop + ld a, [wNumMoves] + inc a + ld [wMenuCursorY], a + jp .menu_loop +; 3e62e + +.pressed_down ; 3e62e + 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 +; 3e643 + +.pressed_select ; 3e643 + ld a, [wMoveSwapBuffer] + and a + jr z, .start_swap + ld hl, BattleMonMoves + call .swap_bytes + ld hl, BattleMonPP + call .swap_bytes + ld hl, PlayerDisableCount + 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, [PlayerSubStatus5] + bit SUBSTATUS_TRANSFORMED, a + jr nz, .transformed + ld hl, PartyMon1Moves + ld a, [CurBattleMon] + 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 +; 3e6c8 + +MoveInfoBox: ; 3e6c8 + xor a + ld [hBGMapMode], a + + hlcoord 0, 8 + ld b, 3 + ld c, 9 + call TextBox + call MobileTextBorder + + ld a, [PlayerDisableCount] + 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, BattleMonMoves + ld a, [wMenuCursorY] + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + ld [CurPlayerMove], a + + ld a, [CurBattleMon] + ld [CurPartyMon], a + ld a, WILDMON + ld [MonType], a + callfar GetMaxPPOfMove + + ld hl, wMenuCursorY + ld c, [hl] + inc [hl] + ld b, 0 + ld hl, BattleMonPP + add hl, bc + ld a, [hl] + and $3f + ld [StringBuffer1], a + call .PrintPP + + hlcoord 1, 9 + ld de, .Type + call PlaceString + + hlcoord 7, 11 + ld [hl], "/" + + callfar UpdateMoveData + ld a, [wPlayerMoveStruct + MOVE_ANIM] + ld b, a + hlcoord 2, 10 + predef PrintMoveType + +.done + ret +; 3e74f + +.Disabled: + db "Disabled!@" +.Type: + db "TYPE/@" +; 3e75f + +.PrintPP: ; 3e75f + hlcoord 5, 11 + ld a, [wLinkMode] ; What's the point of this check? + cp LINK_MOBILE + jr c, .ok + hlcoord 5, 11 +.ok + push hl + ld de, StringBuffer1 + lb bc, 1, 2 + call PrintNum + pop hl + inc hl + inc hl + ld [hl], "/" + inc hl + ld de, wNamedObjectIndexBuffer + lb bc, 1, 2 + call PrintNum + ret +; 3e786 + +CheckPlayerHasUsableMoves: ; 3e786 + ld a, STRUGGLE + ld [CurPlayerMove], a + ld a, [PlayerDisableCount] + and a + ld hl, BattleMonPP + jr nz, .disabled + + ld a, [hli] + or [hl] + inc hl + or [hl] + inc hl + or [hl] + and $3f + 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. + ; Replace with "and $3f" to fix. + and a + ret nz + +.force_struggle + ld hl, BattleText_PkmnHasNoMovesLeft + call StdBattleTextBox + ld c, 60 + call DelayFrames + xor a + ret +; 3e7c1 + +ParseEnemyAction: ; 3e7c1 + ld a, [wEnemyIsSwitching] + and a + ret nz + ld a, [wLinkMode] + and a + jr z, .not_linked + call EmptyBattleTextBox + call LoadTileMapToTempTileMap + ld a, [wPlayerAction] + and a + call z, LinkBattleSendReceiveAction + call Call_LoadTempTileMapToTileMap + ld a, [wBattleAction] + cp BATTLEACTION_E + jp z, .struggle + cp BATTLEACTION_D + jp z, .battle_action_d + cp BATTLEACTION_SWITCH1 + jp nc, ResetVarsForSubstatusRage + ld [CurEnemyMoveNum], a + ld c, a + ld a, [EnemySubStatus1] + bit SUBSTATUS_ROLLOUT, a + jp nz, .skip_load + ld a, [EnemySubStatus3] + and 1 << SUBSTATUS_CHARGED | 1 << SUBSTATUS_RAMPAGE | 1 << SUBSTATUS_BIDE + jp nz, .skip_load + + ld hl, EnemySubStatus5 + bit SUBSTATUS_ENCORED, [hl] + ld a, [LastEnemyMove] + jp nz, .finish + ld hl, EnemyMonMoves + ld b, 0 + add hl, bc + ld a, [hl] + jp .finish + +.not_linked + ld hl, EnemySubStatus5 + bit SUBSTATUS_ENCORED, [hl] + jr z, .skip_encore + ld a, [LastEnemyMove] + jp .finish + +.skip_encore + call CheckEnemyLockedIn + jp nz, ResetVarsForSubstatusRage + jr .continue + +.battle_action_d + ld a, $ff + jr .finish + +.continue + ld hl, EnemyMonMoves + ld de, EnemyMonPP + ld b, NUM_MOVES +.loop + ld a, [hl] + and a + jp z, .struggle + ld a, [EnemyDisabledMove] + cp [hl] + jr z, .disabled + ld a, [de] + and $3f + 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, EnemyMonMoves + call BattleRandom + and 3 ; TODO factor in NUM_MOVES + ld c, a + ld b, 0 + add hl, bc + ld a, [EnemyDisableCount] + swap a + and $f + dec a + cp c + jr z, .loop2 + ld a, [hl] + and a + jr z, .loop2 + ld hl, EnemyMonPP + add hl, bc + ld b, a + ld a, [hl] + and $3f + jr z, .loop2 + ld a, c + ld [CurEnemyMoveNum], a + ld a, b + +.finish + ld [CurEnemyMove], 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 [EnemyFuryCutterCount], a + +.fury_cutter + ld a, [wEnemyMoveStruct + MOVE_EFFECT] + cp EFFECT_RAGE + jr z, .no_rage + ld hl, EnemySubStatus4 + 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 [EnemyProtectCount], a + ret + +.struggle + ld a, STRUGGLE + jr .finish +; 3e8c1 + +ResetVarsForSubstatusRage: ; 3e8c1 + xor a + ld [EnemyFuryCutterCount], a + ld [EnemyProtectCount], a + ld [wEnemyRageCounter], a + ld hl, EnemySubStatus4 + res SUBSTATUS_RAGE, [hl] + ret +; 3e8d1 + +CheckEnemyLockedIn: ; 3e8d1 + ld a, [EnemySubStatus4] + and 1 << SUBSTATUS_RECHARGE + ret nz + + ld hl, EnemySubStatus3 + ld a, [hl] + and 1 << SUBSTATUS_CHARGED | 1 << SUBSTATUS_RAMPAGE | 1 << SUBSTATUS_BIDE + ret nz + + ld hl, EnemySubStatus1 + bit SUBSTATUS_ROLLOUT, [hl] + ret +; 3e8e4 + +LinkBattleSendReceiveAction: ; 3e8e4 + farcall _LinkBattleSendReceiveAction + ret +; 3e8eb + +LoadEnemyMon: ; 3e8eb +; Initialize enemy monster parameters +; To do this we pull the species from TempEnemyMonSpecies + +; Notes: +; BattleRandom is used to ensure sync between Game Boys + +; Clear the whole EnemyMon struct + xor a + ld hl, EnemyMonSpecies + ld bc, EnemyMonEnd - EnemyMon + call ByteFill + +; We don't need to be here if we're in a link battle + ld a, [wLinkMode] + and a + jp nz, InitEnemyMon + +; and also not in a BattleTower-Battle + ld a, [InBattleTowerBattle] ; ???? + bit 0, a + jp nz, InitEnemyMon + +; Make sure everything knows what species we're working with + ld a, [TempEnemyMonSpecies] + ld [EnemyMonSpecies], a + ld [CurSpecies], a + ld [CurPartySpecies], 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, [CurPartyMon] + ld hl, OTPartyMon1Item + call GetPartyLocation ; bc = PartyMon[CurPartyMon] - PartyMons + 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, [BattleType] + cp BATTLETYPE_FORCEITEM + ld a, [BaseItems] + 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 1 + (75 percent) + 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, [BaseItems] + jr nc, .UpdateItem + ld a, [BaseItems+1] + +.UpdateItem: + ld [EnemyMonItem], a + +; Initialize DVs + +; If we're in a trainer battle, DVs are predetermined + ld a, [wBattleMode] + and a + jr z, .InitDVs + + ld a, [EnemySubStatus5] + bit SUBSTATUS_TRANSFORMED, a + jr z, .InitDVs + +; Unknown + ld hl, wEnemyBackupDVs + ld de, EnemyMonDVs + 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) work differently +; They have their own structs, which are shorter than normal + ld a, [BattleType] + 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 BattleType + +; 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, EnemyMonDVs + 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, [TempEnemyMonSpecies] + cp UNOWN + jr nz, .Magikarp + +; Get letter based on DVs + ld hl, EnemyMonDVs + 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: +; Skimming this part recommended + + ld a, [TempEnemyMonSpecies] + cp MAGIKARP + jr nz, .Happiness + +; Get Magikarp's length + ld de, EnemyMonDVs + ld bc, PlayerID + callfar CalcMagikarpLength + +; We're clear if the length is < 1536 + ld a, [wMagikarpLength] + cp HIGH(1536) + jr nz, .CheckMagikarpArea + +; 5% chance of skipping both size checks + call Random + cp 5 percent + jr c, .CheckMagikarpArea +; Try again if > 1614 + ld a, [wMagikarpLength + 1] + cp LOW(1614) + 2 + jr nc, .GenerateDVs + +; 20% chance of skipping this check + call Random + cp 20 percent - 1 + jr c, .CheckMagikarpArea +; Try again if > 1598 + ld a, [wMagikarpLength + 1] + cp LOW(1598) + 2 + jr nc, .GenerateDVs + +.CheckMagikarpArea: +; The z checks are supposed to be 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 size flooring in the Lake of Rage area + ld a, [MapGroup] + cp GROUP_LAKE_OF_RAGE + jr z, .Happiness + ld a, [MapNumber] + cp MAP_LAKE_OF_RAGE + jr z, .Happiness +; 40% chance of not flooring + call Random + cp 40 percent - 2 + jr c, .Happiness +; Floor at length 1024 + ld a, [wMagikarpLength] + cp HIGH(1024) + jr c, .GenerateDVs ; try again + +; Finally done with DVs + +.Happiness: +; Set happiness + ld a, BASE_HAPPINESS + ld [EnemyMonHappiness], a +; Set level + ld a, [CurPartyLevel] + ld [EnemyMonLevel], a +; Fill stats + ld de, EnemyMonMaxHP + ld b, FALSE + ld hl, EnemyMonDVs - (MON_DVS - MON_STAT_EXP + 1) ; LinkBattleRNs + 7 ; ? + predef CalcPkmnStats + +; 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, [EnemySubStatus5] + bit SUBSTATUS_TRANSFORMED, a + jp nz, .Moves + +.TreeMon: +; If we're headbutting trees, some monsters enter battle asleep + call CheckSleepingTreeMon + ld a, TREEMON_SLEEP_TURNS + jr c, .UpdateStatus +; Otherwise, no status + xor a + +.UpdateStatus: + ld hl, EnemyMonStatus + ld [hli], a + +; Unused byte + xor a + ld [hli], a + +; Full HP.. + ld a, [EnemyMonMaxHP] + ld [hli], a + ld a, [EnemyMonMaxHP + 1] + ld [hl], a + +; ..unless it's a RoamMon + ld a, [BattleType] + 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 [EnemyMonHP + 1], a + jr .Moves + +.InitRoamHP: +; HP only uses the lo byte in the RoamMon struct since +; Raikou/Entei/Suicune will have < 256 hp at level 40 + ld a, [EnemyMonHP + 1] + ld [hl], a + jr .Moves + +.OpponentParty: +; Get HP from the party struct + ld hl, (OTPartyMon1HP + 1) + ld a, [CurPartyMon] + call GetPartyLocation + ld a, [hld] + ld [EnemyMonHP + 1], a + ld a, [hld] + ld [EnemyMonHP], a + +; Make sure everything knows which monster the opponent is using + ld a, [CurPartyMon] + ld [CurOTMon], a + +; Get status from the party struct + dec hl + ld a, [hl] ; OTPartyMonStatus + ld [EnemyMonStatus], a + +.Moves: + ld hl, BaseType1 + ld de, EnemyMonType1 + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + ld [de], a + +; Get moves + ld de, EnemyMonMoves +; Are we in a trainer battle? + ld a, [wBattleMode] + cp TRAINER_BATTLE + jr nz, .WildMoves +; Then copy moves from the party struct + ld hl, OTPartyMon1Moves + ld a, [CurPartyMon] + call GetPartyLocation + ld bc, NUM_MOVES + call CopyBytes + jr .PP + +.WildMoves: +; Clear EnemyMonMoves + 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, EnemyMonMoves + ld de, EnemyMonPP + predef FillPP + jr .Finish + +.TrainerPP: +; Copy PP from the party struct + ld hl, OTPartyMon1PP + ld a, [CurPartyMon] + call GetPartyLocation + ld de, EnemyMonPP + ld bc, NUM_MOVES + call CopyBytes + +.Finish: +; Only the first five base stats are copied.. + ld hl, BaseStats + ld de, EnemyMonBaseStats + ld b, BaseSpecialDefense - BaseStats +.loop + ld a, [hli] + ld [de], a + inc de + dec b + jr nz, .loop + + ld a, [BaseCatchRate] + ld [de], a + inc de + + ld a, [BaseExp] + ld [de], a + + ld a, [TempEnemyMonSpecies] + ld [wd265], a + + call GetPokemonName + +; Did we catch it? + ld a, [wBattleMode] + and a + ret z + +; Update enemy nick + ld hl, StringBuffer1 + ld de, EnemyMonNick + ld bc, PKMN_NAME_LENGTH + call CopyBytes + +; Saw this mon + ld a, [TempEnemyMonSpecies] + dec a + ld c, a + ld b, SET_FLAG + ld hl, PokedexSeen + predef FlagPredef + + ld hl, EnemyMonStats + ld de, EnemyStats + ld bc, EnemyMonStatsEnd - EnemyMonStats + call CopyBytes + + ret +; 3eb38 + +CheckSleepingTreeMon: ; 3eb38 +; Return carry if species is in the list +; for the current time of day + +; Don't do anything if this isn't a tree encounter + ld a, [BattleType] + cp BATTLETYPE_TREE + jr nz, .NotSleeping + +; Get list for the time of day + ld hl, .Morn + ld a, [TimeOfDay] + cp DAY_F + jr c, .Check + ld hl, .Day + jr z, .Check + ld hl, .Nite + +.Check: + ld a, [TempEnemyMonSpecies] + ld de, 1 ; length of species id + call IsInArray +; If it's a match, the opponent is asleep + ret c + +.NotSleeping: + and a + ret + +.Nite: + db CATERPIE + db METAPOD + db BUTTERFREE + db WEEDLE + db KAKUNA + db BEEDRILL + db SPEAROW + db EKANS + db EXEGGCUTE + db LEDYBA + db AIPOM + db -1 ; end + +.Day: + db VENONAT + db HOOTHOOT + db NOCTOWL + db SPINARAK + db HERACROSS + db -1 ; end + +.Morn: + db VENONAT + db HOOTHOOT + db NOCTOWL + db SPINARAK + db HERACROSS + db -1 ; end +; 3eb75 + +CheckUnownLetter: ; 3eb75 +; Return carry if the Unown letter hasn't been unlocked yet + + ld a, [UnlockedUnowns] + 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, .LetterSets + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + + push de + ld a, [UnownLetter] + 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 .Set1 - .LetterSets + jr c, .loop + +; Hasn't been unlocked, or the letter is invalid + scf + ret + +.match +; Valid letter + and a + ret + +.LetterSets: + dw .Set1 + dw .Set2 + dw .Set3 + dw .Set4 + +.Set1: + ; A B C D E F G H I J K + db 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, $ff +.Set2: + ; L M N O P Q R + db 12, 13, 14, 15, 16, 17, 18, $ff +.Set3: + ; S T U V W + db 19, 20, 21, 22, 23, $ff +.Set4: + ; X Y Z + db 24, 25, 26, $ff + +; 3ebc7 + +SwapBattlerLevels: ; 3ebc7 +; unreferenced + push bc + ld a, [BattleMonLevel] + ld b, a + ld a, [EnemyMonLevel] + ld [BattleMonLevel], a + ld a, b + ld [EnemyMonLevel], a + pop bc + ret +; 3ebd8 + +BattleWinSlideInEnemyTrainerFrontpic: ; 3ebd8 + xor a + ld [TempEnemyMonSpecies], a + call FinishBattleAnim + ld a, [OtherTrainerClass] + ld [TrainerClass], 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 + ld [hBGMapMode], a + ld [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 + ld [hBGMapMode], a + ld c, 4 + call DelayFrames + pop hl + pop bc + dec hl + jr .outer_loop +; 3ec1a + +.CopyColumn: ; 3ec1a + 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 +; 3ec2c + +ApplyStatusEffectOnPlayerStats: ; 3ec2c + ld a, 1 + jr ApplyStatusEffectOnStats +; 3ec30 + +ApplyStatusEffectOnEnemyStats: ; 3ec30 + xor a +; 3ec31 + +ApplyStatusEffectOnStats: ; 3ec31 + ld [hBattleTurn], a + call ApplyPrzEffectOnSpeed + jp ApplyBrnEffectOnAttack +; 3ec39 + +ApplyPrzEffectOnSpeed: ; 3ec39 + ld a, [hBattleTurn] + and a + jr z, .enemy + ld a, [BattleMonStatus] + and 1 << PAR + ret z + ld hl, BattleMonSpeed + 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, [EnemyMonStatus] + and 1 << PAR + ret z + ld hl, EnemyMonSpeed + 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 +; 3ec76 + +ApplyBrnEffectOnAttack: ; 3ec76 + ld a, [hBattleTurn] + and a + jr z, .enemy + ld a, [BattleMonStatus] + and 1 << BRN + ret z + ld hl, BattleMonAttack + 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, [EnemyMonStatus] + and 1 << BRN + ret z + ld hl, EnemyMonAttack + 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 +; 3ecab + +ApplyStatLevelMultiplierOnAllStats: ; 3ecab +; Apply StatLevelMultipliers on all 5 Stats + ld c, 0 +.stat_loop + call ApplyStatLevelMultiplier + inc c + ld a, c + cp 5 + jr nz, .stat_loop + ret +; 3ecb7 + +ApplyStatLevelMultiplier: ; 3ecb7 + push bc + push bc + ld a, [wd265] + and a + ld a, c + ld hl, BattleMonAttack + ld de, PlayerStats + ld bc, PlayerAtkLevel + jr z, .got_pointers + ld hl, EnemyMonAttack + ld de, EnemyStats + ld bc, EnemyAtkLevel + +.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 + dec b + sla b + ld c, b + ld b, 0 + add hl, bc + xor a + ld [hMultiplicand + 0], a + ld a, [de] + ld [hMultiplicand + 1], a + inc de + ld a, [de] + ld [hMultiplicand + 2], a + ld a, [hli] + ld [hMultiplier], a + call Multiply + ld a, [hl] + ld [hDivisor], a + ld b, $4 + call Divide + pop hl + +; Cap at 999. + ld a, [hQuotient + 2] + sub LOW(MAX_STAT_VALUE) + ld a, [hQuotient + 1] + sbc HIGH(MAX_STAT_VALUE) + jp c, .okay3 + + ld a, HIGH(MAX_STAT_VALUE) + ld [hQuotient + 1], a + ld a, LOW(MAX_STAT_VALUE) + ld [hQuotient + 2], a + +.okay3 + ld a, [hQuotient + 1] + ld [hli], a + ld b, a + ld a, [hQuotient + 2] + ld [hl], a + or b + jr nz, .okay4 + inc [hl] + +.okay4 + pop bc + ret +; 3ed2b + +.StatLevelMultipliers: +; / + db 25, 100 ; 25% + db 28, 100 ; 28% + db 33, 100 ; 33% + db 40, 100 ; 40% + db 50, 100 ; 50% + db 66, 100 ; 66% + + db 1, 1 ; 100% + + db 15, 10 ; 150% + db 2, 1 ; 200% + db 25, 10 ; 250% + db 3, 1 ; 300% + db 35, 10 ; 350% + db 4, 1 ; 400% +; 3ed45 + +BadgeStatBoosts: ; 3ed45 +; Raise BattleMon stats depending on which badges have been obtained. + +; Every other badge boosts a stat, starting from the first. + +; ZephyrBadge: Attack +; PlainBadge: Speed +; MineralBadge: Defense +; GlacierBadge: Special Attack +; RisingBadge: 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, [InBattleTowerBattle] + and a + ret nz + + ld a, [JohtoBadges] + +; 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, BattleMonAttack + 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 +; And the last one (RisingBadge) too. + srl a + call c, BoostStat + ret +; 3ed7c + +BoostStat: ; 3ed7c +; 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 +; 3ed9f + +_LoadBattleFontsHPBar: ; 3ed9f + callfar LoadBattleFontsHPBar + ret +; 3eda6 + +_LoadHPBar: ; 3eda6 + callfar LoadHPBar + ret +; 3edad + +LoadHPExpBarGFX: ; unreferenced + 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 +; 3edd1 + +EmptyBattleTextBox: ; 3edd1 + ld hl, .empty + jp BattleTextBox +.empty + db "@" +; 3edd8 + +_BattleRandom:: ; 3edd8 +; 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, [LinkBattleRNCount] + ld c, a + ld b, 0 + ld hl, LinkBattleRNs + add hl, bc + inc a + ld [LinkBattleRNCount], 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 [LinkBattleRNCount], a + ld hl, LinkBattleRNs + 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 +; 3ee0f + +Call_PlayBattleAnim_OnlyIfVisible: ; 3ee0f + ld a, BATTLE_VARS_SUBSTATUS3 + call GetBattleVar + and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND + ret nz +; 3ee17 + +Call_PlayBattleAnim: ; 3ee17 + ld a, e + ld [FXAnimID], a + ld a, d + ld [FXAnimID + 1], a + call WaitBGMap + predef_jump PlayBattleAnim +; 3ee27 + +FinishBattleAnim: ; 3ee27 + 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 +; 3ee3b + +GiveExperiencePoints: ; 3ee3b +; Give experience. +; Don't give experience if linked or in the Battle Tower. + ld a, [wLinkMode] + and a + ret nz + + ld a, [InBattleTowerBattle] + bit 0, a + ret nz + + call .EvenlyDivideExpAmongParticipants + xor a + ld [CurPartyMon], a + ld bc, PartyMon1Species + +.loop + ld hl, MON_HP + add hl, bc + ld a, [hli] + or [hl] + jp z, .skip_stats ; fainted + + push bc + ld hl, wBattleParticipantsNotFainted + ld a, [CurPartyMon] + ld c, a + ld b, CHECK_FLAG + ld d, $0 + predef FlagPredef + ld a, c + and a + pop bc + jp z, .skip_stats + +; give stat exp + ld hl, MON_STAT_EXP + 1 + add hl, bc + ld d, h + ld e, l + ld hl, EnemyMonBaseStats - 1 + push bc + ld c, $5 +.loop1 + inc hl + ld a, [de] + add [hl] + ld [de], a + jr nc, .okay1 + dec de + ld a, [de] + inc a + jr z, .next + ld [de], a + inc de + +.okay1 + push hl + push bc + ld a, MON_PKRUS + call GetPartyParamLocation + ld a, [hl] + and a + pop bc + pop hl + jr z, .skip + ld a, [de] + add [hl] + ld [de], a + jr nc, .skip + dec de + ld a, [de] + inc a + jr z, .next + ld [de], a + inc de + jr .skip + +.next + ld a, $ff + ld [de], a + inc de + ld [de], a + +.skip + inc de + inc de + dec c + jr nz, .loop1 + xor a + ld [hMultiplicand + 0], a + ld [hMultiplicand + 1], a + ld a, [EnemyMonBaseExp] + ld [hMultiplicand + 2], a + ld a, [EnemyMonLevel] + ld [hMultiplier], a + call Multiply + ld a, 7 + ld [hDivisor], a + ld b, 4 + call Divide +; Boost Experience for traded Pokemon + pop bc + ld hl, MON_ID + add hl, bc + ld a, [PlayerID] + cp [hl] + jr nz, .boosted + inc hl + ld a, [PlayerID + 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 [StringBuffer2 + 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 + ld a, [hQuotient + 2] + ld [StringBuffer2 + 1], a + ld a, [hQuotient + 1] + ld [StringBuffer2], a + ld a, [CurPartyMon] + ld hl, PartyMonNicknames + call GetNick + ld hl, Text_PkmnGainedExpPoint + call BattleTextBox + ld a, [StringBuffer2 + 1] + ld [hQuotient + 2], a + ld a, [StringBuffer2] + ld [hQuotient + 1], a + pop bc + call AnimateExpBar + push bc + call LoadTileMapToTempTileMap + pop bc + ld hl, MON_STAT_EXP - 1 + add hl, bc + ld d, [hl] + ld a, [hQuotient + 2] + add d + ld [hld], a + ld d, [hl] + ld a, [hQuotient + 1] + adc d + ld [hl], a + jr nc, .skip2 + dec hl + inc [hl] + jr nz, .skip2 + ld a, $ff + ld [hli], a + ld [hli], a + ld [hl], a + +.skip2 + ld a, [CurPartyMon] + ld e, a + ld d, $0 + ld hl, PartySpecies + add hl, de + ld a, [hl] + ld [CurSpecies], a + call GetBaseData + push bc + ld d, MAX_LEVEL + callfar CalcExpAtLevel + pop bc + ld hl, MON_STAT_EXP - 1 + add hl, bc + push bc + ld a, [hQuotient] + ld b, a + ld a, [hQuotient + 1] + ld c, a + ld a, [hQuotient + 2] + 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 + xor a ; PARTYMON + ld [MonType], a + predef CopyPkmnToTempMon + callfar CalcLevel + pop bc + ld hl, MON_LEVEL + add hl, bc + ld a, [hl] + cp MAX_LEVEL + jp nc, .skip_stats + cp d + jp z, .skip_stats +; <NICKNAME> grew to level ##! + ld [wTempLevel], a + ld a, [CurPartyLevel] + push af + ld a, d + ld [CurPartyLevel], a + ld [hl], a + ld hl, MON_SPECIES + add hl, bc + ld a, [hl] + ld [CurSpecies], a + ld [wd265], a + 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 CalcPkmnStats + 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, [CurBattleMon] + ld d, a + ld a, [CurPartyMon] + cp d + jr nz, .skip_animation + ld de, BattleMonHP + ld a, [hli] + ld [de], a + inc de + ld a, [hli] + ld [de], a + ld de, BattleMonMaxHP + push bc + ld bc, PARTYMON_STRUCT_LENGTH - MON_MAXHP + call CopyBytes + pop bc + ld hl, MON_LEVEL + add hl, bc + ld a, [hl] + ld [BattleMonLevel], a + ld a, [PlayerSubStatus5] + bit SUBSTATUS_TRANSFORMED, a + jr nz, .transformed + ld hl, MON_ATK + add hl, bc + ld de, PlayerStats + ld bc, PARTYMON_STRUCT_LENGTH - MON_ATK + call CopyBytes + +.transformed + xor a + ld [wd265], a + call ApplyStatLevelMultiplierOnAllStats + callfar ApplyStatusEffectOnPlayerStats + callfar BadgeStatBoosts + callfar UpdatePlayerHUD + call EmptyBattleTextBox + call LoadTileMapToTempTileMap + ld a, $1 + ld [hBGMapMode], a + +.skip_animation + farcall LevelUpHappinessMod + ld a, [CurBattleMon] + ld b, a + ld a, [CurPartyMon] + cp b + jr z, .skip_animation2 + ld de, SFX_HIT_END_OF_EXP_BAR + call PlaySFX + call WaitSFX + ld hl, BattleText_StringBuffer1GrewToLevel + call StdBattleTextBox + call LoadTileMapToTempTileMap + +.skip_animation2 + xor a ; PARTYMON + ld [MonType], a + predef CopyPkmnToTempMon + hlcoord 9, 0 + ld b, $a + ld c, $9 + call TextBox + hlcoord 11, 1 + ld bc, 4 + predef PrintTempMonStats + ld c, $1e + call DelayFrames + call WaitPressAorB_BlinkCursor + call Call_LoadTempTileMapToTileMap + xor a ; PARTYMON + ld [MonType], a + ld a, [CurSpecies] + ld [wd265], a + ld a, [CurPartyLevel] + push af + ld c, a + ld a, [wTempLevel] + ld b, a + +.level_loop + inc b + ld a, b + ld [CurPartyLevel], a + push bc + predef LearnLevelMoves + pop bc + ld a, b + cp c + jr nz, .level_loop + pop af + ld [CurPartyLevel], a + ld hl, EvolvableFlags + ld a, [CurPartyMon] + ld c, a + ld b, SET_FLAG + predef FlagPredef + pop af + ld [CurPartyLevel], a + +.skip_stats + ld a, [PartyCount] + ld b, a + ld a, [CurPartyMon] + inc a + cp b + jr z, .done + ld [CurPartyMon], a + ld a, MON_SPECIES + call GetPartyParamLocation + ld b, h + ld c, l + jp .loop + +.done + jp ResetBattleParticipants +; 3f0d4 + +.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 [wd265], a + ld hl, EnemyMonBaseStats + ld c, EnemyMonEnd - EnemyMonBaseStats +.count_loop2 + xor a + ld [hDividend + 0], a + ld a, [hl] + ld [hDividend + 1], a + ld a, [wd265] + ld [hDivisor], a + ld b, 2 + call Divide + ld a, [hQuotient + 2] + ld [hli], a + dec c + jr nz, .count_loop2 + ret +; 3f106 + +BoostExp: ; 3f106 +; Multiply experience by 1.5x + push bc +; load experience value + ld a, [hProduct + 2] + ld b, a + ld a, [hProduct + 3] + ld c, a +; halve it + srl b + rr c +; add it back to the whole exp value + add c + ld [hProduct + 3], a + ld a, [hProduct + 2] + adc b + ld [hProduct + 2], a + pop bc + ret +; 3f11b + +Text_PkmnGainedExpPoint: ; 3f11b + text_jump Text_Gained + start_asm + ld hl, TextJump_StringBuffer2ExpPoints + ld a, [StringBuffer2 + 2] ; IsTradedMon + and a + ret z + + ld hl, TextJump_ABoostedStringBuffer2ExpPoints + ret +; 3f12c + +TextJump_ABoostedStringBuffer2ExpPoints: ; 3f12c + text_jump Text_ABoostedStringBuffer2ExpPoints + db "@" +; 3f131 + +TextJump_StringBuffer2ExpPoints: ; 3f131 + text_jump Text_StringBuffer2ExpPoints + db "@" +; 3f136 + +AnimateExpBar: ; 3f136 + push bc + + ld hl, CurPartyMon + ld a, [CurBattleMon] + cp [hl] + jp nz, .finish + + ld a, [BattleMonLevel] + cp MAX_LEVEL + jp nc, .finish + + ld a, [hProduct + 3] + ld [wd004], a + push af + ld a, [hProduct + 2] + ld [wd003], a + push af + xor a + ld [wd002], a + xor a ; PARTYMON + ld [MonType], a + predef CopyPkmnToTempMon + ld a, [TempMonLevel] + ld b, a + ld e, a + push de + ld de, TempMonExp + 2 + call CalcExpBar + push bc + ld hl, TempMonExp + 2 + ld a, [wd004] + add [hl] + ld [hld], a + ld a, [wd003] + adc [hl] + ld [hld], a + jr nc, .NoOverflow + inc [hl] + jr nz, .NoOverflow + ld a, $ff + ld [hli], a + ld [hli], a + ld [hl], a + +.NoOverflow: + ld d, MAX_LEVEL + callfar CalcExpAtLevel + ld a, [hProduct + 1] + ld b, a + ld a, [hProduct + 2] + ld c, a + ld a, [hProduct + 3] + ld d, a + ld hl, TempMonExp + 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 + cp e + jr nc, .LoopLevels + ld a, e + ld d, a + +.LoopLevels: + ld a, e + cp MAX_LEVEL + jr nc, .FinishExpBar + cp d + jr z, .FinishExpBar + inc a + ld [TempMonLevel], a + ld [CurPartyLevel], a + ld [BattleMonLevel], a + push de + call .PlayExpBarSound + ld c, $40 + call .LoopBarAnimation + call PrintPlayerHUD + ld hl, BattleMonNick + ld de, StringBuffer1 + ld bc, PKMN_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, TempMonExp + 2 + call CalcExpBar + ld a, b + pop bc + ld c, a + call .PlayExpBarSound + call .LoopBarAnimation + call TerminateExpBarSound + pop af + ld [hProduct + 2], a + pop af + ld [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 + ld [hBGMapMode], a + ld c, d + call DelayFrames + xor a + ld [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 + ld [hBGMapMode], a + ld c, d + call DelayFrames + xor a + ld [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 + ld [hBGMapMode], a + ret + +SendOutPkmnText: ; 3f26d + ld a, [wLinkMode] + and a + jr z, .not_linked + + ld hl, JumpText_GoPkmn ; 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 Pkmn, the game prints a different text + ld hl, EnemyMonHP + ld a, [hli] + or [hl] + ld hl, JumpText_GoPkmn + jr z, .skip_to_textbox + + ; compute enemy helth remaining as a percentage + xor a + ld [hMultiplicand + 0], a + ld hl, EnemyMonHP + ld a, [hli] + ld [wEnemyHPAtTimeOfPlayerSwitch], a + ld [hMultiplicand + 1], a + ld a, [hl] + ld [wEnemyHPAtTimeOfPlayerSwitch + 1], a + ld [hMultiplicand + 2], a + ld a, 25 + ld [hMultiplier], a + call Multiply + ld hl, EnemyMonMaxHP + ld a, [hli] + ld b, [hl] + srl a + rr b + srl a + rr b + ld a, b + ld b, 4 + ld [hDivisor], a + call Divide + + ld a, [hQuotient + 2] + ld hl, JumpText_GoPkmn + cp 70 + jr nc, .skip_to_textbox + + ld hl, JumpText_DoItPkmn + cp 40 + jr nc, .skip_to_textbox + + ld hl, JumpText_GoForItPkmn + cp 10 + jr nc, .skip_to_textbox + + ld hl, JumpText_YourFoesWeakGetmPkmn +.skip_to_textbox + jp BattleTextBox +; 3f2d1 + +JumpText_GoPkmn: ; 3f2d1 + text_jump Text_GoPkmn + start_asm + jr Function_TextJump_BattleMonNick01 +; 3f2d6 + +JumpText_DoItPkmn: ; 3f2d8 + text_jump Text_DoItPkmn + start_asm + jr Function_TextJump_BattleMonNick01 +; 3f2dd + +JumpText_GoForItPkmn: ; 3f2df + text_jump Text_GoForItPkmn + start_asm + jr Function_TextJump_BattleMonNick01 +; 3f2e4 + +JumpText_YourFoesWeakGetmPkmn: ; 3f2e6 + text_jump Text_YourFoesWeakGetmPkmn + start_asm +Function_TextJump_BattleMonNick01: ; 3f2eb + ld hl, TextJump_BattleMonNick01 + ret +; 3f2ef + +TextJump_BattleMonNick01: ; 3f2ef + text_jump Text_BattleMonNick01 + db "@" +; 3f2f4 + +WithdrawPkmnText: ; 3f2f4 + ld hl, .WithdrawPkmnText + jp BattleTextBox + +.WithdrawPkmnText: + text_jump Text_BattleMonNickComma + start_asm +; Print text to withdraw Pkmn +; depending on HP the message is different + push de + push bc + ld hl, EnemyMonHP + 1 + ld de, wEnemyHPAtTimeOfPlayerSwitch + 1 + ld b, [hl] + dec hl + ld a, [de] + sub b + ld [hMultiplicand + 2], a + dec de + ld b, [hl] + ld a, [de] + sbc b + ld [hMultiplicand + 1], a + ld a, 25 + ld [hMultiplier], a + call Multiply + ld hl, EnemyMonMaxHP + ld a, [hli] + ld b, [hl] + srl a + rr b + srl a + rr b + ld a, b + ld b, 4 + ld [hDivisor], a + call Divide + pop bc + pop de + ld a, [hQuotient + 2] + ld hl, TextJump_ThatsEnoughComeBack + and a + ret z + + ld hl, TextJump_ComeBack + cp 30 + ret c + + ld hl, TextJump_OKComeBack + cp 70 + ret c + + ld hl, TextJump_GoodComeBack + ret +; 3f348 + +TextJump_ThatsEnoughComeBack: ; 3f348 + text_jump Text_ThatsEnoughComeBack + db "@" +; 3f34d + +TextJump_OKComeBack: ; 3f34d + text_jump Text_OKComeBack + db "@" +; 3f352 + +TextJump_GoodComeBack: ; 3f352 + text_jump Text_GoodComeBack + db "@" +; 3f357 + +UnusedFunction_TextJump_ComeBack: ; 3f357 +; this function doesn't seem to be used + ld hl, TextJump_ComeBack + ret +; 3f35b + +TextJump_ComeBack: ; 3f35b + text_jump Text_ComeBack + db "@" +; 3f360 + +HandleSafariAngerEatingStatus: ; unreferenced + ld hl, wSafariMonEating + ld a, [hl] + and a + jr z, .angry + dec [hl] + ld hl, BattleText_WildPkmnIsEating + jr .finish + +.angry + dec hl ; wSafariMonAngerCount + ld a, [hl] + and a + ret z + dec [hl] + ld hl, BattleText_WildPkmnIsAngry + jr nz, .finish + push hl + ld a, [EnemyMonSpecies] + ld [CurSpecies], a + call GetBaseData + ld a, [BaseCatchRate] + ld [EnemyMonCatchRate], a + pop hl + +.finish + push hl + call Call_LoadTempTileMapToTileMap + pop hl + jp StdBattleTextBox +; 3f390 + +FillInExpBar: ; 3f390 + push hl + call CalcExpBar + pop hl + ld de, 7 + add hl, de + jp PlaceExpBar +; 3f39c + +CalcExpBar: ; 3f39c +; 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] + ld [hMathBuffer + 2], a + pop bc + sub b + ld [hld], a + ld a, [hl] + ld [hMathBuffer + 1], a + pop bc + sbc b + ld [hld], a + ld a, [hl] + ld [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 + ld a, [hMathBuffer + 2] + sub c + ld [hld], a + ld a, [de] + dec de + ld b, a + ld a, [hMathBuffer + 1] + sbc b + ld [hld], a + ld a, [de] + ld c, a + ld a, [hMathBuffer] + sbc c + ld [hld], a + xor a + ld [hl], a +; multiply by 64 + ld a, $40 + ld [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 + ld [hDivisor], a + ld b, 4 + call Divide + ld a, [hQuotient + 2] + ld b, a + ld a, $40 + sub b + ld b, a + ret +; 3f41c + +PlaceExpBar: ; 3f41c + 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 +; 3f43d + +GetBattleMonBackpic: ; 3f43d + ld a, [PlayerSubStatus4] + bit SUBSTATUS_SUBSTITUTE, a + ld hl, BattleAnimCmd_RaiseSub + jr nz, GetBattleMonBackpic_DoAnim ; substitute + +DropPlayerSub: ; 3f447 + ld a, [wPlayerMinimized] + and a + ld hl, BattleAnimCmd_MinimizeOpp + jr nz, GetBattleMonBackpic_DoAnim + ld a, [CurPartySpecies] + push af + ld a, [BattleMonSpecies] + ld [CurPartySpecies], a + ld hl, BattleMonDVs + predef GetUnownLetter + ld de, VTiles2 tile $31 + predef GetMonBackpic + pop af + ld [CurPartySpecies], a + ret +; 3f46f + +GetBattleMonBackpic_DoAnim: ; 3f46f + ld a, [hBattleTurn] + push af + xor a + ld [hBattleTurn], a + ld a, BANK(BattleAnimCommands) + rst FarCall + pop af + ld [hBattleTurn], a + ret +; 3f47c + +GetEnemyMonFrontpic: ; 3f47c + ld a, [EnemySubStatus4] + bit SUBSTATUS_SUBSTITUTE, a + ld hl, BattleAnimCmd_RaiseSub + jr nz, GetEnemyMonFrontpic_DoAnim + +DropEnemySub: ; 3f486 + ld a, [wEnemyMinimized] + and a + ld hl, BattleAnimCmd_MinimizeOpp + jr nz, GetEnemyMonFrontpic_DoAnim + + ld a, [CurPartySpecies] + push af + ld a, [EnemyMonSpecies] + ld [CurSpecies], a + ld [CurPartySpecies], a + call GetBaseData + ld hl, EnemyMonDVs + predef GetUnownLetter + ld de, VTiles2 + predef GetAnimatedFrontpicPredef + pop af + ld [CurPartySpecies], a + ret +; 3f4b4 + +GetEnemyMonFrontpic_DoAnim: ; 3f4b4 + ld a, [hBattleTurn] + push af + call SetEnemyTurn + ld a, BANK(BattleAnimCommands) + rst FarCall + pop af + ld [hBattleTurn], a + ret +; 3f4c1 + +StartBattle: ; 3f4c1 +; 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, [PartyCount] + and a + ret z + + ld a, [TimeOfDayPal] + push af + call BattleIntro + call DoBattle + call ExitBattle + pop af + ld [TimeOfDayPal], a + scf + ret +; 3f4d9 + +_DoBattle: ; 3f4d9 +; unreferenced + call DoBattle + ret +; 3f4dd + +BattleIntro: ; 3f4dd + farcall TrainerRankings_Battles ; mobile + call LoadTrainerOrWildMonPic + xor a + ld [TempBattleMonSpecies], a + ld [wBattleMenuCursorBuffer], a + xor a + ld [hMapAnims], a + farcall PlayBattleMusic + farcall ShowLinkBattleParticipants + farcall FindFirstAliveMonAndStartBattle + call DisableSpriteUpdates + farcall ClearBattleRAM + call InitEnemy + call BackUpVBGMap2 + ld b, SCGB_BATTLE_GRAYSCALE + call GetSGBLayout + ld hl, rLCDC + res 6, [hl] + call InitBattleDisplay + call BattleStartMessage + ld hl, rLCDC + set 6, [hl] + xor a + ld [hBGMapMode], a + call EmptyBattleTextBox + hlcoord 9, 7 + lb bc, 5, 11 + call ClearBox + hlcoord 1, 0 + lb bc, 4, 10 + call ClearBox + call ClearSprites + ld a, [wBattleMode] + cp WILD_BATTLE + call z, UpdateEnemyHUD + ld a, $1 + ld [hBGMapMode], a + ret +; 3f54e + +LoadTrainerOrWildMonPic: ; 3f54e + ld a, [OtherTrainerClass] + and a + jr nz, .Trainer + ld a, [TempWildMonSpecies] + ld [CurPartySpecies], a + +.Trainer: + ld [TempEnemyMonSpecies], a + ret +; 3f55e + +InitEnemy: ; 3f55e + ld a, [OtherTrainerClass] + and a + jp nz, InitEnemyTrainer ; trainer + jp InitEnemyWildmon ; wild +; 3f568 + +BackUpVBGMap2: ; 3f568 + ld a, [rSVBK] + push af + ld a, $6 ; BANK(wDecompressScratch) + ld [rSVBK], a + ld hl, wDecompressScratch + ld bc, $40 tiles ; VBGMap3 - VBGMap2 + ld a, $2 + call ByteFill + ld a, [rVBK] + push af + ld a, $1 + ld [rVBK], a + ld de, wDecompressScratch + hlbgcoord 0, 0 ; VBGMap2 + lb bc, BANK(BackUpVBGMap2), $40 + call Request2bpp + pop af + ld [rVBK], a + pop af + ld [rSVBK], a + ret +; 3f594 + +InitEnemyTrainer: ; 3f594 + ld [TrainerClass], a + farcall TrainerRankings_TrainerBattles + xor a + ld [TempEnemyMonSpecies], a + callfar GetTrainerAttributes + callfar ReadTrainerParty + + ld a, [TrainerClass] + cp RIVAL1 + jr nz, .ok + xor a + ld [OTPartyMon1Item], a +.ok + + ld de, VTiles2 + callfar GetTrainerPic + xor a + ld [hGraphicStartTile], a + dec a + ld [wEnemyItemState], a + hlcoord 12, 0 + lb bc, 7, 7 + predef PlaceGraphic + ld a, -1 + ld [CurOTMon], a + ld a, TRAINER_BATTLE + ld [wBattleMode], a + + call IsJohtoGymLeader + jr nc, .done + xor a + ld [CurPartyMon], a + ld a, [PartyCount] + 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, CurPartyMon + inc [hl] + jr .partyloop +.done + ret +; 3f607 + +InitEnemyWildmon: ; 3f607 + ld a, WILD_BATTLE + ld [wBattleMode], a + farcall TrainerRankings_WildBattles + call LoadEnemyMon + ld hl, EnemyMonMoves + ld de, wWildMonMoves + ld bc, NUM_MOVES + call CopyBytes + ld hl, EnemyMonPP + ld de, wWildMonPP + ld bc, NUM_MOVES + call CopyBytes + ld hl, EnemyMonDVs + predef GetUnownLetter + ld a, [CurPartySpecies] + cp UNOWN + jr nz, .skip_unown + ld a, [wFirstUnownSeen] + and a + jr nz, .skip_unown + ld a, [UnownLetter] + ld [wFirstUnownSeen], a +.skip_unown + ld de, VTiles2 + predef GetAnimatedFrontpicPredef + xor a + ld [TrainerClass], a + ld [hGraphicStartTile], a + hlcoord 12, 0 + lb bc, 7, 7 + predef PlaceGraphic + ret +; 3f662 + +Function3f662: ; 3f662 +; XXX + ld hl, EnemyMonMoves + 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, EnemyMonPP - (EnemyMonMoves + 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, EnemyMonPP - (EnemyMonMoves + 1) + add hl, bc + xor a + ld [hl], a + pop hl + pop bc + dec b + jr nz, .clear + ret +; 3f69e + +ExitBattle: ; 3f69e + call .HandleEndOfBattle + call CleanUpBattleRAM + ret +; 3f6a5 + +.HandleEndOfBattle: ; 3f6a5 + ld a, [wLinkMode] + and a + jr z, .not_linked + call ShowLinkBattleParticipantsAfterEnd + ld c, 150 + call DelayFrames + call DisplayLinkBattleResult + ret + +.not_linked + ld a, [wBattleResult] + and $f + ret nz + call CheckPayDay + xor a + ld [wForceEvolution], a + predef EvolveAfterBattle + farcall GivePokerusAndConvertBerries + ret +; 3f6d0 + +CleanUpBattleRAM: ; 3f6d0 + call BattleEnd_HandleRoamMons + xor a + ld [Danger], a + ld [wBattleMode], a + ld [BattleType], a + ld [AttackMissed], a + ld [TempWildMonSpecies], a + ld [OtherTrainerClass], a + ld [wFailedToFlee], a + ld [wNumFleeAttempts], a + ld [wForcedSwitch], a + ld [wPartyMenuCursor], a + ld [wKeyItemsPocketCursor], a + ld [wItemsPocketCursor], a + ld [wBattleMenuCursorBuffer], a + ld [CurMoveNum], a + ld [wBallsPocketCursor], a + ld [wLastPocket], a + ld [wMenuScrollPosition], a + ld [wKeyItemsPocketScrollPosition], a + ld [wItemsPocketScrollPosition], a + ld [wBallsPocketScrollPosition], a + ld hl, PlayerSubStatus1 + ld b, EnemyFuryCutterCount - PlayerSubStatus1 +.loop + ld [hli], a + dec b + jr nz, .loop + call WaitSFX + ret +; 3f71d + +CheckPayDay: ; 3f71d + 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, Money + 2 + call AddBattleMoneyToAccount + ld hl, BattleText_PlayerPickedUpPayDayMoney + call StdBattleTextBox + ld a, [InBattleTowerBattle] + bit 0, a + ret z + call ClearTileMap + call ClearBGPalettes + ret +; 3f759 + +ShowLinkBattleParticipantsAfterEnd: ; 3f759 + farcall TrainerRankings_LinkBattles + farcall BackupMobileEventIndex + ld a, [CurOTMon] + ld hl, OTPartyMon1Status + call GetPartyLocation + ld a, [EnemyMonStatus] + ld [hl], a + call ClearTileMap + farcall _ShowLinkBattleParticipants + ret +; 3f77c + +DisplayLinkBattleResult: ; 3f77c + farcall CheckMobileBattleError + jp c, .Mobile_InvalidBattle + call IsMobileBattle2 + jr nz, .proceed + + ld hl, wcd2a + bit 4, [hl] + jr z, .proceed + + farcall DetermineLinkBattleResult + +.proceed + ld a, [wBattleResult] + and $f + cp $1 + jr c, .victory + jr z, .loss + farcall TrainerRankings_ColosseumDraws + ld de, .Draw + jr .store_result + +.victory + farcall TrainerRankings_ColosseumWins + ld de, .Win + jr .store_result + +.loss + farcall TrainerRankings_ColosseumLosses + ld de, .Lose + jr .store_result + +.store_result + hlcoord 6, 8 + call PlaceString + farcall BackupMobileEventIndex + ld c, 200 + call DelayFrames + + ld a, BANK(sLinkBattleStats) + call GetSRAMBank + + call AddLastMobileBattleToLinkRecord + call ReadAndPrintLinkBattleRecord + + call CloseSRAM + + call IsMobileBattle2 + jr z, .mobile + call WaitPressAorB_BlinkCursor + call ClearTileMap + ret + +.mobile + ld c, 200 + call DelayFrames + call ClearTileMap + ret +; 3f7f7 + +.Win: + db "YOU WIN@" +.Lose: + db "YOU LOSE@" +.Draw: + db " DRAW@" +; 3f80f + +.Mobile_InvalidBattle: ; 3f80f + hlcoord 6, 8 + ld de, .Invalid + call PlaceString + ld c, 200 + call DelayFrames + call ClearTileMap + ret +; 3f821 + +.Invalid: + db "INVALID BATTLE@" +; 3f830 + +IsMobileBattle2: ; 3f830 + ld a, [wLinkMode] + cp LINK_MOBILE + ret +; 3f836 + +DisplayLinkRecord: ; 3f836 + ld a, BANK(sLinkBattleStats) + call GetSRAMBank + + call ReadAndPrintLinkBattleRecord + + call CloseSRAM + hlcoord 0, 0, AttrMap + 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 +; 3f85f + +ReadAndPrintLinkBattleRecord: ; 3f85f + 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, wd002 + ld bc, 10 + call CopyBytes + ld a, "@" + ld [de], a + inc de + ld bc, 6 + call CopyBytes + ld de, wd002 + pop hl + call PlaceString + pop hl + ld de, 26 + add hl, de + push hl + ld de, wd00d + lb bc, 2, 4 + call PrintNum + pop hl + ld de, 5 + add hl, de + push hl + ld de, wd00f + lb bc, 2, 4 + call PrintNum + pop hl + ld de, 5 + add hl, de + ld de, wd011 + 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 + jr c, .quit + + 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 + call PlaceString + scf + ret +; 3f938 + +.Scores: + db " 0 0 0@" +; 3f947 + +.Format: ; 3f947 + db " --- <LNBRK>" + db " - - -@" +.Record: ; 3f964 + db "<PLAYER>'s RECORD@" +.Result: ; 3f96e + db "RESULT WIN LOSE DRAW@" +.Total: ; 3f983 + db "TOTAL WIN LOSE DRAW@" +; 3f998 + +BattleEnd_HandleRoamMons: ; 3f998 + ld a, [BattleType] + cp BATTLETYPE_ROAMING + jr nz, .not_roaming + ld a, [wBattleResult] + and $f + jr z, .caught_or_defeated_roam_mon + call GetRoamMonHP + ld a, [EnemyMonHP + 1] + ld [hl], a + jr .update_roam_mons + +.caught_or_defeated_roam_mon + call GetRoamMonHP + ld [hl], $0 + call GetRoamMonMapGroup + ld [hl], $ff + call GetRoamMonMapNumber + ld [hl], $ff + call GetRoamMonSpecies + ld [hl], $0 + ret + +.not_roaming + call BattleRandom + and $f + ret nz + +.update_roam_mons + callfar UpdateRoamMons + ret +; 3f9d1 + +GetRoamMonMapGroup: ; 3f9d1 + ld a, [TempEnemyMonSpecies] + 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 +; 3f9e9 + +GetRoamMonMapNumber: ; 3f9e9 + ld a, [TempEnemyMonSpecies] + 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 +; 3fa01 + +GetRoamMonHP: ; 3fa01 +; output: hl = wRoamMonHP + ld a, [TempEnemyMonSpecies] + 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 +; 3fa19 + +GetRoamMonDVs: ; 3fa19 +; output: hl = wRoamMonDVs + ld a, [TempEnemyMonSpecies] + 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 +; 3fa31 + +GetRoamMonSpecies: ; 3fa31 + ld a, [TempEnemyMonSpecies] + ld hl, wRoamMon1Species + cp [hl] + ret z + ld hl, wRoamMon2Species + cp [hl] + ret z + ld hl, wRoamMon3Species + ret +; 3fa42 + +AddLastMobileBattleToLinkRecord: ; 3fa42 + ld hl, OTPlayerID + ld de, StringBuffer1 + ld bc, 2 + call CopyBytes + ld hl, OTPlayerName + ld bc, NAME_LENGTH - 1 + call CopyBytes + ld hl, sLinkBattleResults + 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, StringBuffer1 + call CompareLong + 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, StringBuffer1 + 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 +; 3faa0 +.StoreResult: ; 3faa0 + ld a, [wBattleResult] + and $f + cp $1 + ld bc, sLinkBattleWins + 1 - sLinkBattleResults + jr c, .okay + ld bc, sLinkBattleLosses + 1 - sLinkBattleResults + jr z, .okay + ld bc, sLinkBattleDraws + 1 - sLinkBattleResults +.okay + add hl, bc + call .CheckOverflow + ret nc + inc [hl] + ret nz + dec hl + inc [hl] + ret +; 3fabe + +.CheckOverflow: ; 3fabe + dec hl + ld a, [hl] + inc hl + cp HIGH(MAX_LINK_RECORD) + ret c + ld a, [hl] + cp LOW(MAX_LINK_RECORD) + ret +; 3fac8 + +.FindOpponentAndAppendRecord: ; 3fac8 + ld b, 5 + ld hl, sLinkBattleRecord + 17 + ld de, wd002 +.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, wd002 + add hl, de + push hl + ld a, c + add c + add c + ld e, a + ld d, $0 + ld hl, wd002 + add hl, de + ld d, h + ld e, l + pop hl + push bc + ld c, 3 + call StringCmp + 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, wd002 + 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, wd002 + ld bc, 18 + pop de + call CopyBytes + ret +; 3fb54 + +.LoadPointer: ; 3fb54 + 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 +; 3fb6c + +InitBattleDisplay: ; 3fb6c + call .InitBackPic + hlcoord 0, 12 + ld b, 4 + ld c, 18 + call TextBox + farcall MobileTextBorder + hlcoord 1, 5 + lb bc, 3, 7 + call ClearBox + call LoadStandardFont + call _LoadBattleFontsHPBar + call .BlankBGMap + xor a + ld [hMapAnims], a + ld [hSCY], a + ld a, $90 + ld [hWY], a + ld [rWY], a + call WaitBGMap + xor a + ld [hBGMapMode], a + farcall BattleIntroSlidingPics + ld a, $1 + ld [hBGMapMode], a + ld a, $31 + ld [hGraphicStartTile], a + hlcoord 2, 6 + lb bc, 6, 6 + predef PlaceGraphic + xor a + ld [hWY], a + ld [rWY], a + call WaitBGMap + call HideSprites + ld b, SCGB_BATTLE_COLORS + call GetSGBLayout + call SetPalettes + ld a, $90 + ld [hWY], a + xor a + ld [hSCX], a + ret +; 3fbd6 + +.BlankBGMap: ; 3fbd6 + ld a, [rSVBK] + push af + ld a, $6 + ld [rSVBK], a + + ld hl, wDecompressScratch + ld bc, wScratchAttrMap - wDecompressScratch + ld a, " " + call ByteFill + + ld de, wDecompressScratch + hlbgcoord 0, 0 + lb bc, BANK(.BlankBGMap), $40 + call Request2bpp + + pop af + ld [rSVBK], a + ret +; 3fbf8 + +.InitBackPic: ; 3fbf8 + call GetTrainerBackpic + call CopyBackpic + ret +; 3fbff + +GetTrainerBackpic: ; 3fbff +; Load the player character's backpic (6x6) into VRAM starting from VTiles2 tile $31. + +; Special exception for Dude. + ld b, BANK(DudeBackpic) + ld hl, DudeBackpic + ld a, [BattleType] + cp BATTLETYPE_TUTORIAL + jr z, .Decompress + +; What gender are we? + ld a, [wPlayerSpriteSetupFlags] + bit 2, a ; transformed to male + jr nz, .Chris + ld a, [PlayerGender] + bit 0, a + jr z, .Chris + +; It's a girl. + farcall GetKrisBackpic + ret + +.Chris: +; It's a boy. + ld b, BANK(ChrisBackpic) + ld hl, ChrisBackpic + +.Decompress: + ld de, VTiles2 tile $31 + ld c, $31 + predef DecompressPredef + ret +; 3fc30 + +CopyBackpic: ; 3fc30 + ld a, [rSVBK] + push af + ld a, $6 + ld [rSVBK], a + ld hl, VTiles0 + ld de, VTiles2 tile $31 + ld a, [hROMBank] + ld b, a + ld c, $31 + call Get2bpp + pop af + ld [rSVBK], a + call .LoadTrainerBackpicAsOAM + ld a, $31 + ld [hGraphicStartTile], a + hlcoord 2, 6 + lb bc, 6, 6 + predef PlaceGraphic + ret +; 3fc5b + +.LoadTrainerBackpicAsOAM: ; 3fc5b + ld hl, Sprites + xor a + ld [hMapObjectIndexBuffer], a + ld b, $6 + ld e, 21 * 8 +.outer_loop + ld c, $3 + ld d, 8 * 8 +.inner_loop + ld [hl], d + inc hl + ld [hl], e + inc hl + ld a, [hMapObjectIndexBuffer] + ld [hli], a + inc a + ld [hMapObjectIndexBuffer], a + ld a, $1 + ld [hli], a + ld a, d + add $8 + ld d, a + dec c + jr nz, .inner_loop + ld a, [hMapObjectIndexBuffer] + add $3 + ld [hMapObjectIndexBuffer], a + ld a, e + add $8 + ld e, a + dec b + jr nz, .outer_loop + ret +; 3fc8b + +BattleStartMessage: ; 3fc8b + ld a, [wBattleMode] + dec a + jr z, .wild + + ld de, SFX_SHINE + call PlaySFX + call WaitSFX + + ld c, 20 + call DelayFrames + + farcall Battle_GetTrainerName + + ld hl, WantsToBattleText + jr .PlaceBattleStartText + +.wild + call BattleCheckEnemyShininess + jr nc, .not_shiny + + xor a + ld [wNumHits], a + ld a, 1 + ld [hBattleTurn], a + ld a, 1 + ld [wBattleAnimParam], a + ld de, ANIM_SEND_OUT_MON + call Call_PlayBattleAnim + +.not_shiny + farcall CheckSleepingTreeMon + jr c, .skip_cry + + farcall CheckBattleScene + jr c, .cry_no_anim + + hlcoord 12, 0 + ld d, $0 + ld e, ANIM_MON_NORMAL + predef AnimateFrontpic + jr .skip_cry ; cry is played during the animation + +.cry_no_anim + ld a, $0f + ld [CryTracks], a + ld a, [TempEnemyMonSpecies] + call PlayStereoCry + +.skip_cry + ld a, [BattleType] + cp BATTLETYPE_FISH + jr nz, .NotFishing + + farcall TrainerRankings_HookedEncounters + + ld hl, HookedPokemonAttackedText + jr .PlaceBattleStartText + +.NotFishing: + ld hl, PokemonFellFromTreeText + cp BATTLETYPE_TREE + jr z, .PlaceBattleStartText + ld hl, WildCelebiAppearedText + cp BATTLETYPE_CELEBI + jr z, .PlaceBattleStartText + ld hl, WildPokemonAppearedText + +.PlaceBattleStartText: + push hl + farcall BattleStart_TrainerHuds + pop hl + call StdBattleTextBox + + call IsMobileBattle2 + ret nz + + ld c, $2 ; start + farcall Mobile_PrintOpponentBattleMessage + + ret +; 3fd26 |