summaryrefslogtreecommitdiff
path: root/engine/battle
diff options
context:
space:
mode:
Diffstat (limited to 'engine/battle')
-rw-r--r--engine/battle/animations.asm252
-rw-r--r--engine/battle/battle_transitions.asm4
-rw-r--r--engine/battle/common_text.asm16
-rw-r--r--engine/battle/core.asm560
-rw-r--r--engine/battle/draw_hud_pokeball_gfx.asm10
-rw-r--r--engine/battle/effects.asm59
-rw-r--r--engine/battle/end_of_battle.asm4
-rw-r--r--engine/battle/experience.asm22
-rw-r--r--engine/battle/ghost_marowak_anim.asm5
-rw-r--r--engine/battle/init_battle.asm282
-rw-r--r--engine/battle/link_battle_versus_text.asm3
-rw-r--r--engine/battle/misc.asm19
-rw-r--r--engine/battle/move_effects/transform.asm9
-rw-r--r--engine/battle/pikachu_entrance_anim.asm47
-rw-r--r--engine/battle/read_trainer_party.asm101
-rw-r--r--engine/battle/scale_sprites.asm7
-rw-r--r--engine/battle/trainer_ai.asm27
-rw-r--r--engine/battle/wild_encounters.asm7
18 files changed, 969 insertions, 465 deletions
diff --git a/engine/battle/animations.asm b/engine/battle/animations.asm
index 0673b518..4110e8b6 100644
--- a/engine/battle/animations.asm
+++ b/engine/battle/animations.asm
@@ -15,6 +15,8 @@ DrawFrameBlock:
ld a, [wFBTileCounter]
inc a
ld [wFBTileCounter], a
+ ld a, $2
+ ld [wdef5], a
ld a, [wSubAnimTransform]
dec a
jr z, .flipHorizontalAndVertical ; SUBANIMTYPE_HVFLIP
@@ -46,6 +48,12 @@ DrawFrameBlock:
.finishCopying ; finish copying values to OAM (when subanimation not transformed)
add [hl] ; X offset
ld [de], a ; store X
+ cp 88
+ jr c, .asm_78056
+ ld a, [wdef5]
+ inc a
+ ld [wdef5], a
+.asm_78056
inc hl
inc de
ld a, [hli]
@@ -53,6 +61,9 @@ DrawFrameBlock:
ld [de], a ; store tile ID
inc de
ld a, [hli]
+ ld b, a
+ ld a, [wdef5]
+ or b
ld [de], a ; store flags
inc de
jp .nextTile
@@ -71,6 +82,12 @@ DrawFrameBlock:
ld a, 168
sub b ; flip X coordinate
ld [de], a ; store X
+ cp 88
+ jr c, .asm_78087
+ ld a, [wdef5]
+ inc a
+ ld [wdef5], a
+.asm_78087
inc hl
inc de
ld a, [hli]
@@ -90,7 +107,8 @@ DrawFrameBlock:
jr z, .storeFlags1
ld b, 0
.storeFlags1
- ld a, b
+ ld a, [wdef5]
+ or b
ld [de], a
inc de
jp .nextTile
@@ -107,6 +125,12 @@ DrawFrameBlock:
ld a, 168
sub b ; flip X coordinate
ld [de], a ; store X
+ cp 88
+ jr c, .asm_780c8
+ ld a, [wdef5]
+ inc a
+ ld [wdef5], a
+.asm_780c8
inc hl
inc de
ld a, [hli]
@@ -122,6 +146,9 @@ DrawFrameBlock:
.disableHorizontalFlip
res 5, a
.storeFlags2
+ ld b, a
+ ld a, [wdef5]
+ or b
ld [de], a
inc de
.nextTile
@@ -245,11 +272,13 @@ PlayAnimation:
push af
ld a, [wAnimPalette]
ldh [rOBP0], a
+ call UpdateGBCPal_OBP0
call LoadAnimationTileset
call LoadSubanimation
call PlaySubanimation
pop af
ldh [rOBP0], a
+ call UpdateGBCPal_OBP0
.nextAnimationCommand
pop hl
jr .animationLoop
@@ -366,12 +395,7 @@ AnimationTileset2:
INCBIN "gfx/battle/attack_anim_2.2bpp"
SlotMachineTiles2:
-IF DEF(_RED)
- INCBIN "gfx/slots/red_slots_2.2bpp"
-ENDC
-IF DEF(_BLUE)
- INCBIN "gfx/slots/blue_slots_2.2bpp"
-ENDC
+ INCBIN "gfx/slots/slots_2.2bpp"
SlotMachineTiles2End:
MoveAnimation:
@@ -537,6 +561,8 @@ SetAnimationPalette:
ldh [rOBP0], a
ld a, $6c
ldh [rOBP1], a
+ call UpdateGBCPal_OBP0
+ call UpdateGBCPal_OBP1
ret
.notSGB
ld a, $e4
@@ -544,6 +570,28 @@ SetAnimationPalette:
ldh [rOBP0], a
ld a, $6c
ldh [rOBP1], a
+ call UpdateGBCPal_OBP0
+ call UpdateGBCPal_OBP1
+ ret
+
+Func_78e98:
+ call SaveScreenTilesToBuffer2
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ call ClearScreen
+ ld h, HIGH(vBGMap0)
+ call WriteLowerByteOfBGMapAndEnableBGTransfer
+ call Delay3
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ call LoadScreenTilesFromBuffer2
+ ld h, HIGH(vBGMap1)
+
+WriteLowerByteOfBGMapAndEnableBGTransfer:
+ ld l, LOW(vBGMap0)
+ call BattleAnimCopyTileMapToVRAM
+ ld a, $1
+ ldh [hAutoBGTransferEnabled], a
ret
PlaySubanimation:
@@ -659,6 +707,7 @@ DoBallTossSpecialEffects:
ldh a, [rOBP0]
xor %00111100 ; complement colors 1 and 2
ldh [rOBP0], a
+ call UpdateGBCPal_OBP0
.skipFlashingEffect
ld a, [wSubAnimCounter]
cp 11 ; is it the beginning of the subanimation?
@@ -948,6 +997,7 @@ AnimationFlashScreenLong:
cp $01 ; is it the end of the palettes?
jr z, .endOfPalettes
ldh [rBGP], a
+ call UpdateGBCPal_BGP
call FlashScreenLongDelay
jr .innerLoop
.endOfPalettes
@@ -1010,14 +1060,17 @@ AnimationFlashScreen:
push af ; save initial palette
ld a, %00011011 ; 0, 1, 2, 3 (inverted colors)
ldh [rBGP], a
+ call UpdateGBCPal_BGP
ld c, 2
call DelayFrames
xor a ; white out background
ldh [rBGP], a
+ call UpdateGBCPal_BGP
ld c, 2
call DelayFrames
pop af
ldh [rBGP], a ; restore initial palette
+ call UpdateGBCPal_BGP
ret
AnimationDarkScreenPalette:
@@ -1063,6 +1116,7 @@ SetAnimationBGPalette:
ld a, c
.next
ldh [rBGP], a
+ call UpdateGBCPal_BGP
ret
ld b, $5
@@ -1107,15 +1161,30 @@ AnimationWaterDropletsEverywhere:
_AnimationWaterDroplets:
ld hl, wOAMBuffer
.loop
+ ld a, $1
+ ld [wdef5], a
ld a, [wBaseCoordY]
ld [hli], a ; Y
+ cp 40
+ jr c, .asm_792d7
+ ld a, [wdef5]
+ inc a
+ ld [wdef5], a
+.asm_792d7
ld a, [wBaseCoordX]
add 27
ld [wBaseCoordX], a
ld [hli], a ; X
+ cp 88
+ jr c, .asm_792ee
+ ld a, [wdef5]
+ add $2
+ and $3
+ ld [wdef5], a
+.asm_792ee
ld a, [wDropletTile]
ld [hli], a ; tile
- xor a
+ ld a, [wdef5]
ld [hli], a ; attribute
ld a, [wBaseCoordX]
cp 144
@@ -1258,16 +1327,30 @@ BattleAnimWriteOAMEntry:
; Y coordinate = e (increased by 8 each call, before the write to OAM)
; X coordinate = [wBaseCoordX]
; tile = d
-; attributes = 0
+; attributes = variable (depending on coords)
+ ld a, $1
+ ld [wdef5], a
ld a, e
add 8
ld e, a
ld [hli], a
+ cp 40
+ jr c, .asm_793d8
+ ld a, [wdef5]
+ inc a
+ ld [wdef5], a
+.asm_793d8
ld a, [wBaseCoordX]
ld [hli], a
+ cp 88
+ jr c, .asm_793e8
+ ld a, [wdef5]
+ add $2
+ ld [wdef5], a
+.asm_793e8
ld a, d
ld [hli], a
- xor a
+ ld a, [wdef5]
ld [hli], a
ret
@@ -1472,6 +1555,8 @@ AnimationSpiralBallsInward:
ld a, [hl]
cp $ff
jr z, .done
+ ld a, $2
+ ld [wdef5], a
ld a, [wSpiralBallsBaseY]
add [hl]
ld [de], a ; Y
@@ -1480,9 +1565,20 @@ AnimationSpiralBallsInward:
ld a, [wSpiralBallsBaseX]
add [hl]
ld [de], a ; X
+ cp 88
+ jr c, .asm_79524
+ ld a, $3
+ ld [wdef5], a
+.asm_79524
inc hl
inc de
inc de
+ ld a, [de]
+ and $f0
+ ld b, a
+ ld a, [wdef5]
+ or b
+ ld [de], a
inc de
dec c
jr nz, .innerLoop
@@ -1794,10 +1890,8 @@ _AnimationSlideMonOff:
.PlayerNextTile
ld a, [hl]
add 7
-; This is a bug. The lower right corner tile of the mon back pic is blanked
-; while the mon is sliding off the screen. It should compare with the max tile
-; plus one instead.
- cp $61
+; bugfix: compares against the max tile + 1 as opposed to the max tile
+ cp $62
ret c
ld a, " "
ret
@@ -1934,18 +2028,24 @@ AnimationSubstitute:
CopyMonsterSpriteData:
ld bc, 1 tiles
ld a, BANK(MonsterSprite)
- jp FarCopyData2
+ jp FarCopyData
HideSubstituteShowMonAnim:
ldh a, [hWhoseTurn]
and a
ld hl, wPlayerMonMinimized
+ ld de, wPlayerBattleStatus1
+ ld bc, wPlayerMoveNum
ld a, [wPlayerBattleStatus2]
jr z, .next1
ld hl, wEnemyMonMinimized
+ ld de, wEnemyBattleStatus1
+ ld bc, wEnemyMoveNum
ld a, [wEnemyBattleStatus2]
.next1
push hl
+ push de
+ push bc
; if the substitute broke, slide it down, else slide it offscreen horizontally
bit HAS_SUBSTITUTE_UP, a
jr nz, .substituteStillUp
@@ -1954,12 +2054,65 @@ HideSubstituteShowMonAnim:
.substituteStillUp
call AnimationSlideMonOff
.next2
+ pop bc
+ pop de
+ ld a, [de]
+ bit INVULNERABLE, a
pop hl
+ jr nz, .invulnerable
+ ld a, [bc]
+ cp FLY
+ jr z, .flyOrDig
+ cp DIG
+ jr z, .flyOrDig
+.invulnerable
ld a, [hl]
and a
jp nz, AnimationMinimizeMon
call AnimationFlashMonPic
jp AnimationShowMonPic
+.flyOrDig
+ ldh a, [hWhoseTurn]
+ and a
+ jr nz, .enemy
+ ld a, [wPlayerMonMinimized]
+ and a
+ jr nz, .monIsMinimized
+ ld a, [wBattleMonSpecies]
+ ld [wcf91], a
+ ld [wd0b5], a
+ call GetMonHeader
+ predef LoadMonBackPic
+ ret
+.enemy
+ ld a, [wEnemyMonMinimized]
+ and a
+ jr nz, .monIsMinimized
+ ld a, [wEnemyMonSpecies]
+ ld [wcf91], a
+ ld [wd0b5], a
+ call GetMonHeader
+ ld de, vFrontPic
+ jp LoadMonFrontSprite
+.monIsMinimized
+ ld hl, wTempPic
+ push hl
+ xor a
+ ld bc, 7 * 7 * $10
+ call FillMemory
+ pop hl
+ ld de, $194
+ add hl, de
+ ld de, MinimizedMonSprite
+ ld c, MinimizedMonSpriteEnd - MinimizedMonSprite
+.loop
+ ld a, [de]
+ ld [hli], a
+ ld [hli], a
+ inc de
+ dec c
+ jr nz, .loop
+ jp CopyTempPicToMonPic
ReshowSubstituteAnim:
call AnimationSlideMonOff
@@ -2027,6 +2180,23 @@ AnimationHideEnemyMonPic:
ldh [hAutoBGTransferEnabled], a
jp Delay3
+Func_79929:
+ ld hl, wPlayerMonMinimized
+ ldh a, [hWhoseTurn]
+ and a
+ jr z, .playerTurn
+ ld hl, wEnemyMonMinimized
+.playerTurn
+ ld a, [hl]
+ and a
+ jr z, .notMinimized
+ call AnimationMinimizeMon
+ ret
+.notMinimized
+ call AnimationFlashMonPic
+ call AnimationShowMonPic
+ ret
+
InitMultipleObjectsOAM:
; Writes c OAM entries with tile d.
; Sets their Y coordinates to sequential multiples of 8, starting from 0.
@@ -2048,6 +2218,8 @@ InitMultipleObjectsOAM:
jr nz, .loop
ret
+ ret ; unreferenced
+
AnimationHideMonPic:
; Hides the mon's sprite.
ldh a, [hWhoseTurn]
@@ -2270,17 +2442,13 @@ INCLUDE "data/tilemaps.asm"
AnimationLeavesFalling:
; Makes leaves float down from the top of the screen. This is used
; in Razor Leaf's animation.
- ldh a, [rOBP0]
- push af
ld a, [wAnimPalette]
ldh [rOBP0], a
+ call UpdateGBCPal_OBP0
ld d, $37 ; leaf tile
ld a, 3 ; number of leaves
ld [wNumFallingObjects], a
- call AnimationFallingObjects
- pop af
- ldh [rOBP0], a
- ret
+ jp AnimationFallingObjects
AnimationPetalsFalling:
; Makes lots of petals fall down from the top of the screen. It's used in
@@ -2335,6 +2503,8 @@ FallingObjects_UpdateOAMEntry:
; movement byte.
ld hl, wOAMBuffer
add hl, de
+ ld a, $1
+ ld [wdef5], a
ld a, [hl]
inc a
inc a
@@ -2343,6 +2513,12 @@ FallingObjects_UpdateOAMEntry:
ld a, 160 ; if Y >= 112, put it off-screen
.next
ld [hli], a ; Y
+ cp 40
+ jr c, .asm_79e51
+ ld a, [wdef5]
+ inc a
+ ld [wdef5], a
+.asm_79e51
ld a, [wFallingObjectMovementByte]
ld b, a
ld de, FallingObjects_DeltaXs
@@ -2359,6 +2535,13 @@ FallingObjects_UpdateOAMEntry:
ld a, [de]
add [hl]
ld [hli], a ; X
+ cp 88
+ jr c, .asm_79e75
+ ld a, [wdef5]
+ add $2
+ and $3
+ ld [wdef5], a
+.asm_79e75
inc hl
xor a ; no horizontal flip
jr .next2
@@ -2368,9 +2551,19 @@ FallingObjects_UpdateOAMEntry:
ld a, [hl]
sub b
ld [hli], a ; X
+ cp 88
+ jr c, .asm_79e5c
+ ld a, [wdef5]
+ add $2
+ and $3
+ ld [wdef5], a
+.asm_79e5c
inc hl
ld a, (1 << OAM_X_FLIP)
.next2
+ ld b, a
+ ld a, [wdef5]
+ or b
ld [hl], a ; attribute
ret
@@ -2455,6 +2648,14 @@ AnimationShakeEnemyHUD:
ld hl, vBGMap1 - $20 * 7
call BattleAnimCopyTileMapToVRAM
+; update BGMap attributes
+ ldh a, [hGBC]
+ and a
+ jr z, .notGBC
+ ld c, 13
+ farcall LoadBGMapAttributes
+.notGBC
+
; Move the window so that the row below the enemy HUD (in BG map 0) lines up
; with the top row of the window on the screen. This makes it so that the window
; covers everything below the enemy HD with a copy that looks just like what
@@ -2488,13 +2689,18 @@ AnimationShakeEnemyHUD:
ldh [hWY], a
ld hl, vBGMap1
call BattleAnimCopyTileMapToVRAM
+; update BGMap attributes
+ ldh a, [hGBC]
+ and a
+ jr z, .notGBC2
+ ld c, 11
+ farcall LoadBGMapAttributes
+.notGBC2
xor a
ldh [hWY], a
call SaveScreenTilesToBuffer1
ld hl, vBGMap0
call BattleAnimCopyTileMapToVRAM
- call ClearScreen
- call Delay3
call LoadScreenTilesFromBuffer1
ld hl, vBGMap1
jp BattleAnimCopyTileMapToVRAM
diff --git a/engine/battle/battle_transitions.asm b/engine/battle/battle_transitions.asm
index 90e99f98..6d3a4f9c 100644
--- a/engine/battle/battle_transitions.asm
+++ b/engine/battle/battle_transitions.asm
@@ -163,6 +163,9 @@ BattleTransition_BlackScreen:
ldh [rBGP], a
ldh [rOBP0], a
ldh [rOBP1], a
+ call UpdateGBCPal_BGP
+ call UpdateGBCPal_OBP0
+ call UpdateGBCPal_OBP1
ret
; for non-dungeon trainer battles
@@ -326,6 +329,7 @@ BattleTransition_FlashScreen_:
cp 1
jr z, .done
ldh [rBGP], a
+ call UpdateGBCPal_BGP
ld c, 2
call DelayFrames
jr .loop
diff --git a/engine/battle/common_text.asm b/engine/battle/common_text.asm
index 0e270424..95c06bf5 100644
--- a/engine/battle/common_text.asm
+++ b/engine/battle/common_text.asm
@@ -8,8 +8,20 @@ PrintBeginningBattleText:
cp POKEMON_TOWER_7F + 1
jr c, .pokemonTower
.notPokemonTower
+ ld a, [wBattleType]
+ cp BATTLE_TYPE_PIKACHU
+ jr nz, .notPikachuBattle
+ callfar IsPlayerPikachuAsleepInParty
+ ld e, $24
+ jr c, .asm_f4026
+ ld e, $a
+.asm_f4026
+ callfar PlayPikachuSoundClip
+ jr .continue
+.notPikachuBattle
ld a, [wEnemyMonSpecies2]
call PlayCry
+.continue
ld hl, WildMonAppearedText
ld a, [wMoveMissed]
and a
@@ -23,9 +35,13 @@ PrintBeginningBattleText:
call DelayFrames
ld hl, TrainerWantsToFightText
.wildBattle
+ ld a, [wBattleType]
+ and a
+ jr nz, .doNotDrawPokeballs
push hl
callfar DrawAllPokeballs
pop hl
+.doNotDrawPokeballs
call PrintText
jr .done
.pokemonTower
diff --git a/engine/battle/core.asm b/engine/battle/core.asm
index 417516ae..053d6a1e 100644
--- a/engine/battle/core.asm
+++ b/engine/battle/core.asm
@@ -67,6 +67,9 @@ SlidePlayerAndEnemySilhouettesOnScreen:
ldh [rBGP], a
ldh [rOBP0], a
ldh [rOBP1], a
+ call UpdateGBCPal_BGP
+ call UpdateGBCPal_OBP0
+ call UpdateGBCPal_OBP1
.slideSilhouettesLoop ; slide silhouettes of the player's pic and the enemy's pic onto the screen
ld h, b
ld l, $40
@@ -156,10 +159,16 @@ StartBattle:
call DelayFrames
call SaveScreenTilesToBuffer1
.checkAnyPartyAlive
+ ld a, [wBattleType]
+ cp BATTLE_TYPE_RUN
+ jp z, .specialBattle
+ cp BATTLE_TYPE_PIKACHU
+ jp z, .specialBattle
call AnyPartyAlive
ld a, d
and a
jp z, HandlePlayerBlackOut ; jump if no mon is alive
+.specialBattle
call LoadScreenTilesFromBuffer1
ld a, [wBattleType]
and a ; is it a normal battle?
@@ -893,6 +902,11 @@ ReplaceFaintedEnemyMon:
ld hl, wEnemyHPBarColor
ld e, $30
call GetBattleHealthBarColor
+ ldpal a, SHADE_BLACK, SHADE_DARK, SHADE_LIGHT, SHADE_WHITE
+ ldh [rOBP0], a
+ ldh [rOBP1], a
+ call UpdateGBCPal_OBP0
+ call UpdateGBCPal_OBP1
callfar DrawEnemyPokeballs
ld a, [wLinkState]
cp LINK_STATE_BATTLING
@@ -958,9 +972,7 @@ TrainerDefeatedText:
PlayBattleVictoryMusic:
push af
- ld a, SFX_STOP_ALL_MUSIC
- ld [wNewSoundID], a
- call PlaySoundWaitForCurrent
+ call StopAllMusic
ld c, BANK(Music_DefeatedTrainer)
pop af
call PlayMusic
@@ -1014,6 +1026,7 @@ RemoveFaintedPlayerMon:
ld a, $ff
ld [wLowHealthAlarm], a ;disable low health alarm
call WaitForSoundToFinish
+ xor a
.skipWaitForSound
; a is 0, so this zeroes the enemy's accumulated damage.
ld hl, wEnemyBideAccumulatedDamage
@@ -1038,10 +1051,36 @@ RemoveFaintedPlayerMon:
and a ; was this called by HandleEnemyMonFainted?
ret z ; if so, return
+ ld a, [wPlayerMonNumber]
+ ld [wWhichPokemon], a
+ callfar IsThisPartymonStarterPikachu_Party
+ jr nc, .notPlayerPikachu
+ ld e, $3
+ callfar PlayPikachuSoundClip
+ jr .printText
+.notPlayerPikachu
ld a, [wBattleMonSpecies]
call PlayCry
+.printText
ld hl, PlayerMonFaintedText
- jp PrintText
+ call PrintText
+ ld a, [wPlayerMonNumber]
+ ld [wWhichPokemon], a
+ ld a, [wBattleMonLevel]
+ ld b, a
+ ld a, [wEnemyMonLevel]
+ sub b ; enemylevel - playerlevel
+ ; are we stronger than the opposing pokemon?
+ jr c, .regularFaint ; if so, deduct happiness regularly
+
+ cp 30 ; is the enemy 30 levels greater than us?
+ jr nc, .carelessTrainer ; if so, punish the player for being careless, as they shouldn't be fighting a very high leveled trainer with such a level difference
+.regularFaint
+ callabd_ModifyPikachuHappiness PIKAHAPPY_FAINTED
+ ret
+.carelessTrainer
+ callabd_ModifyPikachuHappiness PIKAHAPPY_CARELESSTRAINER
+ ret
PlayerMonFaintedText:
text_far _PlayerMonFaintedText
@@ -1098,7 +1137,7 @@ ChooseNextMon:
ld a, [wLinkState]
cp LINK_STATE_BATTLING
jr nz, .notLinkBattle
- inc a ; 1
+ ld a, 1
ld [wActionResultOrTookBattleTurn], a
call LinkBattleExchangeData
.notLinkBattle
@@ -1498,6 +1537,8 @@ TryRunningFromBattle:
ld a, [wBattleType]
cp BATTLE_TYPE_SAFARI
jp z, .canEscape ; jump if it's a safari battle
+ cp BATTLE_TYPE_RUN
+ jp z, .canEscape ; hurry, get away?
ld a, [wLinkState]
cp LINK_STATE_BATTLING
jp z, .canEscape
@@ -1753,19 +1794,46 @@ SendOutMon:
call RunPaletteCommand
ld hl, wEnemyBattleStatus1
res USING_TRAPPING_MOVE, [hl]
+ callfar IsThisPartymonStarterPikachu
+ jr c, .starterPikachu
ld a, $1
ldh [hWhoseTurn], a
ld a, POOF_ANIM
call PlayMoveAnimation
hlcoord 4, 11
predef AnimateSendingOutMon
+ jr .playRegularCry
+.starterPikachu
+ xor a
+ ldh [hWhoseTurn], a
+ ld a, $1
+ ldh [hAutoBGTransferEnabled], a
+ callfar StarterPikachuBattleEntranceAnimation
+ callfar IsPlayerPikachuAsleepInParty
+ ld e, $24
+ jr c, .asm_3cd81
+ ld e, $a
+.asm_3cd81
+ callfar PlayPikachuSoundClip
+ jr .done
+.playRegularCry
ld a, [wcf91]
call PlayCry
+.done
call PrintEmptyString
jp SaveScreenTilesToBuffer1
; show 2 stages of the player mon getting smaller before disappearing
AnimateRetreatingPlayerMon:
+ ld a, [wWhichPokemon]
+ push af
+ ld a, [wPlayerMonNumber]
+ ld [wWhichPokemon], a
+ callfar IsThisPartymonStarterPikachu
+ pop bc
+ ld a, b
+ ld [wWhichPokemon], a
+ jr c, .starterPikachu
hlcoord 1, 5
lb bc, 7, 7
call ClearScreenArea
@@ -1789,10 +1857,17 @@ AnimateRetreatingPlayerMon:
call .clearScreenArea
ld a, $4c
ldcoord_a 5, 11
+ jr .clearScreenArea
+.starterPikachu
+ xor a
+ ldh [hWhoseTurn], a
+ callfar AnimationSlideMonOff
+ ret
.clearScreenArea
hlcoord 1, 5
lb bc, 7, 7
- jp ClearScreenArea
+ call ClearScreenArea
+ ret
; reads player's current mon's HP into wBattleMonHP
ReadPlayerMonCurHPAndStatus:
@@ -2013,40 +2088,52 @@ DisplayBattleMenu::
.menuselected
ld [wTextBoxID], a
call DisplayTextBoxID
- ; handle menu input if it's not the old man tutorial
+ ; handle menu input if it's not the old man tutorial or prof. oak pikachu battle
ld a, [wBattleType]
- dec a
- jp nz, .handleBattleMenuInput
-; the following happens for the old man tutorial
+ cp BATTLE_TYPE_OLD_MAN
+ jr z, .doSimulatedMenuInput
+ cp BATTLE_TYPE_PIKACHU
+ jr z, .doSimulatedMenuInput
+ jp .handleBattleMenuInput
+; the following happens for the old man tutorial and prof. oak pikachu battle
+.doSimulatedMenuInput
; Temporarily save the player name in wLinkEnemyTrainerName.
; Since wLinkEnemyTrainerName == wGrassRate, this affects wild encounters.
; The wGrassRate byte and following wGrassMons buffer are supposed
; to get overwritten when entering a map with wild Pokémon,
; but an oversight prevents this in Cinnabar and Route 21,
; so the infamous MissingNo. glitch can show up.
+ ; However, this has been fixed in Yellow.
ld hl, wPlayerName
ld de, wLinkEnemyTrainerName
ld bc, NAME_LENGTH
call CopyData
ld hl, .oldManName
+ ld a, [wBattleType]
+ dec a
+ jr z, .useOldManName
+ ld hl, .profOakName
+.useOldManName
ld de, wPlayerName
ld bc, NAME_LENGTH
call CopyData
; the following simulates the keystrokes by drawing menus on screen
hlcoord 9, 14
ld [hl], "▶"
- ld c, 80
+ ld c, 20
call DelayFrames
ld [hl], " "
hlcoord 9, 16
ld [hl], "▶"
- ld c, 50
+ ld c, 20
call DelayFrames
ld [hl], "▷"
ld a, $2 ; select the "ITEM" menu
jp .upperLeftMenuItemWasNotSelected
.oldManName
db "OLD MAN@"
+.profOakName
+ db "PROF.OAK@"
.handleBattleMenuInput
ld a, [wBattleAndStartSavedMenuItem]
ld [wCurrentMenuItem], a
@@ -2129,6 +2216,9 @@ DisplayBattleMenu::
.AButtonPressed
call PlaceUnfilledArrowMenuCursor
ld a, [wBattleType]
+ cp BATTLE_TYPE_RUN
+ jr z, .handleUnusedBattle
+ ld a, [wBattleType]
cp BATTLE_TYPE_SAFARI
ld a, [wCurrentMenuItem]
ld [wBattleAndStartSavedMenuItem], a
@@ -2160,7 +2250,18 @@ DisplayBattleMenu::
.throwSafariBallWasSelected
ld a, SAFARI_BALL
ld [wcf91], a
- jr UseBagItem
+ jp UseBagItem
+.handleUnusedBattle
+ ld a, [wCurrentMenuItem]
+ cp $3
+ jp z, BattleMenu_RunWasSelected
+ ld hl, .RunAwayText
+ call PrintText
+ jp DisplayBattleMenu
+
+.RunAwayText
+ text_far _RunAwayText
+ text_end
.upperLeftMenuItemWasNotSelected ; a menu item other than the upper left item was selected
cp $2
@@ -2197,18 +2298,22 @@ BagWasSelected:
call DrawHUDsAndHPBars
.next
ld a, [wBattleType]
- dec a ; is it the old man tutorial?
- jr nz, DisplayPlayerBag ; no, it is a normal battle
- ld hl, OldManItemList
+ cp BATTLE_TYPE_OLD_MAN ; is it the old man tutorial?
+ jr z, .simulatedInputBattle
+ cp BATTLE_TYPE_PIKACHU ; is it the prof oak battle with pikachu?
+ jr z, .simulatedInputBattle
+ jr DisplayPlayerBag
+.simulatedInputBattle
+ ld hl, SimulatedInputBattleItemList
ld a, l
ld [wListPointer], a
ld a, h
ld [wListPointer + 1], a
jr DisplayBagMenu
-OldManItemList:
+SimulatedInputBattleItemList:
db 1 ; # items
- db POKE_BALL, 50
+ db POKE_BALL, 1
db -1 ; end
DisplayPlayerBag:
@@ -2368,6 +2473,8 @@ PartyMenuOrRockOrRun:
predef StatusScreen
predef StatusScreen2
; now we need to reload the enemy mon pic
+ ld a, 1
+ ldh [hWhoseTurn], a
ld a, [wEnemyBattleStatus2]
bit HAS_SUBSTITUTE_UP, a ; does the enemy mon have a substitute?
ld hl, AnimationSubstitute
@@ -2472,13 +2579,13 @@ MoveSelectionMenu:
.writemoves
ld de, wMovesString
- ldh a, [hFlagsFFF6]
+ ldh a, [hFlagsFFFA]
set 2, a
- ldh [hFlagsFFF6], a
+ ldh [hFlagsFFFA], a
call PlaceString
- ldh a, [hFlagsFFF6]
+ ldh a, [hFlagsFFFA]
res 2, a
- ldh [hFlagsFFF6], a
+ ldh [hFlagsFFFA], a
ret
.regularmenu
@@ -2487,8 +2594,7 @@ MoveSelectionMenu:
ld hl, wBattleMonMoves
call .loadmoves
hlcoord 4, 12
- ld b, 4
- ld c, 14
+ lb bc, 4, 14
di ; out of pure coincidence, it is possible for vblank to occur between the di and ei
; so it is necessary to put the di ei block to not cause tearing
call TextBoxBorder
@@ -2506,8 +2612,7 @@ MoveSelectionMenu:
ld hl, wEnemyMonMoves
call .loadmoves
hlcoord 0, 7
- ld b, 4
- ld c, 14
+ lb bc, 4, 14
call TextBoxBorder
hlcoord 2, 8
call .writemoves
@@ -2521,8 +2626,7 @@ MoveSelectionMenu:
call AddNTimes
call .loadmoves
hlcoord 4, 7
- ld b, 4
- ld c, 14
+ lb bc, 4, 14
call TextBoxBorder
hlcoord 6, 8
call .writemoves
@@ -2536,8 +2640,6 @@ MoveSelectionMenu:
ld a, [wMoveMenuType]
cp $1
jr z, .selectedmoveknown
- ld a, $1
- jr nc, .selectedmoveknown
ld a, [wPlayerMoveListIndex]
inc a
.selectedmoveknown
@@ -2598,10 +2700,10 @@ SelectMenuItem:
call AddNTimes
ld [hl], "▷"
.select
- ld hl, hFlagsFFF6
+ ld hl, hFlagsFFFA
set 1, [hl]
call HandleMenuInput
- ld hl, hFlagsFFF6
+ ld hl, hFlagsFFFA
res 1, [hl]
bit BIT_D_UP, a
jp nz, SelectMenuItem_CursorUp
@@ -2609,6 +2711,14 @@ SelectMenuItem:
jp nz, SelectMenuItem_CursorDown
bit BIT_SELECT, a
jp nz, SwapMovesInMenu
+IF DEF(_DEBUG)
+ bit BIT_START, a
+ jp nz, Func_3d4f5
+ bit BIT_D_RIGHT, a
+ jp nz, Func_3d529
+ bit BIT_D_LEFT, a
+ jp nz, Func_3d523
+ENDC
bit BIT_B_BUTTON, a
push af
xor a
@@ -2703,6 +2813,55 @@ SelectMenuItem_CursorDown:
ld [wCurrentMenuItem], a
jp SelectMenuItem
+Func_3d4f5:
+ bit 3, a
+ ld a, $0
+ jr nz, .asm_3d4fd
+ ld a, $1
+.asm_3d4fd
+ ldh [hWhoseTurn], a
+ call LoadScreenTilesFromBuffer1
+ call Func_3d536
+ ld a, [wTestBattlePlayerSelectedMove]
+ and a
+ jp z, MoveSelectionMenu
+ ld [wAnimationID], a
+ xor a
+ ld [wAnimationType], a
+ predef MoveAnimation
+ callfar Func_78e98
+ jp MoveSelectionMenu
+
+Func_3d523:
+ ld a, [wTestBattlePlayerSelectedMove]
+ dec a
+ jr asm_3d52d
+Func_3d529:
+ ld a, [wTestBattlePlayerSelectedMove]
+ inc a
+asm_3d52d:
+ ld [wTestBattlePlayerSelectedMove], a
+ call Func_3d536
+ jp MoveSelectionMenu
+
+Func_3d536:
+ hlcoord 10, 16
+ lb bc, 2, 10
+ call ClearScreenArea
+ hlcoord 10, 17
+ ld de, wTestBattlePlayerSelectedMove
+ lb bc, LEADING_ZEROES | 1, 3
+ call PrintNumber
+ ld a, [wTestBattlePlayerSelectedMove]
+ and a
+ ret z
+ cp STRUGGLE
+ ret nc
+ ld [wd11e], a
+ call GetMoveName
+ hlcoord 13, 17
+ jp PlaceString
+
AnyMoveToSelect:
; return z and Struggle as the selected move if all moves have 0 PP and/or are disabled
ld a, STRUGGLE
@@ -2736,7 +2895,10 @@ AnyMoveToSelect:
or c
jr .handleDisabledMovePPLoop
.allMovesChecked
- and a ; any PP left?
+; bugfix: only check PP value and not PP up bits
+; in case all other moves have no PP left and a move has a PP up used on it
+; and a non-PP up move is disabled
+ and $3f ; any PP left?
ret nz ; return if a move has PP left
.noMovesLeft
ld hl, NoMovesLeftText
@@ -2751,6 +2913,14 @@ NoMovesLeftText:
text_end
SwapMovesInMenu:
+IF DEF(_DEBUG)
+ ld a, [wFlags_D733]
+ bit BIT_TEST_BATTLE, a
+ jp nz, Func_3d4f5
+ENDC
+ ld a, [wPlayerBattleStatus3]
+ bit TRANSFORMED, a
+ jp nz, MoveSelectionMenu
ld a, [wMenuItemToSwap]
and a
jr z, .noMenuItemSelected
@@ -2830,8 +3000,7 @@ PrintMenuItem:
xor a
ldh [hAutoBGTransferEnabled], a
hlcoord 0, 8
- ld b, 3
- ld c, 9
+ lb bc, 3, 9
call TextBoxBorder
ld a, [wPlayerDisabledMove]
and a
@@ -2898,7 +3067,7 @@ PrintMenuItem:
jp Delay3
DisabledText:
- db "disabled!@"
+ db "Disabled!@"
TypeText:
db "TYPE@"
@@ -4991,7 +5160,7 @@ AttackSubstitute:
ldh a, [hWhoseTurn]
xor $01
ldh [hWhoseTurn], a
- callfar HideSubstituteShowMonAnim ; animate the substitute breaking
+ callfar Func_79929 ; animate the substitute breaking
; flip the turn back to the way it was
ldh a, [hWhoseTurn]
xor $01
@@ -5322,6 +5491,17 @@ AIGetTypeEffectiveness:
inc hl
jr .loop
.done
+ ; 40% chance for Lorelei's Dewgong to ignore type effectiveness?
+ ld a, [wTrainerClass]
+ cp LORELEI
+ jr nz, .ok
+ ld a, [wEnemyMonSpecies]
+ cp DEWGONG
+ jr nz, .ok
+ call BattleRandom
+ cp $66 ; 40 percent
+ ret c
+.ok
ld a, [hl]
ld [wTypeEffectiveness], a ; store damage multiplier
ret
@@ -6302,10 +6482,13 @@ SwapPlayerAndEnemyLevels:
; (for use when scrolling the player sprite and enemy's silhouettes on screen)
LoadPlayerBackPic:
ld a, [wBattleType]
- dec a ; is it the old man tutorial?
- ld de, RedPicBack
- jr nz, .next
ld de, OldManPicBack
+ cp BATTLE_TYPE_OLD_MAN ; is it the old man tutorial?
+ jr z, .next
+ ld de, ProfOakPicBack
+ cp BATTLE_TYPE_PIKACHU ; is it the pikachu battle at the beginning of the game?
+ jr z, .next
+ ld de, RedPicBack
.next
ld a, BANK(RedPicBack)
call UncompressSpriteFromDE
@@ -6330,6 +6513,8 @@ LoadPlayerBackPic:
ld [hli], a ; OAM tile number
inc a ; increment tile number
ldh [hOAMTile], a
+ ld a, $2
+ ld [hl], a
inc hl
dec c
jr nz, .innerLoop
@@ -6343,18 +6528,15 @@ LoadPlayerBackPic:
jr nz, .loop
ld de, vBackPic
call InterlaceMergeSpriteBuffers
- ld a, $a
- ld [MBC1SRamEnable], a
- xor a
- ld [MBC1SRamBank], a
+ ld a, $0
+ call SwitchSRAMBankAndLatchClockData
ld hl, vSprites
ld de, sSpriteBuffer1
ldh a, [hLoadedROMBank]
ld b, a
ld c, 7 * 7
call CopyVideoData
- xor a
- ld [MBC1SRamEnable], a
+ call PrepareRTCDataAndDisableSRAM
ld a, $31
ldh [hStartTileID], a
hlcoord 1, 5
@@ -6726,288 +6908,6 @@ HandleExplodingAnimation:
PlayMoveAnimation:
ld [wAnimationID], a
call Delay3
- predef_jump MoveAnimation
-
-InitBattle::
- ld a, [wCurOpponent]
- and a
- jr z, DetermineWildOpponent
-
-InitOpponent:
- ld a, [wCurOpponent]
- ld [wcf91], a
- ld [wEnemyMonSpecies2], a
- jr InitBattleCommon
-
-DetermineWildOpponent:
- ld a, [wd732]
- bit 1, a
- jr z, .asm_3ef2f
- ldh a, [hJoyHeld]
- bit 1, a ; B button pressed?
- ret nz
-.asm_3ef2f
- ld a, [wNumberOfNoRandomBattleStepsLeft]
- and a
- ret nz
- callfar TryDoWildEncounter
- ret nz
-InitBattleCommon:
- ld a, [wMapPalOffset]
- push af
- ld hl, wLetterPrintingDelayFlags
- ld a, [hl]
- push af
- res 1, [hl]
- callfar InitBattleVariables
- ld a, [wEnemyMonSpecies2]
- sub OPP_ID_OFFSET
- jp c, InitWildBattle
- ld [wTrainerClass], a
- call GetTrainerInformation
- callfar ReadTrainer
- call DoBattleTransitionAndInitBattleVariables
- call _LoadTrainerPic
- xor a
- ld [wEnemyMonSpecies2], a
- ldh [hStartTileID], a
- dec a
- ld [wAICount], a
- hlcoord 12, 0
- predef CopyUncompressedPicToTilemap
- ld a, $ff
- ld [wEnemyMonPartyPos], a
- ld a, $2
- ld [wIsInBattle], a
- jp _InitBattleCommon
-
-InitWildBattle:
- ld a, $1
- ld [wIsInBattle], a
- call LoadEnemyMonData
- call DoBattleTransitionAndInitBattleVariables
- ld a, [wCurOpponent]
- cp RESTLESS_SOUL
- jr z, .isGhost
- call IsGhostBattle
- jr nz, .isNoGhost
-.isGhost
- ld hl, wMonHSpriteDim
- ld a, $66
- ld [hli], a ; write sprite dimensions
- ld bc, GhostPic
- ld a, c
- ld [hli], a ; write front sprite pointer
- ld [hl], b
- ld hl, wEnemyMonNick ; set name to "GHOST"
- ld a, "G"
- ld [hli], a
- ld a, "H"
- ld [hli], a
- ld a, "O"
- ld [hli], a
- ld a, "S"
- ld [hli], a
- ld a, "T"
- ld [hli], a
- ld [hl], "@"
- ld a, [wcf91]
- push af
- ld a, MON_GHOST
- ld [wcf91], a
- ld de, vFrontPic
- call LoadMonFrontSprite ; load ghost sprite
- pop af
- ld [wcf91], a
- jr .spriteLoaded
-.isNoGhost
- ld de, vFrontPic
- call LoadMonFrontSprite ; load mon sprite
-.spriteLoaded
- xor a
- ld [wTrainerClass], a
- ldh [hStartTileID], a
- hlcoord 12, 0
- predef CopyUncompressedPicToTilemap
-
-; common code that executes after init battle code specific to trainer or wild battles
-_InitBattleCommon:
- ld b, SET_PAL_BATTLE_BLACK
- call RunPaletteCommand
- call SlidePlayerAndEnemySilhouettesOnScreen
- xor a
- ldh [hAutoBGTransferEnabled], a
- ld hl, .emptyString
- call PrintText
- call SaveScreenTilesToBuffer1
- call ClearScreen
- ld a, $98
- ldh [hAutoBGTransferDest + 1], a
- ld a, $1
- ldh [hAutoBGTransferEnabled], a
- call Delay3
- ld a, $9c
- ldh [hAutoBGTransferDest + 1], a
- call LoadScreenTilesFromBuffer1
- hlcoord 9, 7
- lb bc, 5, 10
- call ClearScreenArea
- hlcoord 1, 0
- lb bc, 4, 10
- call ClearScreenArea
- call ClearSprites
- ld a, [wIsInBattle]
- dec a ; is it a wild battle?
- call z, DrawEnemyHUDAndHPBar ; draw enemy HUD and HP bar if it's a wild battle
- call StartBattle
- callfar EndOfBattle
- pop af
- ld [wLetterPrintingDelayFlags], a
- pop af
- ld [wMapPalOffset], a
- ld a, [wSavedTileAnimations]
- ldh [hTileAnimations], a
- scf
- ret
-.emptyString
- db "@"
-
-_LoadTrainerPic:
-; wd033-wd034 contain pointer to pic
- ld a, [wTrainerPicPointer]
- ld e, a
- ld a, [wTrainerPicPointer + 1]
- ld d, a ; de contains pointer to trainer pic
- ld a, [wLinkState]
- and a
- ld a, BANK(TrainerPics) ; this is where all the trainer pics are (not counting Red's)
- jr z, .loadSprite
- ld a, BANK(RedPicFront)
-.loadSprite
- call UncompressSpriteFromDE
- ld de, vFrontPic
- ld a, $77
- ld c, a
- jp LoadUncompressedSpriteData
-
-; unreferenced
-ResetCryModifiers:
- xor a
- ld [wFrequencyModifier], a
- ld [wTempoModifier], a
- jp PlaySound
-
-; animates the mon "growing" out of the pokeball
-AnimateSendingOutMon:
- ld a, [wPredefRegisters]
- ld h, a
- ld a, [wPredefRegisters + 1]
- ld l, a
- ldh a, [hStartTileID]
- ldh [hBaseTileID], a
- ld b, $4c
- ld a, [wIsInBattle]
- and a
- jr z, .notInBattle
- add b
- ld [hl], a
- call Delay3
- ld bc, -(SCREEN_WIDTH * 2 + 1)
- add hl, bc
- ld a, 1
- ld [wDownscaledMonSize], a
- lb bc, 3, 3
- predef CopyDownscaledMonTiles
- ld c, 4
- call DelayFrames
- ld bc, -(SCREEN_WIDTH * 2 + 1)
- add hl, bc
- xor a
- ld [wDownscaledMonSize], a
- lb bc, 5, 5
- predef CopyDownscaledMonTiles
- ld c, 5
- call DelayFrames
- ld bc, -(SCREEN_WIDTH * 2 + 1)
- jr .next
-.notInBattle
- ld bc, -(SCREEN_WIDTH * 6 + 3)
-.next
- add hl, bc
- ldh a, [hBaseTileID]
- add $31
- jr CopyUncompressedPicToHL
-
-CopyUncompressedPicToTilemap:
- ld a, [wPredefRegisters]
- ld h, a
- ld a, [wPredefRegisters + 1]
- ld l, a
- ldh a, [hStartTileID]
-CopyUncompressedPicToHL::
- lb bc, 7, 7
- ld de, SCREEN_WIDTH
- push af
- ld a, [wSpriteFlipped]
- and a
- jr nz, .flipped
- pop af
-.loop
- push bc
- push hl
-.innerLoop
- ld [hl], a
- add hl, de
- inc a
- dec c
- jr nz, .innerLoop
- pop hl
- inc hl
- pop bc
- dec b
- jr nz, .loop
- ret
-
-.flipped
- push bc
- ld b, 0
- dec c
- add hl, bc
- pop bc
- pop af
-.flippedLoop
- push bc
- push hl
-.flippedInnerLoop
- ld [hl], a
- add hl, de
- inc a
- dec c
- jr nz, .flippedInnerLoop
- pop hl
- dec hl
- pop bc
- dec b
- jr nz, .flippedLoop
+ predef MoveAnimation
+ callfar Func_78e98
ret
-
-LoadMonBackPic:
-; Assumes the monster's attributes have
-; been loaded with GetMonHeader.
- ld a, [wBattleMonSpecies2]
- ld [wcf91], a
- hlcoord 1, 5
- ld b, 7
- ld c, 8
- call ClearScreenArea
- ld hl, wMonHBackSprite - wMonHeader
- call UncompressMonSprite
- predef ScaleSpriteByTwo
- ld de, vBackPic
- call InterlaceMergeSpriteBuffers ; combine the two buffers to a single 2bpp sprite
- ld hl, vSprites
- ld de, vBackPic
- ld c, (2*SPRITEBUFFERSIZE)/16 ; count of 16-byte chunks to be copied
- ldh a, [hLoadedROMBank]
- ld b, a
- jp CopyVideoData
diff --git a/engine/battle/draw_hud_pokeball_gfx.asm b/engine/battle/draw_hud_pokeball_gfx.asm
index 097a0fcc..6aed1d0a 100644
--- a/engine/battle/draw_hud_pokeball_gfx.asm
+++ b/engine/battle/draw_hud_pokeball_gfx.asm
@@ -27,6 +27,8 @@ SetupOwnPartyPokeballs:
ld [hl], a
ld a, 8
ld [wHUDPokeballGfxOffsetX], a
+ xor a
+ ld [wdef5], a
ld hl, wOAMBuffer
jp WritePokeballOAMData
@@ -41,6 +43,8 @@ SetupEnemyPartyPokeballs:
ld [hl], $20
ld a, -8
ld [wHUDPokeballGfxOffsetX], a
+ ld a, $1
+ ld [wdef5], a
ld hl, wOAMBuffer + PARTY_LENGTH * 4
jp WritePokeballOAMData
@@ -104,7 +108,7 @@ WritePokeballOAMData:
ld [hli], a
ld a, [de]
ld [hli], a
- xor a
+ ld a, [wdef5]
ld [hli], a
ld a, [wBaseCoordX]
ld b, a
@@ -174,6 +178,8 @@ SetupPlayerAndEnemyPokeballs:
ld [hl], $40
ld a, 8
ld [wHUDPokeballGfxOffsetX], a
+ xor a
+ ld [wdef5], a
ld hl, wOAMBuffer
call WritePokeballOAMData
ld hl, wEnemyMons
@@ -183,6 +189,8 @@ SetupPlayerAndEnemyPokeballs:
ld a, $50
ld [hli], a
ld [hl], $68
+ ld a, $1
+ ld [wdef5], a
ld hl, wOAMBuffer + $18
jp WritePokeballOAMData
diff --git a/engine/battle/effects.asm b/engine/battle/effects.asm
index f455a407..7573ce8d 100644
--- a/engine/battle/effects.asm
+++ b/engine/battle/effects.asm
@@ -60,6 +60,16 @@ SleepEffect:
call BattleRandom
and $7
jr z, .setSleepCounter
+ ld b, a
+ ld a, [wUnknownSerialFlag_d499]
+ and a
+ jr z, .asm_3f1ba ; XXX stadium stuff?
+ ld a, b
+ and $3
+ jr z, .setSleepCounter
+ ld b, a
+.asm_3f1ba
+ ld a, b
ld [de], a
call PlayCurrentMoveAnimation2
ld hl, FellAsleepText
@@ -211,6 +221,16 @@ FreezeBurnParalyzeEffect:
cp b ; do target type 2 and move type match?
ret z ; return if they match
ld a, [wPlayerMoveEffect]
+ cp UNUSED_EFFECT_23 ; more stadium stuff
+ jr nz, .asm_3f2c7
+ ld a, [wUnknownSerialFlag_d499]
+ and a
+ ld a, FREEZE_SIDE_EFFECT
+ ld b, $4d ; else use 0x4D/0x100 or 77/256 = 30.1%~ chance
+ jr z, .next1
+ ld b, $1a ; 0x1A/0x100 or 26/256 = 10.2%~ chance
+ jr .next1
+.asm_3f2c7
cp PARALYZE_SIDE_EFFECT1 + 1 ; 10% status effects are 04, 05, 06 so 07 will set carry for those
ld b, $1a ; 0x1A/0x100 or 26/256 = 10.2%~ chance
jr c, .next1 ; branch ahead if this is a 10% chance effect..
@@ -263,6 +283,16 @@ FreezeBurnParalyzeEffect:
cp b
ret z
ld a, [wEnemyMoveEffect]
+ cp UNUSED_EFFECT_23 ; more stadium stuff
+ jr nz, .asm_3f341
+ ld a, [wUnknownSerialFlag_d499]
+ and a
+ ld a, FREEZE_SIDE_EFFECT
+ ld b, $4d ; else use 0x4D/0x100 or 77/256 = 30.1%~ chance
+ jr z, .next2
+ ld b, $1a ; 0x1A/0x100 or 26/256 = 10.2%~ chance
+ jr .next2
+.asm_3f341
cp PARALYZE_SIDE_EFFECT1 + 1
ld b, $1a
jr c, .next2
@@ -283,17 +313,23 @@ FreezeBurnParalyzeEffect:
ld a, 1 << PAR
ld [wBattleMonStatus], a
call QuarterSpeedDueToParalysis
+ ld a, ANIM_C7
+ call PlayBattleAnimation2
jp PrintMayNotAttackText
.burn2
ld a, 1 << BRN
ld [wBattleMonStatus], a
call HalveAttackDueToBurn
+ ld a, ANIM_C7
+ call PlayBattleAnimation2
ld hl, BurnedText
jp PrintText
.freeze2
; hyper beam bits aren't reseted for opponent's side
ld a, 1 << FRZ
ld [wBattleMonStatus], a
+ ld a, ANIM_C7
+ call PlayBattleAnimation2
ld hl, FrozenText
jp PrintText
@@ -472,9 +508,9 @@ UpdateStatDone:
bit HAS_SUBSTITUTE_UP, [hl]
push af
push bc
+ push de
ld hl, HideSubstituteShowMonAnim
ld b, BANK(HideSubstituteShowMonAnim)
- push de
call nz, Bankswitch
pop de
.notMinimize
@@ -975,6 +1011,9 @@ FlinchSideEffect:
ld hl, wPlayerBattleStatus1
ld de, wEnemyMoveEffect
.flinchSideEffect
+ ld a, [wLinkState]
+ cp LINK_STATE_BATTLING
+ call z, ClearHyperBeam
ld a, [de]
cp FLINCH_SIDE_EFFECT1
ld b, $1a ; ~10% chance of flinch
@@ -1016,10 +1055,27 @@ ChargeEffect:
set INVULNERABLE, [hl] ; mon is now invulnerable to typical attacks (fly/dig)
ld b, ANIM_C0
.notDigOrFly
+ push de
+ push bc
+ inc hl ; battle status 2
+ push hl
+ ld a, [hl]
+ bit HAS_SUBSTITUTE_UP, a
+ ld hl, HideSubstituteShowMonAnim
+ ld b, BANK(HideSubstituteShowMonAnim)
+ call nz, Bankswitch
+ pop hl
+ pop bc
xor a
ld [wAnimationType], a
ld a, b
call PlayBattleAnimation
+ ld a, [hl]
+ bit HAS_SUBSTITUTE_UP, a
+ ld hl, ReshowSubstituteAnim
+ ld b, BANK(ReshowSubstituteAnim)
+ call nz, Bankswitch
+ pop de
ld a, [de]
ld [wChargeMoveNum], a
ld hl, ChargeMoveEffectText
@@ -1489,6 +1545,7 @@ PlayBattleAnimationGotID:
push de
push bc
predef MoveAnimation
+ callfar Func_78e98
pop bc
pop de
pop hl
diff --git a/engine/battle/end_of_battle.asm b/engine/battle/end_of_battle.asm
index bd4a1901..e64f54e7 100644
--- a/engine/battle/end_of_battle.asm
+++ b/engine/battle/end_of_battle.asm
@@ -10,6 +10,8 @@ EndOfBattle:
ld a, [wEnemyMonStatus]
ld [hl], a
call ClearScreen
+ ld b, SET_PAL_OVERWORLD
+ call RunPaletteCommand
callfar DisplayLinkBattleVersusTextBox
ld a, [wBattleResult]
cp $1
@@ -43,6 +45,8 @@ EndOfBattle:
xor a
ld [wForceEvolution], a
predef EvolutionAfterBattle
+ ld d, $82
+ callfar UpdatePikachuMoodAfterBattle
.resetVariables
xor a
ld [wLowHealthAlarm], a ;disable low health alarm
diff --git a/engine/battle/experience.asm b/engine/battle/experience.asm
index 0eab6e08..61fbdfa3 100644
--- a/engine/battle/experience.asm
+++ b/engine/battle/experience.asm
@@ -43,7 +43,7 @@ GainExperience:
inc de
jr .nextBaseStat
.maxStatExp ; if the upper byte also overflowed, then we have hit the max stat exp
- ld a, $ff
+ dec a ; ld a, $ff; a is 0 from previous check
ld [de], a
inc de
ld [de], a
@@ -233,13 +233,19 @@ GainExperience:
.recalcStatChanges
xor a ; battle mon
ld [wCalculateWhoseStats], a
- callfar CalculateModifiedStats
- callfar ApplyBurnAndParalysisPenaltiesToPlayer
- callfar ApplyBadgeStatBoosts
- callfar DrawPlayerHUDAndHPBar
- callfar PrintEmptyString
+ ld hl, CalculateModifiedStats
+ call CallBattleCore
+ ld hl, ApplyBurnAndParalysisPenaltiesToPlayer
+ call CallBattleCore
+ ld hl, ApplyBadgeStatBoosts
+ call CallBattleCore
+ ld hl, DrawPlayerHUDAndHPBar
+ call CallBattleCore
+ ld hl, PrintEmptyString
+ call CallBattleCore
call SaveScreenTilesToBuffer1
.printGrewLevelText
+ callabd_ModifyPikachuHappiness PIKAHAPPY_LEVELUP
ld hl, GrewLevelText
call PrintText
xor a ; PLAYER_PARTY_DATA
@@ -339,6 +345,10 @@ BoostExp:
ldh [hQuotient + 2], a
ret
+CallBattleCore:
+ ld b, BANK(BattleCore)
+ jp Bankswitch
+
GainedText:
text_far _GainedText
text_asm
diff --git a/engine/battle/ghost_marowak_anim.asm b/engine/battle/ghost_marowak_anim.asm
index 9c1ad96f..fd21b29e 100644
--- a/engine/battle/ghost_marowak_anim.asm
+++ b/engine/battle/ghost_marowak_anim.asm
@@ -2,6 +2,7 @@ MarowakAnim:
; animate the ghost being unveiled as a Marowak
ld a, $e4
ldh [rOBP1], a
+ call UpdateGBCPal_OBP1
call CopyMonPicFromBGToSpriteVRAM ; cover the BG ghost pic with a sprite ghost pic that looks the same
; now that the ghost pic is being displayed using sprites, clear the ghost pic from the BG tilemap
hlcoord 12, 0
@@ -27,6 +28,7 @@ MarowakAnim:
sla a
sla a
ldh [rOBP1], a
+ call UpdateGBCPal_OBP1
jr nz, .fadeOutGhostLoop
call ClearSprites
call CopyMonPicFromBGToSpriteVRAM ; copy Marowak pic from BG to sprite VRAM
@@ -40,6 +42,7 @@ MarowakAnim:
srl b
rra
ldh [rOBP1], a
+ call UpdateGBCPal_OBP1
ld a, b
and a
jr nz, .fadeInMarowakLoop
@@ -74,7 +77,7 @@ CopyMonPicFromBGToSpriteVRAM:
ld [hli], a
ld a, d
ld [hli], a
- ld a, OAM_OBP1
+ ld a, OAM_OBP1 | OAM_HIGH_PALS
ld [hli], a
inc d
dec c
diff --git a/engine/battle/init_battle.asm b/engine/battle/init_battle.asm
new file mode 100644
index 00000000..6a6331b7
--- /dev/null
+++ b/engine/battle/init_battle.asm
@@ -0,0 +1,282 @@
+InitBattle::
+ ld a, [wCurOpponent]
+ and a
+ jr z, DetermineWildOpponent
+
+InitOpponent:
+ ld a, [wCurOpponent]
+ ld [wcf91], a
+ ld [wEnemyMonSpecies2], a
+ jr InitBattleCommon
+
+DetermineWildOpponent:
+ ld a, [wd732]
+ bit 1, a
+ jr z, .asm_3ef2f
+ ldh a, [hJoyHeld]
+ bit 1, a ; B button pressed?
+ ret nz
+.asm_3ef2f
+ ld a, [wNumberOfNoRandomBattleStepsLeft]
+ and a
+ ret nz
+ callfar TryDoWildEncounter
+ ret nz
+InitBattleCommon:
+ ld a, [wMapPalOffset]
+ push af
+ ld hl, wLetterPrintingDelayFlags
+ ld a, [hl]
+ push af
+ res 1, [hl]
+ call InitBattleVariables
+ ld a, [wEnemyMonSpecies2]
+ sub OPP_ID_OFFSET
+ jp c, InitWildBattle
+ ld [wTrainerClass], a
+ call GetTrainerInformation
+ callfar ReadTrainer
+ callfar DoBattleTransitionAndInitBattleVariables
+ call _LoadTrainerPic
+ xor a
+ ld [wEnemyMonSpecies2], a
+ ldh [hStartTileID], a
+ dec a
+ ld [wAICount], a
+ hlcoord 12, 0
+ predef CopyUncompressedPicToTilemap
+ ld a, $ff
+ ld [wEnemyMonPartyPos], a
+ ld a, $2
+ ld [wIsInBattle], a
+
+; Is this a major story battle?
+ ld a, [wLoneAttackNo]
+ and a
+ jp z, _InitBattleCommon
+ callabd_ModifyPikachuHappiness PIKAHAPPY_GYMLEADER ; useless since already in bank3d
+ jp _InitBattleCommon
+
+InitWildBattle:
+ ld a, $1
+ ld [wIsInBattle], a
+ callfar LoadEnemyMonData
+ callfar DoBattleTransitionAndInitBattleVariables
+ ld a, [wCurOpponent]
+ cp RESTLESS_SOUL
+ jr z, .isGhost
+ callfar IsGhostBattle
+ jr nz, .isNoGhost
+.isGhost
+ ld hl, wMonHSpriteDim
+ ld a, $66
+ ld [hli], a ; write sprite dimensions
+ ld bc, GhostPic
+ ld a, c
+ ld [hli], a ; write front sprite pointer
+ ld [hl], b
+ ld hl, wEnemyMonNick ; set name to "GHOST"
+ ld a, "G"
+ ld [hli], a
+ ld a, "H"
+ ld [hli], a
+ ld a, "O"
+ ld [hli], a
+ ld a, "S"
+ ld [hli], a
+ ld a, "T"
+ ld [hli], a
+ ld [hl], "@"
+ ld a, [wcf91]
+ push af
+ ld a, MON_GHOST
+ ld [wcf91], a
+ ld de, vFrontPic
+ call LoadMonFrontSprite ; load ghost sprite
+ pop af
+ ld [wcf91], a
+ jr .spriteLoaded
+.isNoGhost
+ ld de, vFrontPic
+ call LoadMonFrontSprite ; load mon sprite
+.spriteLoaded
+ xor a
+ ld [wTrainerClass], a
+ ldh [hStartTileID], a
+ hlcoord 12, 0
+ predef CopyUncompressedPicToTilemap
+
+; common code that executes after init battle code specific to trainer or wild battles
+_InitBattleCommon:
+ ld b, SET_PAL_BATTLE_BLACK
+ call RunPaletteCommand
+ callfar SlidePlayerAndEnemySilhouettesOnScreen
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ ld hl, .emptyString
+ call PrintText
+ call SaveScreenTilesToBuffer1
+ call ClearScreen
+ ld a, $98
+ ldh [hAutoBGTransferDest + 1], a
+ ld a, $1
+ ldh [hAutoBGTransferEnabled], a
+ call Delay3
+ ld a, $9c
+ ldh [hAutoBGTransferDest + 1], a
+ call LoadScreenTilesFromBuffer1
+ hlcoord 9, 7
+ lb bc, 5, 10
+ call ClearScreenArea
+ hlcoord 1, 0
+ lb bc, 4, 10
+ call ClearScreenArea
+ call ClearSprites
+ ld a, [wIsInBattle]
+ dec a ; is it a wild battle?
+ ld hl, DrawEnemyHUDAndHPBar
+ ld b, BANK(DrawEnemyHUDAndHPBar)
+ call z, Bankswitch ; draw enemy HUD and HP bar if it's a wild battle
+ callfar StartBattle
+ callfar EndOfBattle
+ pop af
+ ld [wLetterPrintingDelayFlags], a
+ pop af
+ ld [wMapPalOffset], a
+ ld a, [wSavedTileAnimations]
+ ldh [hTileAnimations], a
+ scf
+ ret
+.emptyString
+ db "@"
+
+_LoadTrainerPic:
+; wd033-wd034 contain pointer to pic
+ ld a, [wTrainerPicPointer]
+ ld e, a
+ ld a, [wTrainerPicPointer + 1]
+ ld d, a ; de contains pointer to trainer pic
+ ld a, [wLinkState]
+ and a
+ ld a, BANK(TrainerPics) ; this is where all the trainer pics are (not counting Red's)
+ jr z, .loadSprite
+ ld a, BANK(RedPicFront)
+.loadSprite
+ call UncompressSpriteFromDE
+ ld de, vFrontPic
+ ld a, $77
+ ld c, a
+ jp LoadUncompressedSpriteData
+
+LoadMonBackPic:
+; Assumes the monster's attributes have
+; been loaded with GetMonHeader.
+ ld a, [wBattleMonSpecies2]
+ ld [wcf91], a
+ hlcoord 1, 5
+ lb bc, 7, 8
+ call ClearScreenArea
+ ld hl, wMonHBackSprite - wMonHeader
+ call UncompressMonSprite
+ predef ScaleSpriteByTwo
+ ld de, vBackPic
+ call InterlaceMergeSpriteBuffers ; combine the two buffers to a single 2bpp sprite
+ ld hl, vSprites
+ ld de, vBackPic
+ ld c, (2*SPRITEBUFFERSIZE)/16 ; count of 16-byte chunks to be copied
+ ldh a, [hLoadedROMBank]
+ ld b, a
+ jp CopyVideoData
+
+AnimateSendingOutMon:
+ ld a, [wPredefRegisters]
+ ld h, a
+ ld a, [wPredefRegisters + 1]
+ ld l, a
+ ldh a, [hStartTileID]
+ ldh [hDownArrowBlinkCount1], a
+ ld b, $4c
+ ld a, [wIsInBattle]
+ and a
+ jr z, .asm_f61ef
+ add b
+ ld [hl], a
+ call Delay3
+ ld bc, -41
+ add hl, bc
+ ld a, $1
+ ld [wNumMovesMinusOne], a
+ ld bc, $303
+ predef CopyDownscaledMonTiles
+ ld c, $4
+ call DelayFrames
+ ld bc, -41
+ add hl, bc
+ xor a
+ ld [wNumMovesMinusOne], a
+ ld bc, $505
+ predef CopyDownscaledMonTiles
+ ld c, $5
+ call DelayFrames
+ ld bc, -41
+ jr .asm_f61f2
+.asm_f61ef
+ ld bc, -123
+.asm_f61f2
+ add hl, bc
+ ldh a, [hDownArrowBlinkCount1]
+ add $31
+ jr CopyUncompressedPicToHL
+
+CopyUncompressedPicToTilemap:
+ ld a, [wPredefRegisters]
+ ld h, a
+ ld a, [wPredefRegisters + 1]
+ ld l, a
+ ldh a, [hStartTileID]
+CopyUncompressedPicToHL::
+ ld bc, $707
+ ld de, $14
+ push af
+ ld a, [wSpriteFlipped]
+ and a
+ jr nz, .asm_f6220
+ pop af
+.asm_f6211
+ push bc
+ push hl
+.asm_f6213
+ ld [hl], a
+ add hl, de
+ inc a
+ dec c
+ jr nz, .asm_f6213
+ pop hl
+ inc hl
+ pop bc
+ dec b
+ jr nz, .asm_f6211
+ ret
+
+.asm_f6220
+ push bc
+ ld b, $0
+ dec c
+ add hl, bc
+ pop bc
+ pop af
+.asm_f6227
+ push bc
+ push hl
+.asm_f6229
+ ld [hl], a
+ add hl, de
+ inc a
+ dec c
+ jr nz, .asm_f6229
+ pop hl
+ dec hl
+ pop bc
+ dec b
+ jr nz, .asm_f6227
+ ret
diff --git a/engine/battle/link_battle_versus_text.asm b/engine/battle/link_battle_versus_text.asm
index 29c11356..e55a0672 100644
--- a/engine/battle/link_battle_versus_text.asm
+++ b/engine/battle/link_battle_versus_text.asm
@@ -2,8 +2,7 @@
DisplayLinkBattleVersusTextBox:
call LoadTextBoxTilePatterns
hlcoord 3, 4
- ld b, 7
- ld c, 12
+ lb bc, 7, 12
call TextBoxBorder
hlcoord 4, 5
ld de, wPlayerName
diff --git a/engine/battle/misc.asm b/engine/battle/misc.asm
index 33af6f6f..df9145f2 100644
--- a/engine/battle/misc.asm
+++ b/engine/battle/misc.asm
@@ -101,22 +101,3 @@ InitList:
ld a, b
ld [wItemPrices + 1], a
ret
-
-; get species of mon e in list [wMonDataLocation] for LoadMonData
-GetMonSpecies:
- ld hl, wPartySpecies
- ld a, [wMonDataLocation]
- and a
- jr z, .getSpecies
- dec a
- jr z, .enemyParty
- ld hl, wBoxSpecies
- jr .getSpecies
-.enemyParty
- ld hl, wEnemyPartyMons
-.getSpecies
- ld d, 0
- add hl, de
- ld a, [hl]
- ld [wcf91], a
- ret
diff --git a/engine/battle/move_effects/transform.asm b/engine/battle/move_effects/transform.asm
index 56dda7f4..af47ae1b 100644
--- a/engine/battle/move_effects/transform.asm
+++ b/engine/battle/move_effects/transform.asm
@@ -100,18 +100,11 @@ TransformEffect_:
and a
jr z, .lessThanFourMoves
ld a, $5
- ld [de], a
- inc de
- dec b
- jr nz, .copyPPLoop
- jr .copyStats
.lessThanFourMoves
-; 0 PP for blank moves
- xor a
ld [de], a
inc de
dec b
- jr nz, .lessThanFourMoves
+ jr nz, .copyPPLoop
.copyStats
; original (unmodified) stats and stat mods
pop hl
diff --git a/engine/battle/pikachu_entrance_anim.asm b/engine/battle/pikachu_entrance_anim.asm
new file mode 100644
index 00000000..8af65cee
--- /dev/null
+++ b/engine/battle/pikachu_entrance_anim.asm
@@ -0,0 +1,47 @@
+StarterPikachuBattleEntranceAnimation:
+ hlcoord 0, 5
+ ld c, 0
+.loop1
+ inc c
+ ld a, c
+ cp 9
+ ret z
+ ld d, 7 * 13
+ push bc
+ push hl
+.loop2
+ call .PlaceColumn
+ dec hl
+ ld a, d
+ sub 7
+ ld d, a
+ dec c
+ jr nz, .loop2
+ ld c, 2
+ call DelayFrames
+ pop hl
+ pop bc
+ inc hl
+ jr .loop1
+
+.PlaceColumn:
+ push hl
+ push de
+ push bc
+ ld e, 7
+.loop3
+ ld a, d
+ cp 7 * 7
+ jr nc, .okay
+ ld a, $7f
+.okay
+ ld [hl], a
+ ld bc, SCREEN_WIDTH
+ add hl, bc
+ inc d
+ dec e
+ jr nz, .loop3
+ pop bc
+ pop de
+ pop hl
+ ret
diff --git a/engine/battle/read_trainer_party.asm b/engine/battle/read_trainer_party.asm
index a0132a4f..02fbfeda 100644
--- a/engine/battle/read_trainer_party.asm
+++ b/engine/battle/read_trainer_party.asm
@@ -15,8 +15,8 @@ ReadTrainer:
ld [hl], a
; get the pointer to trainer data for this class
- ld a, [wCurOpponent]
- sub OPP_ID_OFFSET + 1 ; convert value from pokemon to trainer
+ ld a, [wTrainerClass] ; get trainer class
+ dec a
add a
ld hl, TrainerDataPointers
ld c, a
@@ -53,7 +53,7 @@ ReadTrainer:
.LoopTrainerData
ld a, [hli]
and a ; have we reached the end of the trainer data?
- jr z, .FinishUp
+ jp z, .AddAdditionalMoveData
ld [wcf91], a ; write species somewhere (XXX why?)
ld a, ENEMY_PARTY_DATA
ld [wMonDataLocation], a
@@ -68,7 +68,7 @@ ReadTrainer:
; - if [wLoneAttackNo] != 0, one pokemon on the team has a special move
ld a, [hli]
and a ; have we reached the end of the trainer data?
- jr z, .AddLoneMove
+ jr z, .AddAdditionalMoveData
ld [wCurEnemyLVL], a
ld a, [hli]
ld [wcf91], a
@@ -78,69 +78,48 @@ ReadTrainer:
call AddPartyMon
pop hl
jr .SpecialTrainer
-.AddLoneMove
-; does the trainer have a single monster with a different move?
- ld a, [wLoneAttackNo] ; Brock is 01, Misty is 02, Erika is 04, etc
+.AddAdditionalMoveData
+; does the trainer have additional move data?
+ ld a, [wTrainerClass]
+ ld b, a
+ ld a, [wTrainerNo]
+ ld c, a
+ ld hl, SpecialTrainerMoves
+.loopAdditionalMoveData
+ ld a, [hli]
+ cp $ff
+ jr z, .FinishUp
+ cp b
+ jr nz, .asm_39c46
+ ld a, [hli]
+ cp c
+ jr nz, .asm_39c46
+ ld d, h
+ ld e, l
+.writeAdditionalMoveDataLoop
+ ld a, [de]
+ inc de
and a
- jr z, .AddTeamMove
+ jp z, .FinishUp
+ dec a
+ ld hl, wEnemyMon1Moves
+ ld bc, wEnemyMon2 - wEnemyMon1
+ call AddNTimes
+ ld a, [de]
+ inc de
dec a
- add a
ld c, a
ld b, 0
- ld hl, LoneMoves
add hl, bc
+ ld a, [de]
+ inc de
+ ld [hl], a
+ jr .writeAdditionalMoveDataLoop
+.asm_39c46
ld a, [hli]
- ld d, [hl]
- ld hl, wEnemyMon1Moves + 2
- ld bc, wEnemyMon2 - wEnemyMon1
- call AddNTimes
- ld [hl], d
- jr .FinishUp
-.AddTeamMove
-; check if our trainer's team has special moves
-
-; get trainer class number
- ld a, [wCurOpponent]
- sub OPP_ID_OFFSET
- ld b, a
- ld hl, TeamMoves
-
-; iterate through entries in TeamMoves, checking each for our trainer class
-.IterateTeamMoves
- ld a, [hli]
- cp b
- jr z, .GiveTeamMoves ; is there a match?
- inc hl ; if not, go to the next entry
- inc a
- jr nz, .IterateTeamMoves
-
-; no matches found. is this trainer champion rival?
- ld a, b
- cp RIVAL3
- jr z, .ChampionRival
- jr .FinishUp ; nope
-.GiveTeamMoves
- ld a, [hl]
- ld [wEnemyMon5Moves + 2], a
- jr .FinishUp
-.ChampionRival ; give moves to his team
-
-; pidgeot
- ld a, SKY_ATTACK
- ld [wEnemyMon1Moves + 2], a
-
-; starter
- ld a, [wRivalStarter]
- cp STARTER3
- ld b, MEGA_DRAIN
- jr z, .GiveStarterMove
- cp STARTER1
- ld b, FIRE_BLAST
- jr z, .GiveStarterMove
- ld b, BLIZZARD ; must be squirtle
-.GiveStarterMove
- ld a, b
- ld [wEnemyMon6Moves + 2], a
+ and a
+ jr nz, .asm_39c46
+ jr .loopAdditionalMoveData
.FinishUp
; clear wAmountMoneyWon addresses
xor a
diff --git a/engine/battle/scale_sprites.asm b/engine/battle/scale_sprites.asm
index 8b8942e6..38ebff21 100644
--- a/engine/battle/scale_sprites.asm
+++ b/engine/battle/scale_sprites.asm
@@ -2,6 +2,13 @@
; assumes that input sprite chunks are 4x4 tiles, and the rightmost and bottommost 4 pixels will be ignored
; resulting in a 7*7 tile output sprite chunk
ScaleSpriteByTwo:
+ ld a, $0
+ call SwitchSRAMBankAndLatchClockData
+ call .ScaleSpriteByTwo
+ call PrepareRTCDataAndDisableSRAM
+ ret
+
+.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
diff --git a/engine/battle/trainer_ai.asm b/engine/battle/trainer_ai.asm
index d70f98a1..a2c5e5fb 100644
--- a/engine/battle/trainer_ai.asm
+++ b/engine/battle/trainer_ai.asm
@@ -288,13 +288,19 @@ INCLUDE "data/trainers/special_moves.asm"
INCLUDE "data/trainers/parties.asm"
TrainerAI:
- and a
ld a, [wIsInBattle]
dec a
- ret z ; if not a trainer, we're done here
+ jr z, .done ; if not a trainer, we're done here
ld a, [wLinkState]
cp LINK_STATE_BATTLING
- ret z ; if in a link battle, we're done as well
+ jr z, .done ; if in a link battle, we're done as well
+ ld a, [wEnemyBattleStatus1]
+ and 1 << CHARGING_UP | 1 << THRASHING_ABOUT | 1 << STORING_ENERGY
+ jr nz, .done ; don't follow trainer ai if opponent is in a locked state
+ ld a, [wEnemyBattleStatus2]
+ and 1 << USING_RAGE
+ jr nz, .done ; don't follow trainer ai if opponent is locked in rage
+ ; note that this doesn't check for hyper beam recharge which can cause problems
ld a, [wTrainerClass] ; what trainer class is this?
dec a
ld c, a
@@ -305,7 +311,7 @@ TrainerAI:
add hl, bc
ld a, [wAICount]
and a
- ret z ; if no AI uses left, we're done here
+ jr z, .done ; if no AI uses left, we're done here
inc hl
inc a
jr nz, .getpointer
@@ -318,6 +324,9 @@ TrainerAI:
ld l, a
call Random
jp hl
+.done
+ and a
+ ret
INCLUDE "data/trainers/ai_pointers.asm"
@@ -377,22 +386,22 @@ ErikaAI:
jp AIUseSuperPotion
KogaAI:
- cp 25 percent + 1
+ cp 13 percent - 1
ret nc
jp AIUseXAttack
BlaineAI:
cp 25 percent + 1
ret nc
+ ld a, 10
+ call AICheckIfHPBelowFraction
+ ret nc
jp AIUseSuperPotion
SabrinaAI:
cp 25 percent + 1
ret nc
- ld a, 10
- call AICheckIfHPBelowFraction
- ret nc
- jp AIUseHyperPotion
+ jp AIUseXDefend
Rival2AI:
cp 13 percent - 1
diff --git a/engine/battle/wild_encounters.asm b/engine/battle/wild_encounters.asm
index 8c9c1529..d16c6515 100644
--- a/engine/battle/wild_encounters.asm
+++ b/engine/battle/wild_encounters.asm
@@ -24,8 +24,9 @@ TryDoWildEncounter:
ld [wRepelRemainingSteps], a
.next
; determine if wild pokemon can appear in the half-block we're standing in
-; is the bottom right tile (9,9) of the half-block we're standing in a grass/water tile?
- hlcoord 9, 9
+; is the bottom left tile (8,9) of the half-block we're standing in a grass/water tile?
+; note that by using the bottom left tile, this prevents the "left-shore" tiles from generating grass encounters
+ hlcoord 8, 9
ld c, [hl]
ld a, [wGrassTile]
cp c
@@ -68,8 +69,6 @@ TryDoWildEncounter:
cp $14 ; is the bottom left tile (8,9) of the half-block we're standing in a water tile?
jr nz, .gotWildEncounterType ; else, it's treated as a grass tile by default
ld hl, wWaterMons
-; since the bottom right tile of a "left shore" half-block is $14 but the bottom left tile is not,
-; "left shore" half-blocks (such as the one in the east coast of Cinnabar) load grass encounters.
.gotWildEncounterType
ld b, 0
add hl, bc