pokegold-spaceworld/engine/battle/core.asm
DrippingYellow 452a322140
Some checks failed
CI / build (push) Has been cancelled
Finish labelling bank $0f (#127)
* Split bank $0f into engine/battle/core.asm and engine/overworld/wildmons.asm
* Split wildmon probabilities into separate data/wild/probabilities.inc file for consistency
2026-01-21 18:43:18 -05:00

6728 lines
109 KiB
NASM
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

INCLUDE "constants.asm"
SECTION "engine/battle/core.asm@DoBattle", ROMX
DoBattle:
xor a
ld [wBattleParticipantsNotFainted], a
ld [wBattleParticipantsIncludingFainted], a
ld [wBattlePlayerAction], a
inc a
ld [wBattleHasJustStarted], a
ld hl, wOTPartyMon1HP
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
ldh a, [hSerialConnectionStatus]
cp USING_INTERNAL_CLOCK
jr z, .player_2
.not_linked
ld a, [wBattleMode]
dec a
jr z, .wild
call EnemySwitch
call NewEnemyMonStatus
.wild
ld c, 40
call DelayFrames
.player_2
call BackUpTilesToBuffer
.check_any_alive
call CheckPlayerPartyForFitMon
ld a, d
and a
jp z, LostBattle
call ReloadTilesFromBuffer
ld a, [wBattleType]
and a
jp nz, .SafariZoneBattleTurn
xor a
ld [wCurPartyMon], a
.loop2
call CheckIfCurPartyMonIsFitToFight
jr nz, .alive2
ld hl, wCurPartyMon
inc [hl]
jr .loop2
.alive2
ld a, [wCurPartyMon]
ld [wCurBattleMon], a
inc a
ld hl, wPartySpecies - 1
ld c, a
ld b, 0
add hl, bc
ld a, [hl]
ld [wCurPartySpecies], a
ld [wTempBattleMonSpecies], a
hlcoord 1, 5
ld a, 9
call SlideBattlePicOut
call BackUpTilesToBuffer
ld a, [wCurPartyMon]
ld c, a
ld b, SET_FLAG
push bc
ld hl, wBattleParticipantsNotFainted
predef SmallFarFlagAction
ld hl, wBattleParticipantsIncludingFainted
pop bc
predef SmallFarFlagAction
call LoadBattleMonFromParty
call ApplyStatMods
call SendOutMonText
call NewBattleMonStatus
call SendOutPlayerMon
call EmptyBattleTextbox
call BackUpTilesToBuffer
xor a
ldh [hBattleTurn], a
call SpikesDamage
ld a, [wLinkMode]
and a
jr z, .to_battle
ldh a, [hSerialConnectionStatus]
cp USING_INTERNAL_CLOCK
jr nz, .to_battle
call EnemySwitch
call NewEnemyMonStatus
ld a, 1
ldh [hBattleTurn], a
call SpikesDamage
.to_battle
jp BattleTurn
; Old Safari Zone code from Red & Green.
.SafariZoneBattleTurn
call BattleMenu
ret c
ld a, [wBattlePlayerAction]
and a ; if non-zero, this would have meant that the item was used successfully
jr z, .SafariZoneBattleTurn
; There used to be code checking for Safari Balls here, but it was taken out.
call ReloadTilesFromBuffer
ld hl, Unused_OutOfSafariBallsText
jp PrintText
; Unreferenced.
.not_out_of_safari_balls
call PrintSafariZoneBattleText
ld a, [wEnemyMonSpeed + 1]
add a
ld b, a
jp c, WildFled_EnemyFled_LinkBattleCanceled
ld a, [wUnused_SafariBaitFactor]
and a
jr z, .check_escape_factor
srl b
srl b
.check_escape_factor
ld a, [wUnused_SafariEscapeFactor]
and a
jr z, .compare_with_random_value
sla b
jr nc, .compare_with_random_value
ld b, $ff
.compare_with_random_value
call BattleRandom
cp b
jp nc, .check_any_alive
jr WildFled_EnemyFled_LinkBattleCanceled
Unused_OutOfSafariBallsText:
text "アナウンス『ピンポーン!"
para "サファリ ボールを"
line "ぜんぶ なげました!"
prompt
WildFled_EnemyFled_LinkBattleCanceled:
call ReloadTilesFromBuffer
ld a, DRAW
ld [wBattleResult], a
ld a, [wLinkMode]
and a
ld hl, WildPokemonFledText
jr z, .print_text
xor a ; WIN
ld [wBattleResult], a
ld hl, EnemyPokemonFledText
.print_text
call PrintText
ld de, SFX_RUN
call PlaySFX
xor a
ldh [hBattleTurn], a
; Was originally AnimationSlideEnemyMonOff in pokered.
jpfar Functioncc000
WildPokemonFledText:
text "やせいの@"
text_from_ram wEnemyMonNickname
text "は にげだした!"
prompt
EnemyPokemonFledText:
text "てきの@"
text_from_ram wEnemyMonNickname
text "は にげだした!"
prompt
BattleTurn:
call UpdateBattleMonInParty
ldh a, [hSerialConnectionStatus]
cp USING_EXTERNAL_CLOCK
jr z, .CheckEnemyFirst
call CheckFaint_Player
jp z, HandlePlayerMonFaint
call CheckFaint_Enemy
jp z, HandleEnemyMonFaint
call HandlePerishSong
call CheckFaint_Player
jp z, HandlePlayerMonFaint
call CheckFaint_Enemy
jp z, HandleEnemyMonFaint
jr .PerishSongDone
.CheckEnemyFirst:
call CheckFaint_Enemy
jp z, HandleEnemyMonFaint
call CheckFaint_Player
jp z, HandlePlayerMonFaint
call HandlePerishSong
call CheckFaint_Enemy
jp z, HandleEnemyMonFaint
call CheckFaint_Player
jp z, HandlePlayerMonFaint
.PerishSongDone:
call HandleSafeguard
call HandleWeather
call HandleStatBoostingHeldItems
call HandleHealingItems
call UpdateBattleMonInParty
call BackUpTilesToBuffer
call TryEnemyFlee
jp c, WildFled_EnemyFled_LinkBattleCanceled
xor a
ld [wBattleHasJustStarted], a
ld a, [wPlayerSubStatus4]
and ((1 << SUBSTATUS_RECHARGE) | (1 << SUBSTATUS_RAGE))
jp nz, .locked_in
ld hl, wEnemySubStatus3
res SUBSTATUS_FLINCHED, [hl]
ld hl, wPlayerSubStatus3
res SUBSTATUS_FLINCHED, [hl]
ld a, [hl]
and ((1 << SUBSTATUS_RAMPAGE) | (1 << SUBSTATUS_CHARGED))
jp nz, .locked_in
ld hl, wPlayerSubStatus1
bit SUBSTATUS_ROLLOUT, [hl]
jp nz, .locked_in
.loop1
call BattleMenu
ret c
ld a, [wBattleEnded]
and a
ret nz
ld hl, wPlayerSubStatus5
bit SUBSTATUS_ENCORED, [hl]
jr z, .not_encored
ld a, [wPlayerEncoreCount]
dec a
ld [wPlayerEncoreCount], a
jr nz, .encored
.clear_encore
ld hl, wPlayerSubStatus5
res SUBSTATUS_ENCORED, [hl]
xor a
ldh [hBattleTurn], a
ld hl, BattleText_TargetsEncoreEnded
call PrintText
jr .not_encored
.encored
; If the player hasn't used a move (possible via sleep and freeze), Encore gets cleared.
ld a, [wLastPlayerCounterMove]
and a
jr z, .clear_encore
ld a, [wCurMoveNum]
ld c, a
ld b, 0
ld hl, wBattleMonPP
add hl, bc
ld a, [hl]
and PP_MASK
jr z, .clear_encore
ld a, [wLastPlayerCounterMove]
ld [wCurPlayerMove], a
jr .encored2
.not_encored
ld a, [wPlayerSubStatus3]
and ((1 << SUBSTATUS_BIDE) | (1 << SUBSTATUS_USING_TRAPPING_MOVE))
jr nz, .locked_in
ld a, [wBattlePlayerAction]
and a ; BATTLEPLAYERACTION_USEMOVE
jr nz, .locked_in
xor a
ld [wMoveSelectionMenuType], a
inc a ; MOVE_POUND
ld [wFXAnimID], a
call MoveSelectionScreen
push af
call ReloadTilesFromBuffer
call UpdateBattleHuds
pop af
jp nz, .loop1
.encored2
xor a
ldh [hBattleTurn], a
callfar UpdateMoveData
ld a, [wPlayerMoveStructEffect]
cp EFFECT_FURY_CUTTER
jr z, .continue_fury_cutter
xor a
ld [wPlayerFuryCutterCount], a
jr .next
.locked_in
xor a
ld [wPlayerFuryCutterCount], a
.continue_fury_cutter
.next
call ParseEnemyAction
ld a, [wLinkMode]
and a
jr z, .use_move
ld a, [wOtherPlayerLinkAction]
cp BATTLEACTION_FORFEIT
jp z, WildFled_EnemyFled_LinkBattleCanceled
cp BATTLEACTION_STRUGGLE
jr z, .use_move
cp BATTLEACTION_SKIPTURN
jr z, .use_move
sub BATTLEACTION_SKIPTURN - BATTLEACTION_SWITCH6
jr c, .use_move
ld a, [wPlayerSubStatus3]
bit SUBSTATUS_USING_TRAPPING_MOVE, a
jr z, .dont_change_last_move
ld a, [wCurMoveNum]
ld hl, wBattleMonMoves
ld c, a
ld b, 0
add hl, bc
ld a, [hl]
cp MOVE_METRONOME
jr nz, .dont_change_last_move
ld [wCurPlayerMove], a
.dont_change_last_move
callfar AI_Switch
ld a, 1
ldh [hBattleTurn], a
call SpikesDamage
jp Battle_EnemyFirst
.use_move
ld a, [wCurPlayerMove]
call GetMoveEffect
cp EFFECT_PRIORITY_HIT
jr nz, .no_priority_player
ld a, [wCurEnemyMove]
call GetMoveEffect
cp EFFECT_PRIORITY_HIT
jr z, .equal_priority
jp Battle_PlayerFirst
.no_priority_player
ld a, [wCurEnemyMove]
call GetMoveEffect
cp EFFECT_PRIORITY_HIT
jp z, Battle_EnemyFirst
ld a, [wCurPlayerMove]
call GetMoveEffect
cp EFFECT_COUNTER
jr nz, .no_counter_player
ld a, [wCurEnemyMove]
call GetMoveEffect
cp EFFECT_COUNTER
jr z, .equal_priority
jp Battle_EnemyFirst
.no_counter_player
ld a, [wCurEnemyMove]
call GetMoveEffect
cp EFFECT_COUNTER
jp z, Battle_PlayerFirst
.equal_priority
xor a
ldh [hBattleTurn], a
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 Battle_PlayerFirst
.player_no_quick_claw
ld a, b
cp HELD_QUICK_CLAW
jr nz, .speed_check
call BattleRandom
cp c
jr nc, .speed_check
jp Battle_EnemyFirst
.both_have_quick_claw
ldh a, [hSerialConnectionStatus]
cp USING_INTERNAL_CLOCK
jr z, .player_2b
call BattleRandom
cp c
jp c, Battle_EnemyFirst
call BattleRandom
cp e
jp c, Battle_PlayerFirst
jr .speed_check
.player_2b
call BattleRandom
cp e
jp c, Battle_PlayerFirst
call BattleRandom
cp c
jp c, Battle_EnemyFirst
jr .speed_check
.speed_check
ld de, wBattleMonSpeed
ld hl, wEnemyMonSpeed
ld c, 2
call CompareBytes
jr z, .speed_tie
jp nc, Battle_PlayerFirst
jr Battle_EnemyFirst
.speed_tie
ldh a, [hSerialConnectionStatus]
cp USING_INTERNAL_CLOCK
jr z, .player_2c
call BattleRandom
cp 50 percent + 1
jp c, Battle_PlayerFirst
jr Battle_EnemyFirst
.player_2c
call BattleRandom
cp 50 percent + 1
jr c, Battle_EnemyFirst
jp Battle_PlayerFirst
TryEnemyFlee:
ld a, [wBattleMode]
dec a
jr nz, .stay
ld a, [wDebugFlags]
bit DEBUG_BATTLE_F, a
jr nz, .stay
ld a, [wEnemySubStatus5]
bit SUBSTATUS_CANT_RUN, a
jr nz, .stay
call BattleRandom
cp 4 percent ; 10/256 chance for any Pokémon to run away
jr nc, .stay
scf
ret
.stay
and a
ret
GetMoveEffect:
dec a
ld hl, Moves + MOVE_EFFECT
ld bc, MOVE_LENGTH
call AddNTimes
ld a, BANK(Moves)
jp GetFarByte
Battle_EnemyFirst:
ld a, 1
ldh [hBattleTurn], a
callfar AI_SwitchOrTryItem
jr c, .switch_item
callfar DoEnemyTurn
call EndOpponentProtectEndureDestinyBond
ld a, [wBattleEnded]
and a
ret nz
call CheckFaint_Player
jp z, HandlePlayerMonFaint
.switch_item
call ResidualDamage
jp z, HandleEnemyMonFaint
call UpdateBattleHuds
callfar DoPlayerTurn
call EndOpponentProtectEndureDestinyBond
ld a, [wBattleEnded]
and a
ret nz
call CheckFaint_Enemy
jp z, HandleEnemyMonFaint
call ResidualDamage
jp z, HandlePlayerMonFaint
call UpdateBattleHuds
call CheckForEndOfTrappingMoves
xor a ; BATTLEPLAYERACTION_USEMOVE
ld [wBattlePlayerAction], a
jp BattleTurn
Battle_PlayerFirst:
callfar DoPlayerTurn
call EndOpponentProtectEndureDestinyBond
ld a, [wBattleEnded]
and a
ret nz
call CheckFaint_Enemy
jp z, HandleEnemyMonFaint
call ResidualDamage
jp z, HandlePlayerMonFaint
call UpdateBattleHuds
ld a, 1
ldh [hBattleTurn], a
callfar AI_SwitchOrTryItem
jr c, .switch_item
callfar DoEnemyTurn
call EndOpponentProtectEndureDestinyBond
ld a, [wBattleEnded]
and a
ret nz
call CheckFaint_Player
jp z, HandlePlayerMonFaint
.switch_item
call ResidualDamage
jp z, HandleEnemyMonFaint
call UpdateBattleHuds
call CheckForEndOfTrappingMoves
xor a
ld [wFieldMoveSucceeded], a
jp BattleTurn
EndOpponentProtectEndureDestinyBond:
ld hl, wEnemySubStatus5
ld de, wEnemySubStatus1
ldh a, [hBattleTurn]
and a
jr z, .ok
ld hl, wPlayerSubStatus5
ld de, wPlayerSubStatus1
.ok
res SUBSTATUS_DESTINY_BOND, [hl]
ld a, [de]
res SUBSTATUS_PROTECT, a
res SUBSTATUS_ENDURE, a
ld [de], a
ret
CheckFaint_Enemy:
ld hl, wEnemyMonHP
jr CheckIfHPIsZero
CheckFaint_Player:
ld hl, wBattleMonHP
CheckIfHPIsZero:
ld a, [hli]
or [hl]
ret
; Return z if the user fainted before
; or as a result of residual damage.
ResidualDamage:
ld hl, wBattleMonStatus
ldh a, [hBattleTurn]
and a
jr z, .ok
ld hl, wEnemyMonStatus
.ok
ld a, [hl]
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 PrintText
pop de
xor a
ld [wNumHits], a
call Call_PlayBattleAnim
call GetEighthMaxHP
ld hl, wPlayerSubStatus5
ld de, wPlayerToxicCount
ldh a, [hBattleTurn]
and a
jr z, .check_toxic
ld hl, wEnemySubStatus5
ld de, wEnemyToxicCount
.check_toxic
bit SUBSTATUS_TOXIC, [hl]
jr z, .did_toxic
; Multiplies the initial 1/8th health reduction by the toxic count
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
ld hl, wPlayerSubStatus4
ldh a, [hBattleTurn]
and a
jr z, .check_seed
ld hl, wEnemySubStatus4
.check_seed
bit SUBSTATUS_LEECH_SEED, [hl]
jr z, .not_seeded
ldh a, [hBattleTurn]
push af
xor 1
ldh [hBattleTurn], a
xor a
ld [wNumHits], a
ld de, ANIM_SAP
call Call_PlayBattleAnim
pop af
ldh [hBattleTurn], a
call GetEighthMaxHP
call SubtractHPFromUser
call RestoreHP
ld hl, LeechSeedSapsText
call PrintText
.not_seeded
ld hl, wPlayerSubStatus1
ldh a, [hBattleTurn]
and a
jr z, .check_nightmare
ld hl, wEnemySubStatus1
.check_nightmare
bit SUBSTATUS_NIGHTMARE, [hl]
jr z, .not_nightmare
xor a
ld [wNumHits], a
ld de, ANIM_IN_NIGHTMARE
call Call_PlayBattleAnim
call GetQuarterMaxHP
call SubtractHPFromUser
ld hl, HasANightmareText
call PrintText
.not_nightmare
ld hl, wPlayerSubStatus1
ldh a, [hBattleTurn]
and a
jr z, .check_curse
ld hl, wEnemySubStatus1
.check_curse
bit SUBSTATUS_CURSE, [hl]
jr z, .not_cursed
xor a
ld [wNumHits], a
ld de, ANIM_IN_NIGHTMARE
call Call_PlayBattleAnim
call GetQuarterMaxHP
call SubtractHPFromUser
ld hl, HurtByCurseText
call PrintText
.not_cursed
ld hl, wPlayerScreens
ldh a, [hBattleTurn]
and a
jr z, .check_sandstorm
ld hl, wEnemyScreens
.check_sandstorm
bit SCREENS_SANDSTORM, [hl]
jr z, .no_sandstorm
ldh a, [hBattleTurn]
push af
xor 1
ldh [hBattleTurn], a
xor a
ld [wNumHits], a
ld de, ANIM_IN_SANDSTORM
call Call_PlayBattleAnim
pop af
ldh [hBattleTurn], a
call GetEighthMaxHP
call SubtractHPFromUser
ld hl, SandstormHitsText
call PrintText
.no_sandstorm
ld hl, wBattleMonHP
ldh a, [hBattleTurn]
and a
jr z, .got_hp
ld hl, wEnemyMonHP
.got_hp
ld a, [hli]
or [hl]
ret nz
call UpdateBattleHuds
ld c, 20
call DelayFrames
xor a
ret
HurtByPoisonText:
text "<USER>は"
line "どくの ダメージを うけている!"
prompt
HurtByBurnText:
text "<USER>は"
line "やけどの ダメージを うけている!"
prompt
LeechSeedSapsText:
text "やどりぎが <USER>の"
line "たいりょくを うばう!"
prompt
HasANightmareText:
text "<USER>は"
line "あくむに うなされている!"
prompt
HurtByCurseText:
text "<USER>は"
line "のろわれている!"
prompt
SandstormHitsText:
text "すなあらしが <USER>を"
line "おそう!"
prompt
HandlePerishSong:
ldh a, [hSerialConnectionStatus]
cp USING_EXTERNAL_CLOCK
jr z, .player1
xor a
ldh [hBattleTurn], a
call .do_it
ld a, 1
ldh [hBattleTurn], a
call .do_it
ret
.player1
ld a, 1
ldh [hBattleTurn], a
call .do_it
xor a
ldh [hBattleTurn], a
call .do_it
ret
.do_it
ld hl, wPlayerSubStatus1
ld de, wPlayerPerishCount
ldh a, [hBattleTurn]
and a
jr z, .got_count
ld hl, wEnemySubStatus1
ld de, wEnemyPerishCount
.got_count
bit SUBSTATUS_PERISH, [hl]
ret z
ld a, [de]
dec a
ld [de], a
ld [wTextDecimalByte], a
push af
push hl
ld hl, PerishCountText
call PrintText
pop hl
pop af
ret nz
res SUBSTATUS_PERISH, [hl]
ldh a, [hBattleTurn]
and a
jr nz, .kill_enemy
ld hl, wBattleMonHP
xor a
ld [hli], a
ld [hl], a
ld hl, wPartyMon1HP
ld a, [wCurBattleMon]
ld bc, PARTYMON_STRUCT_LENGTH
call AddNTimes
xor a
ld [hli], a
ld [hl], a
ret
.kill_enemy
ld hl, wEnemyMonHP
xor a
ld [hli], a
ld [hl], a
ld a, [wBattleMode]
dec a
ret z
ld hl, wOTPartyMon1HP
ld a, [wCurOTMon]
ld bc, PARTYMON_STRUCT_LENGTH
call AddNTimes
xor a
ld [hli], a
ld [hl], a
ret
PerishCountText:
text "<USER>の ほろびの"
line "カウントが @"
deciram wNumSetBits, 1, 1
text "になった!"
prompt
HandleSafeguard:
ld a, [wPlayerScreens]
bit SCREENS_SAFEGUARD, a
jr z, .check_enemy
ld hl, wPlayerSafeguardCount
dec [hl]
jr nz, .check_enemy
res SCREENS_SAFEGUARD, a
ld [wPlayerScreens], a
xor a
call .PrintSafeguardFadedText
.check_enemy
ld a, [wEnemyScreens]
bit SCREENS_SAFEGUARD, a
ret z
ld hl, wEnemySafeguardCount
dec [hl]
ret nz
res SCREENS_SAFEGUARD, a
ld [wEnemyScreens], a
ld a, 1
.PrintSafeguardFadedText:
ldh [hBattleTurn], a
ld hl, BattleText_SafeguardFaded
jp PrintText
BattleText_SafeguardFaded:
text "<USER>を つつんでいた"
line "しんぴの ベールが なくなった!"
prompt
HandleWeather:
ld a, [wBattleWeather]
and a ; WEATHER_NONE
ret z
dec a
ld c, a
ld hl, wWeatherCount
dec [hl]
ld hl, .WeatherMessages
jr nz, .PrintWeatherMessage
xor a
ld [wBattleWeather], a
ld hl, .WeatherEndedMessages
.PrintWeatherMessage:
ld b, 0
add hl, bc
add hl, bc
ld a, [hli]
ld h, [hl]
ld l, a
call PrintText
ret
.WeatherMessages:
dw BattleText_RainContinuesToFall
dw BattleText_TheSunlightIsStrong
.WeatherEndedMessages:
dw BattleText_TheRainStopped
dw BattleText_TheSunlightFaded
BattleText_RainContinuesToFall:
text "あめが ふりつずいている"
prompt
BattleText_TheSunlightIsStrong:
text "ひざしが つよい"
prompt
BattleText_TheRainStopped:
text "あめが やんだ!"
prompt
BattleText_TheSunlightFaded:
text "ひざしが よわくなった!"
prompt
; Subtract c HP from mon
SubtractHPFromUser:
ld hl, wBattleMonHP
ldh a, [hBattleTurn]
and a
jr z, .got_mon_hp
ld hl, wEnemyMonHP
.got_mon_hp
inc hl
ld a, [hl]
ld [wHPBarOldHP], a
sub c
ld [hld], a
ld [wHPBarNewHP], a
ld a, [hl]
ld [wHPBarOldHP + 1], a
sbc b
ld [hl], a
ld [wHPBarNewHP + 1], a
jr nc, .end
xor a
ld [hli], a
ld [hl], a
ld [wHPBarNewHP], a
ld [wHPBarNewHP + 1], a
.end
call UpdateHPBarBattleHuds
ret
; Output: bc
GetEighthMaxHP:
ld hl, wBattleMonMaxHP
ldh a, [hBattleTurn]
and a
jr z, .got_max_hp
ld hl, wEnemyMonMaxHP
.got_max_hp
ld a, [hli]
ld [wHPBarMaxHP + 1], a
ld b, a
ld a, [hl]
ld [wHPBarMaxHP], a
ld c, a
; Quarter result.
srl b
rr c
srl b
rr c
; Assumes nothing can have 1024 or more HP.
; Halve result.
srl c
; Make sure the amount is at least 1.
ld a, c
and a
jr nz, .end
inc c
.end
ret
; Output: bc
GetQuarterMaxHP:
ld hl, wBattleMonMaxHP
ldh a, [hBattleTurn]
and a
jr z, .got_max_hp
ld hl, wEnemyMonMaxHP
.got_max_hp
ld a, [hli]
ld [wHPBarMaxHP + 1], a
ld b, a
ld a, [hl]
ld [wHPBarMaxHP], a
ld c, a
; Quarter result
srl b
rr c
srl b
rr c
; Assumes nothing can have 1024 or more hp.
; Make sure the amount is at least 1.
ld a, c
and a
jr nz, .end
inc c
.end
ret
; Output: bc
GetHalfMaxHP:
ld hl, wBattleMonMaxHP
ldh a, [hBattleTurn]
and a
jr z, .got_max_hp
ld hl, wEnemyMonMaxHP
.got_max_hp
ld a, [hli]
ld [wHPBarMaxHP + 1], a
ld b, a
ld a, [hl]
ld [wHPBarMaxHP], a
ld c, a
; Half result
srl b
rr c
; MINOR BUG: If something has a multiple of 512 HP, then the HP amount will be increased by 1.
; This amount is achievable by using monsters with high base HP, e.g. Chansey.
ld a, c
and a
jr nz, .end
inc c
.end
ret
GetMaxHP:
ld hl, wBattleMonMaxHP
ldh a, [hBattleTurn]
and a
jr z, .got_max_hp
ld hl, wEnemyMonMaxHP
.got_max_hp
ld a, [hli]
ld [wHPBarMaxHP + 1], a
ld b, a
ld a, [hl]
ld [wHPBarMaxHP], a
ld c, a
ret
RestoreHP:
ld hl, wEnemyMonMaxHP
ldh a, [hBattleTurn]
and a
jr z, .ok
ld hl, wBattleMonMaxHP
.ok
ld a, [hli]
ld [wHPBarMaxHP + 1], a
ld a, [hld]
ld [wHPBarMaxHP], a
dec hl
ld a, [hl]
ld [wHPBarOldHP], a
add c
ld [hld], a
ld [wHPBarNewHP], a
ld a, [hl]
ld [wHPBarOldHP + 1], a
adc b
ld [hli], a
ld [wHPBarNewHP + 1], a
ld a, [wHPBarMaxHP]
ld c, a
ld a, [hld]
sub c
ld a, [wHPBarMaxHP + 1]
ld b, a
ld a, [hl]
sbc b
jr c, .overflow
ld a, b
ld [hli], a
ld [wHPBarNewHP + 1], a
ld a, c
ld [hl], a
ld [wHPBarNewHP], a
.overflow
ldh a, [hBattleTurn]
push af
xor 1
ldh [hBattleTurn], a
call UpdateHPBarBattleHuds
pop af
ldh [hBattleTurn], a
ret
UpdateHPBarBattleHuds:
hlcoord 10, 9
ldh a, [hBattleTurn]
and a
ld a, 1
jr z, .ok
hlcoord 2, 2
xor a
.ok
push bc
ld [wWhichHPBar], a
predef UpdateHPBar
pop bc
ret
; Clears SUBSTATUS_USING_TRAPPING_MOVE if a Pokémon's Rollout count is zero.
CheckForEndOfTrappingMoves:
ld a, [wPlayerRolloutCount]
and a
jr nz, .check_enemy
ld hl, wPlayerSubStatus3
res SUBSTATUS_USING_TRAPPING_MOVE, [hl]
.check_enemy
ld a, [wEnemyRolloutCount]
and a
ret nz
ld hl, wEnemySubStatus3
res SUBSTATUS_USING_TRAPPING_MOVE, [hl]
ret
HandleEnemyMonFaint:
xor a
ld [wWhichMonFaintedFirst], a
call UpdateBattleStateAndExperienceAfterEnemyFaint
call CheckPlayerPartyForFitMon
ld a, d
and a
jp z, LostBattle
ld hl, wBattleMonHP
ld a, [hli]
or [hl]
call nz, UpdatePlayerHUD
ld c, 60
call DelayFrames
ld a, [wBattleMode]
dec a
ret z
call CheckEnemyTrainerDefeated
jp z, WinTrainerBattle
ld hl, wBattleMonHP
ld a, [hli]
or [hl]
jr nz, .notfainted
call AskUseNextPokemon
ret c
call ForcePlayerMonChoice
.notfainted
ld a, 1
ld [wBattlePlayerAction], a
call HandleEnemySwitch
jp z, WildFled_EnemyFled_LinkBattleCanceled
xor a
ld [wFieldMoveSucceeded], a
jp BattleTurn
UpdateBattleStateAndExperienceAfterEnemyFaint:
call UpdateBattleMonInParty
ld a, [wBattleMode]
dec a
jr z, .wild
ld a, [wCurOTMon]
ld hl, wOTPartyMon1HP
ld bc, PARTYMON_STRUCT_LENGTH
call AddNTimes
xor a
ld [hli], a
ld [hl], a
.wild
ld hl, wPlayerSubStatus3
res SUBSTATUS_IN_LOOP, [hl]
xor a
ld hl, wPlayerDamageTaken
ld [hli], a
ld [hli], a
ld [hli], a
ld [hl], a
ld hl, wEnemySubStatus1
ld [hli], a
ld [hli], a
ld [hli], a
ld [hli], a
ld [hl], a
ld [wEnemyDisableCount], a
ld [wEnemyDisabledMove], a
ld [wEnemyMinimized], a
ld hl, wLastPlayerCounterMove
ld [hli], a
ld [hl], a
hlcoord 12, 5
decoord 12, 6
call MonFaintedAnimation
hlcoord 1, 0
lb bc, 4, 10
call ClearBox
ld a, [wBattleMode]
dec a
jr z, .wild2
push de
ld de, SFX_KINESIS
call PlaySFX
call WaitSFX
pop de
push de
ld de, SFX_FAINT
call PlaySFX
call WaitSFX
pop de
jr .trainer
.wild2
call StopDangerSound
ld a, 0
call PlayVictoryMusic
.trainer
ld hl, wBattleMonHP
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 UpdateFaintedPlayerMon
.player_mon_did_not_faint
call CheckPlayerPartyForFitMon
ld a, d
and a
ret z
ld hl, EnemyMonFainted
call PrintText
call EmptyBattleTextbox
call BackUpTilesToBuffer
xor a
ld [wBattleResult], a
ld b, ITEM_EXP_ALL_RED
call Call_GetItemAmount
push af
jr z, .skip_exp
ld hl, wEnemyMonBaseStats
ld b, wEnemyMonEnd - wEnemyMonBaseStats
.loop
srl [hl]
inc hl
dec b
jr nz, .loop
.skip_exp
xor a ; FALSE
ld [wBoostExpByExpAll], a
call GiveExperiencePoints
pop af
ret z
ld a, TRUE
ld [wBoostExpByExpAll], a
ld a, [wPartyCount]
ld b, 0
.gain_exp_loop
scf
rl b
dec a
jr nz, .gain_exp_loop
ld a, b
ld [wBattleParticipantsNotFainted], a
jp GiveExperiencePoints
EnemyMonFainted:
text "てきの @"
text_from_ram wEnemyMonNickname
text "は たおれた!"
prompt
; TODO: Does it really stop the Danger Sound? wBattleLowHealthAlarm doesn't appear to be read anywhere else...
StopDangerSound:
inc a
ld [wBattleLowHealthAlarm], a
ret
CheckEnemyTrainerDefeated:
ld a, [wOTPartyCount]
ld b, a
xor a
ld hl, wOTPartyMon1HP
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
HandleEnemySwitch:
ld hl, wEnemyHPPal
ld e, HP_BAR_LENGTH_PX
call UpdateHPPal
callfar EnemySwitch_TrainerHud
ld a, [wLinkMode]
and a
jr z, .not_linked
call LinkBattleSendRecieveAction
ld a, [wOtherPlayerLinkAction]
cp BATTLEACTION_FORFEIT
ret z
call ReloadTilesFromBuffer
.not_linked
call EnemySwitch
call NewEnemyMonStatus
ld a, 1
ldh [hBattleTurn], a
call SpikesDamage
xor a
ld [wEnemyMoveStruct], a
ld [wFieldMoveSucceeded], a
ld [wEnemyTurnsTaken], a
inc a
ret
WinTrainerBattle:
call StopDangerSound
ld b, MUSIC_NONE
ld a, [wUnused_GymLeaderNo]
and a
jr nz, .gym_leader
ld b, MUSIC_VICTORY_TRAINER
.gym_leader
ld a, [wTrainerClass]
cp TRAINER_OPP_RIVAL3_RED
jr nz, .notrival_red
ld b, MUSIC_NONE
ld hl, wDebugFlags ; wStatusFlags7
set DEBUG_FIELD_F, [hl] ; BIT_NO_MAP_MUSIC
.notrival_red
ld a, [wLinkMode]
and a
ld a, b
call z, PlayVictoryMusic
callfar Battle_GetTrainerName
ld hl, BattleText_EnemyWasDefeated
call PrintText
ld a, [wLinkMode]
cp LINK_COLOSSEUM
ret z
call BattleWinSlideInEnemyTrainerFrontpic
ld c, 40
call DelayFrames
ld a, [wOtherTrainerClass]
cp TRAINER_RIVAL
jr nz, .notrival
ld hl, RivalLossText
call PrintText
callfar HealParty
.notrival
; No win/loss text implemented in this build, except for the rival's.
ld a, [wBattleMonItem]
ld b, a
callfar GetItemHeldEffect
ld a, b
cp HELD_AMULET_COIN
jr nz, .dont_double_reward
ld hl, wBattleReward + 2
sla [hl]
dec hl
rl [hl]
dec hl
rl [hl]
jr nc, .not_overflow
ld a, $ff
ld [hli], a
ld [hli], a
ld [hl], a
.dont_double_reward
.not_overflow
ld de, wMoney + 2
ld hl, wBattleReward + 2
ld c, 3
and a
; Add battle money to account
.loop
ld a, [de]
adc [hl]
ld [de], a
dec de
dec hl
dec c
jr nz, .loop
ld hl, GotMoneyForWinningText
call PrintText
ret
GotMoneyForWinningText:
text "<PLAYER>は しょうきんとして"
line "@"
deciram wBattleReward, 3, 6
text "円 てにいれた!"
prompt
BattleText_EnemyWasDefeated:
text_from_ram wOTClassName
text "の @"
text_from_ram wStringBuffer1
text_start
line "との しょうぶに かった!"
prompt
RivalLossText:
text "<RIVAL>『あれー?"
line "おまえの #に"
cont "すりゃあ よかったのかなあ?"
prompt
PlayVictoryMusic:
push de
ld de, MUSIC_NONE
call PlayMusic
call DelayFrame
ld de, MUSIC_VICTORY_TRAINER
call PlayMusic
pop de
ret
HandlePlayerMonFaint:
ld a, 1
ld [wWhichMonFaintedFirst], a
call UpdateFaintedPlayerMon
call CheckPlayerPartyForFitMon
ld a, d
and a
jp z, LostBattle
ld hl, wEnemyMonHP
ld a, [hli]
or [hl]
jr nz, .notfainted
call UpdateBattleStateAndExperienceAfterEnemyFaint
ld a, [wBattleMode]
dec a
ret z
call CheckEnemyTrainerDefeated
jp z, WinTrainerBattle
.notfainted
call AskUseNextPokemon
ret c
call ForcePlayerMonChoice
jp nz, BattleTurn
ld a, BATTLEPLAYERACTION_USEITEM
ld [wBattlePlayerAction], a
call HandleEnemySwitch
jp z, WildFled_EnemyFled_LinkBattleCanceled
xor a
ld [wFieldMoveSucceeded], a
jp BattleTurn
UpdateFaintedPlayerMon:
ld a, [wCurBattleMon]
ld c, a
ld hl, wBattleParticipantsNotFainted
ld b, RESET_FLAG
predef SmallFarFlagAction
ld hl, wEnemySubStatus3
res SUBSTATUS_IN_LOOP, [hl]
ld a, [wLowHealthAlarmBuffer]
bit DANGER_ON_F, a
jr z, .no_low_health_alarm
ld a, $ff
ld [wLowHealthAlarmBuffer], a
call WaitSFX
.no_low_health_alarm
ld hl, wEnemyDamageTaken
ld [hli], a
ld [hl], a
ld [wBattleMonStatus], a
ld [wBattleMonStatus + 1], a
call UpdateBattleMonInParty
hlcoord 9, 7
lb bc, 5, 11
call ClearBox
hlcoord 1, 10
decoord 1, 11
call MonFaintedAnimation
ld a, LOSE
ld [wBattleResult], a
ld a, [wWhichMonFaintedFirst]
and a
ret z
ld a, $f0
ld [wCryTracks], a
ld a, [wBattleMonSpecies]
call PlayStereoCry
ld hl, FaintedText
jp PrintText
FaintedText:
text_from_ram wBattleMonNickname
text "は たおれた!"
prompt
AskUseNextPokemon:
call EmptyBattleTextbox
call BackUpTilesToBuffer
; 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 PrintText
.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, wPartyMon1Speed
ld de, wEnemyMonSpeed
jp TryToRunAwayFromBattle
BattleText_UseNextMon:
text "つぎの #をつかいますか?"
done
ForcePlayerMonChoice:
call LoadStandardMenuHeader
ld a, PARTYMENUACTION_SWITCH
ld [wPartyMenuActionText], a
predef OpenPartyMenu_ClearGraphics
.pick
jr nc, .picked
.not_fit_to_fight
predef OpenPartyMenu
jr .pick
.picked
call CheckIfCurPartyMonIsFitToFight
jr z, .not_fit_to_fight
ld a, [wLinkMode]
cp LINK_COLOSSEUM
jr nz, .skip_link
; BUG TODO: Doesn't this result in invalid wBattlePlayerAction arguments?
inc a ; BATTLEPLAYERACTION_USEITEM
ld [wBattlePlayerAction], a
call LinkBattleSendRecieveAction
.skip_link
xor a ; BATTLEPLAYERACTION_USEMOVE
ld [wBattlePlayerAction], a
call ClearSprites
ld a, [wCurPartyMon]
ld [wCurBattleMon], a
ld c, a
ld hl, wBattleParticipantsNotFainted
ld b, SET_FLAG
push bc
predef SmallFarFlagAction
pop bc
ld hl, wBattleParticipantsIncludingFainted
predef SmallFarFlagAction
call LoadBattleMonFromParty
call ApplyStatMods
call ClearPalettes
call _LoadHPBar
call CloseWindow
call GetMemSGBLayout
call SetPalettes
call SendOutMonText
call NewBattleMonStatus
call SendOutPlayerMon
call EmptyBattleTextbox
call BackUpTilesToBuffer
xor a
ldh [hBattleTurn], a
call SpikesDamage
ld hl, wEnemyMonHP
ld a, [hli]
or [hl]
ret
LostBattle:
ld a, [wLinkMode]
and a
jr nz, .link
ld a, [wOtherTrainerClass]
cp TRAINER_RIVAL
jr nz, .not_rival
ld hl, wTileMap
lb bc, 8, 21
call ClearBox
call BattleWinSlideInEnemyTrainerFrontpic
ld c, 40
call DelayFrames
ld hl, RivalWinText
call PrintText
callfar HealParty
ret
.link
.not_rival
; Grayscale
ld b, SGB_BATTLE_GRAYSCALE
call GetSGBLayout
ld hl, OutOfUsableMonsText
ld a, [wLinkMode]
cp LINK_COLOSSEUM
jr nz, .not_link
ld hl, LostAgainstText
.not_link
call PrintText
call ClearTileMap
scf
ret
RivalWinText:
text "<RIVAL>『やった!"
line "いい# えらんだかも!"
prompt
OutOfUsableMonsText:
text "<PLAYER>の てもとには"
line "たたかえる #が いない!"
para "<PLAYER>は"
line "めのまえが まっくらに なった!"
prompt
LostAgainstText:
text_from_ram wOTClassName
text "との"
line "しょうぶに まけた!"
prompt
MonFaintedAnimation:
ld a, [wJoypadFlags]
push af
set 6, a ; JOYPAD_DISABLE_MON_FAINT_F
ld [wJoypadFlags], 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, SCREEN_WIDTH
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 [wJoypadFlags], a
ret
.Spaces:
db "       @"
SlideBattlePicOut:
ldh [hSpriteWidth], 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
.DoFrame:
ldh a, [hSpriteWidth]
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
EnemySwitch:
ld hl, wBattleParticipantsNotFainted
xor a
ld [hl], a
ld a, [wCurBattleMon]
ld c, a
ld b, SET_FLAG
push bc
predef SmallFarFlagAction
ld hl, wBattleParticipantsIncludingFainted
xor a
ld [hl], a
pop bc
predef SmallFarFlagAction
xor a
ld hl, wLastPlayerCounterMove
ld [hli], a
ld [hl], a
dec a
ld [wEnemyItemState], a
ld hl, wPlayerSubStatus3
res SUBSTATUS_USING_TRAPPING_MOVE, [hl]
hlcoord 18, 0
ld a, 8
call SlideBattlePicOut
call EmptyBattleTextbox
call LoadStandardMenuHeader
ld a, [wLinkMode]
and a
jr z, FindMonInOTPartyToSwitchIntoBattle
ld a, [wOtherPlayerLinkAction]
sub BATTLEACTION_SWITCH1
ld b, a
jp LoadEnemyMonToSwitchTo
FindMonInOTPartyToSwitchIntoBattle:
ld a, [wBattleHasJustStarted]
and a
jp nz, GetRandomOTPartyMon
ld b, -1
ld a, 1
ld [wEnemyEffectivenessVsPlayerMons], a
ld [wPlayerEffectivenessVsEnemyMons], a
.loop
ld hl, wEnemyEffectivenessVsPlayerMons
sla [hl]
inc hl
sla [hl]
inc b
ld a, [wOTPartyCount]
cp b
jp z, ScoreMonTypeMatchups
ld a, [wCurOTMon]
cp b
jr z, .discourage
ld hl, wOTPartyMon1HP
push bc
ld a, b
ld bc, PARTYMON_STRUCT_LENGTH
call AddNTimes
ld a, [hli]
ld c, a
ld a, [hl]
or c
pop bc
jr z, .discourage
call LookUpTheEffectivenessOfEveryMove
call IsThePlayerMonTypesEffectiveAgainstOTMon
jr .loop
.discourage
ld hl, wPlayerEffectivenessVsEnemyMons
set 0, [hl]
jr .loop
LookUpTheEffectivenessOfEveryMove:
push bc
ld hl, wOTPartyMon1Moves
ld a, b
ld bc, $30
call AddNTimes
pop bc
ld e, 5
.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, 7
call AddNTimes
ld de, wEnemyMoveStruct
ld a, BANK(Moves)
call FarCopyBytes
ld a, 1
ldh [hBattleTurn], a
callfar BattleCheckTypeMatchup
pop bc
pop de
pop hl
ld a, [wNumSetBits]
cp $b
jr c, .loop
ld hl, wEnemyEffectivenessVsPlayerMons
set 0, [hl]
ret
.done
ret
IsThePlayerMonTypesEffectiveAgainstOTMon:
push bc
ld hl, wOTPartyCount
ld a, b
inc a
ld c, a
ld b, 0
add hl, bc
ld a, [hl]
dec a
ld hl, BaseData + (wMonHTypes - wMonHeader)
ld bc, (wMonHeaderEnd - wMonHeader)
call AddNTimes
ld de, wEnemyMonType
ld bc, 2
ld a, BANK(BaseData)
call FarCopyBytes
ld a, [wBattleMonType1]
ld [wPlayerMoveStructType], a
xor a
ldh [hBattleTurn], a
callfar BattleCheckTypeMatchup
ld a, [wNumSetBits]
cp $b
jr nc, .super_effective
ld a, [wBattleMonType2]
ld [wPlayerMoveStructType], a
callfar BattleCheckTypeMatchup
ld a, [wNumSetBits]
cp $b
jr nc, .super_effective
pop bc
ret
.super_effective
pop bc
ld hl, wEnemyEffectivenessVsPlayerMons
bit 0, [hl]
jr nz, .reset
inc hl
set 0, [hl]
ret
.reset
res 0, [hl]
ret
ScoreMonTypeMatchups:
.loop1
ld hl, wEnemyEffectivenessVsPlayerMons
sla [hl]
inc hl
sla [hl]
jr nc, .loop1
ld a, [wOTPartyCount]
ld b, a
ld c, [hl]
.loop2
sla c
jr nc, .okay
dec b
jr z, GetRandomOTPartyMon
jr .loop2
.okay
ld a, [wEnemyEffectivenessVsPlayerMons]
and a
jr z, .okay2
ld b, -1
ld c, a
.loop3
inc b
sla c
jr nc, .loop3
jr LoadEnemyMonToSwitchTo
.okay2
ld b, -1
ld a, [wPlayerEffectivenessVsEnemyMons]
ld c, a
.loop4
inc b
sla c
jr c, .loop4
jr LoadEnemyMonToSwitchTo
GetRandomOTPartyMon:
.loop
call BattleRandom
maskbits PARTY_LENGTH
cp PARTY_LENGTH
jr nc, .loop
ld b, a
ld a, [wCurOTMon]
cp b
jr z, .loop
ld hl, wOTPartyMon1HP
push bc
ld a, b
ld bc, PARTYMON_STRUCT_LENGTH
call AddNTimes
pop bc
ld a, [hli]
ld c, a
ld a, [hl]
or c
jr z, .loop
LoadEnemyMonToSwitchTo:
; 'b' contains the PartyNr of the mon the AI will switch to
ld a, b
ld [wCurPartyMon], a
ld hl, wOTPartyMon1Level
ld bc, PARTYMON_STRUCT_LENGTH
call AddNTimes
ld a, [hl]
ld [wCurPartyLevel], a
ld a, [wCurPartyMon]
inc a
ld hl, wOTPartySpecies - 1
ld c, a
ld b, 0
add hl, bc
ld a, [hl]
ld [wTempEnemyMonSpecies], a
ld [wCurPartySpecies], a
call LoadEnemyMon
ld hl, wEnemyMonHP
ld a, [hli]
ld [wEnemyHPAtTimeOfPlayerSwitch], a
ld a, [hl]
ld [wEnemyHPAtTimeOfPlayerSwitch + 1], a
ld a, 1
ld [wMenuCursorY], a
ld a, [wBattleHasJustStarted]
dec a
jr z, EnemySendOutFirstMon
ld a, [wPartyCount]
dec a
jr z, EnemySendOutFirstMon
ld a, [wLinkMode]
and a
jr nz, EnemySendOutFirstMon
ld a, [wOptions]
bit BATTLE_SHIFT_F, a
jr nz, EnemySendOutFirstMon
callfar Battle_GetTrainerName
ld hl, TrainerAboutToUseText
call PrintText
lb bc, 1, 7
call PlaceYesNoBox
ld a, [wMenuCursorY]
dec a
jr nz, EnemySendOutFirstMon
ld a, PARTYMENUACTION_SWITCH
ld [wPartyMenuActionText], a
predef OpenPartyMenu_ClearGraphics
.pick
ld a, 1
ld [wMenuCursorY], a
jr c, .canceled_switch
ld hl, wCurBattleMon
ld a, [wCurPartyMon]
cp [hl]
jr nz, .notout
ld hl, BattleText_MonIsAlreadyOut_0f
call PrintText
.fainted
predef OpenPartyMenu
jr .pick
.notout
call CheckIfCurPartyMonIsFitToFight
jr z, .fainted
xor a
ld [wMenuCursorY], a
.canceled_switch
call ClearPalettes
call _LoadHPBar
EnemySendOutFirstMon:
call CloseWindow
call ClearSprites
hlcoord 1, 0
lb bc, 4, 10
call ClearBox
ld b, SGB_BATTLE_COLORS
call GetSGBLayout
call SetPalettes
callfar Battle_GetTrainerName
ld hl, TrainerSentOutText
call PrintText
ld a, [wTempEnemyMonSpecies]
ld [wCurPartySpecies], a
ld [wCurSpecies], a
call GetBaseData
ld a, OTPARTYMON
ld [wMonType], a
predef CopyMonToTempMon
ld hl, wTempMonDVs
predef GetUnownLetter
ld de, vFrontPic
call LoadMonFrontSprite
xor a
ld [wNumHits], a
inc a
ldh [hBattleTurn], a
; Play shiny animation for Sunflora and Pikachu
ld b, 1
ld a, [wCurPartySpecies]
cp DEX_SUNNY
jr z, .apply_animation
cp DEX_PIKACHU
jr z, .apply_animation
; Play scanline fade animation for Hoothoot
ld b, 2
cp DEX_HOHO
jr z, .apply_animation
; Play normal send out animation for everyone else
ld b, 0
.apply_animation
ld a, b
ld [wBattleAnimParam], a
ld de, ANIM_SEND_OUT_MON
call Call_PlayBattleAnim
; mon on the right side
ld a, $f
ld [wCryTracks], a
ld a, [wTempEnemyMonSpecies]
call PlayStereoCry
call UpdateEnemyHUD
; If battle has just started, go ahead and switch in your monster
ld a, [wMenuCursorY]
and a
ret nz
xor a
ld [wBattleParticipantsNotFainted], a
ld [wBattleParticipantsIncludingFainted], a
call BackUpTilesToBuffer
jp PlayerSwitch
; BUG: They forgot to terminate the line immediately after StringBuffer1.
; This makes the game halt the script early and throw up an error handler,
; due to reading the start of the following 'text' line as a <NULL> character.
TrainerAboutToUseText:
text_from_ram wOTClassName
text "の @"
text_from_ram wStringBuffer1
text "は"
line
text_from_ram wEnemyMonNickname
text "を くりだそうと している"
para "<PLAYER>も #を"
line "とりかえますか?"
done
TrainerSentOutText:
text_from_ram wOTClassName
text "の @"
text_from_ram wStringBuffer1
text "は"
line "@"
text_from_ram wEnemyMonNickname
text "を くりだした!"
done
NewEnemyMonStatus:
xor a
ld hl, wLastEnemyCounterMove
ld [hli], a
ld [hl], a
ld hl, wEnemySubStatus1
rept 4
ld [hli], a
endr
ld [hl], a
ld [wEnemyDisableCount], a
ld [wEnemyFuryCutterCount], a
ld [wEnemyDisabledMove], a
ld [wEnemyMinimized], a
ret
CheckPlayerPartyForFitMon:
; Has the player any mon in his Party that can fight?
ld a, [wPartyCount]
ld e, a
xor a
ld hl, wPartyMon1HP
ld bc, PARTYMON_STRUCT_LENGTH - 1
.loop
or [hl]
inc hl
or [hl]
add hl, bc
dec e
jr nz, .loop
ld d, a
ret
CheckIfCurPartyMonIsFitToFight:
ld a, [wCurPartyMon]
ld hl, wPartyMon1HP
ld bc, PARTYMON_STRUCT_LENGTH
call AddNTimes
ld a, [hli]
or [hl]
ret nz
ld a, [wBattleHasJustStarted]
and a
jr nz, .has_hp
ld hl, BattleText_TheresNoWillToBattle
call PrintText
.has_hp
xor a
ret
BattleText_TheresNoWillToBattle:
text "たたかう きりょくが ない!"
prompt
TryToRunAwayFromBattle:
ld a, [wBattleType]
cp BATTLETYPE_DEBUG
jp z, .can_escape
ld a, [wLinkMode]
and a
jp nz, .can_escape
ld a, [wBattleMode]
dec a
jp nz, .trainer_battle
ld a, [wPlayerSubStatus5]
bit SUBSTATUS_CANT_RUN, a
jp nz, .cannot_escape
push hl
push de
ld a, [wBattleMonItem]
ld [wNamedObjectIndexBuffer], a
ld b, a
callfar GetItemHeldEffect
ld a, b
cp HELD_ESCAPE
pop de
pop hl
jr nz, .no_flee_item
call GetItemName
ld hl, BattleText_UserFledUsingAStringBuffer1
call PrintText
jp .can_escape
.no_flee_item
ld a, [wNumFleeAttempts]
inc a
ld [wNumFleeAttempts], a
ld a, [hli]
ldh [hMultiplicand + 1], a
ld a, [hl]
ldh [hMultiplicand + 2], a
ld a, [de]
inc de
ldh [hEnemyMonSpeed], a
ld a, [de]
ldh [hEnemyMonSpeed + 1], a
call ReloadTilesFromBuffer
ld de, hMultiplicand + 1
ld hl, hEnemyMonSpeed
ld c, 2
call CompareBytes
jr nc, .can_escape
xor a
ldh [hMultiplicand], a
ld a, 32
ldh [hMultiplier], a
call Multiply
ldh a, [hProduct + 2]
ldh [hDividend], a
ldh a, [hProduct + 3]
ldh [hDividend + 1], a
ldh a, [hEnemyMonSpeed]
ld b, a
ldh a, [hEnemyMonSpeed + 1]
srl b
rr a
srl b
rr a
and a
jr z, .can_escape
ldh [hDivisor], a
ld b, 2
call Divide
ldh a, [hMultiplicand + 1]
and a
jr nz, .can_escape
ld a, [wNumFleeAttempts]
ld c, a
.loop
dec c
jr z, .cant_escape_2
ld b, 30
ldh a, [hMultiplicand + 2]
add b
ldh [hMultiplicand + 2], a
jr c, .can_escape
jr .loop
.cant_escape_2
call BattleRandom
ld b, a
ldh a, [hMultiplicand + 2]
cp b
jr nc, .can_escape
ld a, BATTLEPLAYERACTION_USEITEM
ld [wBattlePlayerAction], a
.cannot_escape
ld hl, BattleText_CantEscape
jr .print_text
.trainer_battle
ld hl, BattleText_TheresNoEscapeFromTrainerBattle
.print_text
call PrintText
ld a, TRUE
ld [wFailedToFlee], a
call BackUpTilesToBuffer
and a
ret
.can_escape
ld a, [wLinkMode]
and a
ld a, DRAW
jr z, .fled
call BackUpTilesToBuffer
xor a ; BATTLEPLAYERACTION_USEMOVE
ld [wBattlePlayerAction], a
ld a, BATTLEACTION_FORFEIT
ld [wCurMoveNum], a
call LinkBattleSendRecieveAction
call ReloadTilesFromBuffer
ld a, [wOtherPlayerLinkAction]
cp BATTLEACTION_FORFEIT
ld a, DRAW
jr z, .fled
dec a
.fled
ld [wBattleResult], a
push de
ld de, SFX_RUN
call WaitPlaySFX
pop de
call WaitSFX
ld hl, BattleText_GotAwaySafely
call PrintText
call WaitSFX
call BackUpTilesToBuffer
scf
ret
BattleText_CantEscape:
text "にげられない!"
prompt
BattleText_TheresNoEscapeFromTrainerBattle:
text "ダメだ!"
line "しょうぶの さいちゅうに"
cont "あいてに せなかは みせられない!"
prompt
BattleText_GotAwaySafely:
text "うまく にげきれた!"
prompt
BattleText_UserFledUsingAStringBuffer1:
text "<TARGET>は そうびしていた"
line "@"
text_from_ram wStringBuffer1
text "を つかって にげた"
prompt
LoadBattleMonFromParty:
ld a, [wCurPartyMon]
ld bc, PARTYMON_STRUCT_LENGTH
ld hl, wPartyMon1
call AddNTimes
; Copy species, held item, and move
ld de, wBattleMon
ld bc, (wPartyMon1ID - wPartyMon1Species) ; 6
call CopyBytes
; Skip ID, experience, and stat experience
ld bc, (wPartyMon1DVs - wPartyMon1ID) ; 15
add hl, bc
; Copy DVs, PP, and happiness
ld de, wBattleMonDVs
ld bc, (wPartyMon1PokerusStatus - wPartyMon1DVs) ; 7
call CopyBytes
; Copy level, status, current and max HP, and stats
inc hl
inc hl
inc hl
ld de, wBattleMonLevel
ld bc, (wPartyMon1StatsEnd - wPartyMon1Level) ; 17
call CopyBytes
; Copy both types
ld a, [wTempBattleMonSpecies]
ld [wCurSpecies], a
call GetBaseData
ld a, [wMonHType1]
ld [wBattleMonType1], a
ld a, [wMonHType2]
ld [wBattleMonType2], a
ld hl, wPartyMonNicknames
ld a, [wCurBattleMon]
call SkipNames
ld de, wBattleMonNickname
ld bc, MON_NAME_LENGTH
call CopyBytes
ld hl, wBattleMonStats
ld de, wPlayerStats
ld bc, 2 * NUM_BATTLE_STATS
call CopyBytes
call ApplyStatusEffectOnPlayerStats
call BadgeStatBoosts
xor a
ldh [hBattleTurn], a
callfar GetMonSGBPaletteFlags
ret
ApplyStatMods:
ld a, 7
ld b, 8
ld hl, wPlayerStatLevels
.loop
ld [hli], a
dec b
jr nz, .loop
ret
LoadEnemyMonFromParty:
ld a, [wCurPartyMon]
ld bc, PARTYMON_STRUCT_LENGTH
ld hl, wOTPartyMons
call AddNTimes
; Copy species, held item, and move
ld de, wEnemyMon
ld bc, (wPartyMon1ID - wPartyMon1Species) ; 6
call CopyBytes
; Skip ID, experience, and stat experience
ld bc, (wPartyMon1DVs - wPartyMon1ID) ; 15
add hl, bc
; Copy DVs, PP, and happiness
ld de, wEnemyMonDVs
ld bc, (wPartyMon1PokerusStatus - wPartyMon1DVs) ; 7
call CopyBytes
; Copy level, status, current and max HP, and stats
inc hl
inc hl
inc hl
ld de, wEnemyMonLevel
ld bc, (wPartyMon1StatsEnd - wPartyMon1Level) ; 17
call CopyBytes
ld a, [wEnemyMonSpecies]
ld [wCurSpecies], a
call GetBaseData
ld hl, wOTPartyMonNicknames
ld a, [wCurPartyMon]
call SkipNames
ld de, wEnemyMonNickname
ld bc, MON_NAME_LENGTH
call CopyBytes
ld hl, wEnemyMonStats
ld de, wEnemyStats
ld bc, 2 * NUM_BATTLE_STATS
call CopyBytes
call ApplyStatusEffectOnEnemyStats
ld hl, wMonHType1
ld de, wEnemyMonType1
ld a, [hli]
ld [de], a
inc de
ld a, [hl]
ld [de], a
ld hl, wMonHBaseStats
ld de, wEnemyMonBaseStats
ld b, 5
.base_stats_loop
ld a, [hli]
ld [de], a
inc de
dec b
jr nz, .base_stats_loop
ld a, 7
ld b, 8
ld hl, wEnemyStatLevels
.stat_mod_loop
ld [hli], a
dec b
jr nz, .stat_mod_loop
ld a, [wCurPartyMon]
ld [wCurOTMon], a
ret
SendOutPlayerMon:
ld hl, wBattleMonDVs
predef GetUnownLetter
predef LoadMonBackPic
xor a
ldh [hGraphicStartTile], a
ld hl, wBattleMenuCursorPosition
ld [hli], a
ld [hl], a
ld [wTypeModifier], a
ld [wPlayerMoveStruct + MOVE_ANIM], a
ld b, SGB_BATTLE_COLORS
call GetSGBLayout
ld hl, wEnemySubStatus3
res SUBSTATUS_USING_TRAPPING_MOVE, [hl]
xor a
ldh [hBattleTurn], a
ld [wNumHits], a
; Play shiny animation for Sunflora and Pikachu
ld b, 1
ld a, [wCurPartySpecies]
cp DEX_SUNNY
jr z, .apply_animation
cp DEX_PIKACHU
jr z, .apply_animation
; Play scanline fade animation for Hoothoot
ld b, 2
cp DEX_HOHO
jr z, .apply_animation
; Play send out animation for everyone else
ld b, 0
.apply_animation
ld a, b
ld [wBattleAnimParam], a
ld de, ANIM_SEND_OUT_MON
call Call_PlayBattleAnim
; mon on the left side
ld a, $f0
ld [wCryTracks], a
ld a, [wCurPartySpecies]
call PlayStereoCry
call UpdatePlayerHUD
ret
NewBattleMonStatus:
xor a
ld hl, wLastPlayerCounterMove
ld [hli], a
ld [hl], a
ld hl, wPlayerSubStatus1
rept 4
ld [hli], a
endr
ld [hl], a
ld [wPlayerDisableCount], a
ld [wPlayerFuryCutterCount], a
ld [wDisabledMove], a
ld [wPlayerMinimized], a
ret
SpikesDamage:
ld hl, wPlayerScreens
ld de, wBattleMonType
ldh a, [hBattleTurn]
and a
jr z, .ok
ld hl, wEnemyScreens
ld de, wEnemyMonType
.ok
bit SCREENS_SPIKES, [hl]
ret z
; Flying-types aren't affected by Spikes.
ld a, [de]
cp TYPE_FLYING
ret z
inc de
ld a, [de]
cp TYPE_FLYING
ret z
ld hl, BattleText_UserHurtBySpikes
call PrintText
call GetEighthMaxHP
call SubtractHPFromUser
ret
BattleText_UserHurtBySpikes:
text "<USER>は まきびしの"
line "ダメージを うけた!"
prompt
RecallPlayerMon:
ldh a, [hBattleTurn]
push af
xor a
ldh [hBattleTurn], a
ld [wNumHits], a
ld de, ANIM_RETURN_MON
call Call_PlayBattleAnim
pop af
ldh [hBattleTurn], a
ret
; Update level, status, current HP
UpdateBattleMonInParty:
ld a, [wCurBattleMon]
ld hl, wPartyMon1Level
ld bc, PARTYMON_STRUCT_LENGTH
call AddNTimes
ld d, h
ld e, l
ld hl, wBattleMonLevel
ld bc, (wBattleMonHP - wBattleMonLevel) + 2
jp CopyBytes
; Only handles HP-healing items at this point.
; Status-healing items aren't handled except at the moment when the target is afflicted.
HandleHealingItems:
ldh a, [hSerialConnectionStatus]
cp 1
jr z, .player1
call .DoPlayer
call .DoEnemy
ret
.player1:
call .DoEnemy
call .DoPlayer
ret
.DoPlayer:
xor a
ldh [hBattleTurn], a
call HandleHPHealingItem
ld a, 1
ldh [hBattleTurn], a
call HandleHPHealingItem
ret
.DoEnemy:
ld a, 1
ldh [hBattleTurn], a
call HandleHPHealingItem
xor a
ldh [hBattleTurn], a
call HandleHPHealingItem
ret
HandleHPHealingItem:
callfar GetOpponentItem
ld a, b
cp HELD_BERRY
ret nz
ld de, wEnemyMonHP + 1
ld hl, wEnemyMonMaxHP + 1
ldh a, [hBattleTurn]
and a
jr z, .go
ld de, wBattleMonHP + 1
ld hl, wBattleMonMaxHP + 1
.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 [wHPBuffer2], a
add a
ld c, a
dec de
ld a, [de]
inc de
ld [wHPBuffer2 + 1], a
adc a
ld b, a
ld a, c
cp [hl]
dec hl
ld a, b
sbc [hl]
pop bc
ret nc
; store max HP in wHPBuffer1
ld a, [hli]
ld [wHPBuffer1 + 1], a
ld a, [hl]
ld [wHPBuffer1], a
ld a, [de]
add c
ld [wHPBuffer3], a
ld c, a
dec de
ld a, [de]
adc 0
ld [wHPBuffer3 + 1], a
ld b, a
ld a, [hld]
cp c
ld a, [hl]
sbc b
jr nc, .okay
ld a, [hli]
ld [wHPBuffer3 + 1], a
ld a, [hl]
ld [wHPBuffer3], a
.okay
ld a, [wHPBuffer3 + 1]
ld [de], a
inc de
ld a, [wHPBuffer3]
ld [de], a
call ItemRecoveryAnim
ldh 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 UpdateHPBar
call UpdateBattleHuds
callfar GetOpponentItem
ld a, [hl]
ld [wNamedObjectIndexBuffer], a
call GetItemName
callfar ConsumeHeldItem
ld hl, RecoveredUsingText
jp PrintText
ItemRecoveryAnim:
ld a, MOVE_RECOVER
ld [wFXAnimID], a
ldh a, [hBattleTurn]
push af
xor 1
ldh [hBattleTurn], a
xor a
ld [wNumHits], a
ld [wFXAnimID + 1], a
predef PlayBattleAnim
pop af
ldh [hBattleTurn], a
ret
RecoveredUsingText:
text "<TARGET>は そうびしていた"
line "@"
text_from_ram wStringBuffer1
text "で かいふくした!"
prompt
HandleStatBoostingHeldItems:
ldh a, [hSerialConnectionStatus]
cp USING_EXTERNAL_CLOCK
jr z, .player1
call .DoPlayer
call .DoEnemy
ret
.player1
call .DoEnemy
call .DoPlayer
ret
.DoPlayer:
ld hl, wPartyMon1Item
ld a, [wCurBattleMon]
ld bc, PARTYMON_STRUCT_LENGTH
call AddNTimes
ld bc, wBattleMonItem
ld de, wPlayerMoveStruct
ld a, 0
call .HandleItem
ret
.DoEnemy:
ld hl, wOTPartyMon1Item
ld a, [wCurOTMon]
ld bc, PARTYMON_STRUCT_LENGTH
call AddNTimes
ld bc, wEnemyMonItem
ld de, wEnemyMoveStruct
ld a, 1
call .HandleItem
ret
.HandleItem:
ldh [hBattleTurn], a
push hl
push bc
ld a, [bc]
ld b, a
callfar GetItemHeldEffect
ld hl, HeldStatUpItems
.loop:
ld a, [hli]
cp -1
jr z, .finish
inc hl
cp b
jr nz, .loop
pop bc
ld a, [bc]
ld [wNumSetBits], a
xor a
ld [bc], a
dec hl
ld b, [hl]
pop hl
ld [hl], 0
push de
push bc
call GetItemName
ld hl, UseItemFailedText
call PrintText
pop bc
pop de
; Play the Growth animation when using the item.
ld a, [de]
push af
ld a, MOVE_GROWTH
ld [de], a
inc de
ld a, [de]
push af
push de
ld a, b
ld [de], a
callfar BattleCommand_StatUp
pop de
pop af
ld [de], a
pop af
dec de
ld [de], a
ret
.finish
pop bc
pop hl
ret
INCLUDE "data/battle/held_stat_up.inc"
UseItemFailedText:
text "<USER>が そうびしていた"
line "@"
text_from_ram wStringBuffer1
text "が さどうした!"
prompt
UpdateBattleHuds::
call UpdatePlayerHUD
jp UpdateEnemyHUD
UpdatePlayerHUD:
xor a
ldh [hBGMapMode], a
hlcoord 9, 7
lb bc, 5, 11
call ClearBox
callfar DrawPlayerHUDBorder
hlcoord 18, 9
ld [hl], $73
ld de, wBattleMonNickname
hlcoord 10, 8
call CenterMonName
call PlaceString
push bc
ld hl, wBattleMon
ld de, wTempMon
ld bc, (wBattleMonMovesEnd - wBattleMonSpecies)
call CopyBytes
ld hl, wBattleMonLevel
ld de, wTempMonLevel
ld bc, (wBattleMonStatsEnd - wBattleMonLevel)
call CopyBytes
ld a, [wTempMonSpecies]
ld [wCurSpecies], a
call GetBaseData
pop hl
push hl
inc hl
ld de, wTempMonStatus
predef PlaceNonFaintStatus
pop hl
jr nz, .dont_print_level
call PrintLevel
.dont_print_level
ld a, [wTempMonSpecies]
ld [wCurPartySpecies], a
hlcoord 10, 9
ld b, 1
predef DrawPlayerHP
push de
ld a, [wCurBattleMon]
ld hl, wPartyMon1Exp + 2
ld bc, PARTYMON_STRUCT_LENGTH
call AddNTimes
ld d, h
ld e, l
hlcoord 10, 11
ld a, [wTempMonLevel]
ld b, a
call CalcAndPlaceExpBar
ld a, 1
ldh [hBGMapMode], a
pop de
ld hl, wPlayerHPPal
call UpdateHPPal
ld hl, wBattleMonHP
ld a, [hli]
or [hl]
jr z, .no_danger
ld a, [wBattleLowHealthAlarm]
and a
ret nz
ld a, [wPlayerHPPal]
cp HP_RED
jr z, .danger
.no_danger
ld hl, wLowHealthAlarmBuffer
bit DANGER_ON_F, [hl]
ld [hl], 0
ret z
ret
.danger
ld hl, wLowHealthAlarmBuffer
set DANGER_ON_F, [hl]
ret
UpdateEnemyHUD:
xor a
ldh [hBGMapMode], a
hlcoord 1, 0
lb bc, 4, 11
call ClearBox
callfar DrawEnemyHUDBorder
ld de, wEnemyMonNickname
hlcoord 2, 1
call CenterMonName
call PlaceString
ld h, b
ld l, c
push hl
inc hl
ld de, wEnemyMonStatus
predef PlaceNonFaintStatus
pop hl
jr nz, .dont_print_level
ld a, [wEnemyMonLevel]
ld [wTempMonLevel], a
call PrintLevel
.dont_print_level
ld hl, wEnemyMonHP
ld a, [hli]
ldh [hMultiplicand + 1], a
ld a, [hld]
ldh [hMultiplicand + 2], a
or [hl]
jr nz, .hp_not_zero
ld c, a
ld e, a
ld d, 6
jp .draw_hp_bar
.hp_not_zero
xor a
ldh [hMultiplicand], a
ld a, 48
ldh [hMultiplier], a
call Multiply
ld hl, wEnemyMonMaxHP
ld a, [hli]
ld b, a
ld a, [hl]
ldh [hDivisor], a
ld a, b
and a
jr z, .do_divide
; if max HP > 255, scale both (current HP * 48) and max HP by dividing by 4 so that max HP fits in one byte
; (it needs to be one byte so it can be used as the divisor for the Divide function)
ldh a, [hDivisor]
srl b
rr a
srl b
rr a
ldh [hDivisor], a
ldh a, [hProduct + 2]
ld b, a
srl b
ldh a, [hProduct + 3]
rr a
srl b
rr a
ldh [hDividend + 3], a
ld a, b
ldh [hDividend + 2], a
.do_divide
ldh a, [hDividend + 2]
ldh [hDividend], a
ldh a, [hDividend + 3]
ldh [hDividend + 1], a
ld a, 2
ld b, a
call Divide
ldh a, [hQuotient + 3]
ld e, a
ld a, 6
ld d, a
ld c, a
.draw_hp_bar
xor a
ld [wWhichHPBar], a
hlcoord 2, 2
ld b, 0
call DrawBattleHPBar
ld a, 1
ldh [hBGMapMode], a
ld hl, wEnemyHPPal
; fallthrough
UpdateHPPal:
ld b, [hl]
call SetHPPal
ld a, [hl]
cp b
ret z
ld b, SGB_BATTLE_COLORS
jp GetSGBLayout
; center's mon's name on the battle screen
; if the name is 1 or 2 letters long, it is printed 2 spaces more to the right than usual
; (i.e. for names longer than 4 letters)
; if the name is 3 or 4 letters long, it is printed 1 space more to the right than usual
; (i.e. for names longer than 4 letters)
CenterMonName:
; Function is dummied out in the final game. See "Battle_DummyFunction" in pokegold.
push de
inc hl
inc hl
ld b, 2
.loop:
inc de
ld a, [de]
cp '@'
jr z, .done
inc de
ld a, [de]
cp '@'
jr z, .done
dec hl
dec b
jr nz, .loop
.done:
pop de
ret
BattleMenu:
call ReloadTilesFromBuffer
ld a, [wBattleType]
and a
jr nz, .ok
call UpdateBattleHuds
call EmptyBattleTextbox
call BackUpTilesToBuffer
.ok
.loop
callfar LoadBattleMenu
jr c, .loop
ld a, [wStartmenuCursor]
cp 1
jp z, BattleMenu_Fight
cp 2
jp z, BattleMenu_Pack
cp 3
jp z, BattleMenu_PKMN
cp 4
jp z, BattleMenu_Run
jr .loop
BattleMenu_Fight:
xor a
ld [wNumFleeAttempts], a
call ReloadTilesFromBuffer
and a
ret
BattleMenu_Pack:
ld a, [wLinkMode]
and a
jp nz, .ItemsCantBeUsed
call LoadStandardMenuHeader
callfar GetPocket2Status
xor a
ld [wSelectedSwapPosition], a
call ClearPalettes
callfar DrawBackpack
.item_menu_loop
xor a
ldh [hBGMapMode], a
call ClearSprites
hlcoord 2, 2
ld b, 8
ld c, 15
call DrawTextBox
call Call_DebugBackpackLoop
jr c, .didnt_use_item
call BattleMenuPack_SelectItem
ld a, [wItemEffectSucceeded]
and a
jr z, .item_menu_loop
call Call_LoadBattleFontsHPBar
call ClearSprites
ld a, 1
ld [wMenuCursorY], a
call StopUsingTrappingMove
ld a, [wWildMon]
and a
jr nz, .run
call CloseWindow
call BackUpTilesToBuffer
call UpdateBattleHuds
call WaitBGMap
call ClearWindowData
call SetPalettes
and a
ret
.run
xor a
ld [wWildMon], a
ld a, DRAW
ld [wBattleResult], a
call ClearWindowData
call SetPalettes
scf
ret
.didnt_use_item
call ClearPalettes
call DelayFrame
call Call_LoadBattleFontsHPBar
call CloseWindow
call BackUpTilesToBuffer
call SetPalettes
jp BattleMenu
.ItemsCantBeUsed
ld hl, BattleText_ItemsCantBeUsedHere
call PrintText
jp BattleMenu
BattleText_ItemsCantBeUsedHere:
text "ここでは どうぐを"
line "つかうことは できません"
prompt
StopUsingTrappingMove:
ld a, [wPlayerSubStatus3]
bit SUBSTATUS_USING_TRAPPING_MOVE, a
jr z, .done
ld hl, wPlayerRolloutCount
dec [hl]
jr nz, .done
ld hl, wPlayerSubStatus3
res SUBSTATUS_USING_TRAPPING_MOVE, [hl]
.done
ret
Call_DebugBackpackLoop:
callfar DebugBackpackLoop
ret
BattleMenuPack_SelectItem:
callfar ScrollingMenu_ClearLeftColumn
call PlaceHollowCursor
predef LoadItemData
callfar CheckItemContext
ld a, [wItemAttributeValue]
ld hl, .item_attribute_jump_table
call CallJumptable
ret
.item_attribute_jump_table:
dw .cant_use ; ITEMMENU_NOUSE
dw .cant_use ; TM_HOLDER
dw .ball_holder ; BALL_HOLDER
dw .other_bags ; IMPORTANT_BAG/ITEM_BAG
dw .menu_close ; ITEMMENU_CURRENT
dw .normal_item_effect ; ITEMMENU_PARTY
dw .menu_close ; ITEMMENU_CLOSE
.cant_use:
callfar PrintCantUseText
xor a
ld [wItemEffectSucceeded], a
ret
.ball_holder:
callfar BallPocket
jr nc, .menu_close
xor a
ld [wItemEffectSucceeded], a
ret
.other_bags:
callfar FlipPocket2Status
xor a
ld [wSelectedSwapPosition], a
ld [wItemEffectSucceeded], a
ret
.normal_item_effect:
call DoItemEffect
call ClearPalettes
callfar DrawBackpack
ret
.menu_close:
call DoItemEffect
ret
BattleMenu_PKMN:
call LoadStandardMenuHeader
.BattleMenuPKMN_ReturnFromStats:
call ExitMenu
call LoadStandardMenuHeader
xor a
ld [wPartyMenuActionText], a
predef OpenPartyMenu_ClearGraphics
jp c, .Cancel
jp .loop
.BattleMenuPKMN_Loop:
hlcoord 11, 11
ld bc, $81
ld a, ' '
call ByteFill
xor a
ld [wPartyMenuActionText], a
predef OpenPartyMenu
jr c, .Cancel
.loop
callfar FreezeMonIcons
callfar BattleMonMenu
jr c, .BattleMenuPKMN_Loop
call PlaceHollowCursor
ld a, [wMenuCursorY]
cp 1 ; SWITCH
jp z, .TryPlayerSwitch
cp 2 ; STATS
jr z, .Stats
cp 3 ; CANCEL
jr z, .Cancel
jr .loop
.Stats:
call .Battle_StatsScreen
jp .BattleMenuPKMN_ReturnFromStats
.Cancel:
call ClearSprites
call ClearPalettes
call _LoadHPBar
call CloseWindow
call BackUpTilesToBuffer
call GetMemSGBLayout
call SetPalettes
jp BattleMenu
; TODO: Do the tile identifiers look right (are they not vFrontPic, vBackPic)?...
.Battle_StatsScreen:
call DisableLCD
ld hl, vChars2 tile $31
ld de, vChars0
ld bc, $11 tiles
call CopyBytes
ld hl, vChars2
ld de, vChars0 tile $11
ld bc, $31 tiles
call CopyBytes
call EnableLCD
call ClearSprites
call LowVolume
xor a ; PARTYMON
ld [wMonType], a
ld hl, wPartyMon1Species
predef StatsScreenMain
call MaxVolume
call DisableLCD
ld hl, vChars0
ld de, vChars2 tile $31
ld bc, $11 tiles
call CopyBytes
ld hl, vChars0 tile $11
ld de, vChars2
ld bc, $31 tiles
call CopyBytes
call EnableLCD
ret
.TryPlayerSwitch:
ld a, [wPlayerSubStatus5]
bit SUBSTATUS_CANT_RUN, a
jr z, .not_trapped
ld hl, BattleText_MonCantBeRecalled
call PrintText
jp .BattleMenuPKMN_Loop
.not_trapped
ld a, [wCurBattleMon]
ld d, a
ld a, [wCurPartyMon]
cp d
jr nz, .try_switch
ld hl, BattleText_MonIsAlreadyOut_0f
call PrintText
jp .BattleMenuPKMN_Loop
.try_switch
call CheckIfCurPartyMonIsFitToFight
jp z, .BattleMenuPKMN_Loop
ld a, 1
ld [wFieldMoveSucceeded], a
call ClearPalettes
call ClearSprites
call _LoadHPBar
call CloseWindow
call GetMemSGBLayout
call SetPalettes
PlayerSwitch:
ld a, [wLinkMode]
and a
jr z, .not_linked
call LinkBattleSendRecieveAction
.not_linked
call RetreatMon
ld c, 50
call DelayFrames
call RecallPlayerMon
hlcoord 9, 7
lb bc, 5, 11
call ClearBox
ld a, [wCurPartyMon]
ld [wCurBattleMon], a
ld c, a
ld b, SET_FLAG
push bc
ld hl, wBattleParticipantsNotFainted
predef SmallFarFlagAction
pop bc
ld hl, wBattleParticipantsIncludingFainted
predef SmallFarFlagAction
call LoadBattleMonFromParty
call ApplyStatMods
call SendOutMonText
call NewBattleMonStatus
call SendOutPlayerMon
call EmptyBattleTextbox
call BackUpTilesToBuffer
xor a
ldh [hBattleTurn], a
call SpikesDamage
ld a, 2
ld [wMenuCursorY], a
and a
ret
PassedBattleMonEntrance:
ld c, 50
call DelayFrames
ld a, [wLinkMode]
and a
jr z, .not_link_battle
call LinkBattleSendRecieveAction
.not_link_battle
hlcoord 9, 7
lb bc, 5, 11
call ClearBox
ld a, [wCurPartyMon]
ld [wCurBattleMon], a
ld c, a
ld b, SET_FLAG
push bc
ld hl, wBattleParticipantsNotFainted
predef SmallFarFlagAction
pop bc
ld hl, wBattleParticipantsIncludingFainted
predef SmallFarFlagAction
call LoadBattleMonFromParty
xor a
ld [wApplyStatLevelMultipliersToEnemy], a
call ApplyStatLevelMultiplierOnAllStats
call SendOutPlayerMon
call EmptyBattleTextbox
call BackUpTilesToBuffer
xor a
ldh [hBattleTurn], a
call SpikesDamage
ret
BattleText_MonIsAlreadyOut_0f:
text_from_ram wBattleMonNickname
text "はもうでています"
prompt
BattleText_MonCantBeRecalled:
text_from_ram wBattleMonNickname
text "を もどすことが"
line "できない!"
prompt
BattleMenu_Run:
call ReloadTilesFromBuffer
ld a, 3
ld [wMenuCursorY], a
ld hl, wBattleMonSpeed
ld de, wEnemyMonSpeed
call TryToRunAwayFromBattle
ld a, FALSE
ld [wFailedToFlee], a
ret c
ld a, [wFieldMoveSucceeded]
and a
ret nz
jp BattleMenu
MoveSelectionScreen::
ld hl, wEnemyMonMoves
ld a, [wMoveSelectionMenuType]
dec a
jr z, .got_menu_type
dec a
jr z, .ether_elixer_menu
call .CheckPlayerHasUsableMoves
ret z
ld hl, wBattleMonMoves
jr .got_menu_type
.ether_elixer_menu
ld a, [wCurPartyMon]
ld hl, wPartyMon1Moves
ld bc, PARTYMON_STRUCT_LENGTH
call AddNTimes
.got_menu_type
ld de, wListMoves_MoveIndicesBuffer
ld bc, NUM_MOVES
call CopyBytes
xor a
ldh [hBGMapMode], a
hlcoord 0, 17 - (NUM_MOVES * 2) - 1
ld b, 8
ld c, 8
ld a, [wMoveSelectionMenuType]
cp 2
jr nz, .got_dims
hlcoord 10, 17 - (NUM_MOVES * 2) - 1
ld b, 8
ld c, 8
.got_dims
call DrawTextBox
hlcoord 2, 17 - (NUM_MOVES * 2) + 1
ld a, [wMoveSelectionMenuType]
cp 2
jr nz, .got_start_coord
hlcoord 12, 17 - (NUM_MOVES * 2) + 1
.got_start_coord
ld a, SCREEN_WIDTH * 2
ld [wHPBarMaxHP], a
predef ListMoves
ld b, 1
ld a, [wMoveSelectionMenuType]
cp 2
jr nz, .got_default_coord
ld b, 11
.got_default_coord
ld a, 17 - (NUM_MOVES * 2) + 1
ld [w2DMenuCursorInitY], a
ld a, b
ld [w2DMenuCursorInitX], a
ld a, [wMoveSelectionMenuType]
cp 1
jr z, .skip_inc
ld a, [wCurMoveNum]
inc a
.skip_inc
ld [wMenuCursorY], a
ld a, 1
ld [wMenuCursorX], a
ld a, [wNumMoves]
inc a
ld [w2DMenuNumRows], a
ld a, 1
ld [w2DMenuNumCols], a
ld c, STATICMENU_ENABLE_LEFT_RIGHT | STATICMENU_ENABLE_START | STATICMENU_WRAP
ld a, [wMoveSelectionMenuType]
dec a
ld b, D_DOWN | D_UP | A_BUTTON
jr z, .okay
dec a
ld b, D_DOWN | D_UP | A_BUTTON | B_BUTTON
jr z, .okay
ld a, [wLinkMode]
cp LINK_COLOSSEUM
jr z, .okay
ld a, [wDebugFlags]
bit DEBUG_BATTLE_F, a
ld b, D_DOWN | D_UP | A_BUTTON | B_BUTTON | SELECT
jr z, .okay
ld b, D_DOWN | D_UP | D_LEFT | D_RIGHT | A_BUTTON | B_BUTTON | START | SELECT
ld c, STATICMENU_ENABLE_LEFT_RIGHT | STATICMENU_ENABLE_SELECT | STATICMENU_DISABLE_B | STATICMENU_ENABLE_START | STATICMENU_WRAP
.okay
ld a, b
ld [wMenuJoypadFilter], a
ld a, c
ld [w2DMenuFlags1], a
xor a
ld [w2DMenuFlags2], a
ld a, $20
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, .Unused_BattleText_MimicWhichMove
call PlaceString
jr .interpret_joypad
.battle_player_moves
ld a, [wDebugFlags]
bit DEBUG_BATTLE_F, a
jr nz, .interpret_joypad
call MoveInfoBox
ld a, [wSelectedSwapPosition]
and a
jr z, .interpret_joypad
hlcoord 1, 18 - (NUM_MOVES * 2)
dec a
ld bc, SCREEN_WIDTH * 2
call AddNTimes
ld [hl], '▷'
.interpret_joypad
call WaitBGMap
ld a, 1
ldh [hBGMapMode], a
call ScrollingMenuJoypad
bit D_UP_F, a
jp nz, .pressed_up
bit D_DOWN_F, a
jp nz, .pressed_down
bit SELECT_F, a
jp nz, .pressed_select
bit START_F, a
jp nz, .pressed_start
bit D_RIGHT_F, a
jp nz, .pressed_right
bit D_LEFT_F, a
jp nz, .pressed_left
bit B_BUTTON_F, a
; A button
push af
xor a
ld [wSelectedSwapPosition], a
ld a, [wMenuCursorY]
dec a
ld [wMenuCursorY], a
ld b, a
ld a, [wMoveSelectionMenuType]
dec a
jr nz, .not_enemy_moves_process_b
pop af
ret
.not_enemy_moves_process_b
dec a
ld a, b
ld [wCurMoveNum], a
jr nz, .use_move
pop af
ret
.use_move
pop af
ret nz
ld hl, wBattleMonPP
ld a, [wMenuCursorY]
ld c, a
ld b, 0
add hl, bc
ld a, [hl]
and PP_MASK
jr z, .no_pp_left
ld a, [wPlayerDisableCount]
swap a
and $f
dec a
cp c
jr z, .move_disabled
ld a, [wPlayerSubStatus5]
bit SUBSTATUS_TRANSFORMED, a
jr nz, .transformed
; something was commented out here
.transformed
ld a, [wMenuCursorY]
ld hl, wBattleMonMoves
ld c, a
ld b, 0
add hl, bc
ld a, [hl]
ld [wCurPlayerMove], a
xor a
ret
.move_disabled
ld hl, .BattleText_TheMoveIsDisabled
jr .place_textbox_start_over
.no_pp_left
ld hl, .BattleText_TheresNoPPLeftForThisMove
.place_textbox_start_over
call PrintText
call ReloadTilesFromBuffer
jp MoveSelectionScreen
.BattleText_TheresNoPPLeftForThisMove:
text "わざの のこりポイントが ない!"
prompt
.BattleText_TheMoveIsDisabled:
text "わざを ふうじられている!"
prompt
.Unused_BattleText_MimicWhichMove:
db "どのわざを"
next "ものまねする?@"
.pressed_up
ld a, [wMenuCursorY]
and a
jp nz, .menu_loop
ld a, [wNumMoves]
inc a
ld [wMenuCursorY], a
jp .menu_loop
.pressed_down
ld a, [wMenuCursorY]
ld b, a
ld a, [wNumMoves]
inc a
inc a
cp b
jp nz, .menu_loop
ld a, 1
ld [wMenuCursorY], a
jp .menu_loop
.DebugMovePreview:
.pressed_start
bit START_F, a
ld a, 0
jr nz, .player_side
ld a, 1
.player_side
ldh [hBattleTurn], a
call ReloadTilesFromBuffer
call .DrawDebugMoveSelection
ld a, [wPlayerDebugSelectedMove]
and a
jp z, MoveSelectionScreen
ld [wFXAnimID], a
xor a
ld [wNumHits], a
ld [wFXAnimID + 1], a
predef PlayBattleAnim
jp MoveSelectionScreen
.pressed_left
ld a, [wPlayerDebugSelectedMove]
dec a
jr .pressed_left_right_continue
.pressed_right
ld a, [wPlayerDebugSelectedMove]
inc a
.pressed_left_right_continue
ld [wPlayerDebugSelectedMove], a
call .DrawDebugMoveSelection
jp MoveSelectionScreen
.DrawDebugMoveSelection:
hlcoord 10, 16
lb bc, 2, 10
call ClearBox
hlcoord 10, 17
ld de, wPlayerDebugSelectedMove
lb bc, PRINTNUM_LEADINGZEROS | 1, 3
call PrintNumber
ld a, [wPlayerDebugSelectedMove]
and a
ret z
cp NUM_ATTACKS + 1
ret nc
ld [wNamedObjectIndexBuffer], a
call GetMoveName
hlcoord 13, 17
jp PlaceString
.CheckPlayerHasUsableMoves:
ld a, MOVE_STRUGGLE
ld [wCurPlayerMove], a
ld a, [wPlayerDisableCount]
and a
ld hl, wBattleMonPP
jr nz, .disabled
ld a, [hli]
or [hl]
inc hl
or [hl]
inc hl
or [hl]
; BUG: There should be "and PP_MASK" here
ret nz
jr .force_struggle
.disabled
swap a
and $f
ld b, a
ld d, NUM_MOVES + 1
xor a
.loop
dec d
jr z, .done
ld c, [hl]
inc hl
dec b
jr z, .loop
or c
jr .loop
.done
; BUG: This will result in a move with PP Up confusing the game.
and a ; should be "and PP_MASK"
ret nz
.force_struggle
ld hl, .BattleText_MonHasNoMovesLeft
call PrintText
ld c, 60
call DelayFrames
xor a
ret
.BattleText_MonHasNoMovesLeft:
text_from_ram wBattleMonNickname
text "は だすことの できる"
line "わざが ない!"
done
.pressed_select
ld a, [wDebugFlags]
bit DEBUG_BATTLE_F, a
jp nz, .DebugMovePreview
ld a, [wSelectedSwapPosition]
and a
jr z, .start_swap
ld hl, wBattleMonMoves
call .swap_bytes
ld hl, wBattleMonPP
call .swap_bytes
ld hl, wPlayerDisableCount
ld a, [hl]
swap a
and $f
ld b, a
ld a, [wMenuCursorY]
cp b
jr nz, .not_swapping_disabled_move
ld a, [hl]
and $f
ld b, a
ld a, [wSelectedSwapPosition]
swap a
add b
ld [hl], a
jr .swap_moves_in_party_struct
.not_swapping_disabled_move
ld a, [wSelectedSwapPosition]
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
; BUG: COOLTRAINER glitch from Generation I still exists here.
ld hl, wPartyMon1Moves
ld a, [wCurBattleMon]
ld bc, PARTYMON_STRUCT_LENGTH
call AddNTimes
push hl
call .swap_bytes
pop hl
ld bc, MON_PP - MON_MOVES
add hl, bc
call .swap_bytes
xor a
ld [wSelectedSwapPosition], a
jp MoveSelectionScreen
.swap_bytes
push hl
ld a, [wSelectedSwapPosition]
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 [wSelectedSwapPosition], a
jp MoveSelectionScreen
MoveInfoBox:
xor a
ldh [hBGMapMode], a
hlcoord 9, 12
ld b, 4
ld c, 9
call DrawTextBox
ld a, [wPlayerDisableCount]
and a
jr z, .not_disabled
swap a
and $f
ld b, a
ld a, [wMenuCursorY]
cp b
jr nz, .not_disabled
hlcoord 10, 15
ld de, .Disabled
call PlaceString
jr .done
.not_disabled
ld hl, wMenuCursorY
dec [hl]
xor a
ldh [hBattleTurn], a
ld hl, wBattleMonMoves
ld a, [wMenuCursorY]
ld c, a
ld b, 0
add hl, bc
ld a, [hl]
ld [wCurPlayerMove], a
ld a, [wCurBattleMon]
ld [wCurPartyMon], a
ld a, WILDMON
ld [wMonType], a
callfar GetMaxPPOfMove
ld hl, wMenuCursorY
ld c, [hl]
inc [hl]
ld b, 0
ld hl, wBattleMonPP
add hl, bc
ld a, [hl]
and PP_MASK
ld [wStringBuffer1], a
hlcoord 10, 15
ld de, .Type
call PlaceString
hlcoord 16, 13
ld [hl], ''
hlcoord 14, 16
ld [hl], ''
hlcoord 14, 13
ld de, wStringBuffer1
lb bc, 1, 2
call PrintNumber
hlcoord 17, 13
ld de, wTempPP
lb bc, 1, 2
call PrintNumber
callfar UpdateMoveData
ld a, [wPlayerMoveStruct]
ld b, a
hlcoord 15, 16
predef PrintMoveType
.done
jp WaitBGMap
.Disabled:
db "ふうじられている!@"
.Type:
db "わざタイプ@"
ParseEnemyAction:
ld a, [wLinkMode]
and a
jr z, .not_linked
call BackUpTilesToBuffer
ld a, [wBattlePlayerAction]
and a
call z, LinkBattleSendRecieveAction
call ReloadTilesFromBuffer
ld a, [wOtherPlayerLinkAction]
cp BATTLEACTION_STRUGGLE
jp z, .struggle
cp BATTLEACTION_SKIPTURN
jr z, .skip_turn
cp BATTLEACTION_SWITCH1
jp nc, .locked_in
ld [wCurEnemyMoveNum], a
ld c, a
ld hl, wEnemyMonMoves
ld b, 0
add hl, bc
ld a, [hl]
jp .finish
.not_linked
ld hl, wEnemySubStatus5
bit SUBSTATUS_ENCORED, [hl]
jr z, .not_encored
ld a, [wEnemyEncoreCount]
dec a
ld [wEnemyEncoreCount], a
jr nz, .encored2
.clear_encore
ld hl, wEnemySubStatus5
res SUBSTATUS_ENCORED, [hl]
ld a, 1
ldh [hBattleTurn], a
ld hl, BattleText_TargetsEncoreEnded
call PrintText
jr .not_encored
.encored2
ld a, [wLastEnemyCounterMove]
and a
jr z, .clear_encore
ld hl, wEnemyMonPP
ld a, [wCurEnemyMoveNum]
ld c, a
ld b, 0
add hl, bc
ld a, [hl]
and PP_MASK
jr z, .clear_encore
ld a, [wLastEnemyCounterMove]
jp .finish
.not_encored
ld a, [wEnemySubStatus4]
and ((1 << SUBSTATUS_RECHARGE) | (1 << SUBSTATUS_RAGE))
jp nz, .locked_in
ld hl, wEnemySubStatus3
ld a, [hl]
and ((1 << SUBSTATUS_RAMPAGE) | (1 << SUBSTATUS_CHARGED))
jp nz, .locked_in
ld hl, wEnemySubStatus1
bit SUBSTATUS_ROLLOUT, [hl]
jp nz, .locked_in
ld a, [wEnemySubStatus3]
and ((1 << SUBSTATUS_USING_TRAPPING_MOVE) | (1 << SUBSTATUS_BIDE))
jp nz, .locked_in
ld a, [wPlayerSubStatus3]
bit SUBSTATUS_USING_TRAPPING_MOVE, a
jr .continue
.skip_turn
ld a, $ff
jr .finish
.continue
ld hl, wEnemyMonPP
ld bc, 0
.loop
inc b
ld a, b
cp NUM_MOVES + 1
jr z, .finish_pp_check
ld a, [hli]
and PP_MASK
jr z, .loop
ld a, [wEnemyDisableCount]
swap a
and $f
cp b
jr z, .loop
inc c
jr .loop
.finish_pp_check
ld a, c
and a
jr z, .struggle
ld a, [wBattleMode]
dec a ; WILD_BATTLE
jr z, .wild_loop
; Overwrites wTrainerClass in order to give trainers all the AI layers.
ld a, 1
ld [wTrainerClass], a
callfar AIChooseMove
jr .skip_load
.wild_loop
ld hl, wEnemyMonMoves
call BattleRandom
and 3
ld c, a
ld b, 0
add hl, bc
ld a, [wEnemyDisableCount]
swap a
and $f
dec a
cp c
jr z, .wild_loop
ld a, [hl]
and a
jr z, .wild_loop
ld hl, wEnemyMonPP
add hl, bc
ld b, a
ld a, [hl]
and a
jr z, .wild_loop
ld a, c
ld [wCurEnemyMoveNum], a
ld a, b
.finish
ld [wCurEnemyMove], a
.skip_load
ld a, 1
ldh [hBattleTurn], a
callfar UpdateMoveData
ld a, [wEnemyMoveStructEffect]
cp EFFECT_FURY_CUTTER
ret z
xor a
ld [wEnemyFuryCutterCount], a
ret
.struggle
ld a, MOVE_STRUGGLE
jr .finish
.locked_in
xor a
ld [wEnemyFuryCutterCount], a
ret
LinkBattleSendRecieveAction:
ld a, $ff
ld [wOtherPlayerLinkAction], a
ld a, [wBattlePlayerAction]
and a ; BATTLEPLAYERACTION_USEMOVE?
jr nz, .switch
ld a, [wCurPlayerMove]
cp MOVE_STRUGGLE
ld b, BATTLEACTION_STRUGGLE
jr z, .struggle
dec b
inc a
jr z, .struggle
ld a, [wCurMoveNum]
jr .use_move
.switch
ld a, [wCurPartyMon]
add BATTLEACTION_SWITCH1
ld b, a
.struggle
ld a, b
.use_move
ld [wPlayerLinkAction], a
callfar PlaceWaitingText
.waiting
call LinkTransfer
call DelayFrame
ld a, [wOtherPlayerLinkAction]
inc a
jr z, .waiting
ld b, 10
.recieve
call DelayFrame
call LinkTransfer
dec b
jr nz, .recieve
ld b, 10
.acknowledge
call DelayFrame
call LinkDataReceived
dec b
jr nz, .acknowledge
ret
BattleText_TargetsEncoreEnded:
text "<TARGET>の"
line "アンコールじょうたいが とけた!"
prompt
; The Counter code from Generation I, completely unchanged.
Old_HandleCounterMove:
ldh a, [hBattleTurn]
and a
ld hl, wCurEnemyMove
ld de, wEnemyMoveStructPower
ld a, [wCurPlayerMove]
jr z, .next
ld hl, wCurPlayerMove
ld de, wPlayerMoveStructPower
ld a, [wCurEnemyMove]
.next
cp MOVE_COUNTER
ret nz ; return if not using Counter
ld a, 1
ld [wAttackMissed], a ; initialize the move missed variable to true (it is set to false below if the move hits)
ld a, [hl]
cp MOVE_COUNTER
ret z ; miss if the opponent's last selected move is Counter.
ld a, [de]
and a
ret z ; miss if the opponent's last selected move's Base Power is 0.
inc de
ld a, [de]
and a
jr z, .counterableType
cp TYPE_FIGHTING
jr z, .counterableType
xor a
ret
.counterableType
ld hl, wCurDamage
ld a, [hli]
or [hl]
ret z ; If we made it here, Counter still misses if the last move used in battle did no damage to its target.
; wDamage is shared by both players, so Counter may strike back damage dealt by the Counter user itself
; if the conditions meet, even though 99% of the times damage will come from the target.
; if it did damage, double it
ld a, [hl]
add a
ld [hld], a
ld a, [hl]
adc a
ld [hl], a
jr nc, .noCarry
ld a, $ff
ld [hli], a
ld [hl], a
.noCarry:
xor a
ld [wAttackMissed], a
callfar BattleCommand_CheckHit
xor a
ret
; Initialize enemy monster parameters
; To do this we pull the species from wTempEnemyMonSpecies
LoadEnemyMon:
; Notes:
; BattleRandom is used to ensure sync between Game Boys
; We don't need to be here if we're in a link battle
ld a, [wLinkMode]
and a
jp nz, LoadEnemyMonFromParty
; Make sure everything knows what species we're working with
ld a, [wTempEnemyMonSpecies]
ld [wEnemyMonSpecies], a
ld [wCurSpecies], a
ld [wCurPartySpecies], a
; Grab the BaseData for this species
call GetBaseData
; Let's get the item:
; Is the item predetermined?
ld a, [wBattleMode]
cp TRAINER_BATTLE
jr nz, .WildItem
; If we're in a trainer battle, the item is in the party struct
ld a, [wCurPartyMon]
ld hl, wOTPartyMon1Item
ld bc, PARTYMON_STRUCT_LENGTH
call AddNTimes
ld a, [hl]
jr .UpdateItem
.WildItem
; ~20% chance of getting an item.
call BattleRandom
cp 79 percent - 1
ld a, 0
jr c, .UpdateItem
ld a, [wMonHItems]
.UpdateItem
ld [wEnemyMonItem], a
ld a, [wEnemySubStatus5]
bit SUBSTATUS_TRANSFORMED, a
ld hl, wEnemyBackupDVs
ld a, [hli]
ld b, [hl]
jr nz, .UpdateDVs
; Load preset middle-class DVs for trainer battles.
ld a, [wBattleMode]
cp TRAINER_BATTLE
ln a, 9, 8
ln b, 8, 8
jr z, .UpdateDVs
; Otherwise randomly generate DVs for wild encounters
call BattleRandom
ld b, a
call BattleRandom
.UpdateDVs
ld hl, wEnemyMonDVs
ld [hli], a
ld [hl], b
ld a, [wCurPartyLevel]
ld [wEnemyMonLevel], a
ld de, wEnemyMonMaxHP
ld b, 0
; This address doesn't seem to be referenced anywhere
ld hl, wEnemyMonDVs - (MON_DVS - MON_STAT_EXP + 1)
predef CalcMonStats
ld a, [wBattleMode]
cp TRAINER_BATTLE
jr z, .OpponentParty
ld a, [wEnemySubStatus5]
bit SUBSTATUS_TRANSFORMED, a
jr nz, .Moves
; Zero out status when generating Pokémon
ld hl, wEnemyMonStatus
xor a
ld [hli], a
ld [hli], a
; Set HP equal to max HP.
ld a, [wEnemyMonMaxHP]
ld [hli], a
ld a, [wEnemyMonMaxHP + 1]
ld [hli], a
jr .Moves
.OpponentParty
; Get HP from the party struct
ld hl, wOTPartyMon1HP + 1
ld a, [wCurPartyMon]
ld bc, PARTYMON_STRUCT_LENGTH
call AddNTimes
ld a, [hld]
ld [wEnemyMonHP + 1], a
ld a, [hld]
ld [wEnemyMonHP], a
; Make sure everything knows which monster the opponent is using
ld a, [wCurPartyMon]
ld [wCurOTMon], a
; Get status from the party struct
dec hl
ld a, [hl]
ld [wEnemyMonStatus], a
.Moves
ld hl, wMonHType1
ld de, wEnemyMonType1
ld a, [hli]
ld [de], a
inc de
ld a, [hl]
ld [de], a
ld de, wEnemyMonMoves
ld a, [wBattleMode]
cp TRAINER_BATTLE
jr nz, .WildMoves
ld hl, wOTPartyMon1Moves
ld a, [wCurPartyMon]
ld bc, PARTYMON_STRUCT_LENGTH
call AddNTimes
ld bc, NUM_MOVES
call CopyBytes
jr .PP
.WildMoves
xor a
ld h, d
ld l, e
ld [hli], a
ld [hli], a
ld [hli], a
ld [hl], a
ld [wSkipMovesBeforeLevelUp], a
predef FillMoves
.PP
ld hl, wEnemyMonMoves
ld de, wEnemyMonPP
predef FillPP
.Finish
ld hl, wMonHBaseStats
ld de, wEnemyMonBaseStats
ld b, NUM_BATTLE_STATS
.loop
ld a, [hli]
ld [de], a
inc de
dec b
jr nz, .loop
ld a, [wMonHCatchRate]
ld [de], a
inc de
ld a, [wMonHBaseEXP]
ld [de], a
ld a, [wTempEnemyMonSpecies]
ld [wNamedObjectIndexBuffer], a
call GetPokemonName
; Update enemy nickname
ld hl, wStringBuffer1
ld de, wEnemyMonNickname
ld bc, MON_NAME_LENGTH
call CopyBytes
; Saw this mon
ld a, [wTempEnemyMonSpecies]
dec a
ld c, a
ld b, 1
ld hl, wEndPokedexCaught
predef SmallFarFlagAction
ld hl, wEnemyMonStats
ld de, wEnemyStats
ld bc, NUM_BATTLE_STATS * 2
call CopyBytes
ld a, 7
ld b, 8
ld hl, wEnemyStatLevels
.InitStatLevel
ld [hli], a
dec b
jr nz, .InitStatLevel
ld a, 1
ldh [hBattleTurn], a
callfar GetMonSGBPaletteFlags
ret
; Leftover from Generation I.
Old_SwapPlayerAndEnemyLevels:
push bc
ld a, [wBattleMonLevel]
ld b, a
ld a, [wEnemyMonLevel]
ld [wBattleMonLevel], a
ld a, b
ld [wEnemyMonLevel], a
pop bc
ret
; A leftover from Generation I, where it had no effect due to no stats actually being selected.
; BUG: Remarkably, this is STILL run from HealStatus despite the stat double/halve bitfields
; being overwritten with variables that are actually used as substatuses.
DoubleOrHalveSelectedStats_Old::
call DoubleSelectedStats
jp HalveSelectedStats
DoubleSelectedStats:
ldh a, [hBattleTurn]
and a
ld a, [wPlayerSubStatus1] ; wPlayerStatsToDouble
ld hl, wBattleMonAttack + 1
jr z, .notEnemyTurn
ld a, [wEnemySubStatus1] ; wEnemyStatsToDouble
ld hl, wEnemyMonAttack + 1
.notEnemyTurn
ld c, 4
ld b, a
.loop
srl b
call c, .doubleStat
inc hl
inc hl
dec c
ret z
jr .loop
.doubleStat
ld a, [hl]
add a
ld [hld], a
ld a, [hl]
rl a
ld [hli], a
ret
HalveSelectedStats:
ldh a, [hBattleTurn]
and a
ld a, [wPlayerSubStatus2] ; wPlayerStatsToHalve
ld hl, wBattleMonAttack
jr z, .notEnemyTurn
ld a, [wEnemySubStatus2] ; wEnemyStatsToHalve
ld hl, wEnemyMonAttack
.notEnemyTurn
ld c, 4
ld b, a
.loop
srl b
call c, .halveStat
inc hl
inc hl
dec c
ret z
jr .loop
.halveStat
ld a, [hl]
srl a
ld [hli], a
ld d, a
ld a, [hl]
rr a
ld [hl], a
or d
jr nz, .nonzeroStat
ld a, 1
ld [hl], a
.nonzeroStat
dec hl
ret
BattleWinSlideInEnemyTrainerFrontpic:
xor a
ld [wTempEnemyMonSpecies], a
ld b, SGB_BATTLE_COLORS
call GetSGBLayout
; Should be a call instead
callfar GetTrainerPic
hlcoord 19, 0
ld c, 0
.outer_loop
inc c
ld a, c
cp 7
ret z
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 c, 4
call DelayFrames
pop hl
pop bc
dec hl
jr .outer_loop
.CopyColumn:
push hl
push de
push bc
ld e, 7
.loop
ld [hl], d
ld bc, SCREEN_WIDTH
add hl, bc
inc d
dec e
jr nz, .loop
pop bc
pop de
pop hl
ret
ApplyStatusEffectOnPlayerStats:
ld a, 1
jr ApplyStatusEffectOnStats
ApplyStatusEffectOnEnemyStats:
xor a
ApplyStatusEffectOnStats:
ldh [hBattleTurn], a
call ApplyPrzEffectOnSpeed
jp ApplyBrnEffectOnAttack
ApplyPrzEffectOnSpeed:
ldh a, [hBattleTurn]
and a
jr z, .enemy
ld a, [wBattleMonStatus]
and 1 << PAR
ret z
ld hl, wBattleMonSpeed + 1
ld a, [hld]
ld b, a
ld a, [hl]
srl a
rr b
srl a
rr b
ld [hli], a
or b
jr nz, .player_ok
ld b, 1
.player_ok:
ld [hl], b
ret
.enemy:
ld a, [wEnemyMonStatus]
and 1 << PAR
ret z
ld hl, wEnemyMonSpeed + 1
ld a, [hld]
ld b, a
ld a, [hl]
srl a
rr b
srl a
rr b
ld [hli], a
or b
jr nz, .enemy_ok
ld b, 1
.enemy_ok:
ld [hl], b
ret
ApplyBrnEffectOnAttack:
ldh a, [hBattleTurn]
and a
jr z, .enemy
ld a, [wBattleMonStatus]
and 1 << BRN
ret z
ld hl, wBattleMonAttack + 1
ld a, [hld]
ld b, a
ld a, [hl]
srl a
rr b
ld [hli], a
or b
jr nz, .player_ok
ld b, 1 ; min attack
.player_ok
ld [hl], b
ret
.enemy
ld a, [wEnemyMonStatus]
and 1 << BRN
ret z
ld hl, wEnemyMonAttack + 1
ld a, [hld]
ld b, a
ld a, [hl]
srl a
rr b
ld [hli], a
or b
jr nz, .enemy_ok
ld b, 1 ; min attack
.enemy_ok
ld [hl], b
ret
ApplyStatLevelMultiplierOnAllStats:
ld c, 0
.stat_loop
call ApplyStatLevelMultiplier
inc c
ld a, c
cp NUM_BATTLE_STATS
jr nz, .stat_loop
ret
ApplyStatLevelMultiplier:
push bc
push bc
ld a, [wApplyStatLevelMultipliersToEnemy]
and a
ld a, c
ld hl, wBattleMonStats
ld de, wPlayerStats
ld bc, wPlayerStatLevels
jr z, .got_pointers
ld hl, wEnemyMonStats
ld de, wEnemyStats
ld bc, wEnemyStatLevels
.got_pointers
; Adds a (battle stat index) to StatLevels, increase b if c overflows.
add c
ld c, a
jr nc, .okay
inc b
.okay
ld a, [bc]
pop bc
; b = Stat Level
ld b, a
push bc
; c = Stat index * 2. Add to MonStats pointer.
sla c
ld b, 0
add hl, bc
ld a, c
; Add stat index * 2 to wEnemyStats.
add e
ld e, a
jr nc, .okay2
inc d
.okay2
pop bc
push hl
ld hl, StatLevelMultipliers_Applied
; Get index of stat level from StatLevelMultipliers_Applied.
dec b
sla b
ld c, b
ld b, 0
add hl, bc
; Load enemy's original stat into Multiplicand.
xor a
ldh [hMultiplicand], a
ld a, [de]
ldh [hMultiplicand + 1], a
inc de
ld a, [de]
ldh [hMultiplicand + 2], a
; Load multiplication value from StatLevelMultipliers_Applied.
ld a, [hli]
ldh [hMultiplier], a
call Multiply
; Load division value from same table.
ld a, [hl]
ldh [hDivisor], a
ld b, 4
call Divide
; Cap at 999.
pop hl
ldh a, [hQuotient + 3]
sub LOW(MAX_STAT_VALUE)
ldh a, [hQuotient + 2]
sbc HIGH(MAX_STAT_VALUE)
jp c, .okay3
ld a, HIGH(MAX_STAT_VALUE)
ldh [hQuotient + 2], a
ld a, LOW(MAX_STAT_VALUE)
ldh [hQuotient + 3], a
.okay3
; Load output into MonStat.
ldh a, [hQuotient + 2]
ld [hli], a
ld b, a
ldh a, [hQuotient + 3]
ld [hl], a
or b
; Keep at minimum of 1
jr nz, .okay4
inc [hl]
.okay4
pop bc
ret
StatLevelMultipliers_Applied:
INCLUDE "data/battle/stat_multipliers.inc"
; Checks every odd-numbered badge, and triggers their corresponding boosts.
; Stat boosts are identical to Gen 1, with Special Attack replacing Special.
BadgeStatBoosts::
ld a, [wLinkMode]
cp LINK_COLOSSEUM
ret z
ld a, [wBadges]
ld b, a
ld hl, wBattleMonAttack
ld c, 4
.CheckBadge
srl b
call c, BoostStat
inc hl
inc hl
; Check every other badge.
srl b
dec c
jr nz, .CheckBadge
ret
; Raise stat at hl by 1/8.
BoostStat:
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
Call_LoadBattleFontsHPBar:
jpfar LoadBattleFontsHPBar
_LoadHPBar:
jpfar LoadHPBar
ld de, HpExpBarParts0GFX
ld hl, vChars2 tile $6c
lb bc, BANK(HpExpBarParts0GFX), 04
call Get1bpp
ld de, HpExpBarParts1GFX
ld hl, vChars2 tile $73
lb bc, BANK(HpExpBarParts1GFX), 06
call Get1bpp
ld de, ExpBarGFX
ld hl, vChars2 tile $55
lb bc, BANK(ExpBarGFX), 08
jp Get2bpp
EmptyBattleTextbox:
ld hl, .empty
jp PrintText
.empty:
text_end
_BattleRandom:
; If the normal RNG is used in a link battle it'll desync.
; To circumvent this a shared PRNG is used instead.
; But if we're in a non-link battle we're safe to use it
ld a, [wLinkMode]
and a
jp z, Random
; The PRNG operates in streams of 10 values.
; Which value are we trying to pull?
push hl
push bc
ld a, [wLinkBattleRNCount]
ld c, a
ld b, $0
ld hl, wLinkBattleRNs
add hl, bc
inc a
ld [wLinkBattleRNCount], a
; If we haven't hit the end yet, we're good
cp 9 ; number of seeds, including the last one. see comment in pokecrystal
ld a, [hl]
pop bc
pop hl
ret c
; If we have, we have to generate new pseudorandom data
; Instead of having multiple PRNGs, ten seeds are used
push hl
push bc
push af
; Reset count to 0
xor a
ld [wLinkBattleRNCount], a
ld hl, wLinkBattleRNs
ld b, 9 ; number of seeds; in release, this was increased to 10
; Generate next number in the sequence for each seed
; a[n+1] = (a[n] * 5 + 1) % 256
.loop
; get last #
ld a, [hl]
; a * 5 + 1
ld c, a
add a
add a
add c
inc a
; update #
ld [hli], a
dec b
jr nz, .loop
; This has the side effect of pulling the last value first,
; then wrapping around. As a result, when we check to see if
; we've reached the end, we check the one before it.
pop af
pop bc
pop hl
ret
Call_PlayBattleAnim:
ld a, e
ld [wFXAnimID], a
ld a, d
ld [wFXAnimID + 1], a
call WaitBGMap
predef_jump PlayBattleAnim
; Give experience.
; Don't give experience if linked.
GiveExperiencePoints:
ld a, [wLinkMode]
and a
ret nz
call .EvenlyDivideExpAmongParticipants
xor a
ld [wCurPartyMon], a
ld bc, wPartyMon1Species
.loop:
ld hl, MON_HP
add hl, bc
ld a, [hli]
or [hl]
jp z, .next_mon ; fainted
push bc
ld hl, wBattleParticipantsNotFainted
ld a, [wCurPartyMon]
ld c, a
ld b, CHECK_FLAG
ld d, 0
predef SmallFarFlagAction
ld a, c
and a
pop bc
jp z, .next_mon
; give stat exp
ld hl, MON_STAT_EXP + 1
add hl, bc
ld d, h
ld e, l
ld hl, wEnemyMonBaseStats
push bc
ld c, NUM_EXP_STATS
.stat_exp_loop
ld a, [hli]
ld b, a
ld a, [de]
add b
ld [de], a
jr nc, .no_carry_stat_exp
dec de
ld a, [de]
inc a
jr z, .stat_exp_maxed_out
ld [de], a
inc de
jr .no_carry_stat_exp
.stat_exp_maxed_out
ld a, $ff
ld [de], a
inc de
ld [de], a
.no_carry_stat_exp
dec c
jr z, .stat_exp_awarded
inc de
inc de
jr .stat_exp_loop
.stat_exp_awarded
xor a
ldh [hMultiplicand], a
ldh [hMultiplicand + 1], a
ld a, [wEnemyMonBaseExp]
ldh [hMultiplicand + 2], a
ld a, [wEnemyMonLevel]
ldh [hMultiplier], a
call Multiply
ld a, 7
ldh [hDivisor], a
ld b, 4
call Divide
; Boost Experience for traded Pokemon
pop bc
ld hl, MON_ID
add hl, bc
ld a, [wPlayerID]
cp [hl]
jr nz, .boosted
inc hl
ld a, [wPlayerID + 1]
cp [hl]
ld a, 0
jr z, .no_boost
.boosted
call BoostExp
ld a, 1
.no_boost
; Boost experience for a Trainer Battle
ld [wStringBuffer2 + 2], a
ld a, [wBattleMode]
dec a
call nz, BoostExp
ld hl, MON_EXP + 2
add hl, bc
ld d, [hl]
ldh a, [hQuotient + 3]
ld [wStringBuffer2 + 1], a
add d
ld [hld], a
ld d, [hl]
ldh a, [hQuotient + 2]
ld [wStringBuffer2], a
adc d
ld [hl], a
jr nc, .no_exp_overflow
dec hl
inc [hl]
.no_exp_overflow
ld a, [wCurPartyMon]
ld e, a
ld d, 0
ld hl, wPartySpecies
add hl, de
ld a, [hl]
ld [wCurSpecies], a
call GetBaseData
push bc
ld d, MAX_LEVEL
callfar CalcExpAtLevel
pop bc
ld hl, MON_EXP + 2
add hl, bc
push bc
ldh a, [hQuotient + 1]
ld b, a
ldh a, [hQuotient + 2]
ld c, a
ldh a, [hQuotient + 3]
ld d, a
ld a, [hld]
sub d
ld a, [hld]
sbc c
ld a, [hl]
sbc b
jr c, .not_max_exp
ld a, b
ld [hli], a
ld a, c
ld [hli], a
ld a, d
ld [hld], a
.not_max_exp
; <NICKNAME> grew to level ##!
ld a, [wCurPartyMon]
ld hl, wPartyMonNicknames
call GetNick
ld hl, BoostedExpPointsText
call PrintText
; Check if the mon leveled up
xor a
ld [wMonType], a
predef CopyMonToTempMon
farcall CalcLevel
pop bc
ld hl, MON_LEVEL
add hl, bc
ld a, [hl]
cp d
jp z, .next_mon
ld a, [wCurPartyLevel]
push af
ld a, d
ld [wCurPartyLevel], a
ld [hl], a
ld hl, 0
add hl, bc
ld a, [hl]
ld [wCurSpecies], a
ld [wTempSpecies], a ; unused?
call GetBaseData
ld hl, MON_MAXHP + 1
add hl, bc
ld a, [hld]
ld e, a
ld d, [hl]
push de
ld hl, MON_MAXHP
add hl, bc
ld d, h
ld e, l
ld hl, MON_STAT_EXP - 1
add hl, bc
push bc
ld b, TRUE
predef CalcMonStats
pop bc
pop de
ld hl, MON_MAXHP + 1
add hl, bc
ld a, [hld]
sub e
ld e, a
ld a, [hl]
sbc d
ld d, a
dec hl
ld a, [hl]
add e
ld [hld], a
ld a, [hl]
adc d
ld [hl], a
ld a, [wCurBattleMon]
ld d, a
ld a, [wCurPartyMon]
cp d
jr nz, .skip_active_mon_update
ld de, wBattleMonHP
ld a, [hli]
ld [de], a
inc de
ld a, [hli]
ld [de], a
ld de, wBattleMonMaxHP
push bc
ld bc, PARTYMON_STRUCT_LENGTH - MON_MAXHP
call CopyBytes
pop bc
ld hl, MON_LEVEL
add hl, bc
ld a, [hl]
ld [wBattleMonLevel], a
ld a, [wPlayerSubStatus5]
bit SUBSTATUS_TRANSFORMED, a
jr nz, .transformed
ld hl, MON_ATK
add hl, bc
ld de, wPlayerStats
ld bc, PARTYMON_STRUCT_LENGTH - MON_ATK
call CopyBytes
.transformed
xor a ; FALSE
ld [wApplyStatLevelMultipliersToEnemy], a
call ApplyStatLevelMultiplierOnAllStats
; these three calls should be regular calls
callfar ApplyStatusEffectOnPlayerStats
callfar BadgeStatBoosts
callfar UpdatePlayerHUD
call EmptyBattleTextbox
call BackUpTilesToBuffer
.skip_active_mon_update
ld hl, GrewToLevelText
call PrintText
xor a
ld [wMonType], a
predef CopyMonToTempMon
ld d, 1
callfar PrintTempMonStats
call TextboxWaitPressAorB_BlinkCursor
call ReloadTilesFromBuffer
xor a ; PARTYMON
ld [wMonType], a
ld a, [wCurSpecies]
ld [wTempSpecies], a ; unused?
predef LearnLevelMoves
ld hl, wEvolvableFlags
ld a, [wCurPartyMon]
ld c, a
ld b, SET_FLAG
predef SmallFarFlagAction
pop af
ld [wCurPartyLevel], a
.next_mon
ld a, [wPartyCount]
ld b, a
ld a, [wCurPartyMon]
inc a
cp b
jr z, .done
ld [wCurPartyMon], a
ld bc, PARTYMON_STRUCT_LENGTH
ld hl, wPartyMon1Species
call AddNTimes
ld b, h
ld c, l
jp .loop
.done
ld hl, wBattleParticipantsNotFainted
xor a
ld [hl], a
ld a, [wCurBattleMon]
ld c, a
ld b, SET_FLAG
push bc
predef SmallFarFlagAction
ld hl, wBattleParticipantsIncludingFainted
xor a
ld [hl], a
pop bc
predef_jump SmallFarFlagAction
; Divide enemy base stats, catch rate, and base exp by the number of mons gaining exp.
.EvenlyDivideExpAmongParticipants:
; count number of battle participants
ld a, [wBattleParticipantsNotFainted]
ld b, a
xor a
ld c, 8
ld d, 0
.count_loop
xor a
srl b
adc d
ld d, a
dec c
jr nz, .count_loop
cp 2
ret c
ld [wTempByteValue], a
ld hl, wEnemyMonBaseStats
ld c, wEnemyMonEnd - wEnemyMonBaseStats
.base_stat_division_loop
xor a
ldh [hDividend], a
ld a, [hl]
ldh [hDividend + 1], a
ld a, [wNumSetBits]
ldh [hDivisor], a
ld b, 2
call Divide
ldh a, [hQuotient + 3]
ld [hli], a
dec c
jr nz, .base_stat_division_loop
ret
; Multiply experience by 1.5x
BoostExp:
push bc
; load experience value
ldh a, [hProduct + 2]
ld b, a
ldh a, [hProduct + 3]
ld c, a
; halve it
srl b
rr c
; add it back to the whole exp value
add c
ldh [hProduct + 3], a
ldh a, [hProduct + 2]
adc b
ldh [hProduct + 2], a
pop bc
ret
BoostedExpPointsText:
text_from_ram wStringBuffer1
text "は@"
start_asm
ld a, [wBoostExpByExpAll]
ld hl, .WithExpAllText
and a
ret nz
ld hl, .ExpPointsText
ld a, [wGainBoostedExp]
and a
ret z
ld hl, .BoostedExpPointsText
ret
.WithExpAllText:
text " がくしゅうそうちで@"
start_asm
ld hl, .ExpPointsText
ret
.BoostedExpPointsText:
text " おおめに@"
.ExpPointsText:
text_start
line "@"
deciram wStringBuffer2, 2, 4
text " けいけんちを もらった!"
prompt
GrewToLevelText:
text_from_ram wStringBuffer1
text "は"
line "レベル@"
deciram wCurPartyLevel, 1, 3
text " に あがった!@"
sound_dex_fanfare_50_79
text_end
SendOutMonText:
ld a, [wLinkMode]
and a
jr z, .not_linked
; If we're in a LinkBattle print just "Go <PlayerMon>"
; unless DoBattle already set [wBattleHasJustStarted]
ld hl, GoMonText
ld a, [wBattleHasJustStarted]
and a
jr nz, .skip_to_textbox
; Depending on the HP of the enemy mon, the game prints a different text
.not_linked
ld hl, wEnemyMonHP
ld a, [hli]
or [hl]
ld hl, GoMonText
jr z, .skip_to_textbox
; compute enemy health remaining as a percentage
xor a
ldh [hMultiplicand], a
ld hl, wEnemyMonHP
ld a, [hli]
ld [wEnemyHPAtTimeOfPlayerSwitch], a
ldh [hMultiplicand + 1], a
ld a, [hl]
ld [wEnemyHPAtTimeOfPlayerSwitch + 1], a
ldh [hMultiplicand + 2], a
ld a, 25
ldh [hPrintNumDivisor], a
call Multiply
ld hl, wEnemyMonMaxHP
ld a, [hli]
ld b, [hl]
srl a
rr b
srl a
rr b
ld a, b
ld b, 4
ldh [hDivisor], a
call Divide
; (enemy's current HP * 25) / (enemy's max HP / 4)
; approximates current % of max HP
ldh a, [hQuotient + 3]
; >= 70%
ld hl, GoMonText
cp 70
jr nc, .skip_to_textbox
; 40% <= HP <= 69%
ld hl, DoItMonText
cp 40
jr nc, .skip_to_textbox
; 10% <= HP <= 39%
ld hl, GoForItMonText
cp 10
jr nc, .skip_to_textbox
; < 10%
ld hl, YourFoesWeakGetmMonText
.skip_to_textbox
jp PrintText
GoMonText:
text "ゆけっ! @"
start_asm
jr PrintPlayerMon1Text
DoItMonText:
text "いってこい! @"
start_asm
jr PrintPlayerMon1Text
GoForItMonText:
text "がんばれ! @"
start_asm
jr PrintPlayerMon1Text
YourFoesWeakGetmMonText:
text "あいてが よわっている!"
line "チャンスだ! @"
start_asm
PrintPlayerMon1Text:
ld hl, .Text
ret
.Text:
text_from_ram wBattleMonNickname
text ""
done
RetreatMon:
ld hl, PlayerMon2Text
jp PrintText
PlayerMon2Text:
text_from_ram wBattleMonNickname
text " @"
start_asm
push de
push bc
ld hl, wEnemyMonHP + 1
ld de, wEnemyHPAtTimeOfPlayerSwitch + 1
ld b, [hl]
dec hl
ld a, [de]
sub b
ldh [hMultiplicand + 2], a
dec de
ld b, [hl]
ld a, [de]
sbc b
ldh [hMultiplicand + 1], a
ld a, 25
ldh [hMultiplier], a
call Multiply
ld hl, wEnemyMonMaxHP
ld a, [hli]
ld b, [hl]
srl a
rr b
srl a
rr b
ld a, b
ld b, 4
ldh [hDivisor], a
call Divide
pop bc
pop de
ldh a, [hQuotient + 3]
; HP stays the same
ld hl, EnoughText
and a
ret z
; HP went down 1% - 29%
ld hl, ComeBackText
cp 30
ret c
; HP went down 30% - 69%
ld hl, OKExclamationText
cp 70
ret c
; HP went down 70% or more
ld hl, GoodText
ret
EnoughText:
text "もういい!@"
start_asm
jr PrintComeBackText
OKExclamationText:
text "いいぞ!@"
start_asm
jr PrintComeBackText
GoodText:
text "よくやった!@"
start_asm
jr PrintComeBackText
PrintComeBackText:
ld hl, ComeBackText
ret
ComeBackText:
text_start
line "もどれ!"
done
PrintSafariZoneBattleText:
ld hl, wUnused_SafariBaitFactor
ld a, [hl]
and a
jr z, .no_bait
dec [hl]
ld hl, Unused_SafariZoneEatingText
jr .done
.no_bait
dec hl
ld a, [hl]
and a
ret z
dec [hl]
ld hl, Unused_SafariZoneAngryText
jr nz, .done
push hl
ld a, [wEnemyMonSpecies]
ld [wCurSpecies], a
call GetBaseData
ld a, [wMonHCatchRate]
ld [wEnemyMonCatchRate], a
pop hl
.done
push hl
call ReloadTilesFromBuffer
pop hl
jp PrintText
Unused_SafariZoneEatingText:
text "やせいの@"
text_from_ram wEnemyMonNickname
text "は"
line "エサを たべてる!"
prompt
Unused_SafariZoneAngryText:
text "やせいの@"
text_from_ram wEnemyMonNickname
text "は"
line "おこってる!"
prompt
; Calculate the percent exp between this level and the next
; Level in b, then place the exp bar. Split in the final game.
CalcAndPlaceExpBar:
push hl
push de
ld d, b
push de
callfar CalcExpAtLevel
pop de
; exp at current level gets pushed to the stack
ld hl, hMultiplicand
ld a, [hli]
push af
ld a, [hli]
push af
ld a, [hl]
push af
; next level
inc d
callfar CalcExpAtLevel
; back up the next level exp, and subtract the two levels
ld hl, hMultiplicand + 2
ld a, [hl]
ldh [hMathBuffer + 2], a
pop bc
sub b
ld [hld], a
ld a, [hl]
ldh [hMathBuffer + 1], a
pop bc
sbc b
ld [hld], a
ld a, [hl]
ldh [hMathBuffer], a
pop bc
sbc b
ld [hl], a
pop de
ld hl, hMultiplicand + 1
ld a, [hli]
push af
ld a, [hl]
push af
; get the amount of exp remaining to the next level
ld a, [de]
dec de
ld c, a
ldh a, [hMathBuffer + 2]
sub c
ld [hld], a
ld a, [de]
dec de
ld b, a
ldh a, [hMathBuffer + 1]
sbc b
ld [hld], a
ld a, [de]
ld c, a
ldh a, [hMathBuffer]
sbc c
ld [hld], a
xor a
ld [hl], a
ld a, 64
ldh [hMultiplier], a
call Multiply
pop af
ld c, a
pop af
ld b, a
.loop
ld a, b
and a
jr z, .done
srl b
rr c
ld hl, hProduct
srl [hl]
inc hl
rr [hl]
inc hl
rr [hl]
inc hl
rr [hl]
jr .loop
.done
ld a, c
ldh [hDivisor], a
ld b, 4
call Divide
pop hl
ld bc, 7
add hl, bc
ldh a, [hQuotient + 3]
ld b, a
ld a, $40
sub b
ld b, a
; Separated into PlaceExpBar in the final game
ld c, 8
.loop2
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 .loop2
.next
add 8
jr z, .loop3
add $54 ; tile to the left of small exp bar tile
jr .skip
.loop3
ld a, $62 ; empty bar
.skip
ld [hld], a
ld a, $62 ; empty bar
dec c
jr nz, .loop3
.finish
ret
GetBattleMonBackpic:
ld a, [wPlayerSubStatus4]
bit SUBSTATUS_SUBSTITUTE, a
ld hl, BattleAnimCmd_RaiseSub
jr nz, GetBattleMonBackpic_DoAnim
DropPlayerSub:
ld a, [wPlayerMinimized]
and a
ld hl, BattleAnimCmd_MinimizeOpp
jr nz, GetBattleMonBackpic_DoAnim
ld a, [wCurPartySpecies]
push af
ld a, [wBattleMonSpecies]
ld [wCurSpecies], a
ld [wCurPartySpecies], a
call GetBaseData
ld hl, wMonHBackSprite - wMonHeader
call UncompressMonSprite
ld hl, vBackPic
predef GetMonBackpic
pop af
ld [wCurPartySpecies], a
ret
GetBattleMonBackpic_DoAnim:
ldh a, [hBattleTurn]
push af
xor a
ldh [hBattleTurn], a
ld a, BANK(BattleAnimCmd_RaiseSub)
call FarCall_hl
pop af
ldh [hBattleTurn], a
ret
GetEnemyMonFrontpic:
ld a, [wEnemySubStatus4]
bit SUBSTATUS_SUBSTITUTE, a
ld hl, BattleAnimCmd_RaiseSub
jr nz, GetEnemyMonFrontpic_DoAnim
DropEnemySub:
ld a, [wEnemyMinimized]
and a
ld hl, BattleAnimCmd_MinimizeOpp
jr nz, GetEnemyMonFrontpic_DoAnim
ld a, [wCurPartySpecies]
push af
ld a, [wEnemyMonSpecies]
ld [wCurSpecies], a
ld [wCurPartySpecies], a
call GetBaseData
ld hl, wEnemyMonDVs
predef GetUnownLetter
ld de, vFrontPic
call LoadMonFrontSprite
pop af
ld [wCurPartySpecies], a
ret
GetEnemyMonFrontpic_DoAnim:
ldh a, [hBattleTurn]
push af
ld a, 1
ldh [hBattleTurn], a
ld a, BANK(BattleAnimCmd_RaiseSub)
call FarCall_hl
pop af
ldh [hBattleTurn], a
ret
SECTION "engine/battle/core.asm@StartBattle", ROMX
StartBattle::
ld a, [wOtherTrainerClass]
and a
jr nz, .battle_intro
ld a, [wTempWildMonSpecies]
and a
jr z, .battle_intro
ld [wCurPartySpecies], a
ld [wTempEnemyMonSpecies], a
.battle_intro
ld a, [wTimeOfDayPal]
push af
ld hl, wTextboxFlags
ld a, [hl]
push af
res TEXT_DELAY_F, [hl]
ldh a, [hMapAnims]
ld [wMapAnimsBackup], a
call PlayBattleMusic
call ShowLinkBattleParticipants
call ClearBattleRAM
ld a, [wOtherTrainerClass]
and a
jr nz, .trainer
call InitEnemyWildmon
jr .back_up_bgmap2
.trainer
call InitEnemyTrainer
.back_up_bgmap2
ld b, 0
call GetSGBLayout
ld hl, wStateFlags
res SPRITE_UPDATES_DISABLED_F, [hl]
call InitBattleDisplay
call BattleStartMessage
xor a
ldh [hBGMapMode], a
call EmptyBattleTextbox
hlcoord 9, 7
lb bc, 5, 10
call ClearBox
hlcoord 1, 0
lb bc, 4, 10
call ClearBox
call ClearSprites
ld a, [wBattleMode]
cp WILD_BATTLE
call z, UpdateEnemyHUD
call DoBattle
call ExitBattle
pop af
ld [wTextboxFlags], a
pop af
ld [wTimeOfDayPal], a
ld a, [wMapAnimsBackup]
ldh [hMapAnims], a
scf
ret
InitEnemyTrainer:
ld [wTrainerClass], a
callfar GetTrainerAttributes
callfar ReadTrainerParty
; RIVAL's first mon has no held item
ld a, [wTrainerClass]
cp TRAINER_RIVAL
jr nz, .ok
xor a
ld [wOTPartyMon1Item], a
.ok
call GetTrainerPic
xor a
ld [wTempEnemyMonSpecies], a
ldh [hGraphicStartTile], a
dec a
ld [wEnemyItemState], a
hlcoord 12, 0
lb bc, 7, 7
predef PlaceGraphic
ld a, -1
ld [wCurOTMon], a
ld a, TRAINER_BATTLE
ld [wBattleMode], a
ret
InitEnemyWildmon:
ld a, 1
ld [wBattleMode], a
call LoadEnemyMon
ld hl, wEnemyMonDVs
predef GetUnownLetter
ld de, vFrontPic
call LoadMonFrontSprite
xor a
ld [wTrainerClass], a
ldh [hGraphicStartTile], a
hlcoord 12, 0
lb bc, 7, 7
predef PlaceGraphic
ret
GetTrainerPic:
ld a, [wEnemyTrainerGraphicsPointer]
ld e, a
ld a, [wEnemyTrainerGraphicsPointer + 1]
ld d, a
ld a, BANK("gfx.asm@Trainer Battle Sprites")
call UncompressSpriteFromDE
ld de, vFrontPic
ln a, 7, 7
ld c, a
jp LoadUncompressedSpriteData
; Fill wBoxAlignment-aligned box width b height c
; with iterating tile starting from hGraphicStartTile at hl.
PlaceGraphic:
ld de, SCREEN_WIDTH
ld a, [wSpriteFlipped]
and a
jr nz, .right
ldh a, [hGraphicStartTile]
.x1
push bc
push hl
.y1
ld [hl], a
add hl, de
inc a
dec c
jr nz, .y1
pop hl
inc hl
pop bc
dec b
jr nz, .x1
ret
.right
push bc
ld b, 0
dec c
add hl, bc
pop bc
ldh a, [hGraphicStartTile]
.x2
push bc
push hl
.y2
ld [hl], a
add hl, de
inc a
dec c
jr nz, .y2
pop hl
dec hl
pop bc
dec b
jr nz, .x2
ret
LoadMonBackPic:
ld a, [wTempBattleMonSpecies]
ld [wCurPartySpecies], a
hlcoord 1, 5
ld b, 7
ld c, 8
call ClearBox
ld hl, wMonHBackSprite - wMonHeader
call UncompressMonSprite
ld hl, vBackPic
predef_jump GetMonBackpic
; Old back sprite scaling code from Red & Green.
Old_ScaleSpriteByTwo:
ld de, sSpriteBuffer1 + (4*4*8) - 5 ; last byte of input data, last 4 rows already skipped
ld hl, sSpriteBuffer0 + SPRITEBUFFERSIZE - 1 ; end of destination buffer
call ScaleLastSpriteColumnByTwo ; last tile column is special case
call ScaleFirstThreeSpriteColumnsByTwo ; scale first 3 tile columns
ld de, sSpriteBuffer2 + (4*4*8) - 5 ; last byte of input data, last 4 rows already skipped
ld hl, sSpriteBuffer1 + SPRITEBUFFERSIZE - 1 ; end of destination buffer
call ScaleLastSpriteColumnByTwo ; last tile column is special case
ScaleFirstThreeSpriteColumnsByTwo:
ld b, $3 ; 3 tile columns
.columnLoop
ld c, 4*8 - 4 ; $1c, 4 tiles minus 4 unused rows
.columnInnerLoop
push bc
ld a, [de]
ld bc, -(7*8)+1 ; -$37, scale lower nybble and seek to previous output column
call ScalePixelsByTwo
ld a, [de]
dec de
swap a
ld bc, 7*8+1-2 ; $37, scale upper nybble and seek back to current output column and to the next 2 rows
call ScalePixelsByTwo
pop bc
dec c
jr nz, .columnInnerLoop
dec de
dec de
dec de
dec de
ld a, b
ld bc, -7*8 ; -$38, skip one output column (which has already been written along with the current one)
add hl, bc
ld b, a
dec b
jr nz, .columnLoop
ret
ScaleLastSpriteColumnByTwo:
ld a, 4*8 - 4 ; $1c, 4 tiles minus 4 unused rows
ldh [hSpriteInterlaceCounter], a
ld bc, -1
.columnInnerLoop
ld a, [de]
dec de
swap a ; only high nybble contains information
call ScalePixelsByTwo
ldh a, [hSpriteInterlaceCounter]
dec a
ldh [hSpriteInterlaceCounter], a
jr nz, .columnInnerLoop
dec de ; skip last 4 rows of new column
dec de
dec de
dec de
ret
; scales the given 4 bits in a (4x1 pixels) to 2 output bytes (8x2 pixels)
; hl: destination pointer
; bc: destination pointer offset (added after the two bytes have been written)
ScalePixelsByTwo:
push hl
and $f
ld hl, DuplicateBitsTable
add l
ld l, a
jr nc, .noCarry
inc h
.noCarry
ld a, [hl]
pop hl
ld [hld], a ; write output byte twice to make it 2 pixels high
ld [hl], a
add hl, bc ; add offset
ret
DuplicateBitsTable:
FOR n, 16
db (n & 1) * 3 + (n & 2) * 6 + (n & 4) * 12 + (n & 8) * 24
ENDR
ClearBattleRAM:
xor a
ld [wBattlePlayerAction], a
ld [wBattleResult], a
ld hl, wPartyMenuCursor
ld [hli], a
ld [hli], a
ld [hli], a
ld [hl], a
ld [wMenuScrollPosition], a
ld [wCriticalHit], a
ld [wBattleMonSpecies], a
ld [wBattleParticipantsNotFainted], a
ld [wCurBattleMon], a
ld [wBattleEnded], a
ld [wTimeOfDayPal], a
ld [wEnemyTurnsTaken], a
ld hl, wPlayerHPPal
ld [hli], a
ld [hl], a
ld hl, wBattleMonDVs
ld [hli], a
ld [hl], a
ld hl, wEnemyMonDVs
ld [hli], a
ld [hl], a
; Clear the entire BattleMons area
ld hl, wEnemyMoveStruct
ld bc, wBattleEnd - wBattle
xor a
call ByteFill
call ClearWindowData
ld hl, hBGMapAddress
xor a
ld [hli], a
ld [hl], HIGH(vBGMap0)
ld a, (LCDC_DEFAULT & ~(1 << rLCDC_WINDOW_TILEMAP))
ldh [rLCDC], a
ld a, [wMapId]
cp $d9 ; SAFARI_ZONE_EAST
jr c, .return
cp $dd ; SAFARI_ZONE_CENTER_REST_HOUSE
jr nc, .return
ld a, 2
ld [wBattleType], a
.return
ret
ExitBattle:
call IsLinkBattle
jr nz, .HandleEndOfBattle
call ShowLinkBattleParticipantsAfterEnd
jr .CheckEvolution
.HandleEndOfBattle
ld a, [wBattleResult]
and a
jr nz, .CleanUpBattleRAM
; WIN
call CheckPayDay
.CheckEvolution
xor a
ld [wForceEvolution], a
predef EvolveAfterBattle
.CleanUpBattleRAM:
xor a
ld [wLowHealthAlarmBuffer], a
ld [wBattleMode], a
ld [wBattleType], a
ld [wAttackMissed], a
ld [wTempWildMonSpecies], a
ld [wOtherTrainerClass], a
ld [wFailedToFlee], a
ld [wNumFleeAttempts], a
ld [wBattleEnded], a
ld hl, wPartyMenuCursor
ld [hli], a
ld [hli], a
ld [hli], a
ld [hl], a
ld [wMenuScrollPosition], a
ld hl, wPlayerSubStatus1
ld b, wEnemyFuryCutterCount - wPlayerSubStatus1
.loop
ld [hli], a
dec b
jr nz, .loop
ld hl, wd4a7
set 0, [hl]
call WaitSFX
ld a, $e3
ldh [rLCDC], a
ld hl, wd14f
res 7, [hl]
call ClearPalettes
ret
CheckPayDay:
ld hl, wPayDayMoney
ld a, [hli]
or [hl]
inc hl
or [hl]
ret z
ld a, [wBattleMonItem]
ld b, a
callfar GetItemHeldEffect
ld a, b
cp HELD_AMULET_COIN
jr nz, AddBattleMoneyToAccount
ld hl, wPayDayMoney + 2
sla [hl]
dec hl
rl [hl]
dec hl
rl [hl]
jr nc, AddBattleMoneyToAccount
ld a, $ff
ld [hli], a
ld [hli], a
ld [hl], a
AddBattleMoneyToAccount:
ld hl, wPayDayMoney + 2
ld de, wMoney + 2
ld c, 3
and a
.loop
ld a, [de]
adc [hl]
ld [de], a
dec de
dec hl
dec c
jr nz, .loop
ld hl, BattleText_PlayerPickedUpPayDayMoney
call PrintText
ret
BattleText_PlayerPickedUpPayDayMoney:
text "<PLAYER>は @"
deciram wPayDayMoney, 3, 6
text "円"
line "ひろった!"
prompt
ShowLinkBattleParticipantsAfterEnd:
ld a, [wCurOTMon]
ld hl, wOTPartyMon1Status
ld bc, PARTYMON_STRUCT_LENGTH
call AddNTimes
ld a, [wEnemyMonStatus]
ld [hl], a
call ClearTileMap
call _ShowLinkBattleParticipants
ld a, [wBattleResult]
cp LOSE
ld de, .YouWin
jr c, .store_result
ld de, .YouLose
jr z, .store_result
ld de, .Draw
.store_result
hlcoord 6, 8
call PlaceString
ld c, 200
call DelayFrames
ret
.YouWin:
db "あなたの かち@"
.YouLose:
db "あなたの まけ@"
.Draw:
db "  ひきわけ@"
PlayBattleMusic:
push hl
push de
push bc
xor a
ld [wMusicFade], a
ld de, 0
call PlayMusic
call DelayFrame
call MaxVolume
; plays vs. gym leader music regardless of the battle type
ld de, MUSIC_LEADER_BATTLE
call PlayMusic
pop bc
pop de
pop hl
ret
InitBattleDisplay:
call GetTrainerBackpic
hlcoord 0, 12
ld b, 4
ld c, 18
call DrawTextBox
hlcoord 1, 5
lb bc, 3, 7
call ClearBox
call DisableLCD
call LoadFont
call Call_LoadBattleFontsHPBar
ld hl, vBGMap0
lb bc, 4, 0
ld a, ' '
call ByteFill
call LoadMapTimeOfDay.PushAttrMap
call EnableLCD
xor a
ldh [hMapAnims], a
ldh [hSCY], a
ld a, SCREEN_HEIGHT_PX
ldh [hWY], a
ldh [rWY], a
call WaitBGMap
xor a
ldh [hBGMapMode], a
call BattleIntroSlidingPics
ld a, 1
ldh [hBGMapMode], a
ld a, $31
ldh [hGraphicStartTile], a
hlcoord 2, 6
lb bc, 6, 6
predef PlaceGraphic
xor a
ldh [hWY], a
ldh [rWY], a
call WaitBGMap
ld b, SGB_BATTLE_COLORS
call GetSGBLayout
call HideSprites
ld a, SCREEN_HEIGHT_PX
ldh [hWY], a
xor a
ldh [hSCX], a
ret
BattleIntroSlidingPics:
ld b, $70
ld c, $90
ld a, c
ldh [hSCX], a
call DelayFrame
ld a, %11100100
ldh [rBGP], a
ldh [rOBP0], a
ldh [rOBP1], a
.loop1
push bc
ld h, b
ld l, $40
call .subfunction2
ld h, 0
ld l, $60
call .subfunction2
call .subfunction1
pop bc
ld a, c
ldh [hSCX], a
inc b
inc b
dec c
dec c
jr nz, .loop1
ret
.subfunction1:
push bc
ld hl, wShadowOAMSprite00XCoord
ld c, $12
ld de, SPRITEOAMSTRUCT_LENGTH
.loop2
dec [hl]
dec [hl]
add hl, de
dec c
jr nz, .loop2
pop bc
ret
.subfunction2:
.loop3
ldh a, [rLY]
cp l
jr nz, .loop3
ld a, h
ldh [rSCX], a
.loop4
ldh a, [rLY]
cp h
jr z, .loop4
ret
GetTrainerBackpic:
ld de, PlayerBacksprite
ld a, BANK(PlayerBacksprite)
call UncompressSpriteFromDE
ld hl, vChars2 tile $31
predef GetMonBackpic
ld a, BANK(sSpriteBuffer1)
call OpenSRAM
ld hl, vSprites
ld de, sSpriteBuffer1
ldh a, [hROMBank]
ld b, a
ld c, 7 * 7
call Request2bpp
call CloseSRAM
call .LoadTrainerBackpicAsOAM
ld a, $31
ldh [hGraphicStartTile], a
hlcoord 2, 6
lb bc, 6, 6
predef PlaceGraphic
ret
.LoadTrainerBackpicAsOAM:
ld hl, wShadowOAMSprite00
xor a
ldh [hMapObjectIndex], a
ld b, 6
ld e, (SCREEN_WIDTH + 1) * TILE_WIDTH
.outer_loop
ld c, 3
ld d, 8 * TILE_WIDTH
.inner_loop
ld [hl], d
inc hl
ld [hl], e
inc hl
ldh a, [hMapObjectIndex]
ld [hli], a
inc a
ldh [hMapObjectIndex], a
inc hl
ld a, d
add 1 * TILE_WIDTH
ld d, a
dec c
jr nz, .inner_loop
ldh a, [hMapObjectIndex]
add 3
ldh [hMapObjectIndex], a
ld a, e
add 1 * TILE_WIDTH
ld e, a
dec b
jr nz, .outer_loop
ret
PlayerBacksprite:
INCBIN "gfx/trainer/protagonist_back.pic"
Unused_OldManBacksprite:
INCBIN "gfx/trainer/oldman_back.pic"
BattleStartMessage:
ld a, [wBattleMode]
dec a
jr z, .wild
ld de, SFX_SHINE
call PlaySFX
call WaitSFX
ld c, 20
call DelayFrames
callfar Battle_GetTrainerName
ld hl, WantsToBattleText
jr .PrintBattleStartText
.wild
ld a, $f
ld [wCryTracks], a
ld a, [wTempEnemyMonSpecies]
call PlayStereoCry
ld hl, WildPokemonAppearedText
ld a, [wAttackMissed]
and a
jr z, .PrintBattleStartText
ld hl, HookedPokemonAttackedText
.PrintBattleStartText:
push hl
callfar BattleStart_TrainerHuds
pop hl
call PrintText
ret
WildPokemonAppearedText:
text "あ! やせいの"
line "@"
text_from_ram wEnemyMonNickname
text "が とびだしてきた!"
prompt
HookedPokemonAttackedText:
text "つりあげた @"
text_from_ram wEnemyMonNickname
text "が"
line "とびかかってきた!"
prompt
WantsToBattleText:
text_from_ram wOTClassName
text "の @"
text_from_ram wStringBuffer1
text "が"
line "しょうぶを しかけてきた!"
prompt
ShowLinkBattleParticipants:
call IsLinkBattle
jr nz, .ok
call _ShowLinkBattleParticipants
call ClearTileMap
.ok
call DelayFrame
predef DoBattleTransition
call Call_LoadBattleFontsHPBar
ld a, 1
ldh [hBGMapMode], a
call ClearSprites
call ClearTileMap
xor a
ldh [hBGMapMode], a
ldh [hWY], a
ldh [rWY], a
ldh [hMapAnims], a
ret
_ShowLinkBattleParticipants:
call LoadFontExtra
hlcoord 3, 4
ld b, 7
ld c, 12
call DrawTextBox
hlcoord 4, 6
ld de, wPlayerName
call PlaceString
hlcoord 4, 10
ld de, wOTPlayerName
call PlaceString
hlcoord 9, 8
ld a, ''
ld [hli], a
ld [hl], ''
callfar LinkBattle_TrainerHuds
ld c, 150
jp DelayFrames
IsLinkBattle:
push bc
push af
ld a, [wLinkMode]
cp LINK_COLOSSEUM
pop bc
ld a, b
pop bc
ret